{"openapi":"3.0.3","info":{"title":"Inferrex API","version":"1.0.0","description":"Customer-facing REST API for the Inferrex self-healing integration platform — connect systems, infer schemas, run pipelines, and read the canonical model. The hosted MCP server (mcp.inferrex.com) and a typed TypeScript SDK (@inferrex/sdk) map 1:1 to these operations.\n\n## Rate limits\n\nLimits are **per API key / workspace** (not per IP), so an agent behind one NAT egress IP gets its own ceiling. A token-bucket allows short bursts above the sustained per-minute rate. Every response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` (and the draft `RateLimit-*` equivalents); a `429` adds `Retry-After` (seconds). Public endpoints (`/v1/openapi.json`, `/v1/contact`) are limited per IP. See the `x-ratelimit` extension for the per-tier table.\n\n## Webhooks (event delivery)\n\nRegister an endpoint at `POST /v1/webhooks/subscriptions` and Inferrex POSTs state-change events to it — no polling. Each delivery is HMAC-SHA256-signed: recompute the hex digest over the raw request body keyed by your subscription signing secret (`POST /v1/webhooks/subscriptions/:id/secret`, shown once) and compare to the `X-Inferrex-Signature` header. `X-Inferrex-Event-Id` is stable across redeliveries (dedupe on it); failures retry with exponential backoff then dead-letter. Filter by event type per subscription; the full catalogue is in the `x-webhooks` extension. Send yourself a signed sample with `POST /v1/webhooks/subscriptions/:id/test`.\n\n## Idempotency\n\nMake any unsafe request (POST/PUT/PATCH/DELETE) safe to retry by sending an `Idempotency-Key` header (a unique string per logical operation). The first response is cached for 24h and replayed verbatim for any retry with the same key by the same caller (the same signed-in person, API key or access token; anyone else gets their own run), and a replay carries `Idempotent-Replayed: true`. A response carrying a credential shown once (it says `Cache-Control: no-store`, e.g. a new API key) is never stored: its retry returns `409 idempotent_replay_withheld`. Reusing a key with different parameters returns `409 idempotency_key_reused`; a retry while the first is still in flight returns `409 request_in_progress`. Server errors (5xx) are never cached, so they genuinely re-run.\n\n## Async jobs\n\nLong-running operations return `202` with `{ jobId, status: \"queued\" }`. Poll `GET /v1/jobs/:id` for `{ status, progress, result, error }` — `status` advances queued → running → succeeded/failed. The jobId is stable and pollable (not an opaque queue message id).\n\n## Pagination\n\nMost list endpoints use offset pagination (`limit` + `offset`). High-volume/append-heavy collections use **keyset cursor** pagination instead: pass `limit` + an opaque `cursor`, and the response is `{ <resource>, nextCursor, hasMore }` — follow `nextCursor` until `hasMore` is false. Cursors are stable under inserts and avoid deep-offset cost. Whether an endpoint is offset- or cursor-paginated is visible from its `cursor` vs `offset` query parameter.\n\n## Authentication & scopes\n\nSend an `X-API-Key` header (workspace-scoped) or a Firebase bearer token. API keys carry granular `<resource>:<read|write|delete>` scopes; each operation declares the scope it needs (see its `security`), and the full catalogue is in the `x-api-scopes` extension. A machine-to-machine OAuth 2.0 client-credentials flow shares the same scopes. The public discovery endpoints (`/v1/openapi.json`, `/.well-known/llms.txt`) need no credential. `/v1/pricing` is NOT among them — the pricing catalogue requires a credential.\n\n## Errors\n\nEvery error is `{ error, message, retryable, docs_url, requestId? }`. `retryable` tells an agent whether the same request could succeed on retry (true for 429/503, false for client errors); `docs_url` links the error code's docs so it can self-correct without a human.\n\n## Versioning & deprecation\n\nThe contract is versioned under `/v1`. A deprecated operation is flagged `deprecated: true` here and returns a `Deprecation: true` header (plus `Sunset` with the removal date and a `Link` rel=\"successor-version\" when applicable), so clients get the migration window in-band.","contact":{"name":"Inferrex","url":"https://inferrex.com/docs"}},"x-ratelimit":{"strategy":"token-bucket","scope":"Per API key / workspace for authenticated requests; per IP for public endpoints.","headers":["X-RateLimit-Limit","X-RateLimit-Remaining","X-RateLimit-Reset","RateLimit-Limit","RateLimit-Remaining","RateLimit-Reset","Retry-After"],"retryAfterOn429":true,"tiers":{"beta":{"perMinute":120,"burst":40},"qa_sit":{"perMinute":300,"burst":100},"uat":{"perMinute":1200,"burst":300},"staging":{"perMinute":3000,"burst":600},"production":{"perMinute":6000,"burst":1000},"enterprise":{"perMinute":6000,"burst":1000},"sovereign":{"perMinute":12000,"burst":2000},"internal":{"perMinute":60000,"burst":5000}},"public":{"perMinute":60,"burst":20}},"x-webhooks":{"delivery":"Inferrex POSTs each event to your registered subscription URL(s).","signature":{"header":"X-Inferrex-Signature","algorithm":"HMAC-SHA256","over":"the raw request body, hex-encoded, keyed by the subscription signing secret (POST /v1/webhooks/subscriptions/:id/secret)"},"idempotency":{"header":"X-Inferrex-Event-Id","note":"Stable across redeliveries — dedupe on it."},"reliability":"Exponential-backoff retry then a dead-letter queue on repeated failure.","payload":{"id":"string (event id)","type":"string (event type)","created":"string (ISO-8601)","data":"object (the changed resource)"},"manage":"/v1/webhooks/subscriptions","eventTypes":["alert_rules.created","alert_rules.deleted","alert_rules.updated","approval_policies.created","approval_policies.deleted","approval_policies.updated","circuit_breaker_policies.created","circuit_breaker_policies.deleted","circuit_breaker_policies.updated","connection_environment_bindings.created","connection_environment_bindings.deleted","connection_environment_bindings.updated","environments.created","environments.deleted","environments.updated","field_authority_rules.created","field_authority_rules.deleted","field_authority_rules.updated","initial_loads.created","initial_loads.updated","invite_policies.created","invite_policies.updated","notification_channels.created","notification_channels.deleted","notification_channels.updated","operation_scopes.created","operation_scopes.deleted","operation_scopes.updated","promotion_edges.created","promotion_edges.deleted","promotion_edges.updated","resource_permissions.created","resource_permissions.deleted","restoration_requests.created","retention_policies.created","retention_policies.deleted","retention_policies.updated","review_assignments.deleted","saved_views.created","saved_views.deleted","saved_views.updated","schema_contracts.created","schema_contracts.deleted","schema_contracts.updated","support_tickets.created","support_tickets.updated","team_members.created","team_resources.created","teams.created","teams.deleted","teams.updated","tenant_secrets.created","tenant_secrets.deleted","tenant_secrets.updated","webhook.test","webhook_subscriptions.created","webhook_subscriptions.deleted","webhook_subscriptions.updated","workflows.created","workflows.deleted","workflows.updated","workspace_users.deleted","workspace_users.updated"]},"x-api-scopes":["alert-deliveries:read","alert-rules:delete","alert-rules:read","alert-rules:write","approval-policies:delete","approval-policies:read","approval-policies:write","archival:read","archival:write","assistant:delete","assistant:read","assistant:write","billing:read","billing:write","bloomreach:delete","bloomreach:read","bloomreach:write","canonical-proposals:read","canonical-proposals:write","circuit-breaker-policies:delete","circuit-breaker-policies:read","circuit-breaker-policies:write","circuit-breakers:read","circuit-breakers:write","cli-snippets:delete","cli-snippets:read","cli-snippets:write","cli-socket-tickets:write","connection-environment-bindings:delete","connection-environment-bindings:read","connection-environment-bindings:write","connections:delete","connections:read","connections:write","events:read","events:write","field-authority-rules:delete","field-authority-rules:read","field-authority-rules:write","gamification:delete","gamification:read","gamification:write","golden-records:read","golden-records:write","governance:read","heals:read","heals:write","hooks:receive","initial-loads:read","initial-loads:write","intelligence:delete","intelligence:read","intelligence:write","jobs:read","jobs:write","library:read","library:write","licence:write","mappings:read","mappings:write","monitoring:read","notifications:read","notifications:write","oauth:write","onboarding:read","onboarding:write","operation-scopes:delete","operation-scopes:read","operation-scopes:write","parallel-run-discrepancies:read","pipeline-events:read","pipeline-promotions:read","pipeline-promotions:write","pipeline-targets:read","pipeline-targets:write","pipelines:delete","pipelines:read","pipelines:write","platform-config:read","platform-config:write","platform-value-scores:read","platform-value-scores:write","portal:read","portal:write","pricing:read","quarantine:read","reports:write","restoration-requests:read","restoration-requests:write","retention-policies:delete","retention-policies:read","retention-policies:write","retrieve:read","schema:read","search:read","secrets:delete","secrets:read","secrets:write","settings:delete","settings:read","settings:write","suggestions:read","terms:read","terms:write","unified:delete","unified:read","unified:write","webhooks:delete","webhooks:read","webhooks:write","workflow-runs:read","workflow-runs:write","workflows:delete","workflows:read","workflows:write","workspace-users:write","workspace:delete","workspace:read","workspace:write","workspaces:read"],"servers":[{"url":"https://api.inferrex.com","description":"Production"}],"tags":[{"name":"archival"},{"name":"assistant"},{"name":"billing"},{"name":"bloomreach"},{"name":"cli_snippets"},{"name":"cli_sockets"},{"name":"connections"},{"name":"contact"},{"name":"core"},{"name":"credentials"},{"name":"data_protection"},{"name":"event_subscriptions"},{"name":"events"},{"name":"gamification"},{"name":"golden_record"},{"name":"governance"},{"name":"heals"},{"name":"intelligence"},{"name":"jobs"},{"name":"library"},{"name":"licence"},{"name":"mappings"},{"name":"marketing"},{"name":"mcp_oauth"},{"name":"meta"},{"name":"migration"},{"name":"monitoring"},{"name":"notifications"},{"name":"oauth"},{"name":"onboarding"},{"name":"operations"},{"name":"pipelines"},{"name":"platform_config"},{"name":"portal"},{"name":"pricing"},{"name":"public_corpus"},{"name":"rbac"},{"name":"reports"},{"name":"retrieval"},{"name":"schema"},{"name":"search"},{"name":"settings"},{"name":"sso"},{"name":"support_access"},{"name":"terms"},{"name":"unified_api"},{"name":"workflows"},{"name":"workspace"}],"paths":{"/.well-known/oauth-authorization-server":{"get":{"operationId":"GetMcpAuthorizationServerMetadata","tags":["mcp_oauth"],"summary":"Get Mcp Authorization Server Metadata","security":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"issuer":{"type":"string","minLength":1,"maxLength":2048},"authorization_endpoint":{"type":"string","minLength":1,"maxLength":2048},"token_endpoint":{"type":"string","minLength":1,"maxLength":2048},"registration_endpoint":{"type":"string","minLength":1,"maxLength":2048},"revocation_endpoint":{"type":"string","minLength":1,"maxLength":2048},"response_types_supported":{"type":"array","items":{"type":"string"}},"grant_types_supported":{"type":"array","items":{"type":"string"}},"code_challenge_methods_supported":{"type":"array","items":{"type":"string"}},"token_endpoint_auth_methods_supported":{"type":"array","items":{"type":"string"}},"scopes_supported":{"type":"array","items":{"type":"string"}},"client_id_metadata_document_supported":{"type":"boolean"}},"required":["issuer","authorization_endpoint","token_endpoint","registration_endpoint","revocation_endpoint","response_types_supported","grant_types_supported","code_challenge_methods_supported","token_endpoint_auth_methods_supported","scopes_supported","client_id_metadata_document_supported"]},"example":{"issuer":"string","authorization_endpoint":"string","token_endpoint":"string","registration_endpoint":"string","revocation_endpoint":"string","response_types_supported":["string"],"grant_types_supported":["string"],"code_challenge_methods_supported":["string"],"token_endpoint_auth_methods_supported":["string"],"scopes_supported":["string"],"client_id_metadata_document_supported":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}},"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}}},"400":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"401":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"403":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"404":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"405":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"429":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"500":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"503":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}}}}},"/oauth/authorize":{"get":{"operationId":"BeginMcpAuthorization","tags":["mcp_oauth"],"summary":"Begin Mcp Authorization","security":[],"parameters":[{"name":"client_id","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":2048}},{"name":"redirect_uri","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":2048}},{"name":"response_type","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":32}},{"name":"resource","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":2048}},{"name":"code_challenge","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":128}},{"name":"code_challenge_method","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":32}},{"name":"state","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":1024}},{"name":"scope","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":4096}}],"responses":{"302":{"description":"Redirect","headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}},"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}},"Location":{"schema":{"type":"string","format":"uri"}}}},"400":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"401":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"403":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"404":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"405":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"429":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"500":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"503":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}}}}},"/oauth/mcp-client.json":{"get":{"operationId":"GetMcpClientMetadata","tags":["oauth"],"summary":"Get Mcp Client Metadata","security":[],"description":"OAuth Client ID Metadata Document for Inferrex as an MCP client. `client_id` is this document's own URL; one redirect URI (the API's /oauth/mcp/callback); public client (`token_endpoint_auth_method: none`), authorization code with PKCE and refresh tokens.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"client_id":{"type":"string"},"client_name":{"type":"string"},"client_uri":{"type":"string"},"redirect_uris":{"type":"array","items":{"type":"string"}},"grant_types":{"type":"array","items":{"type":"string"}},"response_types":{"type":"array","items":{"type":"string"}},"token_endpoint_auth_method":{"type":"string"}},"required":["client_id","client_name","client_uri","redirect_uris","grant_types","response_types","token_endpoint_auth_method"]},"example":{"client_id":"string","client_name":"string","client_uri":"string","redirect_uris":["string"],"grant_types":["string"],"response_types":["string"],"token_endpoint_auth_method":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/oauth/register":{"post":{"operationId":"RegisterMcpOAuthClient","tags":["mcp_oauth"],"summary":"Register Mcp OAuth Client","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"client_name":{"type":"string","minLength":1,"maxLength":120},"redirect_uris":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":10},"token_endpoint_auth_method":{"type":"string","minLength":1,"maxLength":32},"grant_types":{"type":"array","items":{"type":"string"},"maxItems":2},"response_types":{"type":"array","items":{"type":"string"},"maxItems":1}},"required":["client_name","redirect_uris","token_endpoint_auth_method"]},"example":{"client_name":"string","redirect_uris":["string"],"token_endpoint_auth_method":"string","grant_types":["string"],"response_types":["string"]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"client_id":{"type":"string","minLength":1,"maxLength":2048},"client_name":{"type":"string","minLength":1,"maxLength":2048},"redirect_uris":{"type":"array","items":{"type":"string"}},"token_endpoint_auth_method":{"type":"string","minLength":1,"maxLength":2048},"grant_types":{"type":"array","items":{"type":"string"}},"response_types":{"type":"array","items":{"type":"string"}}},"required":["client_id","client_name","redirect_uris","token_endpoint_auth_method","grant_types","response_types"]},"example":{"client_id":"string","client_name":"string","redirect_uris":["string"],"token_endpoint_auth_method":"string","grant_types":["string"],"response_types":["string"]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}},"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}}},"400":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"401":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"403":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"404":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"405":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"429":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"500":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"503":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}}}}},"/oauth/revoke":{"post":{"operationId":"RevokeMcpOAuthToken","tags":["mcp_oauth"],"summary":"Revoke Mcp OAuth Token","security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"token":{"type":"string","minLength":1,"maxLength":2048},"client_id":{"type":"string","minLength":1,"maxLength":2048},"token_type_hint":{"type":"string","minLength":1,"maxLength":32}},"required":["token","client_id"]},"example":{"token":"string","client_id":"string","token_type_hint":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}},"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}}},"400":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"401":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"403":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"404":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"405":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"429":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"500":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"503":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}}}}},"/oauth/token":{"post":{"operationId":"ExchangeMcpOAuthToken","tags":["mcp_oauth"],"summary":"Exchange Mcp OAuth Token","security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"grant_type":{"type":"string","minLength":1,"maxLength":32},"client_id":{"type":"string","minLength":1,"maxLength":2048},"resource":{"type":"string","minLength":1,"maxLength":2048},"code":{"type":"string","minLength":1,"maxLength":128},"redirect_uri":{"type":"string","minLength":1,"maxLength":2048},"code_verifier":{"type":"string","minLength":1,"maxLength":128},"refresh_token":{"type":"string","minLength":1,"maxLength":128}},"required":["grant_type","client_id","resource"]},"example":{"grant_type":"string","client_id":"string","resource":"string","code":"string","redirect_uri":"string","code_verifier":"string","refresh_token":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string","minLength":1,"maxLength":2048},"token_type":{"type":"string","minLength":1,"maxLength":2048},"expires_in":{"type":"integer"},"refresh_token":{"type":"string","minLength":1,"maxLength":2048},"scope":{"type":"string","minLength":1,"maxLength":2048}},"required":["access_token","token_type","expires_in","refresh_token","scope"]},"example":{"access_token":"string","token_type":"string","expires_in":0,"refresh_token":"string","scope":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}},"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}}},"400":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"401":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"403":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"404":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"405":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"429":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"500":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"503":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}}}}},"/v1/alert-deliveries":{"get":{"operationId":"AlertDeliveriesList","tags":["monitoring"],"summary":"Alert Deliveries List","security":[{"ApiKeyAuth":["alert-deliveries:read"]},{"BearerAuth":[]},{"OAuth2":["alert-deliveries:read"]}],"description":"List your alert deliveries, newest first. Filter by any field, or search their text with q. Results come a page at a time: pass the nextCursor from one page to get the next.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"rule_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only alert deliveries for this rule. Pass its id."},"description":"Only alert deliveries for this rule. Pass its id."},{"name":"rule_name","in":"query","required":false,"schema":{"type":"string","description":"Only alert deliveries whose rule name is exactly this."},"description":"Only alert deliveries whose rule name is exactly this."},{"name":"rule_name_contains","in":"query","required":false,"schema":{"type":"string","description":"Only alert deliveries whose rule name contains this text (upper and lower case are treated the same)."},"description":"Only alert deliveries whose rule name contains this text (upper and lower case are treated the same)."},{"name":"event_id","in":"query","required":false,"schema":{"type":"string","description":"Only alert deliveries whose event is exactly this."},"description":"Only alert deliveries whose event is exactly this."},{"name":"event_id_contains","in":"query","required":false,"schema":{"type":"string","description":"Only alert deliveries whose event contains this text (upper and lower case are treated the same)."},"description":"Only alert deliveries whose event contains this text (upper and lower case are treated the same)."},{"name":"event_type","in":"query","required":false,"schema":{"type":"string","description":"Only alert deliveries whose event type is exactly this."},"description":"Only alert deliveries whose event type is exactly this."},{"name":"event_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only alert deliveries whose event type contains this text (upper and lower case are treated the same)."},"description":"Only alert deliveries whose event type contains this text (upper and lower case are treated the same)."},{"name":"severity","in":"query","required":false,"schema":{"type":"string","description":"Only alert deliveries whose severity is exactly this."},"description":"Only alert deliveries whose severity is exactly this."},{"name":"severity_contains","in":"query","required":false,"schema":{"type":"string","description":"Only alert deliveries whose severity contains this text (upper and lower case are treated the same)."},"description":"Only alert deliveries whose severity contains this text (upper and lower case are treated the same)."},{"name":"channel_type","in":"query","required":false,"schema":{"type":"string","description":"Only alert deliveries whose channel type is exactly this."},"description":"Only alert deliveries whose channel type is exactly this."},{"name":"channel_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only alert deliveries whose channel type contains this text (upper and lower case are treated the same)."},"description":"Only alert deliveries whose channel type contains this text (upper and lower case are treated the same)."},{"name":"channel_target","in":"query","required":false,"schema":{"type":"string","description":"Only alert deliveries whose channel target is exactly this."},"description":"Only alert deliveries whose channel target is exactly this."},{"name":"channel_target_contains","in":"query","required":false,"schema":{"type":"string","description":"Only alert deliveries whose channel target contains this text (upper and lower case are treated the same)."},"description":"Only alert deliveries whose channel target contains this text (upper and lower case are treated the same)."},{"name":"channel_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only alert deliveries for this channel. Pass its id."},"description":"Only alert deliveries for this channel. Pass its id."},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Only alert deliveries whose status is exactly this."},"description":"Only alert deliveries whose status is exactly this."},{"name":"status_contains","in":"query","required":false,"schema":{"type":"string","description":"Only alert deliveries whose status contains this text (upper and lower case are treated the same)."},"description":"Only alert deliveries whose status contains this text (upper and lower case are treated the same)."},{"name":"error","in":"query","required":false,"schema":{"type":"string","description":"Only alert deliveries whose error is exactly this."},"description":"Only alert deliveries whose error is exactly this."},{"name":"error_contains","in":"query","required":false,"schema":{"type":"string","description":"Only alert deliveries whose error contains this text (upper and lower case are treated the same)."},"description":"Only alert deliveries whose error contains this text (upper and lower case are treated the same)."},{"name":"attempts_gte","in":"query","required":false,"schema":{"type":"number","description":"Only alert deliveries whose attempts is this number or more."},"description":"Only alert deliveries whose attempts is this number or more."},{"name":"attempts_lte","in":"query","required":false,"schema":{"type":"number","description":"Only alert deliveries whose attempts is this number or less."},"description":"Only alert deliveries whose attempts is this number or less."},{"name":"test","in":"query","required":false,"schema":{"type":"boolean","description":"Only alert deliveries where test is true, or false for only those where it is false."},"description":"Only alert deliveries where test is true, or false for only those where it is false."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many alert deliveries to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many alert deliveries to return in one page: 1 to 200, 50 if you leave it out."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","description":"Where the next page starts. Leave it out for the first page, then pass the nextCursor value from the previous response."},"description":"Where the next page starts. Leave it out for the first page, then pass the nextCursor value from the previous response."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns alert deliveries where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns alert deliveries where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"rule_id":{"type":"string","format":"uuid","nullable":true,"description":"The alert rule that fired. Empty if the rule has since been deleted; the delivery record is kept."},"rule_name":{"type":"string","nullable":true},"event_id":{"type":"string","description":"The event that set off the alert. The same event never produces two entries for the same recipient, even if it is processed twice."},"event_type":{"type":"string","nullable":true},"severity":{"type":"string","nullable":true},"channel_type":{"type":"string","description":"How it was sent: email, text message, webhook or in-app."},"channel_target":{"type":"string","description":"Who received it — the address, number or URL the rule named."},"channel_id":{"type":"string","format":"uuid","nullable":true,"description":"Which of your own notification channels sent it. Empty when Inferrex’s own service sent it, or it was shown in the app."},"status":{"type":"string"},"error":{"type":"string","nullable":true},"attempts":{"type":"integer"},"test":{"type":"boolean","description":"Yes when this came from a test send of the rule, so tests are never mistaken for real alerts."},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","event_id","channel_type","channel_target","status"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","rule_id":"00000000-0000-0000-0000-000000000000","rule_name":"string","event_id":"string","event_type":"string","severity":"string","channel_type":"string","channel_target":"string","channel_id":"00000000-0000-0000-0000-000000000000","status":"string","error":"string","attempts":0,"test":true,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/alert-deliveries/{id}":{"get":{"operationId":"AlertDeliveriesGet","tags":["monitoring"],"summary":"Alert Deliveries Get","security":[{"ApiKeyAuth":["alert-deliveries:read"]},{"BearerAuth":[]},{"OAuth2":["alert-deliveries:read"]}],"description":"Get one of your alert deliveries by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the alert delivery."},"description":"The id of the alert delivery."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"rule_id":{"type":"string","format":"uuid","nullable":true,"description":"The alert rule that fired. Empty if the rule has since been deleted; the delivery record is kept."},"rule_name":{"type":"string","nullable":true},"event_id":{"type":"string","description":"The event that set off the alert. The same event never produces two entries for the same recipient, even if it is processed twice."},"event_type":{"type":"string","nullable":true},"severity":{"type":"string","nullable":true},"channel_type":{"type":"string","description":"How it was sent: email, text message, webhook or in-app."},"channel_target":{"type":"string","description":"Who received it — the address, number or URL the rule named."},"channel_id":{"type":"string","format":"uuid","nullable":true,"description":"Which of your own notification channels sent it. Empty when Inferrex’s own service sent it, or it was shown in the app."},"status":{"type":"string"},"error":{"type":"string","nullable":true},"attempts":{"type":"integer"},"test":{"type":"boolean","description":"Yes when this came from a test send of the rule, so tests are never mistaken for real alerts."},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","event_id","channel_type","channel_target","status"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","rule_id":"00000000-0000-0000-0000-000000000000","rule_name":"string","event_id":"string","event_type":"string","severity":"string","channel_type":"string","channel_target":"string","channel_id":"00000000-0000-0000-0000-000000000000","status":"string","error":"string","attempts":0,"test":true,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/alert-rules":{"get":{"operationId":"AlertRulesList","tags":["monitoring"],"summary":"Alert Rules List","security":[{"ApiKeyAuth":["alert-rules:read"]},{"BearerAuth":[]},{"OAuth2":["alert-rules:read"]}],"description":"List your alert rules, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"name","in":"query","required":false,"schema":{"type":"string","description":"Only alert rules whose name is exactly this."},"description":"Only alert rules whose name is exactly this."},{"name":"name_contains","in":"query","required":false,"schema":{"type":"string","description":"Only alert rules whose name contains this text (upper and lower case are treated the same)."},"description":"Only alert rules whose name contains this text (upper and lower case are treated the same)."},{"name":"description","in":"query","required":false,"schema":{"type":"string","description":"Only alert rules whose description is exactly this."},"description":"Only alert rules whose description is exactly this."},{"name":"description_contains","in":"query","required":false,"schema":{"type":"string","description":"Only alert rules whose description contains this text (upper and lower case are treated the same)."},"description":"Only alert rules whose description contains this text (upper and lower case are treated the same)."},{"name":"event_type_match","in":"query","required":false,"schema":{"type":"string","description":"Only alert rules whose event type match is exactly this."},"description":"Only alert rules whose event type match is exactly this."},{"name":"event_type_match_contains","in":"query","required":false,"schema":{"type":"string","description":"Only alert rules whose event type match contains this text (upper and lower case are treated the same)."},"description":"Only alert rules whose event type match contains this text (upper and lower case are treated the same)."},{"name":"severity_match_contains","in":"query","required":false,"schema":{"type":"string"}},{"name":"connection_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only alert rules for this connection. Pass its id."},"description":"Only alert rules for this connection. Pass its id."},{"name":"cooldown_minutes_gte","in":"query","required":false,"schema":{"type":"number","description":"Only alert rules whose cooldown minutes is this number or more."},"description":"Only alert rules whose cooldown minutes is this number or more."},{"name":"cooldown_minutes_lte","in":"query","required":false,"schema":{"type":"number","description":"Only alert rules whose cooldown minutes is this number or less."},"description":"Only alert rules whose cooldown minutes is this number or less."},{"name":"enabled","in":"query","required":false,"schema":{"type":"boolean","description":"Only alert rules where enabled is true, or false for only those where it is false."},"description":"Only alert rules where enabled is true, or false for only those where it is false."},{"name":"last_fired_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only alert rules whose last fired time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only alert rules whose last fired time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"last_fired_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only alert rules whose last fired time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only alert rules whose last fired time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"fire_count_gte","in":"query","required":false,"schema":{"type":"number","description":"Only alert rules whose fire count is this number or more."},"description":"Only alert rules whose fire count is this number or more."},{"name":"fire_count_lte","in":"query","required":false,"schema":{"type":"number","description":"Only alert rules whose fire count is this number or less."},"description":"Only alert rules whose fire count is this number or less."},{"name":"acknowledged_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only alert rules whose acknowledged time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only alert rules whose acknowledged time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"acknowledged_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only alert rules whose acknowledged time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only alert rules whose acknowledged time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"acknowledged_by","in":"query","required":false,"schema":{"type":"string","description":"Only alert rules whose acknowledged by is exactly this."},"description":"Only alert rules whose acknowledged by is exactly this."},{"name":"acknowledged_by_contains","in":"query","required":false,"schema":{"type":"string","description":"Only alert rules whose acknowledged by contains this text (upper and lower case are treated the same)."},"description":"Only alert rules whose acknowledged by contains this text (upper and lower case are treated the same)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many alert rules to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many alert rules to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many alert rules to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many alert rules to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","name","description","event_type_match","connection_id","cooldown_minutes","enabled","last_fired_at","fire_count","acknowledged_at","acknowledged_by","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns alert rules where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns alert rules where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"event_type_match":{"type":"string","nullable":true,"description":"Fire only on pipeline events of this type; blank matches any event."},"severity_match":{"type":"array","items":{"type":"string","enum":["info","warning","error","critical"]},"nullable":true,"description":"Fire only on events at these severities; blank matches any severity."},"connection_id":{"type":"string","format":"uuid","nullable":true},"condition_config":{"type":"object","properties":{"metric":{"type":"string","description":"What is measured over the window. Known values: count, error_rate, latency_p95, volume_delta. Absent: the rule fires on every matching event."},"operator":{"type":"string","description":"Known values: gt, lt, gte, lte, eq."},"threshold":{"type":"number"},"window_minutes":{"type":"number"},"inference_mode":{"type":"string","description":"Limit the rule to one inference mode. The provisioned rules leave it out."}},"description":"The rule's numeric condition. Empty ({}) on a rule made through the API without one: it then fires on every matching event. The API stores whatever object it is sent, so other keys may be present."},"notification_channels":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Where this rule sends its alert: email, SMS, webhook or in-app. Leave a recipient blank to notify the workspace members; pick a channel to send from your own sender."},"cooldown_minutes":{"type":"integer","description":"Minimum minutes between two firings of this rule, to avoid alert floods."},"enabled":{"type":"boolean"},"last_fired_at":{"type":"string","nullable":true},"fire_count":{"type":"integer"},"acknowledged_at":{"type":"string","nullable":true},"acknowledged_by":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","name"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","name":"string","description":"string","event_type_match":"string","severity_match":["info"],"connection_id":"00000000-0000-0000-0000-000000000000","condition_config":{"metric":"string","operator":"string","threshold":0,"window_minutes":0,"inference_mode":"string"},"notification_channels":[{}],"cooldown_minutes":0,"enabled":true,"last_fired_at":"string","fire_count":0,"acknowledged_at":"string","acknowledged_by":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"AlertRulesCreate","tags":["monitoring"],"summary":"Alert Rules Create","security":[{"ApiKeyAuth":["alert-rules:write"]},{"BearerAuth":[]},{"OAuth2":["alert-rules:write"]}],"description":"Create an alert rule. Returns the new alert rule, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string","nullable":true},"event_type_match":{"type":"string","nullable":true,"description":"Fire only on pipeline events of this type; blank matches any event."},"severity_match":{"type":"array","items":{"type":"string","enum":["info","warning","error","critical"]},"nullable":true,"description":"Fire only on events at these severities; blank matches any severity."},"connection_id":{"type":"string","format":"uuid","nullable":true},"condition_config":{"type":"object","additionalProperties":true},"notification_channels":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Where this rule sends its alert: email, SMS, webhook or in-app. Leave a recipient blank to notify the workspace members; pick a channel to send from your own sender."},"cooldown_minutes":{"type":"integer","description":"Minimum minutes between two firings of this rule, to avoid alert floods."},"enabled":{"type":"boolean"},"last_fired_at":{"type":"string","nullable":true},"fire_count":{"type":"integer"},"acknowledged_at":{"type":"string","nullable":true},"acknowledged_by":{"type":"string","nullable":true}},"required":["name"]},"example":{"name":"string","description":"string","event_type_match":"string","severity_match":["info"],"connection_id":"00000000-0000-0000-0000-000000000000","condition_config":{},"notification_channels":[{}],"cooldown_minutes":0,"enabled":true,"last_fired_at":"string","fire_count":0,"acknowledged_at":"string","acknowledged_by":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"event_type_match":{"type":"string","nullable":true,"description":"Fire only on pipeline events of this type; blank matches any event."},"severity_match":{"type":"array","items":{"type":"string","enum":["info","warning","error","critical"]},"nullable":true,"description":"Fire only on events at these severities; blank matches any severity."},"connection_id":{"type":"string","format":"uuid","nullable":true},"condition_config":{"type":"object","properties":{"metric":{"type":"string","description":"What is measured over the window. Known values: count, error_rate, latency_p95, volume_delta. Absent: the rule fires on every matching event."},"operator":{"type":"string","description":"Known values: gt, lt, gte, lte, eq."},"threshold":{"type":"number"},"window_minutes":{"type":"number"},"inference_mode":{"type":"string","description":"Limit the rule to one inference mode. The provisioned rules leave it out."}},"description":"The rule's numeric condition. Empty ({}) on a rule made through the API without one: it then fires on every matching event. The API stores whatever object it is sent, so other keys may be present."},"notification_channels":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Where this rule sends its alert: email, SMS, webhook or in-app. Leave a recipient blank to notify the workspace members; pick a channel to send from your own sender."},"cooldown_minutes":{"type":"integer","description":"Minimum minutes between two firings of this rule, to avoid alert floods."},"enabled":{"type":"boolean"},"last_fired_at":{"type":"string","nullable":true},"fire_count":{"type":"integer"},"acknowledged_at":{"type":"string","nullable":true},"acknowledged_by":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","name"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","name":"string","description":"string","event_type_match":"string","severity_match":["info"],"connection_id":"00000000-0000-0000-0000-000000000000","condition_config":{"metric":"string","operator":"string","threshold":0,"window_minutes":0,"inference_mode":"string"},"notification_channels":[{}],"cooldown_minutes":0,"enabled":true,"last_fired_at":"string","fire_count":0,"acknowledged_at":"string","acknowledged_by":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/alert-rules/{id}":{"delete":{"operationId":"AlertRulesDelete","tags":["monitoring"],"summary":"Alert Rules Delete","security":[{"ApiKeyAuth":["alert-rules:delete"]},{"BearerAuth":[]},{"OAuth2":["alert-rules:delete"]}],"description":"Delete an alert rule permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the alert rule."},"description":"The id of the alert rule."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"AlertRulesGet","tags":["monitoring"],"summary":"Alert Rules Get","security":[{"ApiKeyAuth":["alert-rules:read"]},{"BearerAuth":[]},{"OAuth2":["alert-rules:read"]}],"description":"Get one of your alert rules by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the alert rule."},"description":"The id of the alert rule."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"event_type_match":{"type":"string","nullable":true,"description":"Fire only on pipeline events of this type; blank matches any event."},"severity_match":{"type":"array","items":{"type":"string","enum":["info","warning","error","critical"]},"nullable":true,"description":"Fire only on events at these severities; blank matches any severity."},"connection_id":{"type":"string","format":"uuid","nullable":true},"condition_config":{"type":"object","properties":{"metric":{"type":"string","description":"What is measured over the window. Known values: count, error_rate, latency_p95, volume_delta. Absent: the rule fires on every matching event."},"operator":{"type":"string","description":"Known values: gt, lt, gte, lte, eq."},"threshold":{"type":"number"},"window_minutes":{"type":"number"},"inference_mode":{"type":"string","description":"Limit the rule to one inference mode. The provisioned rules leave it out."}},"description":"The rule's numeric condition. Empty ({}) on a rule made through the API without one: it then fires on every matching event. The API stores whatever object it is sent, so other keys may be present."},"notification_channels":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Where this rule sends its alert: email, SMS, webhook or in-app. Leave a recipient blank to notify the workspace members; pick a channel to send from your own sender."},"cooldown_minutes":{"type":"integer","description":"Minimum minutes between two firings of this rule, to avoid alert floods."},"enabled":{"type":"boolean"},"last_fired_at":{"type":"string","nullable":true},"fire_count":{"type":"integer"},"acknowledged_at":{"type":"string","nullable":true},"acknowledged_by":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","name"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","name":"string","description":"string","event_type_match":"string","severity_match":["info"],"connection_id":"00000000-0000-0000-0000-000000000000","condition_config":{"metric":"string","operator":"string","threshold":0,"window_minutes":0,"inference_mode":"string"},"notification_channels":[{}],"cooldown_minutes":0,"enabled":true,"last_fired_at":"string","fire_count":0,"acknowledged_at":"string","acknowledged_by":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"AlertRulesUpdate","tags":["monitoring"],"summary":"Alert Rules Update","security":[{"ApiKeyAuth":["alert-rules:write"]},{"BearerAuth":[]},{"OAuth2":["alert-rules:write"]}],"description":"Change an alert rule. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the alert rule."},"description":"The id of the alert rule."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string","nullable":true},"event_type_match":{"type":"string","nullable":true,"description":"Fire only on pipeline events of this type; blank matches any event."},"severity_match":{"type":"array","items":{"type":"string","enum":["info","warning","error","critical"]},"nullable":true,"description":"Fire only on events at these severities; blank matches any severity."},"connection_id":{"type":"string","format":"uuid","nullable":true},"condition_config":{"type":"object","additionalProperties":true},"notification_channels":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Where this rule sends its alert: email, SMS, webhook or in-app. Leave a recipient blank to notify the workspace members; pick a channel to send from your own sender."},"cooldown_minutes":{"type":"integer","description":"Minimum minutes between two firings of this rule, to avoid alert floods."},"enabled":{"type":"boolean"},"last_fired_at":{"type":"string","nullable":true},"fire_count":{"type":"integer"},"acknowledged_at":{"type":"string","nullable":true},"acknowledged_by":{"type":"string","nullable":true}}},"example":{"name":"string","description":"string","event_type_match":"string","severity_match":["info"],"connection_id":"00000000-0000-0000-0000-000000000000","condition_config":{},"notification_channels":[{}],"cooldown_minutes":0,"enabled":true,"last_fired_at":"string","fire_count":0,"acknowledged_at":"string","acknowledged_by":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"event_type_match":{"type":"string","nullable":true,"description":"Fire only on pipeline events of this type; blank matches any event."},"severity_match":{"type":"array","items":{"type":"string","enum":["info","warning","error","critical"]},"nullable":true,"description":"Fire only on events at these severities; blank matches any severity."},"connection_id":{"type":"string","format":"uuid","nullable":true},"condition_config":{"type":"object","properties":{"metric":{"type":"string","description":"What is measured over the window. Known values: count, error_rate, latency_p95, volume_delta. Absent: the rule fires on every matching event."},"operator":{"type":"string","description":"Known values: gt, lt, gte, lte, eq."},"threshold":{"type":"number"},"window_minutes":{"type":"number"},"inference_mode":{"type":"string","description":"Limit the rule to one inference mode. The provisioned rules leave it out."}},"description":"The rule's numeric condition. Empty ({}) on a rule made through the API without one: it then fires on every matching event. The API stores whatever object it is sent, so other keys may be present."},"notification_channels":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Where this rule sends its alert: email, SMS, webhook or in-app. Leave a recipient blank to notify the workspace members; pick a channel to send from your own sender."},"cooldown_minutes":{"type":"integer","description":"Minimum minutes between two firings of this rule, to avoid alert floods."},"enabled":{"type":"boolean"},"last_fired_at":{"type":"string","nullable":true},"fire_count":{"type":"integer"},"acknowledged_at":{"type":"string","nullable":true},"acknowledged_by":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","name"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","name":"string","description":"string","event_type_match":"string","severity_match":["info"],"connection_id":"00000000-0000-0000-0000-000000000000","condition_config":{"metric":"string","operator":"string","threshold":0,"window_minutes":0,"inference_mode":"string"},"notification_channels":[{}],"cooldown_minutes":0,"enabled":true,"last_fired_at":"string","fire_count":0,"acknowledged_at":"string","acknowledged_by":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/alert-rules/{id}/acknowledge":{"post":{"operationId":"AcknowledgeAlert","tags":["monitoring"],"summary":"Acknowledge Alert","security":[{"ApiKeyAuth":["alert-rules:write"]},{"BearerAuth":[]},{"OAuth2":["alert-rules:write"]}],"description":"Mark an alert rule as acknowledged, to show someone has seen that it fired and is dealing with it. Records the time and adds an entry to your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the alert rule."},"description":"The id of the alert rule."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]},"example":{"success":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/alert-rules/{id}/test":{"post":{"operationId":"TestAlert","tags":["monitoring"],"summary":"Test Alert","security":[{"ApiKeyAuth":["alert-rules:write"]},{"BearerAuth":[]},{"OAuth2":["alert-rules:write"]}],"description":"Send a test alert through every channel this rule notifies, so you can check the messages arrive. Test alerts are marked as tests, so they are never mistaken for real problems.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the alert rule."},"description":"The id of the alert rule."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"dispatched":{"type":"boolean"}},"required":["dispatched"]},"example":{"dispatched":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/approval-policies":{"get":{"operationId":"ApprovalPoliciesList","tags":["golden_record"],"summary":"Approval Policies List","security":[{"ApiKeyAuth":["approval-policies:read"]},{"BearerAuth":[]},{"OAuth2":["approval-policies:read"]}],"description":"List your approval policies, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"name","in":"query","required":false,"schema":{"type":"string","description":"Only approval policies whose name is exactly this."},"description":"Only approval policies whose name is exactly this."},{"name":"name_contains","in":"query","required":false,"schema":{"type":"string","description":"Only approval policies whose name contains this text (upper and lower case are treated the same)."},"description":"Only approval policies whose name contains this text (upper and lower case are treated the same)."},{"name":"entity_type","in":"query","required":false,"schema":{"type":"string","description":"Only approval policies whose entity type is exactly this."},"description":"Only approval policies whose entity type is exactly this."},{"name":"entity_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only approval policies whose entity type contains this text (upper and lower case are treated the same)."},"description":"Only approval policies whose entity type contains this text (upper and lower case are treated the same)."},{"name":"required_approvers_contains","in":"query","required":false,"schema":{"type":"string"}},{"name":"enabled","in":"query","required":false,"schema":{"type":"boolean","description":"Only approval policies where enabled is true, or false for only those where it is false."},"description":"Only approval policies where enabled is true, or false for only those where it is false."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many approval policies to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many approval policies to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many approval policies to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many approval policies to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","name","entity_type","enabled","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns approval policies where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns approval policies where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"name":{"type":"string","description":"A name for this rule, unique in your workspace. Several rules can cover the same kind of change. Rules made before names existed show a random code until you rename them."},"entity_type":{"type":"string"},"auto_approve_conditions":{"type":"object","properties":{"maxRiskLevel":{"type":"string","enum":["low","medium"]},"maxConflicts":{"type":"integer"},"maxFieldsChanged":{"type":"integer"},"singleProviderOnly":{"type":"boolean"},"maxRiskScore":{"type":"integer"}},"description":"When a change is approved without a person. Missing values read as the evaluator’s defaults (low risk, 0, false)."},"required_approvers":{"type":"array","items":{"type":"string"}},"enabled":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","entity_type"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","name":"string","entity_type":"string","auto_approve_conditions":{"maxRiskLevel":"low","maxConflicts":0,"maxFieldsChanged":0,"singleProviderOnly":true,"maxRiskScore":0},"required_approvers":["string"],"enabled":true,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"ApprovalPoliciesCreate","tags":["golden_record"],"summary":"Approval Policies Create","security":[{"ApiKeyAuth":["approval-policies:write"]},{"BearerAuth":[]},{"OAuth2":["approval-policies:write"]}],"description":"Create an approval policy. Returns the new approval policy, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"A name for this rule, unique in your workspace. Several rules can cover the same kind of change. Rules made before names existed show a random code until you rename them."},"entity_type":{"type":"string"},"auto_approve_conditions":{"type":"object","additionalProperties":true},"required_approvers":{"type":"array","items":{"type":"string"}},"enabled":{"type":"boolean"}},"required":["entity_type"]},"example":{"name":"string","entity_type":"string","auto_approve_conditions":{},"required_approvers":["string"],"enabled":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"name":{"type":"string","description":"A name for this rule, unique in your workspace. Several rules can cover the same kind of change. Rules made before names existed show a random code until you rename them."},"entity_type":{"type":"string"},"auto_approve_conditions":{"type":"object","properties":{"maxRiskLevel":{"type":"string","enum":["low","medium"]},"maxConflicts":{"type":"integer"},"maxFieldsChanged":{"type":"integer"},"singleProviderOnly":{"type":"boolean"},"maxRiskScore":{"type":"integer"}},"description":"When a change is approved without a person. Missing values read as the evaluator’s defaults (low risk, 0, false)."},"required_approvers":{"type":"array","items":{"type":"string"}},"enabled":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","entity_type"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","name":"string","entity_type":"string","auto_approve_conditions":{"maxRiskLevel":"low","maxConflicts":0,"maxFieldsChanged":0,"singleProviderOnly":true,"maxRiskScore":0},"required_approvers":["string"],"enabled":true,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/approval-policies/{id}":{"delete":{"operationId":"ApprovalPoliciesDelete","tags":["golden_record"],"summary":"Approval Policies Delete","security":[{"ApiKeyAuth":["approval-policies:delete"]},{"BearerAuth":[]},{"OAuth2":["approval-policies:delete"]}],"description":"Delete an approval policy permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the approval policy."},"description":"The id of the approval policy."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"ApprovalPoliciesGet","tags":["golden_record"],"summary":"Approval Policies Get","security":[{"ApiKeyAuth":["approval-policies:read"]},{"BearerAuth":[]},{"OAuth2":["approval-policies:read"]}],"description":"Get one of your approval policies by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the approval policy."},"description":"The id of the approval policy."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"name":{"type":"string","description":"A name for this rule, unique in your workspace. Several rules can cover the same kind of change. Rules made before names existed show a random code until you rename them."},"entity_type":{"type":"string"},"auto_approve_conditions":{"type":"object","properties":{"maxRiskLevel":{"type":"string","enum":["low","medium"]},"maxConflicts":{"type":"integer"},"maxFieldsChanged":{"type":"integer"},"singleProviderOnly":{"type":"boolean"},"maxRiskScore":{"type":"integer"}},"description":"When a change is approved without a person. Missing values read as the evaluator’s defaults (low risk, 0, false)."},"required_approvers":{"type":"array","items":{"type":"string"}},"enabled":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","entity_type"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","name":"string","entity_type":"string","auto_approve_conditions":{"maxRiskLevel":"low","maxConflicts":0,"maxFieldsChanged":0,"singleProviderOnly":true,"maxRiskScore":0},"required_approvers":["string"],"enabled":true,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"ApprovalPoliciesUpdate","tags":["golden_record"],"summary":"Approval Policies Update","security":[{"ApiKeyAuth":["approval-policies:write"]},{"BearerAuth":[]},{"OAuth2":["approval-policies:write"]}],"description":"Change an approval policy. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the approval policy."},"description":"The id of the approval policy."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"A name for this rule, unique in your workspace. Several rules can cover the same kind of change. Rules made before names existed show a random code until you rename them."},"entity_type":{"type":"string"},"auto_approve_conditions":{"type":"object","additionalProperties":true},"required_approvers":{"type":"array","items":{"type":"string"}},"enabled":{"type":"boolean"}}},"example":{"name":"string","entity_type":"string","auto_approve_conditions":{},"required_approvers":["string"],"enabled":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"name":{"type":"string","description":"A name for this rule, unique in your workspace. Several rules can cover the same kind of change. Rules made before names existed show a random code until you rename them."},"entity_type":{"type":"string"},"auto_approve_conditions":{"type":"object","properties":{"maxRiskLevel":{"type":"string","enum":["low","medium"]},"maxConflicts":{"type":"integer"},"maxFieldsChanged":{"type":"integer"},"singleProviderOnly":{"type":"boolean"},"maxRiskScore":{"type":"integer"}},"description":"When a change is approved without a person. Missing values read as the evaluator’s defaults (low risk, 0, false)."},"required_approvers":{"type":"array","items":{"type":"string"}},"enabled":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","entity_type"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","name":"string","entity_type":"string","auto_approve_conditions":{"maxRiskLevel":"low","maxConflicts":0,"maxFieldsChanged":0,"singleProviderOnly":true,"maxRiskScore":0},"required_approvers":["string"],"enabled":true,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/archival/activate":{"post":{"operationId":"ActivateArchival","tags":["archival"],"summary":"Activate Archival","security":[{"ApiKeyAuth":["archival:write"]},{"BearerAuth":[]},{"OAuth2":["archival:write"]}],"description":"Set up archiving for one kind of record in a pipeline: which records to archive, after how many days they move to cheaper storage and then to long-term storage, and, optionally, when they are deleted. You can place a legal hold so nothing is deleted, and record the legal basis for keeping the data.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid","description":"The pipeline whose records to archive."},"entityType":{"type":"string","description":"The kind of record to archive."},"jurisdiction":{"type":"string","description":"The country whose data rules apply, as a two-letter code. GB if you leave it out.","default":"GB"},"warmArchiveAfterDays":{"type":"integer","minimum":1,"description":"After how many days a record moves to cheaper storage."},"coldArchiveAfterDays":{"type":"integer","minimum":1,"description":"After how many days a record moves to long-term storage."},"afterArchive":{"type":"string","description":"What happens to a record once it is archived: delete_after (deleted deleteAfterDays later, with a certificate of deletion) or keep_forever (never deleted). delete_after if you leave it out.","default":"delete_after"},"deleteAfterDays":{"type":"integer","minimum":30,"maximum":3650,"nullable":true,"description":"After how many days a record is deleted, from 30 to 3,650. Required when afterArchive is delete_after; leave it out with keep_forever."},"criteria":{"type":"object","additionalProperties":true,"description":"Which records to archive."},"legalHold":{"type":"boolean","description":"true to stop any of these records being deleted, for example during legal proceedings.","default":false},"retrievalTransparency":{"type":"boolean","description":"Whether people are told when a record they ask for comes from the archive. On if you leave it out.","default":true},"complianceBasis":{"type":"string","description":"The legal reason for keeping these records, if any."},"complianceSource":{"type":"string","description":"Where that legal reason comes from, such as the regulation."}},"required":["pipelineId","entityType","warmArchiveAfterDays","coldArchiveAfterDays","criteria"]},"example":{"pipelineId":"00000000-0000-0000-0000-000000000000","entityType":"string","jurisdiction":"GB","warmArchiveAfterDays":0,"coldArchiveAfterDays":0,"afterArchive":"delete_after","deleteAfterDays":0,"criteria":{},"legalHold":false,"retrievalTransparency":true,"complianceBasis":"string","complianceSource":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"policy":{"type":"object","additionalProperties":true}},"required":["policy"]},"example":{"policy":{}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/archival/certificate-keys":{"get":{"operationId":"GetDeletionCertificateKeys","tags":["archival"],"summary":"Get Deletion Certificate Keys","security":[],"description":"The public keys that verify deletion-certificate signatures, as a JSON Web Key Set (RFC 7517; Ed25519 keys per RFC 8037). Each key's `kid` is its RFC 7638 thumbprint, so it can be recomputed from `crv` and `x`, and it matches the `kid` in a certificate's signature envelope. The current key comes first; a previous key stays listed while certificates it signed remain verifiable. Empty when signing has never been configured. No private key material is ever included.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"JWKs: `kty` OKP, `crv` Ed25519, `kid`, `x` (base64url public key), `alg` Ed25519, `use` sig."}},"required":["keys"]},"example":{"keys":[{}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/archival/certificates":{"get":{"operationId":"DeletionCertificatesList","tags":["archival"],"summary":"Deletion Certificates List","security":[{"ApiKeyAuth":["archival:read"]},{"BearerAuth":[]},{"OAuth2":["archival:read"]}],"description":"List your deletion certificates, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"pipeline_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only deletion certificates for this pipeline. Pass its id."},"description":"Only deletion certificates for this pipeline. Pass its id."},{"name":"entity_type","in":"query","required":false,"schema":{"type":"string","description":"Only deletion certificates whose entity type is exactly this."},"description":"Only deletion certificates whose entity type is exactly this."},{"name":"entity_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only deletion certificates whose entity type contains this text (upper and lower case are treated the same)."},"description":"Only deletion certificates whose entity type contains this text (upper and lower case are treated the same)."},{"name":"record_count_gte","in":"query","required":false,"schema":{"type":"number","description":"Only deletion certificates whose record count is this number or more."},"description":"Only deletion certificates whose record count is this number or more."},{"name":"record_count_lte","in":"query","required":false,"schema":{"type":"number","description":"Only deletion certificates whose record count is this number or less."},"description":"Only deletion certificates whose record count is this number or less."},{"name":"deleted_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only deletion certificates whose deleted time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only deletion certificates whose deleted time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"deleted_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only deletion certificates whose deleted time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only deletion certificates whose deleted time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"retention_basis","in":"query","required":false,"schema":{"type":"string","description":"Only deletion certificates whose retention basis is exactly this."},"description":"Only deletion certificates whose retention basis is exactly this."},{"name":"retention_basis_contains","in":"query","required":false,"schema":{"type":"string","description":"Only deletion certificates whose retention basis contains this text (upper and lower case are treated the same)."},"description":"Only deletion certificates whose retention basis contains this text (upper and lower case are treated the same)."},{"name":"compliance_rule_version","in":"query","required":false,"schema":{"type":"string","description":"Only deletion certificates whose compliance rule version is exactly this."},"description":"Only deletion certificates whose compliance rule version is exactly this."},{"name":"compliance_rule_version_contains","in":"query","required":false,"schema":{"type":"string","description":"Only deletion certificates whose compliance rule version contains this text (upper and lower case are treated the same)."},"description":"Only deletion certificates whose compliance rule version contains this text (upper and lower case are treated the same)."},{"name":"certificate_pdf_s3_key","in":"query","required":false,"schema":{"type":"string","description":"Only deletion certificates whose certificate pdf s3 key is exactly this."},"description":"Only deletion certificates whose certificate pdf s3 key is exactly this."},{"name":"certificate_pdf_s3_key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only deletion certificates whose certificate pdf s3 key contains this text (upper and lower case are treated the same)."},"description":"Only deletion certificates whose certificate pdf s3 key contains this text (upper and lower case are treated the same)."},{"name":"issued_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only deletion certificates whose issued time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only deletion certificates whose issued time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"issued_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only deletion certificates whose issued time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only deletion certificates whose issued time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"body_sha256","in":"query","required":false,"schema":{"type":"string","description":"Only deletion certificates whose body sha256 is exactly this."},"description":"Only deletion certificates whose body sha256 is exactly this."},{"name":"body_sha256_contains","in":"query","required":false,"schema":{"type":"string","description":"Only deletion certificates whose body sha256 contains this text (upper and lower case are treated the same)."},"description":"Only deletion certificates whose body sha256 contains this text (upper and lower case are treated the same)."},{"name":"signature","in":"query","required":false,"schema":{"type":"string","description":"Only deletion certificates whose signature is exactly this."},"description":"Only deletion certificates whose signature is exactly this."},{"name":"signature_contains","in":"query","required":false,"schema":{"type":"string","description":"Only deletion certificates whose signature contains this text (upper and lower case are treated the same)."},"description":"Only deletion certificates whose signature contains this text (upper and lower case are treated the same)."},{"name":"signature_alg","in":"query","required":false,"schema":{"type":"string","description":"Only deletion certificates whose signature alg is exactly this."},"description":"Only deletion certificates whose signature alg is exactly this."},{"name":"signature_alg_contains","in":"query","required":false,"schema":{"type":"string","description":"Only deletion certificates whose signature alg contains this text (upper and lower case are treated the same)."},"description":"Only deletion certificates whose signature alg contains this text (upper and lower case are treated the same)."},{"name":"key_id","in":"query","required":false,"schema":{"type":"string","description":"Only deletion certificates whose key is exactly this."},"description":"Only deletion certificates whose key is exactly this."},{"name":"key_id_contains","in":"query","required":false,"schema":{"type":"string","description":"Only deletion certificates whose key contains this text (upper and lower case are treated the same)."},"description":"Only deletion certificates whose key contains this text (upper and lower case are treated the same)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many deletion certificates to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many deletion certificates to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many deletion certificates to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many deletion certificates to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","pipeline_id","entity_type","record_count","deleted_at","retention_basis","compliance_rule_version","certificate_pdf_s3_key","issued_at","body_sha256","signature","signature_alg","key_id"],"description":"The field to sort the list by.","default":"deleted_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns deletion certificates where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns deletion certificates where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"pipeline_id":{"type":"string","format":"uuid"},"entity_type":{"type":"string"},"record_count":{"type":"integer"},"deleted_at":{"type":"string"},"retention_basis":{"type":"string"},"compliance_rule_version":{"type":"string"},"certificate_pdf_s3_key":{"type":"string"},"issued_at":{"type":"string"},"body_sha256":{"type":"string","nullable":true},"signature":{"type":"string","nullable":true},"signature_alg":{"type":"string","nullable":true},"key_id":{"type":"string","nullable":true}},"required":["customer_id","pipeline_id","entity_type","record_count","retention_basis","compliance_rule_version","certificate_pdf_s3_key"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","pipeline_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","record_count":0,"deleted_at":"string","retention_basis":"string","compliance_rule_version":"string","certificate_pdf_s3_key":"string","issued_at":"string","body_sha256":"string","signature":"string","signature_alg":"string","key_id":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/archival/certificates/{id}":{"get":{"operationId":"DeletionCertificatesGet","tags":["archival"],"summary":"Deletion Certificates Get","security":[{"ApiKeyAuth":["archival:read"]},{"BearerAuth":[]},{"OAuth2":["archival:read"]}],"description":"Get one of your deletion certificates by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the deletion certificate."},"description":"The id of the deletion certificate."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"pipeline_id":{"type":"string","format":"uuid"},"entity_type":{"type":"string"},"record_count":{"type":"integer"},"deleted_at":{"type":"string"},"retention_basis":{"type":"string"},"compliance_rule_version":{"type":"string"},"certificate_pdf_s3_key":{"type":"string"},"issued_at":{"type":"string"},"body_sha256":{"type":"string","nullable":true},"signature":{"type":"string","nullable":true},"signature_alg":{"type":"string","nullable":true},"key_id":{"type":"string","nullable":true},"signatureStatus":{"type":"object","properties":{"status":{"type":"string","description":"Known values: verified (signed, and the signature checks out), unsigned (issued before signing was switched on), invalid (the text or signature does not check out, or no published key signed it), unavailable (the check could not be run just now; retry)."},"alg":{"type":"string","nullable":true,"description":"The algorithm that verified, such as Ed25519. Null unless verified."},"kid":{"type":"string","nullable":true,"description":"The published key that verified (RFC 7638 thumbprint). Null unless verified."},"reason":{"type":"string","nullable":true,"description":"Why it is not verified, in words. Null when verified."}},"required":["status","alg","kid","reason"],"description":"Whether this certificate's signature verifies: its stored text checked against its stored signature with the keys published at GET /v1/archival/certificate-keys."}},"required":["customer_id","pipeline_id","entity_type","record_count","retention_basis","compliance_rule_version","certificate_pdf_s3_key","signatureStatus"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","pipeline_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","record_count":0,"deleted_at":"string","retention_basis":"string","compliance_rule_version":"string","certificate_pdf_s3_key":"string","issued_at":"string","body_sha256":"string","signature":"string","signature_alg":"string","key_id":"string","signatureStatus":{"status":"string","alg":"string","kid":"string","reason":"string"}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/archival/certificates/{id}/pdf":{"get":{"operationId":"GetDeletionCertificatePdf","tags":["archival"],"summary":"Get Deletion Certificate Pdf","security":[{"ApiKeyAuth":["archival:read"]},{"BearerAuth":[]},{"OAuth2":["archival:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"Private read-only download URL, valid for 300 seconds. Do not log or share."},"expiresAt":{"type":"string","format":"date-time"},"fileName":{"type":"string"},"sourceSha256":{"type":"string","description":"SHA-256 of the exact original bytes, not a claim of digital signature verification."}},"required":["url","expiresAt","fileName","sourceSha256"]},"example":{"url":"string","expiresAt":"2026-01-01T00:00:00Z","fileName":"string","sourceSha256":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/archival/dashboard":{"get":{"operationId":"GetArchivalDashboard","tags":["archival"],"summary":"Get Archival Dashboard","security":[{"ApiKeyAuth":["archival:read"]},{"BearerAuth":[]},{"OAuth2":["archival:read"]}],"description":"An overview of archiving: your archiving policies, how many records are archived and how much space they take.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"policies":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipeline_id":{"type":"string","format":"uuid"},"entity_type":{"type":"string"},"jurisdiction":{"type":"string"},"warm_archive_after_days":{"type":"integer"},"cold_archive_after_days":{"type":"integer"},"delete_after_days":{"type":"integer","nullable":true},"after_archive":{"type":"string","description":"Known values: delete_after, keep_forever."},"legal_hold":{"type":"boolean"},"retrieval_transparency":{"type":"boolean"},"created_at":{"type":"string"},"customer_approved_at":{"type":"string","nullable":true}},"required":["id","pipeline_id","entity_type","jurisdiction","warm_archive_after_days","cold_archive_after_days","after_archive","legal_hold","retrieval_transparency","created_at"]}},"totalArchivedRecords":{"type":"integer"},"totalBytes":{"type":"number"},"warmCount":{"type":"integer"},"complianceCount":{"type":"integer"},"electiveCount":{"type":"integer"},"legalHoldCount":{"type":"integer"},"totalDeletionCertificates":{"type":"integer"}},"required":["policies","totalArchivedRecords","totalBytes","warmCount","complianceCount","electiveCount","legalHoldCount","totalDeletionCertificates"]},"example":{"policies":[{"id":"00000000-0000-0000-0000-000000000000","pipeline_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","jurisdiction":"string","warm_archive_after_days":0,"cold_archive_after_days":0,"delete_after_days":0,"after_archive":"string","legal_hold":true,"retrieval_transparency":true,"created_at":"string","customer_approved_at":"string"}],"totalArchivedRecords":0,"totalBytes":0,"warmCount":0,"complianceCount":0,"electiveCount":0,"legalHoldCount":0,"totalDeletionCertificates":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/archival/policies/{id}":{"get":{"operationId":"GetArchivalPolicy","tags":["archival"],"summary":"Get Archival Policy","security":[{"ApiKeyAuth":["archival:read"]},{"BearerAuth":[]},{"OAuth2":["archival:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"policy":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipeline_id":{"type":"string","format":"uuid"},"entity_type":{"type":"string"},"jurisdiction":{"type":"string"},"archival_criteria":{"type":"object","additionalProperties":true,"description":"Flat field = value pairs a record must match. Empty or nested criteria match nothing."},"warm_archive_after_days":{"type":"integer"},"cold_archive_after_days":{"type":"integer"},"delete_after_days":{"type":"integer","nullable":true,"description":"Days after archiving that a record is removed, with a deletion certificate. Null when the rule keeps records forever."},"after_archive":{"type":"string","description":"What happens to a record once archived. Known values: delete_after (removed after delete_after_days), keep_forever (never removed). Only delete_after ever removes anything."},"legal_hold":{"type":"boolean","description":"While set, the rule archives nothing and nothing it already archived is removed."},"retrieval_transparency":{"type":"boolean"},"compliance_basis":{"type":"string","nullable":true},"compliance_source":{"type":"string","nullable":true},"created_at":{"type":"string"},"customer_approved_at":{"type":"string","nullable":true,"description":"When the rule was approved. Null = waiting for approval."},"customer_approved_by":{"type":"string","format":"uuid","nullable":true,"description":"The approving member (workspace user id); null when approved by an API key or a platform admin."},"paused_at":{"type":"string","nullable":true},"paused_by":{"type":"string","format":"uuid","nullable":true},"pipeline_archival_enabled":{"type":"boolean","description":"Whether the rule's pipeline has archiving switched on."},"pipeline_status":{"type":"string"},"state":{"type":"string","description":"Known values: awaiting_approval, paused, legal_hold, blocked, active. `active` = the nightly evaluator runs it."},"waiting_on":{"type":"array","items":{"type":"string"},"description":"Every gate stopping the nightly run; empty when active. Known values: approval, paused, legal_hold, pipeline_archival_off, pipeline_archived, no_delete_window (a delete_after rule with no delete window), no_warm_window."}},"required":["id","pipeline_id","entity_type","jurisdiction","archival_criteria","warm_archive_after_days","cold_archive_after_days","after_archive","legal_hold","retrieval_transparency","created_at","pipeline_archival_enabled","pipeline_status","state","waiting_on"]}},"required":["policy"]},"example":{"policy":{"id":"00000000-0000-0000-0000-000000000000","pipeline_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","jurisdiction":"string","archival_criteria":{},"warm_archive_after_days":0,"cold_archive_after_days":0,"delete_after_days":0,"after_archive":"string","legal_hold":true,"retrieval_transparency":true,"compliance_basis":"string","compliance_source":"string","created_at":"string","customer_approved_at":"string","customer_approved_by":"00000000-0000-0000-0000-000000000000","paused_at":"string","paused_by":"00000000-0000-0000-0000-000000000000","pipeline_archival_enabled":true,"pipeline_status":"string","state":"string","waiting_on":["string"]}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/archival/policies/{id}/approve":{"post":{"operationId":"ApproveArchivalPolicy","tags":["archival"],"summary":"Approve Archival Policy","security":[{"ApiKeyAuth":["archival:write"]},{"BearerAuth":[]},{"OAuth2":["archival:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","maxLength":2000,"description":"Kept on the audit entry."}}},"example":{"notes":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"policy":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipeline_id":{"type":"string","format":"uuid"},"entity_type":{"type":"string"},"jurisdiction":{"type":"string"},"archival_criteria":{"type":"object","additionalProperties":true,"description":"Flat field = value pairs a record must match. Empty or nested criteria match nothing."},"warm_archive_after_days":{"type":"integer"},"cold_archive_after_days":{"type":"integer"},"delete_after_days":{"type":"integer","nullable":true,"description":"Days after archiving that a record is removed, with a deletion certificate. Null when the rule keeps records forever."},"after_archive":{"type":"string","description":"What happens to a record once archived. Known values: delete_after (removed after delete_after_days), keep_forever (never removed). Only delete_after ever removes anything."},"legal_hold":{"type":"boolean","description":"While set, the rule archives nothing and nothing it already archived is removed."},"retrieval_transparency":{"type":"boolean"},"compliance_basis":{"type":"string","nullable":true},"compliance_source":{"type":"string","nullable":true},"created_at":{"type":"string"},"customer_approved_at":{"type":"string","nullable":true,"description":"When the rule was approved. Null = waiting for approval."},"customer_approved_by":{"type":"string","format":"uuid","nullable":true,"description":"The approving member (workspace user id); null when approved by an API key or a platform admin."},"paused_at":{"type":"string","nullable":true},"paused_by":{"type":"string","format":"uuid","nullable":true},"pipeline_archival_enabled":{"type":"boolean","description":"Whether the rule's pipeline has archiving switched on."},"pipeline_status":{"type":"string"},"state":{"type":"string","description":"Known values: awaiting_approval, paused, legal_hold, blocked, active. `active` = the nightly evaluator runs it."},"waiting_on":{"type":"array","items":{"type":"string"},"description":"Every gate stopping the nightly run; empty when active. Known values: approval, paused, legal_hold, pipeline_archival_off, pipeline_archived, no_delete_window (a delete_after rule with no delete window), no_warm_window."}},"required":["id","pipeline_id","entity_type","jurisdiction","archival_criteria","warm_archive_after_days","cold_archive_after_days","after_archive","legal_hold","retrieval_transparency","created_at","pipeline_archival_enabled","pipeline_status","state","waiting_on"]},"changed":{"type":"boolean","description":"False when the rule was already in the requested state: the call was a no-op and wrote no audit entry."}},"required":["policy","changed"]},"example":{"policy":{"id":"00000000-0000-0000-0000-000000000000","pipeline_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","jurisdiction":"string","archival_criteria":{},"warm_archive_after_days":0,"cold_archive_after_days":0,"delete_after_days":0,"after_archive":"string","legal_hold":true,"retrieval_transparency":true,"compliance_basis":"string","compliance_source":"string","created_at":"string","customer_approved_at":"string","customer_approved_by":"00000000-0000-0000-0000-000000000000","paused_at":"string","paused_by":"00000000-0000-0000-0000-000000000000","pipeline_archival_enabled":true,"pipeline_status":"string","state":"string","waiting_on":["string"]},"changed":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/archival/policies/{id}/lift-legal-hold":{"post":{"operationId":"LiftArchivalPolicyLegalHold","tags":["archival"],"summary":"Lift Archival Policy Legal Hold","security":[{"ApiKeyAuth":["archival:write"]},{"BearerAuth":[]},{"OAuth2":["archival:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":2000,"description":"Why the hold is no longer needed. Kept on the audit entry."}},"required":["reason"]},"example":{"reason":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"policy":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipeline_id":{"type":"string","format":"uuid"},"entity_type":{"type":"string"},"jurisdiction":{"type":"string"},"archival_criteria":{"type":"object","additionalProperties":true,"description":"Flat field = value pairs a record must match. Empty or nested criteria match nothing."},"warm_archive_after_days":{"type":"integer"},"cold_archive_after_days":{"type":"integer"},"delete_after_days":{"type":"integer","nullable":true,"description":"Days after archiving that a record is removed, with a deletion certificate. Null when the rule keeps records forever."},"after_archive":{"type":"string","description":"What happens to a record once archived. Known values: delete_after (removed after delete_after_days), keep_forever (never removed). Only delete_after ever removes anything."},"legal_hold":{"type":"boolean","description":"While set, the rule archives nothing and nothing it already archived is removed."},"retrieval_transparency":{"type":"boolean"},"compliance_basis":{"type":"string","nullable":true},"compliance_source":{"type":"string","nullable":true},"created_at":{"type":"string"},"customer_approved_at":{"type":"string","nullable":true,"description":"When the rule was approved. Null = waiting for approval."},"customer_approved_by":{"type":"string","format":"uuid","nullable":true,"description":"The approving member (workspace user id); null when approved by an API key or a platform admin."},"paused_at":{"type":"string","nullable":true},"paused_by":{"type":"string","format":"uuid","nullable":true},"pipeline_archival_enabled":{"type":"boolean","description":"Whether the rule's pipeline has archiving switched on."},"pipeline_status":{"type":"string"},"state":{"type":"string","description":"Known values: awaiting_approval, paused, legal_hold, blocked, active. `active` = the nightly evaluator runs it."},"waiting_on":{"type":"array","items":{"type":"string"},"description":"Every gate stopping the nightly run; empty when active. Known values: approval, paused, legal_hold, pipeline_archival_off, pipeline_archived, no_delete_window (a delete_after rule with no delete window), no_warm_window."}},"required":["id","pipeline_id","entity_type","jurisdiction","archival_criteria","warm_archive_after_days","cold_archive_after_days","after_archive","legal_hold","retrieval_transparency","created_at","pipeline_archival_enabled","pipeline_status","state","waiting_on"]},"changed":{"type":"boolean","description":"False when the rule was already in the requested state: the call was a no-op and wrote no audit entry."}},"required":["policy","changed"]},"example":{"policy":{"id":"00000000-0000-0000-0000-000000000000","pipeline_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","jurisdiction":"string","archival_criteria":{},"warm_archive_after_days":0,"cold_archive_after_days":0,"delete_after_days":0,"after_archive":"string","legal_hold":true,"retrieval_transparency":true,"compliance_basis":"string","compliance_source":"string","created_at":"string","customer_approved_at":"string","customer_approved_by":"00000000-0000-0000-0000-000000000000","paused_at":"string","paused_by":"00000000-0000-0000-0000-000000000000","pipeline_archival_enabled":true,"pipeline_status":"string","state":"string","waiting_on":["string"]},"changed":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/archival/policies/{id}/pause":{"post":{"operationId":"PauseArchivalPolicy","tags":["archival"],"summary":"Pause Archival Policy","security":[{"ApiKeyAuth":["archival:write"]},{"BearerAuth":[]},{"OAuth2":["archival:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":2000,"description":"Kept on the audit entry."}}},"example":{"reason":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"policy":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipeline_id":{"type":"string","format":"uuid"},"entity_type":{"type":"string"},"jurisdiction":{"type":"string"},"archival_criteria":{"type":"object","additionalProperties":true,"description":"Flat field = value pairs a record must match. Empty or nested criteria match nothing."},"warm_archive_after_days":{"type":"integer"},"cold_archive_after_days":{"type":"integer"},"delete_after_days":{"type":"integer","nullable":true,"description":"Days after archiving that a record is removed, with a deletion certificate. Null when the rule keeps records forever."},"after_archive":{"type":"string","description":"What happens to a record once archived. Known values: delete_after (removed after delete_after_days), keep_forever (never removed). Only delete_after ever removes anything."},"legal_hold":{"type":"boolean","description":"While set, the rule archives nothing and nothing it already archived is removed."},"retrieval_transparency":{"type":"boolean"},"compliance_basis":{"type":"string","nullable":true},"compliance_source":{"type":"string","nullable":true},"created_at":{"type":"string"},"customer_approved_at":{"type":"string","nullable":true,"description":"When the rule was approved. Null = waiting for approval."},"customer_approved_by":{"type":"string","format":"uuid","nullable":true,"description":"The approving member (workspace user id); null when approved by an API key or a platform admin."},"paused_at":{"type":"string","nullable":true},"paused_by":{"type":"string","format":"uuid","nullable":true},"pipeline_archival_enabled":{"type":"boolean","description":"Whether the rule's pipeline has archiving switched on."},"pipeline_status":{"type":"string"},"state":{"type":"string","description":"Known values: awaiting_approval, paused, legal_hold, blocked, active. `active` = the nightly evaluator runs it."},"waiting_on":{"type":"array","items":{"type":"string"},"description":"Every gate stopping the nightly run; empty when active. Known values: approval, paused, legal_hold, pipeline_archival_off, pipeline_archived, no_delete_window (a delete_after rule with no delete window), no_warm_window."}},"required":["id","pipeline_id","entity_type","jurisdiction","archival_criteria","warm_archive_after_days","cold_archive_after_days","after_archive","legal_hold","retrieval_transparency","created_at","pipeline_archival_enabled","pipeline_status","state","waiting_on"]},"changed":{"type":"boolean","description":"False when the rule was already in the requested state: the call was a no-op and wrote no audit entry."}},"required":["policy","changed"]},"example":{"policy":{"id":"00000000-0000-0000-0000-000000000000","pipeline_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","jurisdiction":"string","archival_criteria":{},"warm_archive_after_days":0,"cold_archive_after_days":0,"delete_after_days":0,"after_archive":"string","legal_hold":true,"retrieval_transparency":true,"compliance_basis":"string","compliance_source":"string","created_at":"string","customer_approved_at":"string","customer_approved_by":"00000000-0000-0000-0000-000000000000","paused_at":"string","paused_by":"00000000-0000-0000-0000-000000000000","pipeline_archival_enabled":true,"pipeline_status":"string","state":"string","waiting_on":["string"]},"changed":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/archival/policies/{id}/resume":{"post":{"operationId":"ResumeArchivalPolicy","tags":["archival"],"summary":"Resume Archival Policy","security":[{"ApiKeyAuth":["archival:write"]},{"BearerAuth":[]},{"OAuth2":["archival:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":2000,"description":"Kept on the audit entry."}}},"example":{"reason":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"policy":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipeline_id":{"type":"string","format":"uuid"},"entity_type":{"type":"string"},"jurisdiction":{"type":"string"},"archival_criteria":{"type":"object","additionalProperties":true,"description":"Flat field = value pairs a record must match. Empty or nested criteria match nothing."},"warm_archive_after_days":{"type":"integer"},"cold_archive_after_days":{"type":"integer"},"delete_after_days":{"type":"integer","nullable":true,"description":"Days after archiving that a record is removed, with a deletion certificate. Null when the rule keeps records forever."},"after_archive":{"type":"string","description":"What happens to a record once archived. Known values: delete_after (removed after delete_after_days), keep_forever (never removed). Only delete_after ever removes anything."},"legal_hold":{"type":"boolean","description":"While set, the rule archives nothing and nothing it already archived is removed."},"retrieval_transparency":{"type":"boolean"},"compliance_basis":{"type":"string","nullable":true},"compliance_source":{"type":"string","nullable":true},"created_at":{"type":"string"},"customer_approved_at":{"type":"string","nullable":true,"description":"When the rule was approved. Null = waiting for approval."},"customer_approved_by":{"type":"string","format":"uuid","nullable":true,"description":"The approving member (workspace user id); null when approved by an API key or a platform admin."},"paused_at":{"type":"string","nullable":true},"paused_by":{"type":"string","format":"uuid","nullable":true},"pipeline_archival_enabled":{"type":"boolean","description":"Whether the rule's pipeline has archiving switched on."},"pipeline_status":{"type":"string"},"state":{"type":"string","description":"Known values: awaiting_approval, paused, legal_hold, blocked, active. `active` = the nightly evaluator runs it."},"waiting_on":{"type":"array","items":{"type":"string"},"description":"Every gate stopping the nightly run; empty when active. Known values: approval, paused, legal_hold, pipeline_archival_off, pipeline_archived, no_delete_window (a delete_after rule with no delete window), no_warm_window."}},"required":["id","pipeline_id","entity_type","jurisdiction","archival_criteria","warm_archive_after_days","cold_archive_after_days","after_archive","legal_hold","retrieval_transparency","created_at","pipeline_archival_enabled","pipeline_status","state","waiting_on"]},"changed":{"type":"boolean","description":"False when the rule was already in the requested state: the call was a no-op and wrote no audit entry."}},"required":["policy","changed"]},"example":{"policy":{"id":"00000000-0000-0000-0000-000000000000","pipeline_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","jurisdiction":"string","archival_criteria":{},"warm_archive_after_days":0,"cold_archive_after_days":0,"delete_after_days":0,"after_archive":"string","legal_hold":true,"retrieval_transparency":true,"compliance_basis":"string","compliance_source":"string","created_at":"string","customer_approved_at":"string","customer_approved_by":"00000000-0000-0000-0000-000000000000","paused_at":"string","paused_by":"00000000-0000-0000-0000-000000000000","pipeline_archival_enabled":true,"pipeline_status":"string","state":"string","waiting_on":["string"]},"changed":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/archival/policies/{id}/retention":{"post":{"operationId":"ChangeArchivalPolicyRetention","tags":["archival"],"summary":"Change Archival Policy Retention","security":[{"ApiKeyAuth":["archival:write"]},{"BearerAuth":[]},{"OAuth2":["archival:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"afterArchive":{"type":"string","description":"Known values: keep_forever, delete_after."},"deleteAfterDays":{"type":"integer","minimum":30,"maximum":3650,"nullable":true,"description":"Required with delete_after; left out with keep_forever."},"reason":{"type":"string","maxLength":2000,"description":"Kept on the audit entry."}},"required":["afterArchive"]},"example":{"afterArchive":"string","deleteAfterDays":0,"reason":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"policy":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipeline_id":{"type":"string","format":"uuid"},"entity_type":{"type":"string"},"jurisdiction":{"type":"string"},"archival_criteria":{"type":"object","additionalProperties":true,"description":"Flat field = value pairs a record must match. Empty or nested criteria match nothing."},"warm_archive_after_days":{"type":"integer"},"cold_archive_after_days":{"type":"integer"},"delete_after_days":{"type":"integer","nullable":true,"description":"Days after archiving that a record is removed, with a deletion certificate. Null when the rule keeps records forever."},"after_archive":{"type":"string","description":"What happens to a record once archived. Known values: delete_after (removed after delete_after_days), keep_forever (never removed). Only delete_after ever removes anything."},"legal_hold":{"type":"boolean","description":"While set, the rule archives nothing and nothing it already archived is removed."},"retrieval_transparency":{"type":"boolean"},"compliance_basis":{"type":"string","nullable":true},"compliance_source":{"type":"string","nullable":true},"created_at":{"type":"string"},"customer_approved_at":{"type":"string","nullable":true,"description":"When the rule was approved. Null = waiting for approval."},"customer_approved_by":{"type":"string","format":"uuid","nullable":true,"description":"The approving member (workspace user id); null when approved by an API key or a platform admin."},"paused_at":{"type":"string","nullable":true},"paused_by":{"type":"string","format":"uuid","nullable":true},"pipeline_archival_enabled":{"type":"boolean","description":"Whether the rule's pipeline has archiving switched on."},"pipeline_status":{"type":"string"},"state":{"type":"string","description":"Known values: awaiting_approval, paused, legal_hold, blocked, active. `active` = the nightly evaluator runs it."},"waiting_on":{"type":"array","items":{"type":"string"},"description":"Every gate stopping the nightly run; empty when active. Known values: approval, paused, legal_hold, pipeline_archival_off, pipeline_archived, no_delete_window (a delete_after rule with no delete window), no_warm_window."}},"required":["id","pipeline_id","entity_type","jurisdiction","archival_criteria","warm_archive_after_days","cold_archive_after_days","after_archive","legal_hold","retrieval_transparency","created_at","pipeline_archival_enabled","pipeline_status","state","waiting_on"]},"changed":{"type":"boolean","description":"False when the rule was already in the requested state: the call was a no-op and wrote no audit entry."}},"required":["policy","changed"]},"example":{"policy":{"id":"00000000-0000-0000-0000-000000000000","pipeline_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","jurisdiction":"string","archival_criteria":{},"warm_archive_after_days":0,"cold_archive_after_days":0,"delete_after_days":0,"after_archive":"string","legal_hold":true,"retrieval_transparency":true,"compliance_basis":"string","compliance_source":"string","created_at":"string","customer_approved_at":"string","customer_approved_by":"00000000-0000-0000-0000-000000000000","paused_at":"string","paused_by":"00000000-0000-0000-0000-000000000000","pipeline_archival_enabled":true,"pipeline_status":"string","state":"string","waiting_on":["string"]},"changed":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/archival/records":{"get":{"operationId":"ListArchivedRecords","tags":["archival"],"summary":"List Archived Records","security":[{"ApiKeyAuth":["archival:read"]},{"BearerAuth":[]},{"OAuth2":["archival:read"]}],"description":"List your archived records, newest first: where each came from, which storage it is in, its size, whether it is on legal hold and when it can be deleted.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"description":"How many to return in one page: 1 to 100, 50 if you leave it out.","default":50},"description":"How many to return in one page: 1 to 100, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many to skip before this page starts.","default":0},"description":"How many to skip before this page starts."},{"name":"storageTier","in":"query","required":false,"schema":{"type":"string","enum":["warm","compliance","elective"],"description":"Only records in this storage: warm, compliance or elective."},"description":"Only records in this storage: warm, compliance or elective."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"records":{"type":"object","additionalProperties":true}},"required":["records"]},"example":{"records":{}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/archival/restore":{"post":{"operationId":"RestoreRecords","tags":["archival"],"summary":"Restore Records","security":[{"ApiKeyAuth":["archival:write"]},{"BearerAuth":[]},{"OAuth2":["archival:write"]}],"description":"Bring archived records back into Inferrex’s live copy of your data. Each record is added back as its latest version and removed from the archive. This does not write to the original system.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"recordIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The ids of the archived records to bring back."}},"required":["recordIds"]},"example":{"recordIds":["00000000-0000-0000-0000-000000000000"]}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"recordCount":{"type":"integer"},"recordIds":{"type":"array","items":{"type":"string","format":"uuid"}}},"required":["status","recordCount","recordIds"]},"example":{"status":"string","recordCount":0,"recordIds":["00000000-0000-0000-0000-000000000000"]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/assistant/actions":{"get":{"operationId":"ListAssistantActions","tags":["assistant"],"summary":"List Assistant Actions","security":[{"ApiKeyAuth":["assistant:read"]},{"BearerAuth":[]},{"OAuth2":["assistant:read"]}],"description":"Your Ask Inferrex changes outside the chat, one page at a time. view=drafts (default): your drafts, newest first. view=review: changes sent to YOU to review, oldest first. view=sent: changes you sent for review that are still waiting. Ties keep a fixed order by id, so paging with offset never repeats or skips a change. q narrows the view; total counts every change that matches, and counts gives each view's size without q.","parameters":[{"name":"view","in":"query","required":false,"schema":{"type":"string","description":"drafts (default), review or sent."},"description":"drafts (default), review or sent."},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":200,"description":"Search text: changes whose summary or tool name contains it (upper and lower case are treated the same)."},"description":"Search text: changes whose summary or tool name contains it (upper and lower case are treated the same)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many changes to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many changes to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many changes to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many changes to skip before this page starts. Add the page size to it to get the next page."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"view":{"type":"string"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversationId":{"type":"string","format":"uuid"},"tool":{"type":"string","description":"The tool (an API operation) it runs. Never changed by an edit."},"summary":{"type":"string","description":"One plain sentence written by the API, rewritten when the input is edited."},"risk":{"type":"string","description":"Today: write, irreversible."},"state":{"type":"string","description":"Open vocabulary. Today: pending (on a chat card), draft, pending_review, approved, declined, expired, failed."},"edited":{"type":"boolean","description":"Someone changed the input the assistant proposed."},"proposedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"]},"assignee":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true,"description":"Who it was sent to for review."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","conversationId","tool","summary","risk","state","edited","proposedBy","createdAt","updatedAt"]}},"total":{"type":"integer","description":"Changes in this view matching q, across every page."},"limit":{"type":"integer","description":"The page size this page was read with."},"offset":{"type":"integer","description":"How many changes this page skipped."},"counts":{"type":"object","properties":{"drafts":{"type":"integer","description":"Your drafts."},"review":{"type":"integer","description":"Changes sent to you to review."},"sent":{"type":"integer","description":"Changes you sent for review that are still waiting."}},"required":["drafts","review","sent"],"description":"How many changes each view holds, ignoring q: the Changes list's tab counts."}},"required":["view","items","total","limit","offset","counts"]},"example":{"view":"string","items":[{"id":"00000000-0000-0000-0000-000000000000","conversationId":"00000000-0000-0000-0000-000000000000","tool":"string","summary":"string","risk":"string","state":"string","edited":true,"proposedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"assignee":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z"}],"total":0,"limit":0,"offset":0,"counts":{"drafts":0,"review":0,"sent":0}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/assistant/actions/{id}":{"get":{"operationId":"GetAssistantAction","tags":["assistant"],"summary":"Get Assistant Action","security":[{"ApiKeyAuth":["assistant:read"]},{"BearerAuth":[]},{"OAuth2":["assistant:read"]}],"description":"One proposed change, for its proposer or its assigned reviewer. target.current is the record as its own GET route answers it for you now (the \"before\"); args is the input that would run (the \"after\"). fields are the tool's inputs with the rule an edit must follow (edit, narrow, locked).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversationId":{"type":"string","format":"uuid"},"tool":{"type":"string","description":"The tool (an API operation) it runs. Never changed by an edit."},"summary":{"type":"string","description":"One plain sentence written by the API, rewritten when the input is edited."},"risk":{"type":"string","description":"Today: write, irreversible."},"state":{"type":"string","description":"Open vocabulary. Today: pending (on a chat card), draft, pending_review, approved, declined, expired, failed."},"edited":{"type":"boolean","description":"Someone changed the input the assistant proposed."},"proposedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"]},"assignee":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true,"description":"Who it was sent to for review."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"method":{"type":"string"},"path":{"type":"string"},"you":{"type":"string","description":"proposer or reviewer."},"resultStatus":{"type":"integer","nullable":true,"description":"The status its route answered when it ran."},"expiresAt":{"type":"string","format":"date-time","nullable":true,"description":"Only while it waits on a chat card; null for a draft or a review."},"confirmedAt":{"type":"string","format":"date-time","nullable":true,"description":"When it was approved."},"decidedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true,"description":"Who approved or declined it — for an approval, the person it ran as."},"declineReason":{"type":"string","nullable":true},"args":{"type":"object","additionalProperties":true,"description":"The input that will run (the edited one, when edited)."},"originalArgs":{"type":"object","additionalProperties":true,"nullable":true,"description":"What the assistant proposed, when someone has edited it since."},"editedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"editedAt":{"type":"string","format":"date-time","nullable":true},"available":{"type":"boolean","description":"False when the tool has left the assistant's catalogue since, so it can no longer run."},"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","description":"string, number, boolean, object or array."},"description":{"type":"string"},"required":{"type":"boolean"},"in":{"type":"string","description":"path, query or body."},"edit":{"type":"string","description":"edit (may change), narrow (a list that may only lose items) or locked."},"lockedReason":{"type":"string"},"enum":{"type":"array","items":{"type":"string"}},"format":{"type":"string","description":"uuid, url, email, datetime, decimal."},"integer":{"type":"boolean"},"items":{"type":"string","description":"string or object: the element type of a list."},"minLength":{"type":"integer"},"maxLength":{"type":"integer"},"minimum":{"type":"number"},"maximum":{"type":"number"}},"required":["name","type","description","required","in","edit"]},"description":"The input fields from the tool's own parameters — the rules the server re-checks an edit with (@inferrex/tools-schema change-input)."},"target":{"type":"object","properties":{"name":{"type":"string","nullable":true},"id":{"type":"string","nullable":true},"readable":{"type":"boolean"},"current":{"type":"object","additionalProperties":true,"nullable":true,"description":"The record as it is now — the \"before\" of the preview."}},"required":["readable"],"description":"The record the change is for, read fresh through its own GET route AS YOU (secret fields stripped). Not readable for a create, or when no read route exists."},"confirmName":{"type":"string","nullable":true,"description":"Irreversible changes: the name to type to approve."},"request":{"type":"object","properties":{"method":{"type":"string"},"path":{"type":"string"},"body":{"type":"object","additionalProperties":true,"nullable":true}},"required":["method","path"],"nullable":true,"description":"The API call the change makes, for \"Copy as API call\"."},"approvals":{"type":"object","properties":{"required":{"type":"array","items":{"type":"string"},"description":"Empty: one approval from the proposer or the reviewer applies."},"satisfied":{"type":"boolean"},"received":{"type":"array","items":{"type":"object","properties":{"approver":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"role":{"type":"string","nullable":true,"description":"The policy entry the approval fills."},"decidedAt":{"type":"string"}},"required":["decidedAt"]}}},"required":["required","satisfied","received"],"description":"The workspace's approval policy for changes Ask Inferrex proposes (approval_policies entity_type assistant_action), and who has approved so far."},"can":{"type":"object","properties":{"approve":{"type":"boolean"},"approveBlockedReason":{"type":"string","nullable":true,"description":"Why not, when an approval policy needs someone else."},"decline":{"type":"boolean"},"edit":{"type":"boolean"},"saveDraft":{"type":"boolean"},"sendForReview":{"type":"boolean"}},"required":["approve","decline","edit","saveDraft","sendForReview"],"description":"What you may do now."},"history":{"type":"array","items":{"type":"object","properties":{"event":{"type":"string","description":"Open vocabulary. Today: proposed, edited, saved_draft, sent_for_review, approved_partly, approved, declined, ran, failed."},"at":{"type":"string"},"by":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"note":{"type":"string","nullable":true},"assignee":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"fields":{"type":"array","items":{"type":"string"},"description":"For edited: the inputs that changed."},"httpStatus":{"type":"integer","nullable":true}},"required":["event","at","fields"]},"description":"The activity trail, oldest first."}},"required":["id","conversationId","tool","summary","risk","state","edited","proposedBy","createdAt","updatedAt","method","path","you","args","available","fields","target","approvals","can","history"]},"example":{"id":"00000000-0000-0000-0000-000000000000","conversationId":"00000000-0000-0000-0000-000000000000","tool":"string","summary":"string","risk":"string","state":"string","edited":true,"proposedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"assignee":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z","method":"string","path":"string","you":"string","resultStatus":0,"expiresAt":"2026-01-01T00:00:00Z","confirmedAt":"2026-01-01T00:00:00Z","decidedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"declineReason":"string","args":{},"originalArgs":{},"editedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"editedAt":"2026-01-01T00:00:00Z","available":true,"fields":[{"name":"string","type":"string","description":"string","required":true,"in":"string","edit":"string","lockedReason":"string","enum":["string"],"format":"string","integer":true,"items":"string","minLength":0,"maxLength":0,"minimum":0,"maximum":0}],"target":{"name":"string","id":"string","readable":true,"current":{}},"confirmName":"string","request":{"method":"string","path":"string","body":{}},"approvals":{"required":["string"],"satisfied":true,"received":[{"approver":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"role":"string","decidedAt":"string"}]},"can":{"approve":true,"approveBlockedReason":"string","decline":true,"edit":true,"saveDraft":true,"sendForReview":true},"history":[{"event":"string","at":"string","by":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"note":"string","assignee":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"fields":["string"],"httpStatus":0}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"operationId":"UpdateAssistantActionInput","tags":["assistant"],"summary":"Update Assistant Action Input","security":[{"ApiKeyAuth":["assistant:write"]},{"BearerAuth":[]},{"OAuth2":["assistant:write"]}],"description":"Edit a draft (its proposer) or a change waiting for review (its proposer or reviewer). The input is re-checked against the tool's parameters: the tool, path parameters, the record and every id are locked and a list may only lose items; the request it builds must call the same route. The edit is recorded (original kept, who and when) and empties approvals given so far.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"args":{"type":"object","additionalProperties":true,"description":"The change's input as you want it."}},"required":["args"]},"example":{"args":{}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversationId":{"type":"string","format":"uuid"},"tool":{"type":"string","description":"The tool (an API operation) it runs. Never changed by an edit."},"summary":{"type":"string","description":"One plain sentence written by the API, rewritten when the input is edited."},"risk":{"type":"string","description":"Today: write, irreversible."},"state":{"type":"string","description":"Open vocabulary. Today: pending (on a chat card), draft, pending_review, approved, declined, expired, failed."},"edited":{"type":"boolean","description":"Someone changed the input the assistant proposed."},"proposedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"]},"assignee":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true,"description":"Who it was sent to for review."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"method":{"type":"string"},"path":{"type":"string"},"you":{"type":"string","description":"proposer or reviewer."},"resultStatus":{"type":"integer","nullable":true,"description":"The status its route answered when it ran."},"expiresAt":{"type":"string","format":"date-time","nullable":true,"description":"Only while it waits on a chat card; null for a draft or a review."},"confirmedAt":{"type":"string","format":"date-time","nullable":true,"description":"When it was approved."},"decidedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true,"description":"Who approved or declined it — for an approval, the person it ran as."},"declineReason":{"type":"string","nullable":true},"args":{"type":"object","additionalProperties":true,"description":"The input that will run (the edited one, when edited)."},"originalArgs":{"type":"object","additionalProperties":true,"nullable":true,"description":"What the assistant proposed, when someone has edited it since."},"editedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"editedAt":{"type":"string","format":"date-time","nullable":true},"available":{"type":"boolean","description":"False when the tool has left the assistant's catalogue since, so it can no longer run."},"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","description":"string, number, boolean, object or array."},"description":{"type":"string"},"required":{"type":"boolean"},"in":{"type":"string","description":"path, query or body."},"edit":{"type":"string","description":"edit (may change), narrow (a list that may only lose items) or locked."},"lockedReason":{"type":"string"},"enum":{"type":"array","items":{"type":"string"}},"format":{"type":"string","description":"uuid, url, email, datetime, decimal."},"integer":{"type":"boolean"},"items":{"type":"string","description":"string or object: the element type of a list."},"minLength":{"type":"integer"},"maxLength":{"type":"integer"},"minimum":{"type":"number"},"maximum":{"type":"number"}},"required":["name","type","description","required","in","edit"]},"description":"The input fields from the tool's own parameters — the rules the server re-checks an edit with (@inferrex/tools-schema change-input)."},"target":{"type":"object","properties":{"name":{"type":"string","nullable":true},"id":{"type":"string","nullable":true},"readable":{"type":"boolean"},"current":{"type":"object","additionalProperties":true,"nullable":true,"description":"The record as it is now — the \"before\" of the preview."}},"required":["readable"],"description":"The record the change is for, read fresh through its own GET route AS YOU (secret fields stripped). Not readable for a create, or when no read route exists."},"confirmName":{"type":"string","nullable":true,"description":"Irreversible changes: the name to type to approve."},"request":{"type":"object","properties":{"method":{"type":"string"},"path":{"type":"string"},"body":{"type":"object","additionalProperties":true,"nullable":true}},"required":["method","path"],"nullable":true,"description":"The API call the change makes, for \"Copy as API call\"."},"approvals":{"type":"object","properties":{"required":{"type":"array","items":{"type":"string"},"description":"Empty: one approval from the proposer or the reviewer applies."},"satisfied":{"type":"boolean"},"received":{"type":"array","items":{"type":"object","properties":{"approver":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"role":{"type":"string","nullable":true,"description":"The policy entry the approval fills."},"decidedAt":{"type":"string"}},"required":["decidedAt"]}}},"required":["required","satisfied","received"],"description":"The workspace's approval policy for changes Ask Inferrex proposes (approval_policies entity_type assistant_action), and who has approved so far."},"can":{"type":"object","properties":{"approve":{"type":"boolean"},"approveBlockedReason":{"type":"string","nullable":true,"description":"Why not, when an approval policy needs someone else."},"decline":{"type":"boolean"},"edit":{"type":"boolean"},"saveDraft":{"type":"boolean"},"sendForReview":{"type":"boolean"}},"required":["approve","decline","edit","saveDraft","sendForReview"],"description":"What you may do now."},"history":{"type":"array","items":{"type":"object","properties":{"event":{"type":"string","description":"Open vocabulary. Today: proposed, edited, saved_draft, sent_for_review, approved_partly, approved, declined, ran, failed."},"at":{"type":"string"},"by":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"note":{"type":"string","nullable":true},"assignee":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"fields":{"type":"array","items":{"type":"string"},"description":"For edited: the inputs that changed."},"httpStatus":{"type":"integer","nullable":true}},"required":["event","at","fields"]},"description":"The activity trail, oldest first."}},"required":["id","conversationId","tool","summary","risk","state","edited","proposedBy","createdAt","updatedAt","method","path","you","args","available","fields","target","approvals","can","history"]},"example":{"id":"00000000-0000-0000-0000-000000000000","conversationId":"00000000-0000-0000-0000-000000000000","tool":"string","summary":"string","risk":"string","state":"string","edited":true,"proposedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"assignee":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z","method":"string","path":"string","you":"string","resultStatus":0,"expiresAt":"2026-01-01T00:00:00Z","confirmedAt":"2026-01-01T00:00:00Z","decidedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"declineReason":"string","args":{},"originalArgs":{},"editedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"editedAt":"2026-01-01T00:00:00Z","available":true,"fields":[{"name":"string","type":"string","description":"string","required":true,"in":"string","edit":"string","lockedReason":"string","enum":["string"],"format":"string","integer":true,"items":"string","minLength":0,"maxLength":0,"minimum":0,"maximum":0}],"target":{"name":"string","id":"string","readable":true,"current":{}},"confirmName":"string","request":{"method":"string","path":"string","body":{}},"approvals":{"required":["string"],"satisfied":true,"received":[{"approver":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"role":"string","decidedAt":"string"}]},"can":{"approve":true,"approveBlockedReason":"string","decline":true,"edit":true,"saveDraft":true,"sendForReview":true},"history":[{"event":"string","at":"string","by":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"note":"string","assignee":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"fields":["string"],"httpStatus":0}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/assistant/actions/{id}/approve":{"post":{"operationId":"ApproveAssistantAction","tags":["assistant"],"summary":"Approve Assistant Action","security":[{"ApiKeyAuth":["assistant:write"]},{"BearerAuth":[]},{"OAuth2":["assistant:write"]}],"description":"Approve and run a change outside the chat. It runs AS YOU, with your permissions, through its own route (audited with via = assistant and this action id). An edit is re-checked as for PATCH; your permission for the change is checked as when it was proposed; an irreversible change needs typedName. With an assistant_action approval policy you cannot approve a change proposed for you, and each listed approver is needed: outcome approved_partly says who is still needed.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"args":{"type":"object","additionalProperties":true,"description":"The input as you edited it. Omit to approve it as it is."},"typedName":{"type":"string","maxLength":500}}},"example":{"args":{},"typedName":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"outcome":{"type":"string","description":"approved (it ran), failed (it ran and its route refused), approved_partly (more approvers needed)."},"remaining":{"type":"array","items":{"type":"string"},"description":"approved_partly: the approver entries still open."},"httpStatus":{"type":"integer","nullable":true,"description":"What the change's route answered."},"action":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversationId":{"type":"string","format":"uuid"},"tool":{"type":"string","description":"The tool (an API operation) it runs. Never changed by an edit."},"summary":{"type":"string","description":"One plain sentence written by the API, rewritten when the input is edited."},"risk":{"type":"string","description":"Today: write, irreversible."},"state":{"type":"string","description":"Open vocabulary. Today: pending (on a chat card), draft, pending_review, approved, declined, expired, failed."},"edited":{"type":"boolean","description":"Someone changed the input the assistant proposed."},"proposedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"]},"assignee":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true,"description":"Who it was sent to for review."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"method":{"type":"string"},"path":{"type":"string"},"you":{"type":"string","description":"proposer or reviewer."},"resultStatus":{"type":"integer","nullable":true,"description":"The status its route answered when it ran."},"expiresAt":{"type":"string","format":"date-time","nullable":true,"description":"Only while it waits on a chat card; null for a draft or a review."},"confirmedAt":{"type":"string","format":"date-time","nullable":true,"description":"When it was approved."},"decidedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true,"description":"Who approved or declined it — for an approval, the person it ran as."},"declineReason":{"type":"string","nullable":true},"args":{"type":"object","additionalProperties":true,"description":"The input that will run (the edited one, when edited)."},"originalArgs":{"type":"object","additionalProperties":true,"nullable":true,"description":"What the assistant proposed, when someone has edited it since."},"editedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"editedAt":{"type":"string","format":"date-time","nullable":true},"available":{"type":"boolean","description":"False when the tool has left the assistant's catalogue since, so it can no longer run."},"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","description":"string, number, boolean, object or array."},"description":{"type":"string"},"required":{"type":"boolean"},"in":{"type":"string","description":"path, query or body."},"edit":{"type":"string","description":"edit (may change), narrow (a list that may only lose items) or locked."},"lockedReason":{"type":"string"},"enum":{"type":"array","items":{"type":"string"}},"format":{"type":"string","description":"uuid, url, email, datetime, decimal."},"integer":{"type":"boolean"},"items":{"type":"string","description":"string or object: the element type of a list."},"minLength":{"type":"integer"},"maxLength":{"type":"integer"},"minimum":{"type":"number"},"maximum":{"type":"number"}},"required":["name","type","description","required","in","edit"]},"description":"The input fields from the tool's own parameters — the rules the server re-checks an edit with (@inferrex/tools-schema change-input)."},"target":{"type":"object","properties":{"name":{"type":"string","nullable":true},"id":{"type":"string","nullable":true},"readable":{"type":"boolean"},"current":{"type":"object","additionalProperties":true,"nullable":true,"description":"The record as it is now — the \"before\" of the preview."}},"required":["readable"],"description":"The record the change is for, read fresh through its own GET route AS YOU (secret fields stripped). Not readable for a create, or when no read route exists."},"confirmName":{"type":"string","nullable":true,"description":"Irreversible changes: the name to type to approve."},"request":{"type":"object","properties":{"method":{"type":"string"},"path":{"type":"string"},"body":{"type":"object","additionalProperties":true,"nullable":true}},"required":["method","path"],"nullable":true,"description":"The API call the change makes, for \"Copy as API call\"."},"approvals":{"type":"object","properties":{"required":{"type":"array","items":{"type":"string"},"description":"Empty: one approval from the proposer or the reviewer applies."},"satisfied":{"type":"boolean"},"received":{"type":"array","items":{"type":"object","properties":{"approver":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"role":{"type":"string","nullable":true,"description":"The policy entry the approval fills."},"decidedAt":{"type":"string"}},"required":["decidedAt"]}}},"required":["required","satisfied","received"],"description":"The workspace's approval policy for changes Ask Inferrex proposes (approval_policies entity_type assistant_action), and who has approved so far."},"can":{"type":"object","properties":{"approve":{"type":"boolean"},"approveBlockedReason":{"type":"string","nullable":true,"description":"Why not, when an approval policy needs someone else."},"decline":{"type":"boolean"},"edit":{"type":"boolean"},"saveDraft":{"type":"boolean"},"sendForReview":{"type":"boolean"}},"required":["approve","decline","edit","saveDraft","sendForReview"],"description":"What you may do now."},"history":{"type":"array","items":{"type":"object","properties":{"event":{"type":"string","description":"Open vocabulary. Today: proposed, edited, saved_draft, sent_for_review, approved_partly, approved, declined, ran, failed."},"at":{"type":"string"},"by":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"note":{"type":"string","nullable":true},"assignee":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"fields":{"type":"array","items":{"type":"string"},"description":"For edited: the inputs that changed."},"httpStatus":{"type":"integer","nullable":true}},"required":["event","at","fields"]},"description":"The activity trail, oldest first."}},"required":["id","conversationId","tool","summary","risk","state","edited","proposedBy","createdAt","updatedAt","method","path","you","args","available","fields","target","approvals","can","history"]}},"required":["outcome","remaining","action"]},"example":{"outcome":"string","remaining":["string"],"httpStatus":0,"action":{"id":"00000000-0000-0000-0000-000000000000","conversationId":"00000000-0000-0000-0000-000000000000","tool":"string","summary":"string","risk":"string","state":"string","edited":true,"proposedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"assignee":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z","method":"string","path":"string","you":"string","resultStatus":0,"expiresAt":"2026-01-01T00:00:00Z","confirmedAt":"2026-01-01T00:00:00Z","decidedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"declineReason":"string","args":{},"originalArgs":{},"editedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"editedAt":"2026-01-01T00:00:00Z","available":true,"fields":[{"name":"string","type":"string","description":"string","required":true,"in":"string","edit":"string","lockedReason":"string","enum":["string"],"format":"string","integer":true,"items":"string","minLength":0,"maxLength":0,"minimum":0,"maximum":0}],"target":{"name":"string","id":"string","readable":true,"current":{}},"confirmName":"string","request":{"method":"string","path":"string","body":{}},"approvals":{"required":["string"],"satisfied":true,"received":[{"approver":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"role":"string","decidedAt":"string"}]},"can":{"approve":true,"approveBlockedReason":"string","decline":true,"edit":true,"saveDraft":true,"sendForReview":true},"history":[{"event":"string","at":"string","by":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"note":"string","assignee":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"fields":["string"],"httpStatus":0}]}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/assistant/actions/{id}/confirm":{"post":{"operationId":"ConfirmAssistantAction","tags":["assistant"],"summary":"Confirm Assistant Action","security":[{"ApiKeyAuth":["assistant:write"]},{"BearerAuth":[]},{"OAuth2":["assistant:write"]}],"description":"Approve a change Ask Inferrex proposed — as proposed, or with args you edited — run it as you through its own API route (audit-logged with via = assistant and this action id), then stream the resumed turn. An edited input is re-checked against the tool's parameters (ids, path parameters and the record are locked; a list may only lose items) and your permission is checked as when it was proposed. Refused when the action is not yours, has expired, or was already decided, and when the workspace's approval policy needs someone else; an irreversible action also needs typedName, compared case-sensitively with the record name read fresh.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"typedName":{"type":"string","maxLength":500},"args":{"type":"object","additionalProperties":true,"description":"The change's input as you edited it. Omit to approve it as proposed."}}},"example":{"typedName":"string","args":{}}}}},"responses":{"201":{"description":"Server-Sent Events stream","content":{"text/event-stream":{"schema":{"type":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/assistant/actions/{id}/decline":{"post":{"operationId":"DeclineAssistantAction","tags":["assistant"],"summary":"Decline Assistant Action","security":[{"ApiKeyAuth":["assistant:write"]},{"BearerAuth":[]},{"OAuth2":["assistant:write"]}],"description":"Decline a change outside the chat — its proposer, or the reviewer it was sent to. Nothing runs. The reason goes to the assistant (as untrusted data) and into the change's history; a reviewer's decline notifies the proposer.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":1000}}},"example":{"reason":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversationId":{"type":"string","format":"uuid"},"tool":{"type":"string","description":"The tool (an API operation) it runs. Never changed by an edit."},"summary":{"type":"string","description":"One plain sentence written by the API, rewritten when the input is edited."},"risk":{"type":"string","description":"Today: write, irreversible."},"state":{"type":"string","description":"Open vocabulary. Today: pending (on a chat card), draft, pending_review, approved, declined, expired, failed."},"edited":{"type":"boolean","description":"Someone changed the input the assistant proposed."},"proposedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"]},"assignee":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true,"description":"Who it was sent to for review."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"method":{"type":"string"},"path":{"type":"string"},"you":{"type":"string","description":"proposer or reviewer."},"resultStatus":{"type":"integer","nullable":true,"description":"The status its route answered when it ran."},"expiresAt":{"type":"string","format":"date-time","nullable":true,"description":"Only while it waits on a chat card; null for a draft or a review."},"confirmedAt":{"type":"string","format":"date-time","nullable":true,"description":"When it was approved."},"decidedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true,"description":"Who approved or declined it — for an approval, the person it ran as."},"declineReason":{"type":"string","nullable":true},"args":{"type":"object","additionalProperties":true,"description":"The input that will run (the edited one, when edited)."},"originalArgs":{"type":"object","additionalProperties":true,"nullable":true,"description":"What the assistant proposed, when someone has edited it since."},"editedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"editedAt":{"type":"string","format":"date-time","nullable":true},"available":{"type":"boolean","description":"False when the tool has left the assistant's catalogue since, so it can no longer run."},"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","description":"string, number, boolean, object or array."},"description":{"type":"string"},"required":{"type":"boolean"},"in":{"type":"string","description":"path, query or body."},"edit":{"type":"string","description":"edit (may change), narrow (a list that may only lose items) or locked."},"lockedReason":{"type":"string"},"enum":{"type":"array","items":{"type":"string"}},"format":{"type":"string","description":"uuid, url, email, datetime, decimal."},"integer":{"type":"boolean"},"items":{"type":"string","description":"string or object: the element type of a list."},"minLength":{"type":"integer"},"maxLength":{"type":"integer"},"minimum":{"type":"number"},"maximum":{"type":"number"}},"required":["name","type","description","required","in","edit"]},"description":"The input fields from the tool's own parameters — the rules the server re-checks an edit with (@inferrex/tools-schema change-input)."},"target":{"type":"object","properties":{"name":{"type":"string","nullable":true},"id":{"type":"string","nullable":true},"readable":{"type":"boolean"},"current":{"type":"object","additionalProperties":true,"nullable":true,"description":"The record as it is now — the \"before\" of the preview."}},"required":["readable"],"description":"The record the change is for, read fresh through its own GET route AS YOU (secret fields stripped). Not readable for a create, or when no read route exists."},"confirmName":{"type":"string","nullable":true,"description":"Irreversible changes: the name to type to approve."},"request":{"type":"object","properties":{"method":{"type":"string"},"path":{"type":"string"},"body":{"type":"object","additionalProperties":true,"nullable":true}},"required":["method","path"],"nullable":true,"description":"The API call the change makes, for \"Copy as API call\"."},"approvals":{"type":"object","properties":{"required":{"type":"array","items":{"type":"string"},"description":"Empty: one approval from the proposer or the reviewer applies."},"satisfied":{"type":"boolean"},"received":{"type":"array","items":{"type":"object","properties":{"approver":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"role":{"type":"string","nullable":true,"description":"The policy entry the approval fills."},"decidedAt":{"type":"string"}},"required":["decidedAt"]}}},"required":["required","satisfied","received"],"description":"The workspace's approval policy for changes Ask Inferrex proposes (approval_policies entity_type assistant_action), and who has approved so far."},"can":{"type":"object","properties":{"approve":{"type":"boolean"},"approveBlockedReason":{"type":"string","nullable":true,"description":"Why not, when an approval policy needs someone else."},"decline":{"type":"boolean"},"edit":{"type":"boolean"},"saveDraft":{"type":"boolean"},"sendForReview":{"type":"boolean"}},"required":["approve","decline","edit","saveDraft","sendForReview"],"description":"What you may do now."},"history":{"type":"array","items":{"type":"object","properties":{"event":{"type":"string","description":"Open vocabulary. Today: proposed, edited, saved_draft, sent_for_review, approved_partly, approved, declined, ran, failed."},"at":{"type":"string"},"by":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"note":{"type":"string","nullable":true},"assignee":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"fields":{"type":"array","items":{"type":"string"},"description":"For edited: the inputs that changed."},"httpStatus":{"type":"integer","nullable":true}},"required":["event","at","fields"]},"description":"The activity trail, oldest first."}},"required":["id","conversationId","tool","summary","risk","state","edited","proposedBy","createdAt","updatedAt","method","path","you","args","available","fields","target","approvals","can","history"]},"example":{"id":"00000000-0000-0000-0000-000000000000","conversationId":"00000000-0000-0000-0000-000000000000","tool":"string","summary":"string","risk":"string","state":"string","edited":true,"proposedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"assignee":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z","method":"string","path":"string","you":"string","resultStatus":0,"expiresAt":"2026-01-01T00:00:00Z","confirmedAt":"2026-01-01T00:00:00Z","decidedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"declineReason":"string","args":{},"originalArgs":{},"editedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"editedAt":"2026-01-01T00:00:00Z","available":true,"fields":[{"name":"string","type":"string","description":"string","required":true,"in":"string","edit":"string","lockedReason":"string","enum":["string"],"format":"string","integer":true,"items":"string","minLength":0,"maxLength":0,"minimum":0,"maximum":0}],"target":{"name":"string","id":"string","readable":true,"current":{}},"confirmName":"string","request":{"method":"string","path":"string","body":{}},"approvals":{"required":["string"],"satisfied":true,"received":[{"approver":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"role":"string","decidedAt":"string"}]},"can":{"approve":true,"approveBlockedReason":"string","decline":true,"edit":true,"saveDraft":true,"sendForReview":true},"history":[{"event":"string","at":"string","by":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"note":"string","assignee":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"fields":["string"],"httpStatus":0}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/assistant/actions/{id}/draft":{"post":{"operationId":"SaveAssistantActionDraft","tags":["assistant"],"summary":"Save Assistant Action Draft","security":[{"ApiKeyAuth":["assistant:write"]},{"BearerAuth":[]},{"OAuth2":["assistant:write"]}],"description":"Keep a change you were proposed as a draft, beyond the chat card's expiry. Works from a chat card, a draft, or a change you sent for review (which takes it back from the reviewer). Nothing runs. Drafts age out with the rest of your history (assistant.retentionDays).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"args":{"type":"object","additionalProperties":true,"description":"The input as you edited it. Omit to keep it as it is."}}},"example":{"args":{}}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversationId":{"type":"string","format":"uuid"},"tool":{"type":"string","description":"The tool (an API operation) it runs. Never changed by an edit."},"summary":{"type":"string","description":"One plain sentence written by the API, rewritten when the input is edited."},"risk":{"type":"string","description":"Today: write, irreversible."},"state":{"type":"string","description":"Open vocabulary. Today: pending (on a chat card), draft, pending_review, approved, declined, expired, failed."},"edited":{"type":"boolean","description":"Someone changed the input the assistant proposed."},"proposedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"]},"assignee":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true,"description":"Who it was sent to for review."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"method":{"type":"string"},"path":{"type":"string"},"you":{"type":"string","description":"proposer or reviewer."},"resultStatus":{"type":"integer","nullable":true,"description":"The status its route answered when it ran."},"expiresAt":{"type":"string","format":"date-time","nullable":true,"description":"Only while it waits on a chat card; null for a draft or a review."},"confirmedAt":{"type":"string","format":"date-time","nullable":true,"description":"When it was approved."},"decidedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true,"description":"Who approved or declined it — for an approval, the person it ran as."},"declineReason":{"type":"string","nullable":true},"args":{"type":"object","additionalProperties":true,"description":"The input that will run (the edited one, when edited)."},"originalArgs":{"type":"object","additionalProperties":true,"nullable":true,"description":"What the assistant proposed, when someone has edited it since."},"editedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"editedAt":{"type":"string","format":"date-time","nullable":true},"available":{"type":"boolean","description":"False when the tool has left the assistant's catalogue since, so it can no longer run."},"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","description":"string, number, boolean, object or array."},"description":{"type":"string"},"required":{"type":"boolean"},"in":{"type":"string","description":"path, query or body."},"edit":{"type":"string","description":"edit (may change), narrow (a list that may only lose items) or locked."},"lockedReason":{"type":"string"},"enum":{"type":"array","items":{"type":"string"}},"format":{"type":"string","description":"uuid, url, email, datetime, decimal."},"integer":{"type":"boolean"},"items":{"type":"string","description":"string or object: the element type of a list."},"minLength":{"type":"integer"},"maxLength":{"type":"integer"},"minimum":{"type":"number"},"maximum":{"type":"number"}},"required":["name","type","description","required","in","edit"]},"description":"The input fields from the tool's own parameters — the rules the server re-checks an edit with (@inferrex/tools-schema change-input)."},"target":{"type":"object","properties":{"name":{"type":"string","nullable":true},"id":{"type":"string","nullable":true},"readable":{"type":"boolean"},"current":{"type":"object","additionalProperties":true,"nullable":true,"description":"The record as it is now — the \"before\" of the preview."}},"required":["readable"],"description":"The record the change is for, read fresh through its own GET route AS YOU (secret fields stripped). Not readable for a create, or when no read route exists."},"confirmName":{"type":"string","nullable":true,"description":"Irreversible changes: the name to type to approve."},"request":{"type":"object","properties":{"method":{"type":"string"},"path":{"type":"string"},"body":{"type":"object","additionalProperties":true,"nullable":true}},"required":["method","path"],"nullable":true,"description":"The API call the change makes, for \"Copy as API call\"."},"approvals":{"type":"object","properties":{"required":{"type":"array","items":{"type":"string"},"description":"Empty: one approval from the proposer or the reviewer applies."},"satisfied":{"type":"boolean"},"received":{"type":"array","items":{"type":"object","properties":{"approver":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"role":{"type":"string","nullable":true,"description":"The policy entry the approval fills."},"decidedAt":{"type":"string"}},"required":["decidedAt"]}}},"required":["required","satisfied","received"],"description":"The workspace's approval policy for changes Ask Inferrex proposes (approval_policies entity_type assistant_action), and who has approved so far."},"can":{"type":"object","properties":{"approve":{"type":"boolean"},"approveBlockedReason":{"type":"string","nullable":true,"description":"Why not, when an approval policy needs someone else."},"decline":{"type":"boolean"},"edit":{"type":"boolean"},"saveDraft":{"type":"boolean"},"sendForReview":{"type":"boolean"}},"required":["approve","decline","edit","saveDraft","sendForReview"],"description":"What you may do now."},"history":{"type":"array","items":{"type":"object","properties":{"event":{"type":"string","description":"Open vocabulary. Today: proposed, edited, saved_draft, sent_for_review, approved_partly, approved, declined, ran, failed."},"at":{"type":"string"},"by":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"note":{"type":"string","nullable":true},"assignee":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"fields":{"type":"array","items":{"type":"string"},"description":"For edited: the inputs that changed."},"httpStatus":{"type":"integer","nullable":true}},"required":["event","at","fields"]},"description":"The activity trail, oldest first."}},"required":["id","conversationId","tool","summary","risk","state","edited","proposedBy","createdAt","updatedAt","method","path","you","args","available","fields","target","approvals","can","history"]},"example":{"id":"00000000-0000-0000-0000-000000000000","conversationId":"00000000-0000-0000-0000-000000000000","tool":"string","summary":"string","risk":"string","state":"string","edited":true,"proposedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"assignee":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z","method":"string","path":"string","you":"string","resultStatus":0,"expiresAt":"2026-01-01T00:00:00Z","confirmedAt":"2026-01-01T00:00:00Z","decidedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"declineReason":"string","args":{},"originalArgs":{},"editedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"editedAt":"2026-01-01T00:00:00Z","available":true,"fields":[{"name":"string","type":"string","description":"string","required":true,"in":"string","edit":"string","lockedReason":"string","enum":["string"],"format":"string","integer":true,"items":"string","minLength":0,"maxLength":0,"minimum":0,"maximum":0}],"target":{"name":"string","id":"string","readable":true,"current":{}},"confirmName":"string","request":{"method":"string","path":"string","body":{}},"approvals":{"required":["string"],"satisfied":true,"received":[{"approver":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"role":"string","decidedAt":"string"}]},"can":{"approve":true,"approveBlockedReason":"string","decline":true,"edit":true,"saveDraft":true,"sendForReview":true},"history":[{"event":"string","at":"string","by":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"note":"string","assignee":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"fields":["string"],"httpStatus":0}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/assistant/actions/{id}/reject":{"post":{"operationId":"RejectAssistantAction","tags":["assistant"],"summary":"Reject Assistant Action","security":[{"ApiKeyAuth":["assistant:write"]},{"BearerAuth":[]},{"OAuth2":["assistant:write"]}],"description":"Decline a change Ask Inferrex proposed, with an optional reason. Nothing runs; the model is told you declined (and why) and the turn resumes as server-sent events.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":1000,"description":"Why, for the assistant and the change's history."}}},"example":{"reason":"string"}}}},"responses":{"201":{"description":"Server-Sent Events stream","content":{"text/event-stream":{"schema":{"type":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/assistant/actions/{id}/review":{"post":{"operationId":"SendAssistantActionForReview","tags":["assistant"],"summary":"Send Assistant Action For Review","security":[{"ApiKeyAuth":["assistant:write"]},{"BearerAuth":[]},{"OAuth2":["assistant:write"]}],"description":"Send a change you were proposed to a colleague to review (or to a different one). They must be an active member who may use Ask Inferrex and make the change themselves. They get a notification and find it in their review list; the change no longer expires. Proposer only.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"assigneeUserId":{"type":"string","format":"uuid"},"note":{"type":"string","maxLength":1000},"args":{"type":"object","additionalProperties":true,"description":"The input as you edited it. Omit to send it as it is."}},"required":["assigneeUserId"]},"example":{"assigneeUserId":"00000000-0000-0000-0000-000000000000","note":"string","args":{}}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversationId":{"type":"string","format":"uuid"},"tool":{"type":"string","description":"The tool (an API operation) it runs. Never changed by an edit."},"summary":{"type":"string","description":"One plain sentence written by the API, rewritten when the input is edited."},"risk":{"type":"string","description":"Today: write, irreversible."},"state":{"type":"string","description":"Open vocabulary. Today: pending (on a chat card), draft, pending_review, approved, declined, expired, failed."},"edited":{"type":"boolean","description":"Someone changed the input the assistant proposed."},"proposedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"]},"assignee":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true,"description":"Who it was sent to for review."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"method":{"type":"string"},"path":{"type":"string"},"you":{"type":"string","description":"proposer or reviewer."},"resultStatus":{"type":"integer","nullable":true,"description":"The status its route answered when it ran."},"expiresAt":{"type":"string","format":"date-time","nullable":true,"description":"Only while it waits on a chat card; null for a draft or a review."},"confirmedAt":{"type":"string","format":"date-time","nullable":true,"description":"When it was approved."},"decidedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true,"description":"Who approved or declined it — for an approval, the person it ran as."},"declineReason":{"type":"string","nullable":true},"args":{"type":"object","additionalProperties":true,"description":"The input that will run (the edited one, when edited)."},"originalArgs":{"type":"object","additionalProperties":true,"nullable":true,"description":"What the assistant proposed, when someone has edited it since."},"editedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"editedAt":{"type":"string","format":"date-time","nullable":true},"available":{"type":"boolean","description":"False when the tool has left the assistant's catalogue since, so it can no longer run."},"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","description":"string, number, boolean, object or array."},"description":{"type":"string"},"required":{"type":"boolean"},"in":{"type":"string","description":"path, query or body."},"edit":{"type":"string","description":"edit (may change), narrow (a list that may only lose items) or locked."},"lockedReason":{"type":"string"},"enum":{"type":"array","items":{"type":"string"}},"format":{"type":"string","description":"uuid, url, email, datetime, decimal."},"integer":{"type":"boolean"},"items":{"type":"string","description":"string or object: the element type of a list."},"minLength":{"type":"integer"},"maxLength":{"type":"integer"},"minimum":{"type":"number"},"maximum":{"type":"number"}},"required":["name","type","description","required","in","edit"]},"description":"The input fields from the tool's own parameters — the rules the server re-checks an edit with (@inferrex/tools-schema change-input)."},"target":{"type":"object","properties":{"name":{"type":"string","nullable":true},"id":{"type":"string","nullable":true},"readable":{"type":"boolean"},"current":{"type":"object","additionalProperties":true,"nullable":true,"description":"The record as it is now — the \"before\" of the preview."}},"required":["readable"],"description":"The record the change is for, read fresh through its own GET route AS YOU (secret fields stripped). Not readable for a create, or when no read route exists."},"confirmName":{"type":"string","nullable":true,"description":"Irreversible changes: the name to type to approve."},"request":{"type":"object","properties":{"method":{"type":"string"},"path":{"type":"string"},"body":{"type":"object","additionalProperties":true,"nullable":true}},"required":["method","path"],"nullable":true,"description":"The API call the change makes, for \"Copy as API call\"."},"approvals":{"type":"object","properties":{"required":{"type":"array","items":{"type":"string"},"description":"Empty: one approval from the proposer or the reviewer applies."},"satisfied":{"type":"boolean"},"received":{"type":"array","items":{"type":"object","properties":{"approver":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"role":{"type":"string","nullable":true,"description":"The policy entry the approval fills."},"decidedAt":{"type":"string"}},"required":["decidedAt"]}}},"required":["required","satisfied","received"],"description":"The workspace's approval policy for changes Ask Inferrex proposes (approval_policies entity_type assistant_action), and who has approved so far."},"can":{"type":"object","properties":{"approve":{"type":"boolean"},"approveBlockedReason":{"type":"string","nullable":true,"description":"Why not, when an approval policy needs someone else."},"decline":{"type":"boolean"},"edit":{"type":"boolean"},"saveDraft":{"type":"boolean"},"sendForReview":{"type":"boolean"}},"required":["approve","decline","edit","saveDraft","sendForReview"],"description":"What you may do now."},"history":{"type":"array","items":{"type":"object","properties":{"event":{"type":"string","description":"Open vocabulary. Today: proposed, edited, saved_draft, sent_for_review, approved_partly, approved, declined, ran, failed."},"at":{"type":"string"},"by":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"note":{"type":"string","nullable":true},"assignee":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"workspace_users.id"},"name":{"type":"string","description":"Display name, else email; \"A former member\" once they have left."}},"required":["id","name"],"nullable":true},"fields":{"type":"array","items":{"type":"string"},"description":"For edited: the inputs that changed."},"httpStatus":{"type":"integer","nullable":true}},"required":["event","at","fields"]},"description":"The activity trail, oldest first."}},"required":["id","conversationId","tool","summary","risk","state","edited","proposedBy","createdAt","updatedAt","method","path","you","args","available","fields","target","approvals","can","history"]},"example":{"id":"00000000-0000-0000-0000-000000000000","conversationId":"00000000-0000-0000-0000-000000000000","tool":"string","summary":"string","risk":"string","state":"string","edited":true,"proposedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"assignee":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z","method":"string","path":"string","you":"string","resultStatus":0,"expiresAt":"2026-01-01T00:00:00Z","confirmedAt":"2026-01-01T00:00:00Z","decidedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"declineReason":"string","args":{},"originalArgs":{},"editedBy":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"editedAt":"2026-01-01T00:00:00Z","available":true,"fields":[{"name":"string","type":"string","description":"string","required":true,"in":"string","edit":"string","lockedReason":"string","enum":["string"],"format":"string","integer":true,"items":"string","minLength":0,"maxLength":0,"minimum":0,"maximum":0}],"target":{"name":"string","id":"string","readable":true,"current":{}},"confirmName":"string","request":{"method":"string","path":"string","body":{}},"approvals":{"required":["string"],"satisfied":true,"received":[{"approver":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"role":"string","decidedAt":"string"}]},"can":{"approve":true,"approveBlockedReason":"string","decline":true,"edit":true,"saveDraft":true,"sendForReview":true},"history":[{"event":"string","at":"string","by":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"note":"string","assignee":{"id":"00000000-0000-0000-0000-000000000000","name":"string"},"fields":["string"],"httpStatus":0}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/assistant/actions/{id}/reviewers":{"get":{"operationId":"ListAssistantActionReviewers","tags":["assistant"],"summary":"List Assistant Action Reviewers","security":[{"ApiKeyAuth":["assistant:read"]},{"BearerAuth":[]},{"OAuth2":["assistant:read"]}],"description":"Who you can send this change to: active members other than you who may use Ask Inferrex and hold the change's own permission (approval runs as the approver). fillsPolicy marks members who would fill an open entry of the workspace's assistant_action approval policy. Empty for anyone but the proposer.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"role":{"type":"string"},"fillsPolicy":{"type":"boolean"}},"required":["id","name","role","fillsPolicy"]}},"policy":{"type":"array","items":{"type":"string"},"description":"The approval policy's required approvers; empty when there is none."}},"required":["items","policy"]},"example":{"items":[{"id":"00000000-0000-0000-0000-000000000000","name":"string","role":"string","fillsPolicy":true}],"policy":["string"]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/assistant/conversations":{"get":{"operationId":"ListAssistantConversations","tags":["assistant"],"summary":"List Assistant Conversations","security":[{"ApiKeyAuth":["assistant:read"]},{"BearerAuth":[]},{"OAuth2":["assistant:read"]}],"description":"Your own Ask Inferrex conversations, most recent first. By default only live ones; archived=true lists only the ones archived by PATCH or by retention (assistant.retentionDays), so an archived chat can be found and brought back. Never another member's.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"archived","in":"query","required":false,"schema":{"type":"boolean","description":"false (the default): live conversations only. true: archived conversations only. Bring one back with PATCH /v1/assistant/conversations/:id { archived: false }.","default":false},"description":"false (the default): live conversations only. true: archived conversations only. Bring one back with PATCH /v1/assistant/conversations/:id { archived: false }."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string","nullable":true},"startPage":{"type":"string","nullable":true,"description":"The page it was started from."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time","description":"Bumped on every message."},"archived":{"type":"boolean","description":"Whether the conversation is archived; matches the archived filter."}},"required":["id","createdAt","updatedAt","archived"]}}},"required":["items"]},"example":{"items":[{"id":"00000000-0000-0000-0000-000000000000","title":"string","startPage":"string","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z","archived":true}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"CreateAssistantConversation","tags":["assistant"],"summary":"Create Assistant Conversation","security":[{"ApiKeyAuth":["assistant:write"]},{"BearerAuth":[]},{"OAuth2":["assistant:write"]}],"description":"Start an Ask Inferrex conversation. The model arm is chosen here (assistant.model; sticky per member when it is ab) and kept for the conversation.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"startPage":{"type":"string","maxLength":200},"title":{"type":"string","maxLength":200}}},"example":{"startPage":"string","title":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string","nullable":true},"startPage":{"type":"string","nullable":true,"description":"The page it was started from."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time","description":"Bumped on every message."}},"required":["id","createdAt","updatedAt"]},"example":{"id":"00000000-0000-0000-0000-000000000000","title":"string","startPage":"string","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/assistant/conversations/{id}":{"get":{"operationId":"GetAssistantConversation","tags":["assistant"],"summary":"Get Assistant Conversation","security":[{"ApiKeyAuth":["assistant:read"]},{"BearerAuth":[]},{"OAuth2":["assistant:read"]}],"description":"One of your own Ask Inferrex conversations with its messages and proposed actions. Tool results are as the model saw them: secret fields stripped and cut to assistant.maxToolResultChars.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"conversation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string","nullable":true},"startPage":{"type":"string","nullable":true,"description":"The page it was started from."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time","description":"Bumped on every message."}},"required":["id","createdAt","updatedAt"]},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"role":{"type":"string","description":"Today: user, assistant, tool (a tool message carries results only; system is never stored)."},"text":{"type":"string","nullable":true,"description":"Null on an assistant message that only called tools, and on tool messages."},"toolCalls":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Matches toolResults[].toolCallId."},"name":{"type":"string"},"arguments":{"type":"string","description":"The arguments as a JSON string."}},"required":["id","name","arguments"]},"description":"The tools an assistant message called; [] otherwise."},"toolResults":{"type":"array","items":{"type":"object","properties":{"toolCallId":{"type":"string"},"status":{"oneOf":[{"type":"integer"},{"type":"string"}],"description":"The HTTP status the route answered, or when it did not run: pending, rejected, expired, refused, error, ok."},"body":{"type":"string"},"truncated":{"type":"boolean"},"actionId":{"type":"string","format":"uuid","description":"The proposed change this result belongs to."}},"required":["toolCallId","status","body","truncated"]},"description":"On a tool message: what each call returned, redacted and cut to assistant.maxToolResultChars; [] otherwise. A proposed change appears as pending, and its outcome later under the same toolCallId — the latest wins."},"feedback":{"type":"string","nullable":true,"description":"up, down, or null."},"feedbackNote":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","role","toolCalls","toolResults","createdAt"]},"description":"Oldest first."},"actions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tool":{"type":"string"},"method":{"type":"string"},"path":{"type":"string"},"args":{"type":"object","additionalProperties":true},"risk":{"type":"string","description":"Today: write, irreversible."},"summary":{"type":"string"},"status":{"type":"string","description":"Open vocabulary. Today: pending, draft, pending_review, approved, declined, expired, failed."},"resultStatus":{"type":"integer","nullable":true,"description":"The HTTP status the change returned when it ran."},"expiresAt":{"type":"string","format":"date-time","nullable":true,"description":"Only while it waits on a chat card."},"edited":{"type":"boolean","description":"Someone changed the input the assistant proposed."},"assigneeUserId":{"type":"string","format":"uuid","nullable":true,"description":"Who it was sent to for review."},"confirmedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","tool","method","path","args","risk","summary","status","edited","createdAt"]},"description":"Every change proposed in the conversation, oldest first."}},"required":["conversation","messages","actions"]},"example":{"conversation":{"id":"00000000-0000-0000-0000-000000000000","title":"string","startPage":"string","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z"},"messages":[{"id":"00000000-0000-0000-0000-000000000000","role":"string","text":"string","toolCalls":[{"id":"string","name":"string","arguments":"string"}],"toolResults":[{"toolCallId":"string","status":null,"body":"string","truncated":true,"actionId":"00000000-0000-0000-0000-000000000000"}],"feedback":"string","feedbackNote":"string","createdAt":"2026-01-01T00:00:00Z"}],"actions":[{"id":"00000000-0000-0000-0000-000000000000","tool":"string","method":"string","path":"string","args":{},"risk":"string","summary":"string","status":"string","resultStatus":0,"expiresAt":"2026-01-01T00:00:00Z","edited":true,"assigneeUserId":"00000000-0000-0000-0000-000000000000","confirmedAt":"2026-01-01T00:00:00Z","createdAt":"2026-01-01T00:00:00Z"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"operationId":"UpdateAssistantConversation","tags":["assistant"],"summary":"Update Assistant Conversation","security":[{"ApiKeyAuth":["assistant:write"]},{"BearerAuth":[]},{"OAuth2":["assistant:write"]}],"description":"Rename or archive one of your own Ask Inferrex conversations. title sets the name (an empty string clears it). archived: true hides it from the list and from GET, as retention does; archived: false brings it back, refused with 409 once any of its messages has passed assistant.retentionDays. Archiving does not delete anything and does not change when the workspace's archive retention deletes it.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","maxLength":200},"archived":{"type":"boolean"}}},"example":{"title":"string","archived":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string","nullable":true},"startPage":{"type":"string","nullable":true},"archived":{"type":"boolean"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","archived","createdAt","updatedAt"]},"example":{"id":"00000000-0000-0000-0000-000000000000","title":"string","startPage":"string","archived":true,"createdAt":"string","updatedAt":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/assistant/memories":{"get":{"operationId":"ListAssistantMemories","tags":["assistant"],"summary":"List Assistant Memories","security":[{"ApiKeyAuth":["assistant:read"]},{"BearerAuth":[]},{"OAuth2":["assistant:read"]}],"description":"The active memories Ask Inferrex recalls for you: the workspace's and your own personal ones, pinned first. Workspace owners and admins also see other members' personal memories (ownerUserId says whose).","parameters":[{"name":"scope","in":"query","required":false,"schema":{"type":"string","enum":["personal","workspace"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"scope":{"type":"string","description":"personal or workspace."},"ownerUserId":{"type":"string","format":"uuid","nullable":true,"description":"Whose personal memory it is; null for a workspace memory."},"content":{"type":"string","description":"The fact, with personal data masked."},"tags":{"type":"array","items":{"type":"string"}},"pinned":{"type":"boolean"},"createdByUserId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","scope","ownerUserId","content","tags","pinned","createdByUserId","createdAt","updatedAt"]},"description":"Pinned first, then most recently changed."}},"required":["items"]},"example":{"items":[{"id":"00000000-0000-0000-0000-000000000000","scope":"string","ownerUserId":"00000000-0000-0000-0000-000000000000","content":"string","tags":["string"],"pinned":true,"createdByUserId":"00000000-0000-0000-0000-000000000000","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"CreateAssistantMemory","tags":["assistant"],"summary":"Create Assistant Memory","security":[{"ApiKeyAuth":["assistant:write"]},{"BearerAuth":[]},{"OAuth2":["assistant:write"]}],"description":"Remember a fact for Ask Inferrex: personal (only you, and your workspace owners/admins) or workspace (the whole team; needs edit permission). Personal data is masked before it is stored, and the change is written to the memory trail with its source. When Ask Inferrex runs it for you, the source is the message that asked for it.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"scope":{"type":"string","enum":["personal","workspace"]},"content":{"type":"string","maxLength":2000},"tags":{"type":"array","items":{"type":"string"}},"pinned":{"type":"boolean"}},"required":["scope","content"]},"example":{"scope":"personal","content":"string","tags":["string"],"pinned":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"scope":{"type":"string"},"content":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"pinned":{"type":"boolean"}},"required":["id","scope","content","tags","pinned"]},"example":{"id":"00000000-0000-0000-0000-000000000000","scope":"string","content":"string","tags":["string"],"pinned":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/assistant/memories/{id}":{"delete":{"operationId":"DeleteAssistantMemory","tags":["assistant"],"summary":"Delete Assistant Memory","security":[{"ApiKeyAuth":["assistant:delete"]},{"BearerAuth":[]},{"OAuth2":["assistant:delete"]}],"description":"Delete a memory so Ask Inferrex no longer recalls it. The same permissions as changing it. The memory is marked deleted and a deleted event is written to the immutable trail; nothing is erased from the trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"deleted":{"type":"boolean"}},"required":["id","deleted"]},"example":{"id":"00000000-0000-0000-0000-000000000000","deleted":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"operationId":"UpdateAssistantMemory","tags":["assistant"],"summary":"Update Assistant Memory","security":[{"ApiKeyAuth":["assistant:write"]},{"BearerAuth":[]},{"OAuth2":["assistant:write"]}],"description":"Change a memory's content, tags or pin. Your own personal memory is yours to change; a workspace memory needs edit permission; another member's personal memory needs workspace owner or admin. Personal data is masked before it is stored and the change is written to the memory trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"string","maxLength":2000},"tags":{"type":"array","items":{"type":"string"}},"pinned":{"type":"boolean"}}},"example":{"content":"string","tags":["string"],"pinned":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"scope":{"type":"string"},"content":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"pinned":{"type":"boolean"}},"required":["id","scope","content","tags","pinned"]},"example":{"id":"00000000-0000-0000-0000-000000000000","scope":"string","content":"string","tags":["string"],"pinned":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/assistant/messages/{id}/feedback":{"post":{"operationId":"SubmitAssistantFeedback","tags":["assistant"],"summary":"Submit Assistant Feedback","security":[{"ApiKeyAuth":["assistant:write"]},{"BearerAuth":[]},{"OAuth2":["assistant:write"]}],"description":"Thumbs up or down, with an optional note, on one of Ask Inferrex's answers to you.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"feedback":{"type":"string","enum":["up","down"]},"note":{"type":"string","maxLength":2000}},"required":["feedback"]},"example":{"feedback":"up","note":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"feedback":{"type":"string"}},"required":["id","feedback"]},"example":{"id":"00000000-0000-0000-0000-000000000000","feedback":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/assistant/turns":{"post":{"operationId":"AssistantTurn","tags":["assistant"],"summary":"Assistant Turn","security":[{"ApiKeyAuth":["assistant:write"]},{"BearerAuth":[]},{"OAuth2":["assistant:write"]}],"description":"Send a message to Ask Inferrex and stream the answer as server-sent events: conversation, text deltas, tool activity, confirm_required (a proposed change the server will not run until POST /v1/assistant/actions/:id/confirm), permission_denied, navigate, awaiting_confirmation, error, done. Reads run at once as you; changes never run without your confirmation. Omit conversationId to start a conversation.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"conversationId":{"type":"string","format":"uuid"},"message":{"type":"string","maxLength":8000},"pageContext":{"type":"object","additionalProperties":true,"description":"Where the user is: { pageId?, route?, module? }. module is the route group whose tools the turn is offered first."}},"required":["message"]},"example":{"conversationId":"00000000-0000-0000-0000-000000000000","message":"string","pageContext":{}}}}},"responses":{"201":{"description":"Server-Sent Events stream","content":{"text/event-stream":{"schema":{"type":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/auth/sso/discover":{"post":{"operationId":"DiscoverSsoProvider","tags":["sso"],"summary":"Discover Sso Provider","security":[],"description":"Discover single sign-on for a work email or a workspace ID. Answers 200 `{ sso: false }` for an unknown, unverified or switched-off domain and `{ sso: true, domainHint, loginHint, workspaceId }` for a verified domain whose federated identity provider is live — never the workspace name or the provider type. Limited per internet address and per email; over the limit the answer is `{ sso: false }`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":320,"description":"The work email to look up. Its domain is matched against verified SSO domains; the address itself is only echoed back as the login hint. Anything that is not an email address answers `sso: false`."},"workspaceId":{"type":"string","format":"uuid","description":"A workspace ID (from its sign-in link or the workspace-ID box) to look up instead of an email."}}},"example":{"email":"string","workspaceId":"00000000-0000-0000-0000-000000000000"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"sso":{"type":"boolean","description":"Whether sign-in should go to a federated identity provider."},"domainHint":{"type":"string","nullable":true,"description":"The `domain_hint` for the Microsoft sign-in redirect. Present only when sso is true."},"loginHint":{"type":"string","nullable":true,"description":"The `login_hint` for the redirect: the email that was looked up, normalised. Present only when sso is true and an email was given."},"workspaceId":{"type":"string","nullable":true,"description":"The workspace the domain or ID resolved to, so the sign-in page can name it for this session (tenant-scoped sign-in). A selector, not a secret. Present only when sso is true."}},"required":["sso"]},"example":{"sso":true,"domainHint":"string","loginHint":"string","workspaceId":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/billing/checkout":{"post":{"operationId":"CreateCheckout","tags":["billing"],"summary":"Create Checkout","security":[{"ApiKeyAuth":["billing:write"]},{"BearerAuth":[]},{"OAuth2":["billing:write"]}],"description":"Get a secure payment page link to restart a paid subscription that has lapsed or been cancelled, on a plan the pricing catalogue offers. New subscriptions are not available this way: Inferrex is currently by invitation, starting with the Beta. A plan that is no longer offered cannot be restarted (409).","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tier":{"type":"string","description":"The plan to restart, as GET /v1/pricing names it (an environment rung such as production). A retired plan answers 409."},"frequency":{"type":"string","enum":["monthly","quarterly","annual"],"description":"How often to pay: monthly (the default), quarterly or annual.","default":"monthly"},"currency":{"type":"string","enum":["gbp","eur","usd"],"description":"The currency to pay in: gbp (the default), eur or usd.","default":"gbp"}},"required":["tier"]},"example":{"tier":"string","frequency":"monthly","currency":"gbp"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"checkoutUrl":{"type":"string"}},"required":["checkoutUrl"]},"example":{"checkoutUrl":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/billing/portal":{"post":{"operationId":"CreatePortalSession","tags":["billing"],"summary":"Create Portal Session","security":[{"ApiKeyAuth":["billing:write"]},{"BearerAuth":[]},{"OAuth2":["billing:write"]}],"description":"Get a link to the billing portal, where you can update your payment method and see invoices. After they finish, the person is sent back to returnUrl, or to Settings if you leave it out.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"returnUrl":{"type":"string","format":"uri","description":"Where to send the person when they leave the billing portal."}}},"example":{"returnUrl":"https://example.com"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"portalUrl":{"type":"string"}},"required":["portalUrl"]},"example":{"portalUrl":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/billing/profile":{"post":{"operationId":"SubmitProfile","tags":["billing"],"summary":"Submit Profile","security":[{"ApiKeyAuth":["billing:write"]},{"BearerAuth":[]},{"OAuth2":["billing:write"]}],"description":"Complete your company profile: who you are, what you want to connect and where your data should be kept. Submitting it starts your trial.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"companyName":{"type":"string","minLength":1,"description":"Your company’s name."},"companyWebsite":{"type":"string","format":"uri","description":"Your company’s website."},"companySize":{"type":"string","enum":["1-10","11-50","51-200","201-1000","1001-5000","5000+"],"description":"How many people work at your company."},"industry":{"type":"string","description":"Your industry."},"jobTitle":{"type":"string","description":"Your job title."},"phone":{"type":"string","description":"A phone number we can reach you on."},"useCase":{"type":"string","description":"What you want to use Inferrex for."},"systemsToConnect":{"type":"array","items":{"type":"string"},"description":"The systems you plan to connect."},"expectedRecordVolume":{"type":"string","enum":["under_100k","100k_1m","1m_10m","10m_100m","over_100m"],"description":"Roughly how many records you expect to sync."},"countryCode":{"type":"string","description":"Your country, as a two-letter code. GB if you leave it out.","default":"GB"},"billingAddress":{"type":"object","additionalProperties":true,"description":"Your billing address."},"vatNumber":{"type":"string","description":"Your VAT number, if you have one."},"dataResidency":{"type":"string","enum":["eu","uk","any"],"description":"Where your data should be kept: eu (the default), uk or any.","default":"eu"}},"required":["companyName","companySize","industry","jobTitle","useCase"]},"example":{"companyName":"string","companyWebsite":"https://example.com","companySize":"1-10","industry":"string","jobTitle":"string","phone":"string","useCase":"string","systemsToConnect":["string"],"expectedRecordVolume":"under_100k","countryCode":"GB","billingAddress":{},"vatNumber":"string","dataResidency":"eu"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"}},"required":["status"]},"example":{"status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/billing/purchase-pack":{"post":{"operationId":"PurchasePack","tags":["billing"],"summary":"Purchase Pack","security":[{"ApiKeyAuth":["billing:write"]},{"BearerAuth":[]},{"OAuth2":["billing:write"]}],"description":"Add a pack to your workspace to raise one of its limits (connected systems, relationships between systems, or analyses) straight away. The pack’s price is recorded against your account.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dimension":{"type":"string","enum":["systems","relationships","analyses"],"description":"Which limit to raise: systems, relationships or analyses."},"unitSize":{"type":"integer","description":"The size of the pack, as offered in your pricing catalogue."}},"required":["dimension","unitSize"]},"example":{"dimension":"systems","unitSize":0}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"purchaseId":{"type":"string","format":"uuid"},"dimension":{"type":"string"},"unitSize":{"type":"integer"},"amountPence":{"type":"integer"},"allowance":{"type":"integer"}},"required":["purchaseId","dimension","unitSize","amountPence","allowance"]},"example":{"purchaseId":"00000000-0000-0000-0000-000000000000","dimension":"string","unitSize":0,"amountPence":0,"allowance":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/billing/request-upgrade":{"post":{"operationId":"RequestUpgrade","tags":["billing"],"summary":"Request Upgrade","security":[{"ApiKeyAuth":["billing:write"]},{"BearerAuth":[]},{"OAuth2":["billing:write"]}],"description":"Ask to move your workspace to a higher environment level, with your reason. The Inferrex team picks it up from there; nothing changes until they do.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"requestedTier":{"type":"string","enum":["qa_sit","uat","staging","production","enterprise","sovereign"],"description":"The environment level you want."},"reason":{"type":"string","description":"Why you need it."},"systemsPlanned":{"type":"array","items":{"type":"string"},"description":"The systems you plan to connect at that level."}},"required":["requestedTier","reason"]},"example":{"requestedTier":"qa_sit","reason":"string","systemsPlanned":["string"]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"requestId":{"type":"string","format":"uuid"}},"required":["requestId"]},"example":{"requestId":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/billing/status":{"get":{"operationId":"GetBillingStatus","tags":["billing"],"summary":"Get Billing Status","security":[{"ApiKeyAuth":["billing:read"]},{"BearerAuth":[]},{"OAuth2":["billing:read"]}],"description":"Your workspace’s account standing: its status and level, when any trial ends, whether payments are up to date and any grace period, whether your company profile is complete, and any price agreed with you.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"tier":{"type":"string"},"trialEndsAt":{"type":"string","nullable":true},"stripeCustomerId":{"type":"string","nullable":true},"subscriptionId":{"type":"string","nullable":true},"paymentStatus":{"type":"string"},"gracePeriodEndsAt":{"type":"string","nullable":true},"profileComplete":{"type":"boolean"},"companyName":{"type":"string","nullable":true},"deals":{"type":"array","items":{"type":"object","properties":{"tier":{"type":"string","nullable":true,"description":"The environment the price is for; null when the agreement names none."},"currency":{"type":"string"},"frequency":{"type":"string","description":"monthly, quarterly or annual."},"amount":{"type":"integer","description":"Minor units."},"display":{"type":"string","description":"The amount as a reader sees it, such as £1,000."}},"required":["currency","frequency","amount","display"]},"description":"The prices agreed with this workspace and in force now: its own only. Empty when it pays the listed price."}},"required":["status","tier","paymentStatus","profileComplete","deals"]},"example":{"status":"string","tier":"string","trialEndsAt":"string","stripeCustomerId":"string","subscriptionId":"string","paymentStatus":"string","gracePeriodEndsAt":"string","profileComplete":true,"companyName":"string","deals":[{"tier":"string","currency":"string","frequency":"string","amount":0,"display":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/bloomreach/activity":{"get":{"operationId":"GetBloomreachActivity","tags":["bloomreach"],"summary":"Get Bloomreach Activity","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":400,"description":"How many days, ending today (UTC). Default 30."},"description":"How many days, ending today (UTC). Default 30."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","nullable":true,"description":"The Engagement connection, or null when none is connected."},"days":{"type":"integer"},"recordedSince":{"type":"string","nullable":true,"description":"The first day with a snapshot (YYYY-MM-DD), or null before the first."},"lastSnapshotAt":{"type":"string","format":"date-time","nullable":true},"series":{"type":"array","items":{"type":"object","properties":{"day":{"type":"string","description":"The UTC day (YYYY-MM-DD)."},"recordsWritten":{"type":"integer","nullable":true,"description":"Records the project's flows wrote that day (sync runs started that day). Null before the first run."},"recordsFailed":{"type":"integer","nullable":true,"description":"Records the project's flows failed to write that day."},"recordsSkipped":{"type":"integer","nullable":true,"description":"Records left unwritten on purpose that day (unchanged, or not for this project)."},"triggerSignals":{"type":"integer","nullable":true,"description":"API trigger signals sent that day: the change in the total from the day before. Null without both days' snapshots."},"triggerBehind":{"type":"integer","nullable":true,"description":"Changes the API triggers had not yet sent, at the day's last snapshot."},"segmentMembers":{"type":"integer","nullable":true,"description":"Members across the project's external segments, at the day's last snapshot."},"segmentJoined":{"type":"integer","nullable":true,"description":"Members who joined a segment that day."},"segmentLeft":{"type":"integer","nullable":true,"description":"Members who left a segment that day."},"feedRows":{"type":"integer","nullable":true,"description":"Rows across the project's feed files, at the day's last snapshot."},"heldBack":{"type":"integer","nullable":true,"description":"Writes to the project held back for review, at the day's last snapshot."}},"required":["day","recordsWritten","recordsFailed","recordsSkipped","triggerSignals","triggerBehind","segmentMembers","segmentJoined","segmentLeft","feedRows","heldBack"]}}},"required":["connectionId","days","recordedSince","lastSnapshotAt","series"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","days":0,"recordedSince":"string","lastSnapshotAt":"2026-01-01T00:00:00Z","series":[{"day":"string","recordsWritten":0,"recordsFailed":0,"recordsSkipped":0,"triggerSignals":0,"triggerBehind":0,"segmentMembers":0,"segmentJoined":0,"segmentLeft":0,"feedRows":0,"heldBack":0}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/api-triggers":{"get":{"operationId":"GetBloomreachApiTriggers","tags":["bloomreach"],"summary":"Get Bloomreach Api Triggers","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","nullable":true},"triggers":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Each trigger as stored (ApiTriggerDef in @inferrex/service-schema bloomreach-engagement-apis.ts)."},"programs":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"The gamification programs a trigger may watch for level-ups, each `{ key, name }`: the workspace's programs that are not archived. Empty without the gamification add-on."},"intervalSeconds":{"type":"integer","description":"Least seconds between two signals, all triggers together (bloomreach.apiTriggerIntervalSeconds)."},"guide":{"type":"array","items":{"type":"object","additionalProperties":true}},"facts":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["connectionId","triggers","programs","intervalSeconds","guide","facts"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","triggers":[{}],"programs":[{}],"intervalSeconds":0,"guide":[{}],"facts":[{}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"CreateBloomreachApiTrigger","tags":["bloomreach"],"summary":"Create Bloomreach Api Trigger","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120,"description":"A name to know it by in Inferrex."},"url":{"type":"string","format":"uri","maxLength":2048,"description":"The trigger URL Bloomreach shows in Data & Assets > API trigger: https://<API host>/campaigns/trigger/<id>/<trigger name>."},"watch":{"type":"object","additionalProperties":true,"description":"What fires it: { kind: \"golden\", entityType } for golden records of a type, { kind: \"system\", connectionId, entity } for one object of a connected system (a catalog's source, say), or { kind: \"level-ups\", program } for each level a player reaches in that gamification program (its key). A level-up carries player, level, value (the total after it), metric, program and at: conditions and parameters name those."},"conditions":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Up to 10 `{ field, op, value? }` the changed record must meet; op as for segments. None: every change fires."},"params":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"The signal's parameters, named as on the trigger in Bloomreach: each `{ name, field }` (a field of the changed record, or one of a level-up's values) or `{ name, value }` (a fixed text). Up to 20."}},"required":["name","url","watch","params"]},"example":{"name":"string","url":"https://example.com","watch":{},"conditions":[{}],"params":[{}]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","format":"uuid"},"name":{"type":"string"},"triggerName":{"type":"string","description":"The trigger's name as its URL ends."}},"required":["key","name","triggerName"]},"example":{"key":"00000000-0000-0000-0000-000000000000","name":"string","triggerName":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/api-triggers/{triggerKey}/state":{"post":{"operationId":"SetBloomreachApiTriggerState","tags":["bloomreach"],"summary":"Set Bloomreach Api Trigger State","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"triggerKey","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["start","stop"],"description":"start: fire on every matching change from now on. stop: send nothing more."}},"required":["action"]},"example":{"action":"start"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","format":"uuid"},"enabled":{"type":"boolean"},"status":{"type":"string"}},"required":["key","enabled","status"]},"example":{"key":"00000000-0000-0000-0000-000000000000","enabled":true,"status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/backfills":{"get":{"operationId":"GetBloomreachBackfills","tags":["bloomreach"],"summary":"Get Bloomreach Backfills","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","nullable":true},"backfills":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"sourceKey":{"type":"string"},"title":{"type":"string"},"eventType":{"type":"string","nullable":true},"from":{"type":"string","description":"YYYY-MM-DD."},"startedAt":{"type":"string","format":"date-time"},"startedBy":{"type":"string"},"pipelineId":{"type":"string","format":"uuid"},"status":{"type":"string","description":"queued, reading, finishing, imported, empty, refused, failed or unknown."},"detail":{"type":"string","description":"Where it is, in one sentence."},"rows":{"type":"integer","nullable":true,"description":"Rows in the file, once made."},"importId":{"type":"string","nullable":true,"description":"Engagement's import id, once created."},"readAt":{"type":"string","format":"date-time","nullable":true,"description":"When the read the file was made from ended: live sending starts after it."}},"required":["id","sourceKey","title","eventType","from","startedAt","startedBy","pipelineId","status","detail","rows","importId","readAt"]}},"limits":{"type":"object","properties":{"perMinute":{"type":"integer"},"perDay":{"type":"integer"},"activeDefinitions":{"type":"integer"},"maxRows":{"type":"integer"},"permission":{"type":"string","description":"The permission the key needs, in Bloomreach's words."},"startedLastDay":{"type":"integer"},"importsCreated":{"type":"integer","description":"Of every recorded load (the newest 200, not only those listed), those whose import Engagement created. Each stays an import definition there until deleted in Engagement."}},"required":["perMinute","perDay","activeDefinitions","maxRows","permission","startedLastDay","importsCreated"]},"warnings":{"type":"array","items":{"type":"string"}}},"required":["connectionId","backfills","limits","warnings"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","backfills":[{"id":"00000000-0000-0000-0000-000000000000","sourceKey":"string","title":"string","eventType":"string","from":"string","startedAt":"2026-01-01T00:00:00Z","startedBy":"string","pipelineId":"00000000-0000-0000-0000-000000000000","status":"string","detail":"string","rows":0,"importId":"string","readAt":"2026-01-01T00:00:00Z"}],"limits":{"perMinute":0,"perDay":0,"activeDefinitions":0,"maxRows":0,"permission":"string","startedLastDay":0,"importsCreated":0},"warnings":["string"]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/connection":{"get":{"operationId":"GetBloomreachConnection","tags":["bloomreach"],"summary":"Get Bloomreach Connection","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connected":{"type":"boolean"},"connectionId":{"type":"string","format":"uuid","nullable":true},"displayName":{"type":"string","nullable":true},"baseUrl":{"type":"string","nullable":true},"status":{"type":"string","nullable":true,"description":"The connection's state, as on the Systems page."},"createdAt":{"type":"string","format":"date-time","nullable":true},"keyTests":{"type":"object","properties":{"permissionTest":{"type":"object","properties":{"ranAt":{"type":"string","format":"date-time"},"ranBy":{"type":"string","description":"Who ran it, as the audit trail names a person."},"outcome":{"type":"string","description":"The test's outcome (ready, missing-permissions, credentials-rejected, could-not-check); for the property list read, its status (read, refused, failed, timed-out)."},"rows":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"status":{"type":"string","description":"granted, missing, rejected, unknown or not-checked."},"httpStatus":{"type":"integer","nullable":true},"detail":{"type":"string","nullable":true,"description":"Bloomreach's own words for a refusal, or why it was not checked. Never an answer body."}},"required":["key","status","httpStatus","detail"]}}},"required":["ranAt","ranBy","outcome","rows"],"nullable":true,"description":"The last POST /v1/bloomreach/connection/permission-test."},"writeTest":{"type":"object","properties":{"ranAt":{"type":"string","format":"date-time"},"ranBy":{"type":"string","description":"Who ran it, as the audit trail names a person."},"outcome":{"type":"string","description":"The test's outcome (ready, missing-permissions, credentials-rejected, could-not-check); for the property list read, its status (read, refused, failed, timed-out)."},"rows":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"status":{"type":"string","description":"granted, missing, rejected, unknown or not-checked."},"httpStatus":{"type":"integer","nullable":true},"detail":{"type":"string","nullable":true,"description":"Bloomreach's own words for a refusal, or why it was not checked. Never an answer body."}},"required":["key","status","httpStatus","detail"]}},"cleanup":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"status":{"type":"string"},"detail":{"type":"string","nullable":true}},"required":["key","label","status","detail"]}},"remains":{"type":"array","items":{"type":"string"}}},"required":["ranAt","ranBy","outcome","rows","cleanup","remains"],"nullable":true,"description":"The last POST /v1/bloomreach/connection/write-test, failed or not."},"propertyListRead":{"type":"object","properties":{"ranAt":{"type":"string","format":"date-time"},"ranBy":{"type":"string","description":"Who ran it, as the audit trail names a person."},"outcome":{"type":"string","description":"The test's outcome (ready, missing-permissions, credentials-rejected, could-not-check); for the property list read, its status (read, refused, failed, timed-out)."},"rows":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"status":{"type":"string","description":"granted, missing, rejected, unknown or not-checked."},"httpStatus":{"type":"integer","nullable":true},"detail":{"type":"string","nullable":true,"description":"Bloomreach's own words for a refusal, or why it was not checked. Never an answer body."}},"required":["key","status","httpStatus","detail"]}}},"required":["ranAt","ranBy","outcome","rows"],"nullable":true,"description":"The last GET /v1/bloomreach/project-schema?readPropertyList=true: it proves GDPR > Export customers."},"importForm":{"type":"object","properties":{"form":{"type":"string"},"acceptedAt":{"type":"string","format":"date-time"},"acceptedBy":{"type":"string"}},"required":["form","acceptedAt","acceptedBy"],"nullable":true,"description":"The Create import form Bloomreach last accepted in a write test (2026-10-28), which history loads send: timestamp-column (as documented) or timestamp-column-and-property (the time column also mapped to the timestamp property). Null when none was accepted yet; history loads then send the documented form and, only on Bloomreach's \"timestamp unmapped\" refusal, the other once."},"format":{"type":"integer"}},"required":["permissionTest","writeTest","propertyListRead","importForm","format"],"nullable":true,"description":"The project's last key tests, kept by Inferrex (manifest destination-key-tests). Null when none was run."},"projects":{"type":"array","items":{"type":"object","properties":{"keyTests":{"type":"object","properties":{"permissionTest":{"type":"object","properties":{"ranAt":{"type":"string","format":"date-time"},"ranBy":{"type":"string","description":"Who ran it, as the audit trail names a person."},"outcome":{"type":"string","description":"The test's outcome (ready, missing-permissions, credentials-rejected, could-not-check); for the property list read, its status (read, refused, failed, timed-out)."},"rows":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"status":{"type":"string","description":"granted, missing, rejected, unknown or not-checked."},"httpStatus":{"type":"integer","nullable":true},"detail":{"type":"string","nullable":true,"description":"Bloomreach's own words for a refusal, or why it was not checked. Never an answer body."}},"required":["key","status","httpStatus","detail"]}}},"required":["ranAt","ranBy","outcome","rows"],"nullable":true,"description":"The last POST /v1/bloomreach/connection/permission-test."},"writeTest":{"type":"object","properties":{"ranAt":{"type":"string","format":"date-time"},"ranBy":{"type":"string","description":"Who ran it, as the audit trail names a person."},"outcome":{"type":"string","description":"The test's outcome (ready, missing-permissions, credentials-rejected, could-not-check); for the property list read, its status (read, refused, failed, timed-out)."},"rows":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"status":{"type":"string","description":"granted, missing, rejected, unknown or not-checked."},"httpStatus":{"type":"integer","nullable":true},"detail":{"type":"string","nullable":true,"description":"Bloomreach's own words for a refusal, or why it was not checked. Never an answer body."}},"required":["key","status","httpStatus","detail"]}},"cleanup":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"status":{"type":"string"},"detail":{"type":"string","nullable":true}},"required":["key","label","status","detail"]}},"remains":{"type":"array","items":{"type":"string"}}},"required":["ranAt","ranBy","outcome","rows","cleanup","remains"],"nullable":true,"description":"The last POST /v1/bloomreach/connection/write-test, failed or not."},"propertyListRead":{"type":"object","properties":{"ranAt":{"type":"string","format":"date-time"},"ranBy":{"type":"string","description":"Who ran it, as the audit trail names a person."},"outcome":{"type":"string","description":"The test's outcome (ready, missing-permissions, credentials-rejected, could-not-check); for the property list read, its status (read, refused, failed, timed-out)."},"rows":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"status":{"type":"string","description":"granted, missing, rejected, unknown or not-checked."},"httpStatus":{"type":"integer","nullable":true},"detail":{"type":"string","nullable":true,"description":"Bloomreach's own words for a refusal, or why it was not checked. Never an answer body."}},"required":["key","status","httpStatus","detail"]}}},"required":["ranAt","ranBy","outcome","rows"],"nullable":true,"description":"The last GET /v1/bloomreach/project-schema?readPropertyList=true: it proves GDPR > Export customers."},"importForm":{"type":"object","properties":{"form":{"type":"string"},"acceptedAt":{"type":"string","format":"date-time"},"acceptedBy":{"type":"string"}},"required":["form","acceptedAt","acceptedBy"],"nullable":true,"description":"The Create import form Bloomreach last accepted in a write test (2026-10-28), which history loads send: timestamp-column (as documented) or timestamp-column-and-property (the time column also mapped to the timestamp property). Null when none was accepted yet; history loads then send the documented form and, only on Bloomreach's \"timestamp unmapped\" refusal, the other once."},"format":{"type":"integer"}},"required":["permissionTest","writeTest","propertyListRead","importForm","format"],"nullable":true,"description":"The project's last key tests, kept by Inferrex (manifest destination-key-tests). Null when none was run."},"connectionId":{"type":"string","format":"uuid","description":"Pass as engagementConnectionId."},"label":{"type":"string"},"baseUrl":{"type":"string"},"status":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"purpose":{"type":"string","nullable":true,"description":"Open vocabulary: brand, region, environment, or the tenant's own word."},"scope":{"type":"object","properties":{"brand":{"type":"string"},"region":{"type":"string"},"environmentId":{"type":"string","format":"uuid"}}},"isDefault":{"type":"boolean","description":"The project the Bloomreach pages open on (the only one, when there is one). Never a fallback for the API."}},"required":["keyTests","connectionId","label","baseUrl","status","createdAt","purpose","scope","isDefault"]},"description":"Every Engagement project of the workspace, newest first (design §N.4.5)."}},"required":["connected","connectionId","displayName","baseUrl","status","createdAt","keyTests","projects"]},"example":{"connected":true,"connectionId":"00000000-0000-0000-0000-000000000000","displayName":"string","baseUrl":"string","status":"string","createdAt":"2026-01-01T00:00:00Z","keyTests":{"permissionTest":{"ranAt":"2026-01-01T00:00:00Z","ranBy":"string","outcome":"string","rows":[{"key":"string","status":"string","httpStatus":0,"detail":"string"}]},"writeTest":{"ranAt":"2026-01-01T00:00:00Z","ranBy":"string","outcome":"string","rows":[{"key":"string","status":"string","httpStatus":0,"detail":"string"}],"cleanup":[{"key":"string","label":"string","status":"string","detail":"string"}],"remains":["string"]},"propertyListRead":{"ranAt":"2026-01-01T00:00:00Z","ranBy":"string","outcome":"string","rows":[{"key":"string","status":"string","httpStatus":0,"detail":"string"}]},"importForm":{"form":"string","acceptedAt":"2026-01-01T00:00:00Z","acceptedBy":"string"},"format":0},"projects":[{"keyTests":{"permissionTest":{"ranAt":"2026-01-01T00:00:00Z","ranBy":"string","outcome":"string","rows":[{"key":"string","status":"string","httpStatus":0,"detail":"string"}]},"writeTest":{"ranAt":"2026-01-01T00:00:00Z","ranBy":"string","outcome":"string","rows":[{"key":"string","status":"string","httpStatus":0,"detail":"string"}],"cleanup":[{"key":"string","label":"string","status":"string","detail":"string"}],"remains":["string"]},"propertyListRead":{"ranAt":"2026-01-01T00:00:00Z","ranBy":"string","outcome":"string","rows":[{"key":"string","status":"string","httpStatus":0,"detail":"string"}]},"importForm":{"form":"string","acceptedAt":"2026-01-01T00:00:00Z","acceptedBy":"string"},"format":0},"connectionId":"00000000-0000-0000-0000-000000000000","label":"string","baseUrl":"string","status":"string","createdAt":"2026-01-01T00:00:00Z","purpose":"string","scope":{"brand":"string","region":"string","environmentId":"00000000-0000-0000-0000-000000000000"},"isDefault":true}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"ConnectBloomreachEngagement","tags":["bloomreach"],"summary":"Connect Bloomreach Engagement","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"description":"Connect Bloomreach Engagement with a private API key. Give the API base URL, the API key ID and secret, and the project token. The secret is stored encrypted and never returned.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"baseUrl":{"type":"string","format":"uri","maxLength":2048,"description":"The API base URL Bloomreach shows for the project, such as https://api-engagement.bloomreach.com. Must be https on a public host."},"apiKeyId":{"type":"string","minLength":1,"maxLength":256,"description":"The private API key's ID."},"apiSecret":{"type":"string","minLength":1,"maxLength":1024,"description":"The private API key's secret. Stored encrypted; never returned."},"projectToken":{"type":"string","minLength":1,"maxLength":128,"description":"The Engagement project's token."},"label":{"type":"string","maxLength":80,"description":"What the project is called here (a brand, a region, …); it becomes the connection's name. Required once the workspace has a project."},"purpose":{"type":"string","maxLength":40,"description":"What the project is for, in an open vocabulary: brand, region, environment, or your own word."}},"required":["baseUrl","apiKeyId","apiSecret","projectToken"]},"example":{"baseUrl":"https://example.com","apiKeyId":"string","apiSecret":"string","projectToken":"string","label":"string","purpose":"string"}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"jobId":{"type":"string"}},"required":["connectionId","jobId"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","jobId":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"ReplaceBloomreachCredentials","tags":["bloomreach"],"summary":"Replace Bloomreach Credentials","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"baseUrl":{"type":"string","format":"uri","maxLength":2048,"description":"Must be the connection's current address."},"apiKeyId":{"type":"string","minLength":1,"maxLength":256},"apiSecret":{"type":"string","minLength":1,"maxLength":1024,"description":"Stored encrypted; never returned."},"projectToken":{"type":"string","minLength":1,"maxLength":128},"force":{"type":"boolean","description":"Use the new key even if Bloomreach does not accept it in the test."}},"required":["baseUrl","apiKeyId","apiSecret","projectToken"]},"example":{"baseUrl":"https://example.com","apiKeyId":"string","apiSecret":"string","projectToken":"string","force":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"replaced":{"type":"boolean","description":"Whether the new key is now in use."},"rotation":{"type":"object","properties":{"key":{"type":"string","description":"The secret now holding the new value: the live secret's name when it went live, else the stand-by copy's."},"live":{"type":"boolean","description":"Whether the new value is now in use."},"forced":{"type":"boolean","description":"It went live only because force was set."},"outcome":{"type":"string","description":"The worst test answer: accepted, refused, inconclusive, or untested."},"message":{"type":"string"},"previousKey":{"type":"string","nullable":true,"description":"Where the replaced value is kept, so it can be put back."},"candidateKey":{"type":"string","nullable":true,"description":"The new value's stand-by copy while it waits for a passing test; null once it is live."},"tests":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"connectionName":{"type":"string"},"testOutcome":{"type":"string","description":"The connection test's own answer: signed-in, credentials-rejected, forbidden, not-found, unreachable, redirect or not-testable."},"outcome":{"type":"string","description":"What it means for the secret. accepted: the API took it — a signed-in read of a declared endpoint answered 2xx with data (testOutcome signed-in). refused: 401 or 403. inconclusive: anything else, any 404 and the bare base address included."},"httpStatus":{"type":"integer","nullable":true},"detail":{"type":"string","description":"The answer in plain words. A refusal names the secret, its purpose and who saved it when; never its value."},"testedUrlTemplate":{"type":"string"},"provedBy":{"type":"string","nullable":true,"description":"The endpoint whose answer proved the read; null unless accepted."}},"required":["connectionId","connectionName","testOutcome","outcome","httpStatus","detail","testedUrlTemplate","provedBy"]}}},"required":["key","live","forced","outcome","message","previousKey","candidateKey","tests"]}},"required":["connectionId","replaced","rotation"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","replaced":true,"rotation":{"key":"string","live":true,"forced":true,"outcome":"string","message":"string","previousKey":"string","candidateKey":"string","tests":[{"connectionId":"00000000-0000-0000-0000-000000000000","connectionName":"string","testOutcome":"string","outcome":"string","httpStatus":0,"detail":"string","testedUrlTemplate":"string","provedBy":"string"}]}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/connection/permission-test":{"post":{"operationId":"TestBloomreachPermissions","tags":["bloomreach"],"summary":"Test Bloomreach Permissions","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"testedAt":{"type":"string","format":"date-time"},"outcome":{"type":"string","enum":["ready","missing-permissions","credentials-rejected","could-not-check"],"description":"ready: every check the test made is granted. missing-permissions: at least one is missing. credentials-rejected: Bloomreach did not accept the key. could-not-check: at least one check got no answer that says either way (and none is missing or refused)."},"results":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"area":{"type":"string","description":"Where it sits in Bloomreach's permission list."},"label":{"type":"string"},"access":{"type":"string","enum":["read","write"]},"neededFor":{"type":"string"},"status":{"type":"string","enum":["granted","missing","rejected","unknown","not-checked"]},"detail":{"type":"string","nullable":true,"description":"Bloomreach's own words for a refusal, or why it was not checked."},"httpStatus":{"type":"integer","nullable":true}},"required":["key","area","label","access","neededFor","status","detail","httpStatus"]}}},"required":["connectionId","testedAt","outcome","results"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","testedAt":"2026-01-01T00:00:00Z","outcome":"ready","results":[{"key":"string","area":"string","label":"string","access":"read","neededFor":"string","status":"granted","detail":"string","httpStatus":0}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/connection/write-test":{"post":{"operationId":"TestBloomreachWrites","tags":["bloomreach"],"summary":"Test Bloomreach Writes","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"description":"Write test: proves Customer properties > Set, Events > Set, Catalogs > Create catalog, Catalogs > Partial update catalog item and Imports > Allow to Create new Imports with named test data, then cleans up what it can. Send confirmWrites: true.","parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmWrites":{"type":"boolean","description":"Must be true: the caller confirms that test data is written to the Engagement project (a test customer \"inferrex-permission-test\" with one property and test events, which stay; a test catalog and an import definition, deleted when the key may)."}},"required":["confirmWrites"]},"example":{"confirmWrites":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"testedAt":{"type":"string","format":"date-time"},"outcome":{"type":"string","enum":["ready","missing-permissions","credentials-rejected","could-not-check"],"description":"Over the write permissions only. ready: every write the test tried is granted. missing-permissions: at least one is missing. credentials-rejected: Bloomreach did not accept the key. could-not-check: at least one write got no answer that says either way (and none is missing or refused)."},"results":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"area":{"type":"string"},"label":{"type":"string"},"access":{"type":"string","enum":["read","write"]},"neededFor":{"type":"string"},"status":{"type":"string","enum":["granted","missing","rejected","unknown","not-checked"]},"detail":{"type":"string","nullable":true,"description":"Bloomreach's own words for a refusal, or why it was not tried."},"httpStatus":{"type":"integer","nullable":true}},"required":["key","area","label","access","neededFor","status","detail","httpStatus"]},"description":"One row per permission, as the permission test returns them; reads are not-checked here (the permission test checks them)."},"cleanup":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","enum":["earlier-catalog-delete","catalog-delete","import-delete"]},"label":{"type":"string"},"status":{"type":"string","enum":["done","failed"]},"detail":{"type":"string","nullable":true},"httpStatus":{"type":"integer","nullable":true}},"required":["key","label","status","detail","httpStatus"]},"description":"Each removal of something the test made (or an earlier test left)."},"remains":{"type":"array","items":{"type":"string"},"description":"What stays in the Engagement project after the test, in plain words."}},"required":["connectionId","testedAt","outcome","results","cleanup","remains"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","testedAt":"2026-01-01T00:00:00Z","outcome":"ready","results":[{"key":"string","area":"string","label":"string","access":"read","neededFor":"string","status":"granted","detail":"string","httpStatus":0}],"cleanup":[{"key":"earlier-catalog-delete","label":"string","status":"done","detail":"string","httpStatus":0}],"remains":["string"]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/data-manager-export":{"delete":{"operationId":"ClearBloomreachDataManagerExport","tags":["bloomreach"],"summary":"Clear Bloomreach Data Manager Export","security":[{"ApiKeyAuth":["bloomreach:delete"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:delete"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"importedAt":{"type":"string","format":"date-time","nullable":true,"description":"When the facts kept were read from an export; null when none is kept."},"importedBy":{"type":"string","nullable":true,"description":"Who pasted it, as the audit trail names a person."},"sizeBytes":{"type":"integer","nullable":true,"description":"The size of the export read (it was not kept)."},"exportVersion":{"type":"string","nullable":true,"description":"The export's own version (the Bloomreach release that wrote it)."},"summary":{"type":"object","additionalProperties":true,"nullable":true,"description":"{ eventTypes, projectEventTypes, rolesMapped, rolesUnmapped, consentsMapped, customerPropertiesMapped, catalog, eventProperties, apiTriggerParams, items, templateItems }: counts of the facts kept; null when none is kept."},"facts":{"type":"object","additionalProperties":true,"nullable":true,"description":"DataManagerFacts (@inferrex/service-schema bloomreach-data-manager-export.ts): eventTypes [{ name, from, strength }], standardEvents [{ role, eventType, filter, fields, unmappedFields }], unmappedRoles, consents [{ role, category }], unmappedConsents, customerProperties [{ role, property }], unmappedCustomerProperties, catalogs, mainCatalog, eventProperties [{ eventType, strength, properties: [{ name, strength, values }] }], customerPropertyNames, apiTriggerParams, scenarios { webhookNodes, apiTriggers }, items, truncated. strength: project (the project's own objects or mapping) or template (only Bloomreach library templates: a weak hint). Null when none is kept."},"clearedAt":{"type":"string","format":"date-time","nullable":true,"description":"When facts kept before were last cleared, if they were."},"steps":{"type":"array","items":{"type":"string"},"description":"Where to get an export in Bloomreach, step by step."},"secretsNote":{"type":"string","description":"What is discarded, in words for the page."},"maxBytes":{"type":"integer","description":"The largest export read."}},"required":["connectionId","importedAt","importedBy","sizeBytes","exportVersion","summary","facts","clearedAt","steps","secretsNote","maxBytes"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","importedAt":"2026-01-01T00:00:00Z","importedBy":"string","sizeBytes":0,"exportVersion":"string","summary":{},"facts":{},"clearedAt":"2026-01-01T00:00:00Z","steps":["string"],"secretsNote":"string","maxBytes":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"GetBloomreachDataManagerExport","tags":["bloomreach"],"summary":"Get Bloomreach Data Manager Export","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"importedAt":{"type":"string","format":"date-time","nullable":true,"description":"When the facts kept were read from an export; null when none is kept."},"importedBy":{"type":"string","nullable":true,"description":"Who pasted it, as the audit trail names a person."},"sizeBytes":{"type":"integer","nullable":true,"description":"The size of the export read (it was not kept)."},"exportVersion":{"type":"string","nullable":true,"description":"The export's own version (the Bloomreach release that wrote it)."},"summary":{"type":"object","additionalProperties":true,"nullable":true,"description":"{ eventTypes, projectEventTypes, rolesMapped, rolesUnmapped, consentsMapped, customerPropertiesMapped, catalog, eventProperties, apiTriggerParams, items, templateItems }: counts of the facts kept; null when none is kept."},"facts":{"type":"object","additionalProperties":true,"nullable":true,"description":"DataManagerFacts (@inferrex/service-schema bloomreach-data-manager-export.ts): eventTypes [{ name, from, strength }], standardEvents [{ role, eventType, filter, fields, unmappedFields }], unmappedRoles, consents [{ role, category }], unmappedConsents, customerProperties [{ role, property }], unmappedCustomerProperties, catalogs, mainCatalog, eventProperties [{ eventType, strength, properties: [{ name, strength, values }] }], customerPropertyNames, apiTriggerParams, scenarios { webhookNodes, apiTriggers }, items, truncated. strength: project (the project's own objects or mapping) or template (only Bloomreach library templates: a weak hint). Null when none is kept."},"clearedAt":{"type":"string","format":"date-time","nullable":true,"description":"When facts kept before were last cleared, if they were."},"steps":{"type":"array","items":{"type":"string"},"description":"Where to get an export in Bloomreach, step by step."},"secretsNote":{"type":"string","description":"What is discarded, in words for the page."},"maxBytes":{"type":"integer","description":"The largest export read."}},"required":["connectionId","importedAt","importedBy","sizeBytes","exportVersion","summary","facts","clearedAt","steps","secretsNote","maxBytes"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","importedAt":"2026-01-01T00:00:00Z","importedBy":"string","sizeBytes":0,"exportVersion":"string","summary":{},"facts":{},"clearedAt":"2026-01-01T00:00:00Z","steps":["string"],"secretsNote":"string","maxBytes":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"SubmitBloomreachDataManagerExport","tags":["bloomreach"],"summary":"Submit Bloomreach Data Manager Export","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"exportJson":{"type":"string","minLength":2,"maxLength":10485760,"description":"The whole Data Manager export as the text Bloomreach gives ({ \"items\": [...], \"mapping\": {...}, \"version\": \"...\" }), at most 10 MB. Only facts derived from it are kept; the text is discarded."}},"required":["exportJson"]},"example":{"exportJson":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"importedAt":{"type":"string","format":"date-time","nullable":true,"description":"When the facts kept were read from an export; null when none is kept."},"importedBy":{"type":"string","nullable":true,"description":"Who pasted it, as the audit trail names a person."},"sizeBytes":{"type":"integer","nullable":true,"description":"The size of the export read (it was not kept)."},"exportVersion":{"type":"string","nullable":true,"description":"The export's own version (the Bloomreach release that wrote it)."},"summary":{"type":"object","additionalProperties":true,"nullable":true,"description":"{ eventTypes, projectEventTypes, rolesMapped, rolesUnmapped, consentsMapped, customerPropertiesMapped, catalog, eventProperties, apiTriggerParams, items, templateItems }: counts of the facts kept; null when none is kept."},"facts":{"type":"object","additionalProperties":true,"nullable":true,"description":"DataManagerFacts (@inferrex/service-schema bloomreach-data-manager-export.ts): eventTypes [{ name, from, strength }], standardEvents [{ role, eventType, filter, fields, unmappedFields }], unmappedRoles, consents [{ role, category }], unmappedConsents, customerProperties [{ role, property }], unmappedCustomerProperties, catalogs, mainCatalog, eventProperties [{ eventType, strength, properties: [{ name, strength, values }] }], customerPropertyNames, apiTriggerParams, scenarios { webhookNodes, apiTriggers }, items, truncated. strength: project (the project's own objects or mapping) or template (only Bloomreach library templates: a weak hint). Null when none is kept."},"clearedAt":{"type":"string","format":"date-time","nullable":true,"description":"When facts kept before were last cleared, if they were."},"steps":{"type":"array","items":{"type":"string"},"description":"Where to get an export in Bloomreach, step by step."},"secretsNote":{"type":"string","description":"What is discarded, in words for the page."},"maxBytes":{"type":"integer","description":"The largest export read."}},"required":["connectionId","importedAt","importedBy","sizeBytes","exportVersion","summary","facts","clearedAt","steps","secretsNote","maxBytes"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","importedAt":"2026-01-01T00:00:00Z","importedBy":"string","sizeBytes":0,"exportVersion":"string","summary":{},"facts":{},"clearedAt":"2026-01-01T00:00:00Z","steps":["string"],"secretsNote":"string","maxBytes":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/engagement-merges":{"get":{"operationId":"GetBloomreachEngagementMerges","tags":["bloomreach"],"summary":"Get Bloomreach Engagement Merges","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"entityClusterIds","in":"query","required":true,"schema":{"type":"string","maxLength":800,"description":"Comma-separated golden record ids, at most 20."},"description":"Comma-separated golden record ids, at most 20."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"hardId":{"type":"string"},"goldenId":{"type":"string"},"people":{"type":"array","items":{"type":"object","properties":{"entityClusterId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["read","not-sent","refused","failed"]},"merges":{"type":"integer"},"sentences":{"type":"array","items":{"type":"string"}},"detail":{"type":"string","nullable":true}},"required":["entityClusterId","status","merges","sentences","detail"]}},"facts":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["connectionId","hardId","goldenId","people","facts"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","hardId":"string","goldenId":"string","people":[{"entityClusterId":"00000000-0000-0000-0000-000000000000","status":"read","merges":0,"sentences":["string"],"detail":"string"}],"facts":[{}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/external-segments":{"get":{"operationId":"GetBloomreachExternalSegments","tags":["bloomreach"],"summary":"Get Bloomreach External Segments","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","nullable":true},"integration":{"type":"object","additionalProperties":true,"nullable":true,"description":"{ baseUrl, integrationId, setBy, setAt }: the External segments integration, when its key is saved."},"segments":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Each segment as stored (ExternalSegmentDef in @inferrex/service-schema bloomreach-engagement-apis.ts), with `property`, the true/false customer property Engagement keeps it in; `source`, where its people come from ({ kind: \"golden\", entityType } or { kind: \"system\", connectionId, entity }; a segment saved before 2026-10-28 is golden); and `sourceName`, that in words."},"syncMinutes":{"type":"integer","description":"Minutes between updates of each segment (bloomreach.externalSegmentSyncMinutes)."},"goldenTypes":{"type":"array","items":{"type":"string"},"description":"The workspace's golden record types a segment may be made of."},"systems":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"name":{"type":"string"},"entities":{"type":"array","items":{"type":"object","properties":{"apiName":{"type":"string"},"displayName":{"type":"string"},"fields":{"type":"array","items":{"type":"object","properties":{"apiName":{"type":"string"},"displayName":{"type":"string"},"type":{"type":"string"},"sensitivity":{"type":"string","nullable":true},"visible":{"type":"boolean","description":"False when the caller's role may not see this field; it cannot be named."}},"required":["apiName","displayName","type","sensitivity","visible"]}}},"required":["apiName","displayName","fields"]}}},"required":["connectionId","name","entities"]},"description":"The connected systems whose objects a segment may be made of instead, as GET /v1/bloomreach/setup/options lists them (no Engagement project). Send one as source: { kind: \"system\", connectionId, entity: <an entity's apiName> }, with idField and conditions from its fields the caller may see."},"guide":{"type":"array","items":{"type":"object","additionalProperties":true}},"facts":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["connectionId","integration","segments","syncMinutes","goldenTypes","systems","guide","facts"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","integration":{},"segments":[{}],"syncMinutes":0,"goldenTypes":["string"],"systems":[{"connectionId":"00000000-0000-0000-0000-000000000000","name":"string","entities":[{"apiName":"string","displayName":"string","fields":[{"apiName":"string","displayName":"string","type":"string","sensitivity":"string","visible":true}]}]}],"guide":[{}],"facts":[{}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"CreateBloomreachExternalSegment","tags":["bloomreach"],"summary":"Create Bloomreach External Segment","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":256,"description":"The segment's name in Engagement, e.g. \"High value\"; it becomes the customer property ext_segment_<name>."},"goldenEntityType":{"type":"string","maxLength":128,"description":"Golden records: the golden record type whose records are the people, e.g. \"person\". Send this or source, not both."},"source":{"type":"object","properties":{"kind":{"type":"string","enum":["system","golden"],"description":"system: one object of a connected system. golden: golden records, the same as goldenEntityType."},"connectionId":{"type":"string","format":"uuid","description":"kind system: the system's connection id."},"entity":{"type":"string","maxLength":256,"description":"kind system: the object's apiName."},"entityType":{"type":"string","maxLength":128,"description":"kind golden: the golden record type."}},"required":["kind"],"description":"One connected system's object instead of golden records: { kind: \"system\", connectionId, entity }, connectionId a system of this workspace (not an Engagement project) and entity its object's apiName, both from systems in GET /v1/bloomreach/external-segments. Send this or goldenEntityType, not both; idField is then required."},"idField":{"type":"string","maxLength":300,"description":"The source's field whose value is sent as the customer id: the hard id chosen on the Bloomreach integration. Required for a system's object; for golden records the setup plan's registered field when left out."},"conditions":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"The field the condition reads: a name, or a dotted path into the record (e.g. \"address.country\")."},"op":{"type":"string","enum":["equals","not-equals","in","exists","missing","gt","gte","lt","lte","contains"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string"}}],"description":"`in` takes a list of values; `exists` and `missing` take none; gt, gte, lt and lte a number; the rest one value."}},"required":["field","op"]},"description":"Up to 10 `{ field, op, value? }` on fields of the source, all of which must hold; op is equals, not-equals, in (value a list), exists, missing, gt, gte, lt, lte (value a number) or contains. None: every record of the source."}},"required":["name"]},"example":{"name":"string","goldenEntityType":"string","source":{"kind":"system","connectionId":"00000000-0000-0000-0000-000000000000","entity":"string","entityType":"string"},"idField":"string","conditions":[{"field":"string","op":"equals","value":[]}]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","format":"uuid"},"name":{"type":"string"},"property":{"type":"string","description":"The customer property Engagement will keep the segment in."},"source":{"type":"object","additionalProperties":true,"description":"Where its people come from: { kind: \"golden\", entityType } or { kind: \"system\", connectionId, entity }."},"sourceName":{"type":"string","description":"That in words."}},"required":["key","name","property","source","sourceName"]},"example":{"key":"00000000-0000-0000-0000-000000000000","name":"string","property":"string","source":{},"sourceName":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/external-segments/{segmentKey}/state":{"post":{"operationId":"SetBloomreachExternalSegmentState","tags":["bloomreach"],"summary":"Set Bloomreach External Segment State","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"segmentKey","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["start","stop","push-now"],"description":"start: push it again on schedule. stop: push nothing more. push-now: update it within a minute."}},"required":["action"]},"example":{"action":"start"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","format":"uuid"},"enabled":{"type":"boolean"},"status":{"type":"string"}},"required":["key","enabled","status"]},"example":{"key":"00000000-0000-0000-0000-000000000000","enabled":true,"status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/external-segments/integration":{"put":{"operationId":"SetBloomreachExternalSegmentsIntegration","tags":["bloomreach"],"summary":"Set Bloomreach External Segments Integration","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"endpointUrl":{"type":"string","format":"uri","maxLength":2048,"description":"The endpoint URL Bloomreach shows for the integration (or the instance's API base URL)."},"integrationId":{"type":"string","maxLength":64,"description":"The integration ID Bloomreach shows; may be left out when the endpoint URL holds it."},"accessKey":{"type":"string","minLength":1,"maxLength":2048,"description":"The integration's access key (shown once by Bloomreach). Stored encrypted; never returned."}},"required":["endpointUrl","accessKey"]},"example":{"endpointUrl":"https://example.com","integrationId":"string","accessKey":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"baseUrl":{"type":"string"},"integrationId":{"type":"string"}},"required":["connectionId","baseUrl","integrationId"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","baseUrl":"string","integrationId":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/file-feeds":{"get":{"operationId":"GetBloomreachFileFeeds","tags":["bloomreach"],"summary":"Get Bloomreach File Feeds","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","nullable":true},"feeds":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Each feed as stored (FileFeedDef in @inferrex/service-schema bloomreach-engagement-apis.ts) with `url` (its address) and `username`."},"guide":{"type":"object","additionalProperties":true,"description":"{ catalog, voucher }: the steps in Bloomreach for each kind."},"facts":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["connectionId","feeds","guide","facts"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","feeds":[{}],"guide":{},"facts":[{}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"CreateBloomreachFileFeed","tags":["bloomreach"],"summary":"Create Bloomreach File Feed","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["catalog","voucher"],"description":"catalog: an item_id column and the columns chosen. voucher: one column of codes."},"name":{"type":"string","minLength":1,"maxLength":120,"description":"A name to know it by."},"source":{"type":"object","additionalProperties":true,"description":"{ kind: \"golden\", entityType } or { kind: \"system\", connectionId, entity }: what the file is built from."},"idField":{"type":"string","maxLength":300,"description":"The field holding each row's id: the catalog item id, or the voucher code."},"columns":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Catalogs only: the other columns, each `{ field, column? }` (column defaults to the field's name). Up to 100."},"conditions":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Up to 10 `{ field, op, value? }` a record must meet to be in the file."},"cadence":{"type":"string","enum":["hourly","daily","weekly"],"description":"How often Inferrex rebuilds the file. Schedule the Bloomreach import after it."}},"required":["kind","name","source","idField","cadence"]},"example":{"kind":"catalog","name":"string","source":{},"idField":"string","columns":[{}],"conditions":[{}],"cadence":"hourly"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","format":"uuid"},"url":{"type":"string","description":"The feed's address, for the import's URL source."},"username":{"type":"string"},"issuedPassword":{"type":"string","description":"The feed's password. Shown once; never returned again."}},"required":["key","url","username","issuedPassword"]},"example":{"key":"00000000-0000-0000-0000-000000000000","url":"string","username":"string","issuedPassword":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/file-feeds/{feedKey}/password":{"post":{"operationId":"RotateBloomreachFileFeedPassword","tags":["bloomreach"],"summary":"Rotate Bloomreach File Feed Password","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"feedKey","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","format":"uuid"},"username":{"type":"string"},"issuedPassword":{"type":"string","description":"Shown once; never returned again."}},"required":["key","username","issuedPassword"]},"example":{"key":"00000000-0000-0000-0000-000000000000","username":"string","issuedPassword":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/file-feeds/{feedKey}/state":{"post":{"operationId":"SetBloomreachFileFeedState","tags":["bloomreach"],"summary":"Set Bloomreach File Feed State","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"feedKey","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["start","stop","build-now"],"description":"start: rebuild on schedule. stop: delete the file and rebuild no more. build-now: rebuild within a minute."}},"required":["action"]},"example":{"action":"start"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","format":"uuid"},"enabled":{"type":"boolean"},"status":{"type":"string"}},"required":["key","enabled","status"]},"example":{"key":"00000000-0000-0000-0000-000000000000","enabled":true,"status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/gdpr/requests":{"get":{"operationId":"GetBloomreachGdprRequests","tags":["bloomreach"],"summary":"Get Bloomreach Gdpr Requests","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"setting":{"type":"string","enum":["confirm","automatic","off"],"description":"bloomreach.anonymiseOnErasure for this workspace."},"requests":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Each request without its ids: { id, kind, entityClusterId, status, setting, requested, done, detail, projects: [{ connectionId, label, archived, status, detail, done, idNames, subjectHash }] }. status is failed while any project is not done."},"facts":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["setting","requests","facts"]},"example":{"setting":"confirm","requests":[{}],"facts":[{}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"CreateBloomreachGdprRequest","tags":["bloomreach"],"summary":"Create Bloomreach Gdpr Request","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["erasure","access"],"description":"erasure: anonymise in Engagement (by the setting). access: export what Engagement holds."},"entityClusterId":{"type":"string","format":"uuid","description":"The golden record of the person: its ids as last sent to Engagement are used."},"customerIds":{"type":"object","additionalProperties":{"type":"string"},"description":"Or the person's ids in Engagement, by id name, e.g. { \"registered\": \"…\" }; only the ids Inferrex sends (the hard id and the golden id)."},"confirmErasure":{"type":"boolean","description":"Required true for an erasure while the setting is automatic: the person confirms it is anonymised at once and cannot be undone."}},"required":["kind"]},"example":{"kind":"erasure","entityClusterId":"00000000-0000-0000-0000-000000000000","customerIds":{},"confirmErasure":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string"},"status":{"type":"string","enum":["waiting-confirmation","anonymised","not-sent","failed","exported"]},"detail":{"type":"string","nullable":true},"projects":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"One outcome per project: { connectionId, label, archived, status, detail, done, idNames, subjectHash }."},"exports":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Access only, one per project (empty for an erasure): { connectionId, label, export: { ids, properties, events } as that project returned them, or null when it could not be read }."}},"required":["id","kind","status","detail","projects","exports"]},"example":{"id":"00000000-0000-0000-0000-000000000000","kind":"string","status":"waiting-confirmation","detail":"string","projects":[{}],"exports":[{}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/gdpr/requests/{requestId}/anonymise":{"post":{"operationId":"AnonymiseBloomreachCustomer","tags":["bloomreach"],"summary":"Anonymise Bloomreach Customer","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"requestId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmAnonymise":{"type":"boolean","description":"Must be true: the person confirms this person is anonymised in Engagement, which cannot be undone."}},"required":["confirmAnonymise"]},"example":{"confirmAnonymise":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["waiting-confirmation","anonymised","not-sent","failed","exported"]},"detail":{"type":"string","nullable":true},"projects":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"One outcome per project: { connectionId, label, archived, status, detail, done, idNames, subjectHash }."}},"required":["id","status","detail","projects"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"waiting-confirmation","detail":"string","projects":[{}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/id-differences":{"get":{"operationId":"GetBloomreachIdDifferences","tags":["bloomreach"],"summary":"Get Bloomreach Id Differences","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"hardId":{"type":"string"},"goldenId":{"type":"string"},"registeredFrom":{"type":"string","nullable":true},"canSeeValues":{"type":"boolean"},"truncated":{"type":"boolean"},"differences":{"type":"array","items":{"type":"object","properties":{"entityClusterId":{"type":"string","format":"uuid"},"entityType":{"type":"string"},"kinds":{"type":"array","items":{"type":"string"},"description":"changed, pending, shared, gone."},"sent":{"type":"string"},"sentBefore":{"type":"string","nullable":true},"now":{"type":"string","nullable":true},"sharedWith":{"type":"array","items":{"type":"string"}},"causes":{"type":"array","items":{"type":"string"}},"at":{"type":"string","format":"date-time"}},"required":["entityClusterId","entityType","kinds","sent","sentBefore","now","sharedWith","causes","at"]}}},"required":["connectionId","hardId","goldenId","registeredFrom","canSeeValues","truncated","differences"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","hardId":"string","goldenId":"string","registeredFrom":"string","canSeeValues":true,"truncated":true,"differences":[{"entityClusterId":"00000000-0000-0000-0000-000000000000","entityType":"string","kinds":["string"],"sent":"string","sentBefore":"string","now":"string","sharedWith":["string"],"causes":["string"],"at":"2026-01-01T00:00:00Z"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/message-captures":{"get":{"operationId":"GetBloomreachMessageCaptures","tags":["bloomreach"],"summary":"Get Bloomreach Message Captures","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string"},"captures":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"at":{"type":"string","format":"date-time"},"route":{"type":"string","description":"Open vocabulary. bloomreach-sends: the event Inferrex would have tracked to Engagement for the project's scenario to send (test mode holds route A, 2026-10-29). inferrex-delivers: the message Inferrex would have sent through the workspace's own provider. Absent on a test send kept before routes were recorded: inferrex-delivers."},"channel":{"type":"string"},"to":{"type":"string","description":"The address, shortened."},"subject":{"type":"string","nullable":true,"description":"The email's subject, or the start of the SMS."},"campaignName":{"type":"string"},"provider":{"type":"string","nullable":true,"description":"The provider that would have sent it."}},"required":["id","at","channel","to","subject","campaignName","provider"]}},"total":{"type":"integer"},"retentionDays":{"type":"integer"},"max":{"type":"integer"},"storage":{"type":"string","description":"ready, or not-configured when no object storage holds test sends."}},"required":["mode","captures","total","retentionDays","max","storage"]},"example":{"mode":"string","captures":[{"id":"00000000-0000-0000-0000-000000000000","at":"2026-01-01T00:00:00Z","route":"string","channel":"string","to":"string","subject":"string","campaignName":"string","provider":"string"}],"total":0,"retentionDays":0,"max":0,"storage":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/message-captures/{captureId}":{"get":{"operationId":"GetBloomreachMessageCapture","tags":["bloomreach"],"summary":"Get Bloomreach Message Capture","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"captureId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"at":{"type":"string","format":"date-time"},"route":{"type":"string","description":"Open vocabulary. bloomreach-sends: the event Inferrex would have tracked to Engagement for the project's scenario to send (test mode holds route A, 2026-10-29). inferrex-delivers: the message Inferrex would have sent through the workspace's own provider. Absent on a test send kept before routes were recorded: inferrex-delivers."},"event":{"type":"object","properties":{"type":{"type":"string"},"customerIds":{"type":"object","additionalProperties":true},"timestamp":{"type":"integer","description":"Seconds since the epoch."},"properties":{"type":"object","additionalProperties":true,"description":"The rendered content the project's template reads."}},"required":["type","customerIds","timestamp","properties"],"nullable":true,"description":"Route bloomreach-sends only: the event that would have been tracked to Engagement, exactly as its command would have carried it. No credential."},"channel":{"type":"string"},"to":{"type":"string"},"from":{"type":"string","nullable":true},"replyTo":{"type":"string","nullable":true},"subject":{"type":"string","nullable":true},"preheader":{"type":"string","nullable":true},"html":{"type":"string","nullable":true,"description":"Shown only in a sandboxed frame (no scripts, no network)."},"text":{"type":"string","nullable":true},"sms":{"type":"object","properties":{"text":{"type":"string"},"segments":{"type":"object","properties":{"encoding":{"type":"string"},"units":{"type":"integer"},"segments":{"type":"integer"}},"required":["encoding","units","segments"]}},"required":["text","segments"],"nullable":true},"campaign":{"type":"object","properties":{"key":{"type":"string","format":"uuid"},"name":{"type":"string"},"connectionId":{"type":"string","format":"uuid"}},"required":["key","name","connectionId"]},"messageId":{"type":"string"},"trigger":{"type":"object","properties":{"source":{"type":"string"},"reference":{"type":"string","nullable":true},"requestedAt":{"type":"string","nullable":true}},"required":["source","reference","requestedAt"]},"provider":{"type":"object","properties":{"profileKey":{"type":"string"},"displayName":{"type":"string"},"connectionId":{"type":"string","format":"uuid"},"connectionName":{"type":"string"}},"required":["profileKey","displayName","connectionId","connectionName"],"nullable":true},"request":{"type":"object","properties":{"method":{"type":"string"},"url":{"type":"string"},"headers":{"type":"object","additionalProperties":true},"body":{"type":"object","additionalProperties":true}},"required":["method","url","headers","body"],"nullable":true,"description":"The request that would have been sent: method, url, headers (every credential removed) and the JSON body."},"note":{"type":"string","nullable":true}},"required":["id","at","channel","to","from","replyTo","subject","preheader","html","text","sms","campaign","messageId","trigger","provider","request","note"]},"example":{"id":"00000000-0000-0000-0000-000000000000","at":"2026-01-01T00:00:00Z","route":"string","event":{"type":"string","customerIds":{},"timestamp":0,"properties":{}},"channel":"string","to":"string","from":"string","replyTo":"string","subject":"string","preheader":"string","html":"string","text":"string","sms":{"text":"string","segments":{"encoding":"string","units":0,"segments":0}},"campaign":{"key":"00000000-0000-0000-0000-000000000000","name":"string","connectionId":"00000000-0000-0000-0000-000000000000"},"messageId":"string","trigger":{"source":"string","reference":"string","requestedAt":"string"},"provider":{"profileKey":"string","displayName":"string","connectionId":"00000000-0000-0000-0000-000000000000","connectionName":"string"},"request":{"method":"string","url":"string","headers":{},"body":{}},"note":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/message-captures/clear":{"post":{"operationId":"ClearBloomreachMessageCaptures","tags":["bloomreach"],"summary":"Clear Bloomreach Message Captures","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmClear":{"type":"boolean","description":"Must be true."}},"required":["confirmClear"]},"example":{"confirmClear":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"integer"}},"required":["deleted"]},"example":{"deleted":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/message-channel":{"get":{"operationId":"GetBloomreachMessageChannel","tags":["bloomreach"],"summary":"Get Bloomreach Message Channel","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","nullable":true},"eventType":{"type":"string"},"brand":{"type":"object","properties":{"companyName":{"type":"string","maxLength":120,"description":"The brand name shown in the email and given to the model."},"senderName":{"type":"string","maxLength":120,"description":"The From name the email node uses."},"senderEmail":{"type":"string","maxLength":254,"nullable":true,"description":"The From address, plain ASCII."},"replyTo":{"type":"string","maxLength":254,"nullable":true},"smsSender":{"type":"string","maxLength":16,"nullable":true,"description":"The SMS sender profile's sender: up to 11 letters and digits, or 3 to 15 digits."},"logoUrl":{"type":"string","maxLength":2048,"nullable":true,"description":"An https address of the logo image."},"logoAlt":{"type":"string","maxLength":120,"nullable":true},"colours":{"type":"object","properties":{"primary":{"type":"string","maxLength":7,"nullable":true},"background":{"type":"string","maxLength":7,"nullable":true},"text":{"type":"string","maxLength":7,"nullable":true},"accent":{"type":"string","maxLength":7,"nullable":true}},"description":"Each a colour like #1A2B3C, or null for a neutral default."},"fontFamily":{"type":"string","maxLength":200,"nullable":true,"description":"A CSS font stack: letters, digits, spaces, commas, hyphens and quotes."},"footer":{"type":"string","maxLength":1000,"description":"The footer: legal name, address, why people receive it. Plain text; line breaks kept."},"links":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","maxLength":60},"url":{"type":"string","maxLength":2048}},"required":["label","url"]},"description":"Up to 5 footer links."},"voice":{"type":"string","maxLength":1000,"nullable":true,"description":"How the brand speaks, given to the model."},"language":{"type":"string","maxLength":16,"nullable":true,"description":"The language the copy is written in, e.g. en-GB."},"unsubscribeUrl":{"type":"string","maxLength":2048,"nullable":true,"description":"An https address where a person unsubscribes. Required for email Inferrex delivers itself (it goes in the email and its List-Unsubscribe header); Bloomreach's own scenarios use {{ consent.page }} instead."}},"nullable":true},"set":{"type":"object","properties":{"by":{"type":"string"},"at":{"type":"string","format":"date-time"}},"required":["by","at"],"nullable":true},"channels":{"type":"array","items":{"type":"object","properties":{"channel":{"type":"string","description":"email or sms."},"templateHash":{"type":"string","nullable":true,"description":"What an approval is of; null until the brand is saved."},"approved":{"type":"object","properties":{"by":{"type":"string"},"at":{"type":"string","format":"date-time"}},"required":["by","at"],"nullable":true},"current":{"type":"boolean","description":"True when the approval in force is of exactly the template now."},"template":{"type":"string","nullable":true},"subject":{"type":"string","nullable":true},"preheader":{"type":"string","nullable":true},"setup":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Setup items (SetupPackItem in @inferrex/service-schema destination-setup-pack.ts): key, title, why, steps, where, source, readOn, artefact."}},"required":["channel","templateHash","approved","current","template","subject","preheader","setup"]}},"access":{"type":"object","additionalProperties":true,"nullable":true,"description":"The private key's permission step for the event type (a SetupPackItem)."},"consentCategories":{"type":"array","items":{"type":"string"}},"consentCategoriesProblem":{"type":"string","nullable":true},"attributes":{"type":"array","items":{"type":"string"},"description":"The event's attribute names."},"facts":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["connectionId","eventType","brand","set","channels","access","consentCategories","consentCategoriesProblem","attributes","facts"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","eventType":"string","brand":{"companyName":"string","senderName":"string","senderEmail":"string","replyTo":"string","smsSender":"string","logoUrl":"string","logoAlt":"string","colours":{"primary":"string","background":"string","text":"string","accent":"string"},"fontFamily":"string","footer":"string","links":[{"label":"string","url":"string"}],"voice":"string","language":"string","unsubscribeUrl":"string"},"set":{"by":"string","at":"2026-01-01T00:00:00Z"},"channels":[{"channel":"string","templateHash":"string","approved":{"by":"string","at":"2026-01-01T00:00:00Z"},"current":true,"template":"string","subject":"string","preheader":"string","setup":[{}]}],"access":{},"consentCategories":["string"],"consentCategoriesProblem":"string","attributes":["string"],"facts":[{}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"SetBloomreachMessageChannel","tags":["bloomreach"],"summary":"Set Bloomreach Message Channel","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"brand":{"type":"object","properties":{"companyName":{"type":"string","maxLength":120,"description":"The brand name shown in the email and given to the model."},"senderName":{"type":"string","maxLength":120,"description":"The From name the email node uses."},"senderEmail":{"type":"string","maxLength":254,"nullable":true,"description":"The From address, plain ASCII."},"replyTo":{"type":"string","maxLength":254,"nullable":true},"smsSender":{"type":"string","maxLength":16,"nullable":true,"description":"The SMS sender profile's sender: up to 11 letters and digits, or 3 to 15 digits."},"logoUrl":{"type":"string","maxLength":2048,"nullable":true,"description":"An https address of the logo image."},"logoAlt":{"type":"string","maxLength":120,"nullable":true},"colours":{"type":"object","properties":{"primary":{"type":"string","maxLength":7,"nullable":true},"background":{"type":"string","maxLength":7,"nullable":true},"text":{"type":"string","maxLength":7,"nullable":true},"accent":{"type":"string","maxLength":7,"nullable":true}},"description":"Each a colour like #1A2B3C, or null for a neutral default."},"fontFamily":{"type":"string","maxLength":200,"nullable":true,"description":"A CSS font stack: letters, digits, spaces, commas, hyphens and quotes."},"footer":{"type":"string","maxLength":1000,"description":"The footer: legal name, address, why people receive it. Plain text; line breaks kept."},"links":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","maxLength":60},"url":{"type":"string","maxLength":2048}},"required":["label","url"]},"description":"Up to 5 footer links."},"voice":{"type":"string","maxLength":1000,"nullable":true,"description":"How the brand speaks, given to the model."},"language":{"type":"string","maxLength":16,"nullable":true,"description":"The language the copy is written in, e.g. en-GB."},"unsubscribeUrl":{"type":"string","maxLength":2048,"nullable":true,"description":"An https address where a person unsubscribes. Required for email Inferrex delivers itself (it goes in the email and its List-Unsubscribe header); Bloomreach's own scenarios use {{ consent.page }} instead."}},"required":["companyName","senderName","footer"]},"eventType":{"type":"string","maxLength":64,"description":"Lower-case ASCII letters, digits and _, starting with a letter. Default inferrex_message."}},"required":["brand"]},"example":{"brand":{"companyName":"string","senderName":"string","senderEmail":"string","replyTo":"string","smsSender":"string","logoUrl":"string","logoAlt":"string","colours":{"primary":"string","background":"string","text":"string","accent":"string"},"fontFamily":"string","footer":"string","links":[{"label":"string","url":"string"}],"voice":"string","language":"string","unsubscribeUrl":"string"},"eventType":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"eventType":{"type":"string"},"channels":{"type":"array","items":{"type":"object","properties":{"channel":{"type":"string","description":"email or sms."},"templateHash":{"type":"string","nullable":true,"description":"What an approval is of; null until the brand is saved."},"approved":{"type":"object","properties":{"by":{"type":"string"},"at":{"type":"string","format":"date-time"}},"required":["by","at"],"nullable":true},"current":{"type":"boolean","description":"True when the approval in force is of exactly the template now."}},"required":["channel","templateHash","approved","current"]}}},"required":["connectionId","eventType","channels"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","eventType":"string","channels":[{"channel":"string","templateHash":"string","approved":{"by":"string","at":"2026-01-01T00:00:00Z"},"current":true}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/message-channel/approve":{"post":{"operationId":"ApproveBloomreachMessageTemplate","tags":["bloomreach"],"summary":"Approve Bloomreach Message Template","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string","enum":["email","sms"]},"templateHash":{"type":"string","maxLength":64,"description":"The hash GET /v1/bloomreach/message-channel showed with the template."},"confirmTemplate":{"type":"boolean","description":"Must be true: the person read the template."}},"required":["channel","templateHash","confirmTemplate"]},"example":{"channel":"email","templateHash":"string","confirmTemplate":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string"},"templateHash":{"type":"string"},"approvedBy":{"type":"string"},"approvedAt":{"type":"string","format":"date-time"}},"required":["channel","templateHash","approvedBy","approvedAt"]},"example":{"channel":"string","templateHash":"string","approvedBy":"string","approvedAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/message-delivery":{"get":{"operationId":"GetBloomreachMessageDelivery","tags":["bloomreach"],"summary":"Get Bloomreach Message Delivery","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","description":"capture (the default: nothing is sent on either route — no message through the provider, and no event tracked to Bloomreach for a campaign Bloomreach sends — and each is kept as a test send) or live."},"live":{"type":"object","properties":{"by":{"type":"string"},"at":{"type":"string","format":"date-time"}},"required":["by","at"],"nullable":true,"description":"Who switched live on, and when; null in capture mode."},"liveAllowed":{"type":"boolean","description":"Whether live could be switched on now. With no provider connection chosen it can: live then covers the campaigns Bloomreach sends, and a message asked of Inferrex waits. A provider that is chosen must be approved and hold a key."},"liveProblem":{"type":"string","nullable":true,"description":"Why live cannot be switched on now."},"provider":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"name":{"type":"string"},"baseUrl":{"type":"string","nullable":true},"status":{"type":"string"},"approved":{"type":"boolean","description":"True while the connection is approved or active: live delivery needs it."},"profileKey":{"type":"string"},"providerName":{"type":"string"}},"required":["connectionId","name","baseUrl","status","approved","profileKey","providerName"],"nullable":true,"description":"The workspace's messaging provider connection."},"providerMissing":{"type":"boolean","description":"True when a provider connection is chosen but is archived or gone: choose another, or none."},"candidates":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"name":{"type":"string"},"baseUrl":{"type":"string","nullable":true},"status":{"type":"string"},"approved":{"type":"boolean","description":"True while the connection is approved or active: live delivery needs it."},"profileKey":{"type":"string"},"providerName":{"type":"string"}},"required":["connectionId","name","baseUrl","status","approved","profileKey","providerName"]},"description":"The workspace's connections that are a messaging provider Inferrex can send through."},"providers":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"displayName":{"type":"string"},"baseUrlExample":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"},"description":"What the key must hold."},"facts":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["key","displayName","baseUrlExample","scopes","facts"]},"description":"The provider profiles Inferrex knows, with what was read from each provider's published specification."},"receiver":{"type":"object","properties":{"path":{"type":"string"},"issuedAt":{"type":"string","format":"date-time"},"issuedBy":{"type":"string"},"acceptOAuth":{"type":"boolean"},"secretHeader":{"type":"string"},"tokenScope":{"type":"string"}},"required":["path","issuedAt","issuedBy","acceptOAuth","secretHeader","tokenScope"],"nullable":true,"description":"The receive address the project's scenario posts to (path; prefix it with the API host), when it was made and by whom, the header the secret goes in, and whether an access token holding hooks:receive is accepted instead. Never the secret."},"webhookBody":{"type":"string","description":"The webhook node's body (Bloomreach Jinja)."},"guide":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"body":{"type":"string"}},"required":["title","body"]},"description":"The steps in Bloomreach."},"facts":{"type":"array","items":{"type":"object","additionalProperties":true}},"captures":{"type":"object","properties":{"retentionDays":{"type":"integer"},"max":{"type":"integer"}},"required":["retentionDays","max"]}},"required":["mode","live","liveAllowed","liveProblem","provider","providerMissing","candidates","providers","receiver","webhookBody","guide","facts","captures"]},"example":{"mode":"string","live":{"by":"string","at":"2026-01-01T00:00:00Z"},"liveAllowed":true,"liveProblem":"string","provider":{"connectionId":"00000000-0000-0000-0000-000000000000","name":"string","baseUrl":"string","status":"string","approved":true,"profileKey":"string","providerName":"string"},"providerMissing":true,"candidates":[{"connectionId":"00000000-0000-0000-0000-000000000000","name":"string","baseUrl":"string","status":"string","approved":true,"profileKey":"string","providerName":"string"}],"providers":[{"key":"string","displayName":"string","baseUrlExample":"string","scopes":["string"],"facts":[{}]}],"receiver":{"path":"string","issuedAt":"2026-01-01T00:00:00Z","issuedBy":"string","acceptOAuth":true,"secretHeader":"string","tokenScope":"string"},"webhookBody":"string","guide":[{"title":"string","body":"string"}],"facts":[{}],"captures":{"retentionDays":0,"max":0}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"SetBloomreachMessageDelivery","tags":["bloomreach"],"summary":"Set Bloomreach Message Delivery","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"providerConnectionId":{"type":"string","format":"uuid","nullable":true,"description":"The provider connection, or null for none. Left out: unchanged."},"acceptOAuth":{"type":"boolean","description":"Also accept an Inferrex OAuth access token holding hooks:receive instead of the secret."}}},"example":{"providerConnectionId":"00000000-0000-0000-0000-000000000000","acceptOAuth":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","description":"capture (the default: nothing is sent on either route — no message through the provider, and no event tracked to Bloomreach for a campaign Bloomreach sends — and each is kept as a test send) or live."},"live":{"type":"object","properties":{"by":{"type":"string"},"at":{"type":"string","format":"date-time"}},"required":["by","at"],"nullable":true,"description":"Who switched live on, and when; null in capture mode."},"liveAllowed":{"type":"boolean","description":"Whether live could be switched on now. With no provider connection chosen it can: live then covers the campaigns Bloomreach sends, and a message asked of Inferrex waits. A provider that is chosen must be approved and hold a key."},"liveProblem":{"type":"string","nullable":true,"description":"Why live cannot be switched on now."},"provider":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"name":{"type":"string"},"baseUrl":{"type":"string","nullable":true},"status":{"type":"string"},"approved":{"type":"boolean","description":"True while the connection is approved or active: live delivery needs it."},"profileKey":{"type":"string"},"providerName":{"type":"string"}},"required":["connectionId","name","baseUrl","status","approved","profileKey","providerName"],"nullable":true,"description":"The workspace's messaging provider connection."},"providerMissing":{"type":"boolean","description":"True when a provider connection is chosen but is archived or gone: choose another, or none."},"candidates":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"name":{"type":"string"},"baseUrl":{"type":"string","nullable":true},"status":{"type":"string"},"approved":{"type":"boolean","description":"True while the connection is approved or active: live delivery needs it."},"profileKey":{"type":"string"},"providerName":{"type":"string"}},"required":["connectionId","name","baseUrl","status","approved","profileKey","providerName"]},"description":"The workspace's connections that are a messaging provider Inferrex can send through."},"providers":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"displayName":{"type":"string"},"baseUrlExample":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"},"description":"What the key must hold."},"facts":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["key","displayName","baseUrlExample","scopes","facts"]},"description":"The provider profiles Inferrex knows, with what was read from each provider's published specification."},"receiver":{"type":"object","properties":{"path":{"type":"string"},"issuedAt":{"type":"string","format":"date-time"},"issuedBy":{"type":"string"},"acceptOAuth":{"type":"boolean"},"secretHeader":{"type":"string"},"tokenScope":{"type":"string"}},"required":["path","issuedAt","issuedBy","acceptOAuth","secretHeader","tokenScope"],"nullable":true,"description":"The receive address the project's scenario posts to (path; prefix it with the API host), when it was made and by whom, the header the secret goes in, and whether an access token holding hooks:receive is accepted instead. Never the secret."},"webhookBody":{"type":"string","description":"The webhook node's body (Bloomreach Jinja)."},"guide":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"body":{"type":"string"}},"required":["title","body"]},"description":"The steps in Bloomreach."},"facts":{"type":"array","items":{"type":"object","additionalProperties":true}},"captures":{"type":"object","properties":{"retentionDays":{"type":"integer"},"max":{"type":"integer"}},"required":["retentionDays","max"]}},"required":["mode","live","liveAllowed","liveProblem","provider","providerMissing","candidates","providers","receiver","webhookBody","guide","facts","captures"]},"example":{"mode":"string","live":{"by":"string","at":"2026-01-01T00:00:00Z"},"liveAllowed":true,"liveProblem":"string","provider":{"connectionId":"00000000-0000-0000-0000-000000000000","name":"string","baseUrl":"string","status":"string","approved":true,"profileKey":"string","providerName":"string"},"providerMissing":true,"candidates":[{"connectionId":"00000000-0000-0000-0000-000000000000","name":"string","baseUrl":"string","status":"string","approved":true,"profileKey":"string","providerName":"string"}],"providers":[{"key":"string","displayName":"string","baseUrlExample":"string","scopes":["string"],"facts":[{}]}],"receiver":{"path":"string","issuedAt":"2026-01-01T00:00:00Z","issuedBy":"string","acceptOAuth":true,"secretHeader":"string","tokenScope":"string"},"webhookBody":"string","guide":[{"title":"string","body":"string"}],"facts":[{}],"captures":{"retentionDays":0,"max":0}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/message-delivery/mode":{"post":{"operationId":"SetBloomreachMessageDeliveryMode","tags":["bloomreach"],"summary":"Set Bloomreach Message Delivery Mode","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["live","capture"]},"confirmLive":{"type":"boolean","description":"Must be true to switch to live: the person confirms messages go to real people."}},"required":["mode"]},"example":{"mode":"live","confirmLive":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","description":"capture (the default: nothing is sent on either route — no message through the provider, and no event tracked to Bloomreach for a campaign Bloomreach sends — and each is kept as a test send) or live."},"live":{"type":"object","properties":{"by":{"type":"string"},"at":{"type":"string","format":"date-time"}},"required":["by","at"],"nullable":true,"description":"Who switched live on, and when; null in capture mode."},"liveAllowed":{"type":"boolean","description":"Whether live could be switched on now. With no provider connection chosen it can: live then covers the campaigns Bloomreach sends, and a message asked of Inferrex waits. A provider that is chosen must be approved and hold a key."},"liveProblem":{"type":"string","nullable":true,"description":"Why live cannot be switched on now."},"provider":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"name":{"type":"string"},"baseUrl":{"type":"string","nullable":true},"status":{"type":"string"},"approved":{"type":"boolean","description":"True while the connection is approved or active: live delivery needs it."},"profileKey":{"type":"string"},"providerName":{"type":"string"}},"required":["connectionId","name","baseUrl","status","approved","profileKey","providerName"],"nullable":true,"description":"The workspace's messaging provider connection."},"providerMissing":{"type":"boolean","description":"True when a provider connection is chosen but is archived or gone: choose another, or none."},"candidates":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"name":{"type":"string"},"baseUrl":{"type":"string","nullable":true},"status":{"type":"string"},"approved":{"type":"boolean","description":"True while the connection is approved or active: live delivery needs it."},"profileKey":{"type":"string"},"providerName":{"type":"string"}},"required":["connectionId","name","baseUrl","status","approved","profileKey","providerName"]},"description":"The workspace's connections that are a messaging provider Inferrex can send through."},"providers":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"displayName":{"type":"string"},"baseUrlExample":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"},"description":"What the key must hold."},"facts":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["key","displayName","baseUrlExample","scopes","facts"]},"description":"The provider profiles Inferrex knows, with what was read from each provider's published specification."},"receiver":{"type":"object","properties":{"path":{"type":"string"},"issuedAt":{"type":"string","format":"date-time"},"issuedBy":{"type":"string"},"acceptOAuth":{"type":"boolean"},"secretHeader":{"type":"string"},"tokenScope":{"type":"string"}},"required":["path","issuedAt","issuedBy","acceptOAuth","secretHeader","tokenScope"],"nullable":true,"description":"The receive address the project's scenario posts to (path; prefix it with the API host), when it was made and by whom, the header the secret goes in, and whether an access token holding hooks:receive is accepted instead. Never the secret."},"webhookBody":{"type":"string","description":"The webhook node's body (Bloomreach Jinja)."},"guide":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"body":{"type":"string"}},"required":["title","body"]},"description":"The steps in Bloomreach."},"facts":{"type":"array","items":{"type":"object","additionalProperties":true}},"captures":{"type":"object","properties":{"retentionDays":{"type":"integer"},"max":{"type":"integer"}},"required":["retentionDays","max"]}},"required":["mode","live","liveAllowed","liveProblem","provider","providerMissing","candidates","providers","receiver","webhookBody","guide","facts","captures"]},"example":{"mode":"string","live":{"by":"string","at":"2026-01-01T00:00:00Z"},"liveAllowed":true,"liveProblem":"string","provider":{"connectionId":"00000000-0000-0000-0000-000000000000","name":"string","baseUrl":"string","status":"string","approved":true,"profileKey":"string","providerName":"string"},"providerMissing":true,"candidates":[{"connectionId":"00000000-0000-0000-0000-000000000000","name":"string","baseUrl":"string","status":"string","approved":true,"profileKey":"string","providerName":"string"}],"providers":[{"key":"string","displayName":"string","baseUrlExample":"string","scopes":["string"],"facts":[{}]}],"receiver":{"path":"string","issuedAt":"2026-01-01T00:00:00Z","issuedBy":"string","acceptOAuth":true,"secretHeader":"string","tokenScope":"string"},"webhookBody":"string","guide":[{"title":"string","body":"string"}],"facts":[{}],"captures":{"retentionDays":0,"max":0}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/message-delivery/secret":{"post":{"operationId":"IssueBloomreachMessageDeliverySecret","tags":["bloomreach"],"summary":"Issue Bloomreach Message Delivery Secret","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"path":{"type":"string","description":"The receive address's path; prefix it with the API host."},"secret":{"type":"string","description":"Shown once."},"secretHeader":{"type":"string"},"previousAcceptedHours":{"type":"integer","description":"How long the replaced secret is still accepted; 0 for a first secret."}},"required":["path","secret","secretHeader","previousAcceptedHours"]},"example":{"path":"string","secret":"string","secretHeader":"string","previousAcceptedHours":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/messages":{"get":{"operationId":"GetBloomreachMessages","tags":["bloomreach"],"summary":"Get Bloomreach Messages","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","nullable":true},"campaigns":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","format":"uuid"},"name":{"type":"string"},"channel":{"type":"string"},"mode":{"type":"string","description":"per-segment or per-person."},"delivery":{"type":"string","description":"Open vocabulary. engagement-event: Inferrex tracks an event and the project's scenario sends it through Bloomreach. provider: the project's scenario asks Inferrex to deliver each message through the workspace's own messaging provider (or into Test sends while capture mode is on)."},"status":{"type":"string","description":"Open vocabulary. Known: draft, generating, ready, approved, sending, sent, partly-sent, failed, cancelled, captured (every message kept as a test send, none sent)."},"audience":{"type":"string","description":"The audience in words."},"consent":{"type":"object","properties":{"field":{"type":"string"},"category":{"type":"string"}},"required":["field","category"]},"created":{"type":"object","properties":{"by":{"type":"string"},"at":{"type":"string","format":"date-time"}},"required":["by","at"]},"approval":{"type":"object","properties":{"by":{"type":"string"},"at":{"type":"string","format":"date-time"},"recipients":{"type":"integer"},"templateHash":{"type":"string"}},"required":["by","at","recipients","templateHash"],"nullable":true},"state":{"type":"object","properties":{"cursor":{"type":"string","nullable":true},"generated":{"type":"integer"},"skipped":{"type":"object","additionalProperties":true,"description":"People not messaged, by reason: no-consent, no-id, no-address, over-limit, content."},"aiCalls":{"type":"integer"},"sent":{"type":"integer"},"refused":{"type":"integer"},"unknown":{"type":"integer"},"captured":{"type":"integer","description":"Messages kept as test sends (capture mode), never sent."},"failuresInRow":{"type":"integer"},"lastError":{"type":"string","nullable":true},"lastRunAt":{"type":"string","format":"date-time","nullable":true},"finishedAt":{"type":"string","format":"date-time","nullable":true}},"required":["cursor","generated","skipped","aiCalls","sent","refused","unknown","failuresInRow","lastError","lastRunAt","finishedAt"],"description":"Progress: where writing got to, how many written, skipped by reason, model calls, sent, refused, not known."},"subject":{"type":"string","nullable":true}},"required":["key","name","channel","mode","delivery","status","audience","consent","created","approval","state","subject"]}},"limits":{"type":"object","properties":{"maxAudience":{"type":"integer"},"perPersonMax":{"type":"integer"}},"required":["maxAudience","perPersonMax"]}},"required":["connectionId","campaigns","limits"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","campaigns":[{"key":"00000000-0000-0000-0000-000000000000","name":"string","channel":"string","mode":"string","delivery":"string","status":"string","audience":"string","consent":{"field":"string","category":"string"},"created":{"by":"string","at":"2026-01-01T00:00:00Z"},"approval":{"by":"string","at":"2026-01-01T00:00:00Z","recipients":0,"templateHash":"string"},"state":{"cursor":"string","generated":0,"skipped":{},"aiCalls":0,"sent":0,"refused":0,"unknown":0,"captured":0,"failuresInRow":0,"lastError":"string","lastRunAt":"2026-01-01T00:00:00Z","finishedAt":"2026-01-01T00:00:00Z"},"subject":"string"}],"limits":{"maxAudience":0,"perPersonMax":0}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"CreateBloomreachMessage","tags":["bloomreach"],"summary":"Create Bloomreach Message","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":120},"channel":{"type":"string","enum":["email","sms"]},"mode":{"type":"string","enum":["per-segment","per-person"],"description":"Default per-segment."},"delivery":{"type":"string","enum":["engagement-event","provider"],"description":"Default engagement-event (Inferrex tracks an event; Bloomreach's scenario sends it). provider: the project's scenario asks Inferrex to deliver each message through the workspace's own messaging provider, or into Test sends while capture mode is on; needs addressField, and for email the brand's sender address and unsubscribe page."},"audience":{"type":"object","properties":{"source":{"type":"object","properties":{"kind":{"type":"string","enum":["golden","system"]},"entityType":{"type":"string","maxLength":128},"connectionId":{"type":"string","format":"uuid"},"entity":{"type":"string","maxLength":256}},"required":["kind"],"description":"{ kind: \"golden\", entityType } or { kind: \"system\", connectionId, entity }."},"conditions":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"The field the condition reads: a name, or a dotted path into the record (e.g. \"address.country\")."},"op":{"type":"string","enum":["equals","not-equals","in","exists","missing","gt","gte","lt","lte","contains"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string"}}],"description":"`in` takes a list of values; `exists` and `missing` take none; gt, gte, lt and lte a number; the rest one value."}},"required":["field","op"]},"description":"Up to 10 { field, op, value? }, all of which a person must meet."},"idField":{"type":"string","maxLength":300,"description":"The field whose value is the person's registered id. Required for a system's object."},"personKey":{"type":"string","maxLength":300,"description":"One person only: a golden record's id, or a system record's id."},"addressField":{"type":"string","maxLength":300,"description":"The field holding the email or phone; people without a value are skipped."}},"required":["source"]},"consent":{"type":"object","properties":{"field":{"type":"string","maxLength":300,"description":"The source field that says yes (true, yes, opt-in, subscribed…) for this channel; anything else, or no value, is no message."},"category":{"type":"string","maxLength":128,"description":"The project's consent category the scenario's channel node names."}},"required":["field","category"]},"brief":{"type":"object","properties":{"goal":{"type":"string","maxLength":2000,"description":"What the message is for."},"offer":{"type":"string","maxLength":1000,"nullable":true},"tone":{"type":"string","maxLength":300,"nullable":true},"ctaUrl":{"type":"string","maxLength":2048,"description":"The one https link the message carries; never written by the model."},"ctaLabel":{"type":"string","maxLength":40,"nullable":true}},"required":["goal","ctaUrl"]},"fields":{"type":"array","items":{"type":"string"},"description":"Up to 10 source fields the copy may use (per-person: their values go to the model through ModelRouter)."},"gamification":{"type":"object","properties":{"programKey":{"type":"string","maxLength":63},"playerField":{"type":"string","maxLength":300,"description":"The source field whose value is the player id."}},"required":["programKey","playerField"],"nullable":true}},"required":["name","channel","audience","consent","brief"]},"example":{"name":"string","channel":"email","mode":"per-segment","delivery":"engagement-event","audience":{"source":{"kind":"golden","entityType":"string","connectionId":"00000000-0000-0000-0000-000000000000","entity":"string"},"conditions":[{"field":"string","op":"equals","value":[]}],"idField":"string","personKey":"string","addressField":"string"},"consent":{"field":"string","category":"string"},"brief":{"goal":"string","offer":"string","tone":"string","ctaUrl":"string","ctaLabel":"string"},"fields":["string"],"gamification":{"programKey":"string","playerField":"string"}}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"delivery":{"type":"string"},"audience":{"type":"string"},"idField":{"type":"string"},"addressField":{"type":"string","nullable":true}},"required":["key","name","status","delivery","audience","idField","addressField"]},"example":{"key":"00000000-0000-0000-0000-000000000000","name":"string","status":"string","delivery":"string","audience":"string","idField":"string","addressField":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/messages/{campaignKey}":{"get":{"operationId":"GetBloomreachMessage","tags":["bloomreach"],"summary":"Get Bloomreach Message","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"campaignKey","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"campaign":{"type":"object","additionalProperties":true,"description":"The summary fields, plus brief, fields, gamification, audienceDetail and copy."},"counts":{"type":"object","additionalProperties":true,"description":"Messages by status: ready, requested (asked for by the project's scenario, Inferrex's own delivery), sending, sent, refused, unknown, captured (kept as a test send), skipped-consent (consent withdrawn by the time it was due), skipped-address (the address changed since approval)."},"total":{"type":"integer"},"messagesDigest":{"type":"string","nullable":true,"description":"The digest of every message exactly as it will be tracked (each person's record key, id, message id and attributes); null when none is written. Approving names it: a rewrite or any change since makes the approval refused."},"preview":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"customer":{"type":"string"},"messageId":{"type":"string"},"to":{"type":"string","nullable":true,"description":"The address shortened (Inferrex's own delivery only); null otherwise."},"status":{"type":"string"},"reason":{"type":"string","nullable":true},"at":{"type":"string","nullable":true},"properties":{"type":"object","additionalProperties":true,"description":"The event's attributes as they will be tracked."}},"required":["key","customer","messageId","to","status","reason","at","properties"]}},"emailPreviewHtml":{"type":"string","nullable":true},"template":{"type":"object","properties":{"templateHash":{"type":"string","nullable":true},"approved":{"type":"object","additionalProperties":true,"nullable":true},"current":{"type":"boolean"}},"required":["templateHash","approved","current"],"nullable":true},"storage":{"type":"string","description":"ready, or not-configured when no object storage holds the messages."}},"required":["connectionId","campaign","counts","total","messagesDigest","preview","emailPreviewHtml","template","storage"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","campaign":{},"counts":{},"total":0,"messagesDigest":"string","preview":[{"key":"string","customer":"string","messageId":"string","to":"string","status":"string","reason":"string","at":"string","properties":{}}],"emailPreviewHtml":"string","template":{"templateHash":"string","approved":{},"current":true},"storage":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/messages/{campaignKey}/approve":{"post":{"operationId":"ApproveBloomreachMessage","tags":["bloomreach"],"summary":"Approve Bloomreach Message","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"campaignKey","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmSend":{"type":"boolean","description":"Must be true."},"expectedRecipients":{"type":"integer","minimum":1,"description":"How many messages the person saw waiting."},"messagesDigest":{"type":"string","maxLength":128,"description":"The messagesDigest GET returned with the preview the person read."}},"required":["confirmSend","expectedRecipients","messagesDigest"]},"example":{"confirmSend":true,"expectedRecipients":0,"messagesDigest":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","format":"uuid"},"status":{"type":"string"},"recipients":{"type":"integer"},"approvedBy":{"type":"string"},"approvedAt":{"type":"string","format":"date-time"}},"required":["key","status","recipients","approvedBy","approvedAt"]},"example":{"key":"00000000-0000-0000-0000-000000000000","status":"string","recipients":0,"approvedBy":"string","approvedAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/messages/{campaignKey}/cancel":{"post":{"operationId":"CancelBloomreachMessage","tags":["bloomreach"],"summary":"Cancel Bloomreach Message","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"campaignKey","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","format":"uuid"},"status":{"type":"string"}},"required":["key","status"]},"example":{"key":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/messages/{campaignKey}/generate":{"post":{"operationId":"GenerateBloomreachMessage","tags":["bloomreach"],"summary":"Generate Bloomreach Message","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"campaignKey","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","format":"uuid"},"status":{"type":"string"}},"required":["key","status"]},"example":{"key":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/overview":{"get":{"operationId":"GetBloomreachOverview","tags":["bloomreach"],"summary":"Get Bloomreach Overview","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","nullable":true},"planId":{"type":"string","format":"uuid","nullable":true},"sources":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"title":{"type":"string"},"as":{"type":"string"},"origin":{"type":"string"},"eventType":{"type":"string","nullable":true},"catalog":{"type":"object","properties":{"name":{"type":"string"},"id":{"type":"string","nullable":true},"replaces":{"type":"string","nullable":true}},"required":["name","id","replaces"],"nullable":true},"pipeline":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"lastSyncAt":{"type":"string","format":"date-time","nullable":true},"quarantined":{"type":"integer","description":"Records held back for review, not yet resolved."},"lastRun":{"type":"object","properties":{"status":{"type":"string"},"startedAt":{"type":"string","format":"date-time","nullable":true},"completedAt":{"type":"string","format":"date-time","nullable":true},"recordsWritten":{"type":"integer"},"recordsFailed":{"type":"integer"},"error":{"type":"string","nullable":true},"recordsSkipped":{"type":"integer","description":"Records the last run left unwritten on purpose, never quarantined: unchanged since this pipeline last sent them, or left out by the source's send rule as not for this project (design §N.4.2)."}},"required":["status","startedAt","completedAt","recordsWritten","recordsFailed","error","recordsSkipped"],"nullable":true}},"required":["id","name","status","lastSyncAt","quarantined","lastRun"],"nullable":true}},"required":["key","title","as","origin","eventType","catalog","pipeline"]}},"reads":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"lastSyncAt":{"type":"string","format":"date-time","nullable":true},"quarantined":{"type":"integer","description":"Records held back for review, not yet resolved."},"lastRun":{"type":"object","properties":{"status":{"type":"string"},"startedAt":{"type":"string","format":"date-time","nullable":true},"completedAt":{"type":"string","format":"date-time","nullable":true},"recordsWritten":{"type":"integer"},"recordsFailed":{"type":"integer"},"error":{"type":"string","nullable":true},"recordsSkipped":{"type":"integer","description":"Records the last run left unwritten on purpose, never quarantined: unchanged since this pipeline last sent them, or left out by the source's send rule as not for this project (design §N.4.2)."}},"required":["status","startedAt","completedAt","recordsWritten","recordsFailed","error","recordsSkipped"],"nullable":true}},"required":["id","name","status","lastSyncAt","quarantined","lastRun"]},"description":"Pipelines that read from Engagement."},"otherWrites":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"lastSyncAt":{"type":"string","format":"date-time","nullable":true},"quarantined":{"type":"integer","description":"Records held back for review, not yet resolved."},"lastRun":{"type":"object","properties":{"status":{"type":"string"},"startedAt":{"type":"string","format":"date-time","nullable":true},"completedAt":{"type":"string","format":"date-time","nullable":true},"recordsWritten":{"type":"integer"},"recordsFailed":{"type":"integer"},"error":{"type":"string","nullable":true},"recordsSkipped":{"type":"integer","description":"Records the last run left unwritten on purpose, never quarantined: unchanged since this pipeline last sent them, or left out by the source's send rule as not for this project (design §N.4.2)."}},"required":["status","startedAt","completedAt","recordsWritten","recordsFailed","error","recordsSkipped"],"nullable":true}},"required":["id","name","status","lastSyncAt","quarantined","lastRun"]},"description":"Pipelines a person made that write to Engagement outside the plan."},"ids":{"type":"object","properties":{"hardId":{"type":"string"},"goldenId":{"type":"string"},"registeredFrom":{"type":"string","nullable":true},"golden":{"type":"integer"},"linked":{"type":"integer"},"changed":{"type":"integer"},"sharedIds":{"type":"integer"},"noHardId":{"type":"integer"}},"required":["hardId","goldenId","registeredFrom","golden","linked","changed","sharedIds","noHardId"],"nullable":true,"description":"Null when the plan sends no golden customers."},"routing":{"type":"object","properties":{"rule":{"type":"string","description":"all, when or otherwise."},"words":{"type":"string"},"golden":{"type":"integer","nullable":true},"routedHere":{"type":"integer","nullable":true},"routedNowhere":{"type":"integer"},"truncated":{"type":"boolean"}},"required":["rule","words","golden","routedHere","routedNowhere","truncated"],"nullable":true,"description":"Several projects (design §N.4.2): this project's rule for golden customers and where the golden records go. Null when the plan sends no golden customers. golden, routedHere and routedNowhere are null/0 while every project takes every record (no scan); otherwise counted over at most 20,000 golden records (truncated says when there were more). A record no project's rule takes is sent nowhere."}},"required":["connectionId","planId","sources","reads","otherWrites","ids","routing"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","planId":"00000000-0000-0000-0000-000000000000","sources":[{"key":"string","title":"string","as":"string","origin":"string","eventType":"string","catalog":{"name":"string","id":"string","replaces":"string"},"pipeline":{"id":"00000000-0000-0000-0000-000000000000","name":"string","status":"string","lastSyncAt":"2026-01-01T00:00:00Z","quarantined":0,"lastRun":{"status":"string","startedAt":"2026-01-01T00:00:00Z","completedAt":"2026-01-01T00:00:00Z","recordsWritten":0,"recordsFailed":0,"error":"string","recordsSkipped":0}}}],"reads":[{"id":"00000000-0000-0000-0000-000000000000","name":"string","status":"string","lastSyncAt":"2026-01-01T00:00:00Z","quarantined":0,"lastRun":{"status":"string","startedAt":"2026-01-01T00:00:00Z","completedAt":"2026-01-01T00:00:00Z","recordsWritten":0,"recordsFailed":0,"error":"string","recordsSkipped":0}}],"otherWrites":[{"id":"00000000-0000-0000-0000-000000000000","name":"string","status":"string","lastSyncAt":"2026-01-01T00:00:00Z","quarantined":0,"lastRun":{"status":"string","startedAt":"2026-01-01T00:00:00Z","completedAt":"2026-01-01T00:00:00Z","recordsWritten":0,"recordsFailed":0,"error":"string","recordsSkipped":0}}],"ids":{"hardId":"string","goldenId":"string","registeredFrom":"string","golden":0,"linked":0,"changed":0,"sharedIds":0,"noHardId":0},"routing":{"rule":"string","words":"string","golden":0,"routedHere":0,"routedNowhere":0,"truncated":true}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/project-schema":{"get":{"operationId":"GetBloomreachProjectSchema","tags":["bloomreach"],"summary":"Get Bloomreach Project Schema","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"readPropertyList","in":"query","required":false,"schema":{"type":"boolean","description":"True also reads every customer property and id name from the header line of Export all customers (needs GDPR > Export customers, which this proves). Bloomreach may build the whole export before it answers; Inferrex waits at most 20 seconds for the header line and stops the request either way. Default false."},"description":"True also reads every customer property and id name from the header line of Export all customers (needs GDPR > Export customers, which this proves). Bloomreach may build the whole export before it answers; Inferrex waits at most 20 seconds for the header line and stops the request either way. Default false."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"readAt":{"type":"string","format":"date-time"},"writtenByInferrex":{"type":"object","additionalProperties":true,"description":"From the setup plan in force (authoritative): { planId, appliedAt, ids, customerProperties: [{ name, type, sentAs, source }], eventTypes: [{ name, source, properties: [{ name, type, sentAs, source }] }], catalogs: [{ name, id, source, columns: [{ name, type, searchable, sentAs, source }] }] }. type is the source field's type (a catalog column's type), null where the plan holds none (golden customer properties). Empty lists when no plan is in force."},"foundNotWrittenByInferrex":{"type":"object","additionalProperties":true,"description":"Names found in Bloomreach (the catalogs, the sampled customers, the property list) that the plan in force does not write, names only: { catalogs, catalogColumns: [{ catalog, columns }], customerProperties, ids, otherColumns (property list columns the header does not mark), eventTypes, eventProperties: [{ eventType, properties }] }."},"catalogs":{"type":"object","additionalProperties":true,"description":"{ status: read|refused|failed|not-read, detail, items: [{ id, name, columnsStatus: read|empty|refused|failed|not-read, columns: [name view], detail }], more: catalogs past the 25 read }."},"consentCategories":{"type":"object","additionalProperties":true,"description":"{ status, detail, items: [{ id, legitimateInterest, sources: the sources it allows, languages }] }."},"customers":{"type":"object","additionalProperties":true,"description":"{ status: read|none-sent|refused|failed, detail, asked, read, sampleSize, ids: id names, properties: [name view] }. A name view is { name, valueKinds: text|number|boolean|list|object|empty, inferredType: boolean|list|json|null, seenOn, withheld }; withheld: the caller's role may not see this field class, so its kinds are not shown."},"eventTypes":{"type":"object","additionalProperties":true,"description":"{ status, detail, items: [{ name, seenOn, properties: [name view] }] }: only the types found on the customers read."},"propertyList":{"type":"object","additionalProperties":true,"nullable":true,"description":"Null unless readPropertyList=true. { status: read|refused|failed|timed-out, detail, columns: [{ name, kind: id|property|unknown }] }."},"permissions":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"One permission-test row ({ key, area, label, access, neededFor, status, detail, httpStatus }) for each permission a read above proved or was refused."},"cannotRead":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"[{ what, why, asks }]: what no public call reads, and the partner asks (A2, A7) that would. With a Data Manager export kept, the event types gap says what the export covers."},"dataManagerExport":{"type":"object","additionalProperties":true,"nullable":true,"description":"The Data Manager export kept for the project (POST /v1/bloomreach/data-manager-export), names only: { importedAt, exportVersion, eventTypes: [{ name, strength: project|template }], standardEvents: [{ role, eventType }], consentCategories, mainCatalog }. Its event types the project itself uses are also listed under foundNotWrittenByInferrex.eventTypes when the plan in force does not write them. Null when none is kept."},"facts":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["connectionId","readAt","writtenByInferrex","foundNotWrittenByInferrex","catalogs","consentCategories","customers","eventTypes","propertyList","permissions","cannotRead","dataManagerExport","facts"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","readAt":"2026-01-01T00:00:00Z","writtenByInferrex":{},"foundNotWrittenByInferrex":{},"catalogs":{},"consentCategories":{},"customers":{},"eventTypes":{},"propertyList":{},"permissions":[{}],"cannotRead":[{}],"dataManagerExport":{},"facts":[{}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/projects/{connectionId}/scope":{"put":{"operationId":"SetBloomreachProjectScope","tags":["bloomreach"],"summary":"Set Bloomreach Project Scope","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"connectionId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The project: its connection id, as GET /v1/bloomreach/connection lists it."},"description":"The project: its connection id, as GET /v1/bloomreach/connection lists it."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":80},"purpose":{"type":"string","maxLength":40,"nullable":true,"description":"Open vocabulary: brand, region, environment, or your own word."},"scope":{"type":"object","properties":{"brand":{"type":"string","maxLength":80},"region":{"type":"string","maxLength":80},"environmentId":{"type":"string","format":"uuid"}}},"isDefault":{"type":"boolean","description":"True makes this the project the pages open on, and no other."}},"required":["label"]},"example":{"label":"string","purpose":"string","scope":{"brand":"string","region":"string","environmentId":"00000000-0000-0000-0000-000000000000"},"isDefault":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"label":{"type":"string"},"purpose":{"type":"string","nullable":true},"scope":{"type":"object","properties":{"brand":{"type":"string"},"region":{"type":"string"},"environmentId":{"type":"string","format":"uuid"}}},"isDefault":{"type":"boolean"}},"required":["connectionId","label","purpose","scope","isDefault"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","label":"string","purpose":"string","scope":{"brand":"string","region":"string","environmentId":"00000000-0000-0000-0000-000000000000"},"isDefault":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/recommendations":{"get":{"operationId":"GetBloomreachRecommendations","tags":["bloomreach"],"summary":"Get Bloomreach Recommendations","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"connectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only this system's objects (no golden records): a system's \"Add a flow to…\"."},"description":"Only this system's objects (no golden records): a system's \"Add a flow to…\"."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","description":"The Engagement connection."},"signals":{"type":"array","items":{"type":"string"},"description":"The platform signals recommendations are made from."},"recommendations":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"fingerprint":{"type":"string","description":"Changes when the data it was made from changes; a dismissal of an older one lapses."},"status":{"type":"string","enum":["recommended","not-recommended","dismissed","in-plan"]},"score":{"type":"number"},"title":{"type":"string"},"reasons":{"type":"array","items":{"type":"string"}},"signals":{"type":"array","items":{"type":"string"}},"missing":{"type":"array","items":{"type":"string"},"description":"What the person still has to choose before it can be proposed."},"connectionId":{"type":"string","format":"uuid","nullable":true},"customers":{"type":"object","additionalProperties":true,"nullable":true,"description":"A golden customers choice, as the propose route takes it."},"source":{"type":"object","additionalProperties":true,"nullable":true,"description":"A source choice, as the propose route takes it in `sources`."},"candidates":{"type":"object","additionalProperties":true,"description":"Candidate fields for what is missing, best first."},"proposedNames":{"type":"object","additionalProperties":true,"description":"Phase 11: the destination name proposed for a field (by field), pre-selected or not: a channel property (email, phone, language) or a reserved catalog attribute."}},"required":["key","fingerprint","status","score","title","reasons","signals","missing","connectionId","customers","source","candidates","proposedNames"]},"description":"Recommended first, then not recommended, dismissed, and those already in the plan in force."}},"required":["connectionId","signals","recommendations"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","signals":["string"],"recommendations":[{"key":"string","fingerprint":"string","status":"recommended","score":0,"title":"string","reasons":["string"],"signals":["string"],"missing":["string"],"connectionId":"00000000-0000-0000-0000-000000000000","customers":{},"source":{},"candidates":{},"proposedNames":{}}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/recommendations/dismiss":{"post":{"operationId":"DismissBloomreachRecommendation","tags":["bloomreach"],"summary":"Dismiss Bloomreach Recommendation","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","maxLength":300,"description":"The recommendation's key, as GET /v1/bloomreach/recommendations lists it."},"fingerprint":{"type":"string","maxLength":16,"description":"The recommendation's fingerprint; required to dismiss."},"dismissed":{"type":"boolean","description":"false brings a dismissed recommendation back. True when left out."}},"required":["key"]},"example":{"key":"string","fingerprint":"string","dismissed":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"},"dismissed":{"type":"boolean"}},"required":["key","dismissed"]},"example":{"key":"string","dismissed":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/setup-pack":{"get":{"operationId":"GetBloomreachSetupPack","tags":["bloomreach"],"summary":"Get Bloomreach Setup Pack","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","nullable":true,"description":"The Engagement connection, or null when none is connected."},"planId":{"type":"string","format":"uuid","nullable":true,"description":"The plan in force the pack is made from, or null when no plan is applied (then there are no items)."},"planVersion":{"type":"integer","nullable":true},"destination":{"type":"string"},"generatedAt":{"type":"string","format":"date-time"},"notes":{"type":"array","items":{"type":"string"}},"sections":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"project, access, consent, data, analytics, tracking or channels."},"title":{"type":"string"}},"required":["key","title"]},"description":"The parts of the setup that have items, in order."},"asks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"api":{"type":"string"},"rows":{"type":"array","items":{"type":"number"},"description":"The rows of the design's setup tables it would automate."}},"required":["id","api","rows"]},"description":"The partner-API asks (A1–A17) the items name: what Inferrex asks Bloomreach to open as an API."},"readiness":{"type":"object","properties":{"goldenEntityType":{"type":"string","nullable":true},"total":{"type":"integer","nullable":true},"properties":{"type":"array","items":{"type":"object","properties":{"property":{"type":"string","description":"email, phone or language: the property Engagement's channels read."},"goldenField":{"type":"string","nullable":true},"sentAs":{"type":"string","nullable":true,"description":"The property name the plan sends it as."},"count":{"type":"integer","nullable":true,"description":"Golden customers with a value; null when nothing is sent for it."},"note":{"type":"string"}},"required":["property","goldenField","sentAs","count","note"]}},"consents":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string"},"goldenField":{"type":"string"},"count":{"type":"integer","description":"Golden customers whose value reads as a yes."}},"required":["category","goldenField","count"]}},"notes":{"type":"array","items":{"type":"string"}}},"required":["goldenEntityType","total","properties","consents","notes"],"nullable":true,"description":"Channel readiness from Inferrex's golden records; null when no plan is applied."},"items":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Stable while the suggestion is the same, so a tick carries over to a later plan version."},"section":{"type":"string","description":"Which part of the setup it belongs to (sections)."},"asks":{"type":"array","items":{"type":"string"},"description":"The partner-API asks that would make it an API call; empty when none."},"artefact":{"type":"object","properties":{"title":{"type":"string"},"format":{"type":"string","enum":["list","code"]},"lines":{"type":"array","items":{"type":"string"},"description":"One value per line (list), or the text to paste (code)."}},"required":["title","format","lines"],"nullable":true,"description":"The exact values to enter, generated from the plan in force."},"kind":{"type":"string","description":"project, identifier, api-access, domain, consent, data-manager, data-mapping, aggregate, segmentation, scenario, recommendation, prediction, tag-manager, mobile or channel (open)."},"title":{"type":"string"},"why":{"type":"string"},"steps":{"type":"array","items":{"type":"string"}},"where":{"type":"string","description":"Where in Engagement's UI it is made."},"source":{"type":"string","description":"The public Bloomreach page that says where."},"readOn":{"type":"string","description":"When that page was read (YYYY-MM-DD)."},"verified":{"type":"boolean"},"api":{"type":"string","description":"What Engagement's public API offers for it, as read that day."},"note":{"type":"string","nullable":true},"fromSources":{"type":"array","items":{"type":"string"},"description":"The plan's source keys it is made from."},"done":{"type":"boolean"},"doneBy":{"type":"string","nullable":true},"doneAt":{"type":"string","format":"date-time","nullable":true}},"required":["key","section","asks","artefact","kind","title","why","steps","where","source","readOn","verified","api","note","fromSources","done","doneBy","doneAt"]}},"counts":{"type":"object","properties":{"total":{"type":"integer"},"done":{"type":"integer"}},"required":["total","done"]},"fileName":{"type":"string"},"markdown":{"type":"string","description":"The pack as a Markdown file, ticks included."}},"required":["connectionId","planId","planVersion","destination","generatedAt","notes","sections","asks","readiness","items","counts","fileName","markdown"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","planId":"00000000-0000-0000-0000-000000000000","planVersion":0,"destination":"string","generatedAt":"2026-01-01T00:00:00Z","notes":["string"],"sections":[{"key":"string","title":"string"}],"asks":[{"id":"string","api":"string","rows":[0]}],"readiness":{"goldenEntityType":"string","total":0,"properties":[{"property":"string","goldenField":"string","sentAs":"string","count":0,"note":"string"}],"consents":[{"category":"string","goldenField":"string","count":0}],"notes":["string"]},"items":[{"key":"string","section":"string","asks":["string"],"artefact":{"title":"string","format":"list","lines":["string"]},"kind":"string","title":"string","why":"string","steps":["string"],"where":"string","source":"string","readOn":"string","verified":true,"api":"string","note":"string","fromSources":["string"],"done":true,"doneBy":"string","doneAt":"2026-01-01T00:00:00Z"}],"counts":{"total":0,"done":0},"fileName":"string","markdown":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/setup-pack/checklist":{"post":{"operationId":"SetBloomreachSetupPackItem","tags":["bloomreach"],"summary":"Set Bloomreach Setup Pack Item","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"itemKey":{"type":"string","minLength":1,"maxLength":290,"description":"The item's key, as GET /v1/bloomreach/setup-pack lists it."},"done":{"type":"boolean"}},"required":["itemKey","done"]},"example":{"itemKey":"string","done":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"itemKey":{"type":"string"},"done":{"type":"boolean"},"by":{"type":"string"},"at":{"type":"string","format":"date-time"}},"required":["itemKey","done","by","at"]},"example":{"itemKey":"string","done":true,"by":"string","at":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/setup-plan":{"get":{"operationId":"GetBloomreachSetupPlan","tags":["bloomreach"],"summary":"Get Bloomreach Setup Plan","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","nullable":true},"current":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","description":"draft (proposed, waiting for approval), approved (approved; applying stopped, see plan.applyError), applied, declined."},"version":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"plan":{"type":"object","additionalProperties":true,"description":"The SetupPlan (@inferrex/service-schema destination-setup-plan.ts)."}},"required":["id","status","version","createdAt","createdBy","plan"],"nullable":true,"description":"The newest plan, or null when none was proposed."},"applied":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"},"version":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"plan":{"type":"object","additionalProperties":true}},"required":["id","status","version","createdAt","createdBy","plan"],"nullable":true,"description":"The plan in force, when it is not `current`."}},"required":["connectionId","current","applied"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","current":{"id":"00000000-0000-0000-0000-000000000000","status":"string","version":0,"createdAt":"2026-01-01T00:00:00Z","createdBy":"string","plan":{}},"applied":{"id":"00000000-0000-0000-0000-000000000000","status":"string","version":0,"createdAt":"2026-01-01T00:00:00Z","createdBy":"string","plan":{}}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"ProposeBloomreachSetupPlan","tags":["bloomreach"],"summary":"Propose Bloomreach Setup Plan","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"customers":{"type":"object","properties":{"goldenEntityType":{"type":"string","description":"The golden record type, as GET /v1/bloomreach/setup/options lists it in golden[].entityType (e.g. \"person\")."},"registeredFrom":{"type":"string","description":"The golden field whose value is the tenant's own hard id for the person."},"properties":{"type":"array","items":{"type":"object","properties":{"goldenField":{"type":"string","description":"A golden field name, as golden[].fields[].name lists it."},"property":{"type":"string","description":"The customer property name in the destination. Left out: the golden field's own name."}},"required":["goldenField"]},"description":"At least one golden field to send as a customer property."},"origin":{"type":"string","enum":["recommended","chosen"],"description":"\"recommended\" when taken from a recommendation, else \"chosen\" (the default)."},"routing":{"type":"string","enum":["all","when","otherwise"],"description":"Which golden records this project receives when the workspace has several projects: \"all\" (the default) every one; \"when\" only those meeting every condition of `when`; \"otherwise\" those no other project's `when` matched (one project per golden type)."},"when":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"The field the condition reads: a name, or a dotted path into the record (e.g. \"address.country\")."},"op":{"type":"string","enum":["equals","not-equals","in","exists","missing","gt","gte","lt","lte","contains"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string"}}],"description":"`in` takes a list of values; `exists` and `missing` take none; gt, gte, lt and lte a number; the rest one value."}},"required":["field","op"]},"description":"With routing \"when\": 1 to 10 conditions on golden fields."}},"required":["goldenEntityType","registeredFrom","properties"],"nullable":true,"description":"Golden records sent as customers: the golden type, which golden field is the tenant's own hard id (registeredFrom), and which golden fields become customer properties. OPTIONAL: leave it out (or null) for a plan that sends no golden customers, e.g. only events or catalog items from systems. Several projects (design §N.4.2): `routing` and `when` say which golden records this project receives; a golden record no project's rule matches is sent nowhere, one several match goes to each."},"sources":{"type":"array","items":{"type":"object","properties":{"sourceConnectionId":{"type":"string","format":"uuid","description":"The system's connection id, as GET /v1/bloomreach/setup/options lists it in sources[].connectionId. Never an Engagement project."},"sourceEntity":{"type":"string","description":"The object's API name, as sources[].entities[].apiName lists it (e.g. \"orders\"); never its display name."},"as":{"type":"string","enum":["event","catalog-item","customer"],"description":"\"event\": each record is a thing that happened, tracked against a customer. \"catalog-item\": each record is an item of one catalog. \"customer\": customer properties sent direct from this system."},"origin":{"type":"string","enum":["recommended","chosen"],"description":"\"recommended\" when taken from a recommendation, else \"chosen\" (the default)."},"eventType":{"type":"string","description":"Events (required): the event type every record is tracked as (e.g. \"purchase\"). \"consent\" sends consent and needs `consent`."},"timestampField":{"type":"string","description":"Events (required): the source field holding when it happened. Customers: when the values changed."},"customerIdField":{"type":"string","description":"Events and customers (required): the source field holding the person's hard id. With customerIdLookup: the field holding another system's id for a related record (it may be a path inside an object field, e.g. \"metadata.myobos_order_id\")."},"customerIdLookup":{"type":"object","properties":{"goldenEntityType":{"type":"string","description":"The kind of golden record the id belongs to (e.g. \"order\")."},"sourceIdKey":{"type":"string","description":"The system the id is from, as the key under the golden record's source_ids (e.g. \"inferrexdemo\")."},"returnField":{"type":"string","description":"The golden field holding the person's id (e.g. \"email\"; use the field golden customers are sent with as the hard id)."},"fallbackVia":{"type":"object","properties":{"viaField":{"type":"string","description":"The first golden record's field holding the next id (e.g. \"customer_id\")."},"goldenEntityType":{"type":"string","description":"The second golden record's kind (e.g. \"customer\")."},"sourceIdKey":{"type":"string","description":"The system that id is from (e.g. \"inferrexdemo\")."},"returnField":{"type":"string","description":"The second golden record's field holding the person's id (e.g. \"email\")."}},"required":["viaField","goldenEntityType","sourceIdKey","returnField"],"description":"When returnField is empty: follow an id the golden record holds to a second golden record."}},"required":["goldenEntityType","sourceIdKey","returnField"],"description":"Events and customers: read the person's hard id from a related golden record instead of the source record, for a system whose records hold no person id but name a record of another system (a Stripe charge naming its myobos order). The golden record of goldenEntityType whose source_ids.<sourceIdKey> equals customerIdField gives its returnField; with fallbackVia, when that is empty, its viaField names a second golden record whose returnField is used. A record whose golden record is not found is held back for review, never sent without an id. Example: {\"goldenEntityType\": \"order\", \"sourceIdKey\": \"inferrexdemo\", \"returnField\": \"email\", \"fallbackVia\": {\"viaField\": \"customer_id\", \"goldenEntityType\": \"customer\", \"sourceIdKey\": \"inferrexdemo\", \"returnField\": \"email\"}}."},"catalogName":{"type":"string","description":"Catalog items (required): the catalog's name."},"sourceLabel":{"type":"string","description":"Events: what the event's source property carries. Left out: the system's own label."},"startNow":{"type":"boolean","description":"Start sending once the plan is applied (a first full read, then changes). Left out: true."},"backfillFrom":{"type":"string","description":"Events: a date (YYYY-MM-DD); once applied, the history from that date goes in as one file through the destination's import, then changes."},"fields":{"type":"array","items":{"type":"object","properties":{"sourceField":{"type":"string","description":"The field's API name."},"name":{"type":"string","description":"The name it is sent under. Left out: its own name. A field named email, phone or language (any case) is sent under exactly that name."},"searchable":{"type":"boolean","description":"Catalog items: the column is searchable."}},"required":["sourceField"]},"description":"The source fields to send (at least one, except for consent), by API name, as sources[].entities[].fields[].apiName lists them."},"consent":{"type":"object","properties":{"actionField":{"type":"string","description":"The source field whose value says whether consent was given or withdrawn."},"actions":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string","description":"The source value, exactly as the system holds it."},"action":{"type":"string","description":"The destination's consent action: for Bloomreach Engagement \"accept\" or \"reject\"."}},"required":["value","action"]},"description":"Each source value and the consent action it is; a value not listed is held back."},"category":{"type":"string","description":"One consent category for every record. Give this, or categoryField with categories."},"categoryField":{"type":"string","description":"The source field whose value names the consent category."},"categories":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"category":{"type":"string"}},"required":["value","category"]},"description":"With categoryField: each value and its consent category; a value not listed is held back."},"validUntilField":{"type":"string","description":"The source field holding when a grant ends. Left out: the workspace's default."}},"required":["actionField","actions"],"description":"Events whose eventType is \"consent\" (required for them): the consent mapping."},"sendWhen":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"The field the condition reads: a name, or a dotted path into the record (e.g. \"address.country\")."},"op":{"type":"string","enum":["equals","not-equals","in","exists","missing","gt","gte","lt","lte","contains"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string"}}],"description":"`in` takes a list of values; `exists` and `missing` take none; gt, gte, lt and lte a number; the rest one value."}},"required":["field","op"]},"description":"When the workspace has several projects: up to 10 conditions on this source's sent fields; a record that does not meet them is skipped and counted, never quarantined."},"lineItems":{"type":"object","properties":{"field":{"type":"string","description":"The source field holding the list, a list of records: one whose entry in GET /v1/bloomreach/setup/options has itemFields (e.g. \"items\")."},"eventType":{"type":"string","description":"The event type each line is tracked as, not the record's own (e.g. \"purchase_item\" beside \"purchase\")."},"fields":{"type":"array","items":{"type":"object","properties":{"sourceField":{"type":"string","description":"The line field's API name."},"name":{"type":"string","description":"The name it is sent under (e.g. \"price\" for a unit price). Left out: its own name."}},"required":["sourceField"]},"description":"At least one field of each line, by API name, as itemFields[].apiName lists it."},"carry":{"type":"array","items":{"type":"object","properties":{"sourceField":{"type":"string","description":"The record field's API name."},"name":{"type":"string","description":"The name it is sent under. Left out: its own name."}},"required":["sourceField"]},"description":"Fields of the record carried on every line, by API name (e.g. the order id as \"purchase_id\")."},"idField":{"type":"string","description":"The line field that identifies each line, so a line added or moved later is sent once. Left out: the line field marked primary-key (itemFields[].role), else identifier, else one named \"id\", never a relation such as product_id (a product can be on two lines); with none, lines are known by their place in the list and the plan warns."}},"required":["field","eventType","fields"],"description":"Events, not consent (2026-10-28): each line of a list on the record (an order's items) also sent as an event of its own, after the record's event and only when it is sent (`LineItemsChoice`)."}},"required":["sourceConnectionId","sourceEntity","as","fields"]},"description":"Up to 20 system objects (any number of systems, D14), each sent as events, as items of one catalog, or as customer properties sent direct. OPTIONAL: leave it out for golden customers only. A recommendation from GET /v1/bloomreach/recommendations carries one in its `source`, ready to send once its `missing` is empty. Example, orders sent as purchase events: [{ \"sourceConnectionId\": \"<the system's connection id>\", \"sourceEntity\": \"orders\", \"as\": \"event\", \"eventType\": \"purchase\", \"timestampField\": \"created_at\", \"customerIdField\": \"customer_email\", \"fields\": [{ \"sourceField\": \"total\" }, { \"sourceField\": \"currency\" }] }]. `backfillFrom` (phase 5) loads the history from that date through Engagement's Imports API, then sends changes. A consent source (phase 10) carries no `source` property, and a record whose values the mapping does not cover is held back, never sent. A field named email, phone or language (any case) is sent under exactly that name, an email lower-cased and trimmed and a phone in full international form (phase 11). `lineItems` (events, not consent; 2026-10-28): each line of a list on the record (an order's items, a field setup options lists with `itemFields`) is also sent as an event of its own type (\"purchase_item\" beside \"purchase\"), with the chosen line fields and the record's carried fields (the order id as \"purchase_id\"), the record's time, customer id and source property, after the record's event and only when it is sent; each line is known by `idField` (else the line field marked primary-key, else identifier, else one named id, never a relation such as product_id), so a line added or moved later is sent once, and with none by its place in the list, which the plan warns of."},"propertyCap":{"type":"integer","description":"The project's customer property cap, 255 or 1,024 by contract. 255 when left out."},"propertiesInUse":{"type":"integer","minimum":0,"maximum":1024,"description":"How many customer properties the project already uses, when known."}}},"example":{"customers":{"goldenEntityType":"string","registeredFrom":"string","properties":[{"goldenField":"string","property":"string"}],"origin":"recommended","routing":"all","when":[{"field":"string","op":"equals","value":[]}]},"sources":[{"sourceConnectionId":"00000000-0000-0000-0000-000000000000","sourceEntity":"string","as":"event","origin":"recommended","eventType":"string","timestampField":"string","customerIdField":"string","customerIdLookup":{"goldenEntityType":"string","sourceIdKey":"string","returnField":"string","fallbackVia":{"viaField":"string","goldenEntityType":"string","sourceIdKey":"string","returnField":"string"}},"catalogName":"string","sourceLabel":"string","startNow":true,"backfillFrom":"string","fields":[{"sourceField":"string","name":"string","searchable":true}],"consent":{"actionField":"string","actions":[{"value":"string","action":"string"}],"category":"string","categoryField":"string","categories":[{"value":"string","category":"string"}],"validUntilField":"string"},"sendWhen":[{"field":"string","op":"equals","value":[]}],"lineItems":{"field":"string","eventType":"string","fields":[{"sourceField":"string","name":"string"}],"carry":[{"sourceField":"string","name":"string"}],"idField":"string"}}],"propertyCap":0,"propertiesInUse":0}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"},"version":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"plan":{"type":"object","additionalProperties":true}},"required":["id","status","version","createdAt","createdBy","plan"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string","version":0,"createdAt":"2026-01-01T00:00:00Z","createdBy":"string","plan":{}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/setup-plan/{planId}/approve":{"post":{"operationId":"ApproveBloomreachSetupPlan","tags":["bloomreach"],"summary":"Approve Bloomreach Setup Plan","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmedSteps":{"type":"boolean","description":"True when the person confirms they did the plan's manual steps in Bloomreach (such as adding the inferrex_id identifier). Required when the plan has any. An agent sends it only when the person said so themselves."},"confirmedConsentMapping":{"type":"boolean","description":"Phase 10: true when the person confirms the plan's consent mapping (each value → accept or reject, each category, when consent ends). Required when the plan has a confirm-consent step (bloomreach.consentConfirmMapping, on by default). An agent sends it only when the person said so themselves."}}},"example":{"confirmedSteps":true,"confirmedConsentMapping":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The plan as it now stands (a new version once applied)."},"status":{"type":"string","description":"applied, or approved when the apply stopped (see applyError)."},"applyError":{"type":"string","nullable":true},"sources":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"pipelineId":{"type":"string","format":"uuid","nullable":true},"catalogId":{"type":"string","nullable":true},"started":{"type":"boolean"},"carried":{"type":"boolean","description":"The pipeline the plan before used, kept."}},"required":["key","pipelineId","catalogId","started","carried"]},"description":"What the apply did for each source, so far."},"jobIds":{"type":"array","items":{"type":"string"},"description":"The first syncs started; poll GET /v1/jobs/:id."}},"required":["id","status","applyError","sources","jobIds"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string","applyError":"string","sources":[{"key":"string","pipelineId":"00000000-0000-0000-0000-000000000000","catalogId":"string","started":true,"carried":true}],"jobIds":["string"]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/setup-plan/{planId}/backfill":{"post":{"operationId":"StartBloomreachBackfill","tags":["bloomreach"],"summary":"Start Bloomreach Backfill","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sourceKey":{"type":"string","maxLength":300,"description":"The plan source's key, as the plan lists it (`event:<connection>:<object>`)."},"from":{"type":"string","maxLength":10,"description":"The first day of history to load, `YYYY-MM-DD` (UTC). Not in the future."}},"required":["sourceKey","from"]},"example":{"sourceKey":"string","from":"string"}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"backfillId":{"type":"string","format":"uuid"},"jobId":{"type":"string","format":"uuid","description":"Poll GET /v1/jobs/:id for the read; GET /v1/bloomreach/backfills for the load."},"pipelineId":{"type":"string","format":"uuid"},"status":{"type":"string","description":"queued"}},"required":["backfillId","jobId","pipelineId","status"]},"example":{"backfillId":"00000000-0000-0000-0000-000000000000","jobId":"00000000-0000-0000-0000-000000000000","pipelineId":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/setup-plan/{planId}/decline":{"post":{"operationId":"DeclineBloomreachSetupPlan","tags":["bloomreach"],"summary":"Decline Bloomreach Setup Plan","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"}},"required":["id","status"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/setup-plan/{planId}/send-golden":{"post":{"operationId":"SendGoldenRecordsToBloomreach","tags":["bloomreach"],"summary":"Send Golden Records To Bloomreach","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"planId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"after":{"type":"string","format":"uuid","description":"The cursor a previous page returned: start after this golden record id."},"limit":{"type":"integer","minimum":1,"maximum":500,"description":"Golden records per page: 1 to 500, 200 when left out."}}},"example":{"after":"00000000-0000-0000-0000-000000000000","limit":0}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"queued":{"type":"integer"},"skipped":{"type":"integer","description":"Golden records with no value in the hard-id field, or whose hard-id field the caller may not see."},"notRouted":{"type":"integer","description":"Golden records this project's routing rule does not take (design §N.4.2): sent to no project here."},"nextCursor":{"type":"string","format":"uuid","nullable":true,"description":"Pass as `after` for the next page; null when this was the last."}},"required":["queued","skipped","notRouted","nextCursor"]},"example":{"queued":0,"skipped":0,"notRouted":0,"nextCursor":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/setup/options":{"get":{"operationId":"GetBloomreachSetupOptions","tags":["bloomreach"],"summary":"Get Bloomreach Setup Options","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","nullable":true,"description":"The Engagement connection, or null when none is connected."},"golden":{"type":"array","items":{"type":"object","properties":{"entityType":{"type":"string"},"records":{"type":"integer"},"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"sensitivity":{"type":"string","nullable":true},"visible":{"type":"boolean","description":"False when the caller's role may not see this field; it cannot be chosen."},"label":{"type":"string","description":"What the field holds when its name does not say: for a source_ids.<key> part, which connected system's own id for the record it is."}},"required":["name","sensitivity","visible"]}}},"required":["entityType","records","fields"]}},"sources":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"name":{"type":"string"},"label":{"type":"string","description":"What its events carry in the `source` property unless the person gives another: the system's library key, or its name."},"entities":{"type":"array","items":{"type":"object","properties":{"apiName":{"type":"string"},"displayName":{"type":"string"},"fields":{"type":"array","items":{"type":"object","properties":{"apiName":{"type":"string"},"displayName":{"type":"string"},"type":{"type":"string"},"sensitivity":{"type":"string","nullable":true},"itemFields":{"type":"array","items":{"type":"object","properties":{"apiName":{"type":"string"},"displayName":{"type":"string"},"type":{"type":"string"},"sensitivity":{"type":"string","nullable":true},"role":{"type":"string","nullable":true,"description":"Its semantic role as inference set it; `primary-key` marks the field each line is known by."}},"required":["apiName","displayName","type","sensitivity","role"]},"description":"2026-10-28: present when the field is a list of records (an order's lines: an array with a hasMany edge to another object): the fields of each element, which an event source may send as events of their own (lineItems)."}},"required":["apiName","displayName","type","sensitivity"]}}},"required":["apiName","displayName","fields"]}}},"required":["connectionId","name","label","entities"]}},"consent":{"type":"object","properties":{"categories":{"type":"array","items":{"type":"string"},"nullable":true},"categoriesProblem":{"type":"string","nullable":true},"confirmMapping":{"type":"boolean"},"defaultValidUntil":{"type":"string"}},"required":["categories","categoriesProblem","confirmMapping","defaultValidUntil"],"nullable":true,"description":"Phase 10: for a consent source, the project's consent categories (read from Bloomreach, needs no permission; null with categoriesProblem when they could not be read) and the workspace's consent settings (bloomreach.consentConfirmMapping, bloomreach.consentDefaultValidUntil). Null when no Engagement connection exists."}},"required":["connectionId","golden","sources","consent"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","golden":[{"entityType":"string","records":0,"fields":[{"name":"string","sensitivity":"string","visible":true,"label":"string"}]}],"sources":[{"connectionId":"00000000-0000-0000-0000-000000000000","name":"string","label":"string","entities":[{"apiName":"string","displayName":"string","fields":[{"apiName":"string","displayName":"string","type":"string","sensitivity":"string","itemFields":[{"apiName":"string","displayName":"string","type":"string","sensitivity":"string","role":"string"}]}]}]}],"consent":{"categories":["string"],"categoriesProblem":"string","confirmMapping":true,"defaultValidUntil":"string"}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/site-tags":{"get":{"operationId":"ListBloomreachSiteTags","tags":["bloomreach"],"summary":"List Bloomreach Site Tags","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"maxSites":{"type":"integer"},"sites":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"siteKey":{"type":"string","description":"128 random bits, hex: public, in the tag."},"label":{"type":"string"},"origins":{"type":"array","items":{"type":"string"}},"mode":{"type":"string","description":"floating (pinned mode is phase P5)."},"currentVersion":{"type":"integer","nullable":true},"current":{"type":"object","properties":{"number":{"type":"integer"},"state":{"type":"string","enum":["draft","approved","superseded","declined"]},"config":{"type":"object","additionalProperties":true,"description":"The configuration (see SaveBloomreachSiteTagDraft), with the values Inferrex owns set: siteKey, global, sdk.token, sdk.target, sdk.track.default_properties, identifyIds."},"loader":{"type":"object","properties":{"snippetVersion":{"type":"string"},"sha384":{"type":"string"}},"required":["snippetVersion","sha384"],"nullable":true},"runtimeVersion":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdVia":{"type":"string","nullable":true,"description":"The agent that proposed it; null for a person in the app."},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decidedBy":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}},"required":["number","state","config","loader","runtimeVersion","createdAt","createdBy","createdVia","decidedAt","decidedBy","note"],"nullable":true,"description":"The approved version in force, or null."},"draft":{"type":"object","properties":{"number":{"type":"integer"},"state":{"type":"string","enum":["draft","approved","superseded","declined"]},"config":{"type":"object","additionalProperties":true,"description":"The configuration (see SaveBloomreachSiteTagDraft), with the values Inferrex owns set: siteKey, global, sdk.token, sdk.target, sdk.track.default_properties, identifyIds."},"loader":{"type":"object","properties":{"snippetVersion":{"type":"string"},"sha384":{"type":"string"}},"required":["snippetVersion","sha384"],"nullable":true},"runtimeVersion":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdVia":{"type":"string","nullable":true,"description":"The agent that proposed it; null for a person in the app."},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decidedBy":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}},"required":["number","state","config","loader","runtimeVersion","createdAt","createdBy","createdVia","decidedAt","decidedBy","note"],"nullable":true,"description":"The draft waiting for approval, or null."},"diff":{"type":"object","additionalProperties":true,"nullable":true,"description":"What the draft changes against the version in force: { bindings: { added, changed: [{ before, after }], removed }, events: { added, removed, changed }, settings: [{ path, before, after }], loader: { before, after } | null, runtime: { before, after } | null }."},"blockers":{"type":"array","items":{"type":"string"},"description":"What still stops the draft being approved."},"versions":{"type":"array","items":{"type":"object","properties":{"number":{"type":"integer"},"state":{"type":"string","enum":["draft","approved","superseded","declined"]},"runtimeVersion":{"type":"string"},"loaderVersion":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdVia":{"type":"string","nullable":true},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decidedBy":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}},"required":["number","state","runtimeVersion","loaderVersion","createdAt","createdBy","createdVia","decidedAt","decidedBy","note"]}},"runtime":{"type":"object","properties":{"version":{"type":"string"},"bytes":{"type":"integer","description":"The runtime's size, UTF-8 (design §P.7.6)."}},"required":["version","bytes"]}},"required":["connectionId","siteKey","label","origins","mode","currentVersion","current","draft","diff","blockers","versions","runtime"]}}},"required":["connectionId","maxSites","sites"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","maxSites":0,"sites":[{"connectionId":"00000000-0000-0000-0000-000000000000","siteKey":"string","label":"string","origins":["string"],"mode":"string","currentVersion":0,"current":{"number":0,"state":"draft","config":{},"loader":{"snippetVersion":"string","sha384":"string"},"runtimeVersion":"string","createdAt":"2026-01-01T00:00:00Z","createdBy":"string","createdVia":"string","decidedAt":"2026-01-01T00:00:00Z","decidedBy":"string","note":"string"},"draft":{"number":0,"state":"draft","config":{},"loader":{"snippetVersion":"string","sha384":"string"},"runtimeVersion":"string","createdAt":"2026-01-01T00:00:00Z","createdBy":"string","createdVia":"string","decidedAt":"2026-01-01T00:00:00Z","decidedBy":"string","note":"string"},"diff":{},"blockers":["string"],"versions":[{"number":0,"state":"draft","runtimeVersion":"string","loaderVersion":"string","createdAt":"2026-01-01T00:00:00Z","createdBy":"string","createdVia":"string","decidedAt":"2026-01-01T00:00:00Z","decidedBy":"string","note":"string"}],"runtime":{"version":"string","bytes":0}}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"CreateBloomreachSiteTag","tags":["bloomreach"],"summary":"Create Bloomreach Site Tag","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":100,"description":"The site's name and the \"source\" value on its events, like a connected system's label (no \".\" or \"$\")."},"origins":{"type":"array","items":{"type":"string"},"description":"The https addresses the site runs on (1 to 20), such as \"https://shop.example\". No path."}},"required":["label","origins"]},"example":{"label":"string","origins":["string"]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"siteKey":{"type":"string","description":"128 random bits, hex: public, in the tag."},"label":{"type":"string"},"origins":{"type":"array","items":{"type":"string"}},"mode":{"type":"string","description":"floating (pinned mode is phase P5)."},"currentVersion":{"type":"integer","nullable":true},"current":{"type":"object","properties":{"number":{"type":"integer"},"state":{"type":"string","enum":["draft","approved","superseded","declined"]},"config":{"type":"object","additionalProperties":true,"description":"The configuration (see SaveBloomreachSiteTagDraft), with the values Inferrex owns set: siteKey, global, sdk.token, sdk.target, sdk.track.default_properties, identifyIds."},"loader":{"type":"object","properties":{"snippetVersion":{"type":"string"},"sha384":{"type":"string"}},"required":["snippetVersion","sha384"],"nullable":true},"runtimeVersion":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdVia":{"type":"string","nullable":true,"description":"The agent that proposed it; null for a person in the app."},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decidedBy":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}},"required":["number","state","config","loader","runtimeVersion","createdAt","createdBy","createdVia","decidedAt","decidedBy","note"],"nullable":true,"description":"The approved version in force, or null."},"draft":{"type":"object","properties":{"number":{"type":"integer"},"state":{"type":"string","enum":["draft","approved","superseded","declined"]},"config":{"type":"object","additionalProperties":true,"description":"The configuration (see SaveBloomreachSiteTagDraft), with the values Inferrex owns set: siteKey, global, sdk.token, sdk.target, sdk.track.default_properties, identifyIds."},"loader":{"type":"object","properties":{"snippetVersion":{"type":"string"},"sha384":{"type":"string"}},"required":["snippetVersion","sha384"],"nullable":true},"runtimeVersion":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdVia":{"type":"string","nullable":true,"description":"The agent that proposed it; null for a person in the app."},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decidedBy":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}},"required":["number","state","config","loader","runtimeVersion","createdAt","createdBy","createdVia","decidedAt","decidedBy","note"],"nullable":true,"description":"The draft waiting for approval, or null."},"diff":{"type":"object","additionalProperties":true,"nullable":true,"description":"What the draft changes against the version in force: { bindings: { added, changed: [{ before, after }], removed }, events: { added, removed, changed }, settings: [{ path, before, after }], loader: { before, after } | null, runtime: { before, after } | null }."},"blockers":{"type":"array","items":{"type":"string"},"description":"What still stops the draft being approved."},"versions":{"type":"array","items":{"type":"object","properties":{"number":{"type":"integer"},"state":{"type":"string","enum":["draft","approved","superseded","declined"]},"runtimeVersion":{"type":"string"},"loaderVersion":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdVia":{"type":"string","nullable":true},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decidedBy":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}},"required":["number","state","runtimeVersion","loaderVersion","createdAt","createdBy","createdVia","decidedAt","decidedBy","note"]}},"runtime":{"type":"object","properties":{"version":{"type":"string"},"bytes":{"type":"integer","description":"The runtime's size, UTF-8 (design §P.7.6)."}},"required":["version","bytes"]},"warnings":{"type":"array","items":{"type":"string"}}},"required":["connectionId","siteKey","label","origins","mode","currentVersion","current","draft","diff","blockers","versions","runtime","warnings"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","siteKey":"string","label":"string","origins":["string"],"mode":"string","currentVersion":0,"current":{"number":0,"state":"draft","config":{},"loader":{"snippetVersion":"string","sha384":"string"},"runtimeVersion":"string","createdAt":"2026-01-01T00:00:00Z","createdBy":"string","createdVia":"string","decidedAt":"2026-01-01T00:00:00Z","decidedBy":"string","note":"string"},"draft":{"number":0,"state":"draft","config":{},"loader":{"snippetVersion":"string","sha384":"string"},"runtimeVersion":"string","createdAt":"2026-01-01T00:00:00Z","createdBy":"string","createdVia":"string","decidedAt":"2026-01-01T00:00:00Z","decidedBy":"string","note":"string"},"diff":{},"blockers":["string"],"versions":[{"number":0,"state":"draft","runtimeVersion":"string","loaderVersion":"string","createdAt":"2026-01-01T00:00:00Z","createdBy":"string","createdVia":"string","decidedAt":"2026-01-01T00:00:00Z","decidedBy":"string","note":"string"}],"runtime":{"version":"string","bytes":0},"warnings":["string"]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/site-tags/{siteKey}":{"put":{"operationId":"SaveBloomreachSiteTagDraft","tags":["bloomreach"],"summary":"Save Bloomreach Site Tag Draft","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"siteKey","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"description":"The site's key, as GET /v1/bloomreach/site-tags lists it."},"description":"The site's key, as GET /v1/bloomreach/site-tags lists it."},{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":100},"origins":{"type":"array","items":{"type":"string"}},"config":{"type":"object","additionalProperties":true,"description":"The configuration: { state: \"on\"|\"off\", spa, sdk: { SDK options; token, target and compliance are Inferrex's }, consent: { mode: \"load-after-consent\"|\"sdk-before-consent\", sources: [{ kind: \"google-consent-mode\", type } | { kind: \"data-layer-event\"|\"window-event\", event, field } | { kind: \"site-bus\", object, event, field }] }, events: [{ eventType, properties }], profileFields, bindings: [{ id, trigger: { kind: \"page\", path } | { kind: \"data-layer\"|\"window-event\", event } | { kind: \"site-bus\", object, event } | { kind: \"click\"|\"submit\", selector } | { kind: \"route-change\" }, call: \"track\"|\"identify\"|\"update\", eventType, properties: { name: { from: \"data\", path, transforms } | { from: \"constant\", value, transforms } } }] }. Transforms: trim, lowercase-email, number, iso-date, { first: N }, { map: {…} }."}},"required":["config"]},"example":{"label":"string","origins":["string"],"config":{}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"siteKey":{"type":"string","description":"128 random bits, hex: public, in the tag."},"label":{"type":"string"},"origins":{"type":"array","items":{"type":"string"}},"mode":{"type":"string","description":"floating (pinned mode is phase P5)."},"currentVersion":{"type":"integer","nullable":true},"current":{"type":"object","properties":{"number":{"type":"integer"},"state":{"type":"string","enum":["draft","approved","superseded","declined"]},"config":{"type":"object","additionalProperties":true,"description":"The configuration (see SaveBloomreachSiteTagDraft), with the values Inferrex owns set: siteKey, global, sdk.token, sdk.target, sdk.track.default_properties, identifyIds."},"loader":{"type":"object","properties":{"snippetVersion":{"type":"string"},"sha384":{"type":"string"}},"required":["snippetVersion","sha384"],"nullable":true},"runtimeVersion":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdVia":{"type":"string","nullable":true,"description":"The agent that proposed it; null for a person in the app."},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decidedBy":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}},"required":["number","state","config","loader","runtimeVersion","createdAt","createdBy","createdVia","decidedAt","decidedBy","note"],"nullable":true,"description":"The approved version in force, or null."},"draft":{"type":"object","properties":{"number":{"type":"integer"},"state":{"type":"string","enum":["draft","approved","superseded","declined"]},"config":{"type":"object","additionalProperties":true,"description":"The configuration (see SaveBloomreachSiteTagDraft), with the values Inferrex owns set: siteKey, global, sdk.token, sdk.target, sdk.track.default_properties, identifyIds."},"loader":{"type":"object","properties":{"snippetVersion":{"type":"string"},"sha384":{"type":"string"}},"required":["snippetVersion","sha384"],"nullable":true},"runtimeVersion":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdVia":{"type":"string","nullable":true,"description":"The agent that proposed it; null for a person in the app."},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decidedBy":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}},"required":["number","state","config","loader","runtimeVersion","createdAt","createdBy","createdVia","decidedAt","decidedBy","note"],"nullable":true,"description":"The draft waiting for approval, or null."},"diff":{"type":"object","additionalProperties":true,"nullable":true,"description":"What the draft changes against the version in force: { bindings: { added, changed: [{ before, after }], removed }, events: { added, removed, changed }, settings: [{ path, before, after }], loader: { before, after } | null, runtime: { before, after } | null }."},"blockers":{"type":"array","items":{"type":"string"},"description":"What still stops the draft being approved."},"versions":{"type":"array","items":{"type":"object","properties":{"number":{"type":"integer"},"state":{"type":"string","enum":["draft","approved","superseded","declined"]},"runtimeVersion":{"type":"string"},"loaderVersion":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdVia":{"type":"string","nullable":true},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decidedBy":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}},"required":["number","state","runtimeVersion","loaderVersion","createdAt","createdBy","createdVia","decidedAt","decidedBy","note"]}},"runtime":{"type":"object","properties":{"version":{"type":"string"},"bytes":{"type":"integer","description":"The runtime's size, UTF-8 (design §P.7.6)."}},"required":["version","bytes"]}},"required":["connectionId","siteKey","label","origins","mode","currentVersion","current","draft","diff","blockers","versions","runtime"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","siteKey":"string","label":"string","origins":["string"],"mode":"string","currentVersion":0,"current":{"number":0,"state":"draft","config":{},"loader":{"snippetVersion":"string","sha384":"string"},"runtimeVersion":"string","createdAt":"2026-01-01T00:00:00Z","createdBy":"string","createdVia":"string","decidedAt":"2026-01-01T00:00:00Z","decidedBy":"string","note":"string"},"draft":{"number":0,"state":"draft","config":{},"loader":{"snippetVersion":"string","sha384":"string"},"runtimeVersion":"string","createdAt":"2026-01-01T00:00:00Z","createdBy":"string","createdVia":"string","decidedAt":"2026-01-01T00:00:00Z","decidedBy":"string","note":"string"},"diff":{},"blockers":["string"],"versions":[{"number":0,"state":"draft","runtimeVersion":"string","loaderVersion":"string","createdAt":"2026-01-01T00:00:00Z","createdBy":"string","createdVia":"string","decidedAt":"2026-01-01T00:00:00Z","decidedBy":"string","note":"string"}],"runtime":{"version":"string","bytes":0}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/site-tags/{siteKey}/approve":{"post":{"operationId":"ApproveBloomreachSiteTag","tags":["bloomreach"],"summary":"Approve Bloomreach Site Tag","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"siteKey","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32}},{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmedVersion":{"type":"integer","minimum":1,"description":"The draft's version number, as the person reviewed it."}},"required":["confirmedVersion"]},"example":{"confirmedVersion":0}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"siteKey":{"type":"string","description":"128 random bits, hex: public, in the tag."},"label":{"type":"string"},"origins":{"type":"array","items":{"type":"string"}},"mode":{"type":"string","description":"floating (pinned mode is phase P5)."},"currentVersion":{"type":"integer","nullable":true},"current":{"type":"object","properties":{"number":{"type":"integer"},"state":{"type":"string","enum":["draft","approved","superseded","declined"]},"config":{"type":"object","additionalProperties":true,"description":"The configuration (see SaveBloomreachSiteTagDraft), with the values Inferrex owns set: siteKey, global, sdk.token, sdk.target, sdk.track.default_properties, identifyIds."},"loader":{"type":"object","properties":{"snippetVersion":{"type":"string"},"sha384":{"type":"string"}},"required":["snippetVersion","sha384"],"nullable":true},"runtimeVersion":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdVia":{"type":"string","nullable":true,"description":"The agent that proposed it; null for a person in the app."},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decidedBy":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}},"required":["number","state","config","loader","runtimeVersion","createdAt","createdBy","createdVia","decidedAt","decidedBy","note"],"nullable":true,"description":"The approved version in force, or null."},"draft":{"type":"object","properties":{"number":{"type":"integer"},"state":{"type":"string","enum":["draft","approved","superseded","declined"]},"config":{"type":"object","additionalProperties":true,"description":"The configuration (see SaveBloomreachSiteTagDraft), with the values Inferrex owns set: siteKey, global, sdk.token, sdk.target, sdk.track.default_properties, identifyIds."},"loader":{"type":"object","properties":{"snippetVersion":{"type":"string"},"sha384":{"type":"string"}},"required":["snippetVersion","sha384"],"nullable":true},"runtimeVersion":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdVia":{"type":"string","nullable":true,"description":"The agent that proposed it; null for a person in the app."},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decidedBy":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}},"required":["number","state","config","loader","runtimeVersion","createdAt","createdBy","createdVia","decidedAt","decidedBy","note"],"nullable":true,"description":"The draft waiting for approval, or null."},"diff":{"type":"object","additionalProperties":true,"nullable":true,"description":"What the draft changes against the version in force: { bindings: { added, changed: [{ before, after }], removed }, events: { added, removed, changed }, settings: [{ path, before, after }], loader: { before, after } | null, runtime: { before, after } | null }."},"blockers":{"type":"array","items":{"type":"string"},"description":"What still stops the draft being approved."},"versions":{"type":"array","items":{"type":"object","properties":{"number":{"type":"integer"},"state":{"type":"string","enum":["draft","approved","superseded","declined"]},"runtimeVersion":{"type":"string"},"loaderVersion":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdVia":{"type":"string","nullable":true},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decidedBy":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}},"required":["number","state","runtimeVersion","loaderVersion","createdAt","createdBy","createdVia","decidedAt","decidedBy","note"]}},"runtime":{"type":"object","properties":{"version":{"type":"string"},"bytes":{"type":"integer","description":"The runtime's size, UTF-8 (design §P.7.6)."}},"required":["version","bytes"]}},"required":["connectionId","siteKey","label","origins","mode","currentVersion","current","draft","diff","blockers","versions","runtime"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","siteKey":"string","label":"string","origins":["string"],"mode":"string","currentVersion":0,"current":{"number":0,"state":"draft","config":{},"loader":{"snippetVersion":"string","sha384":"string"},"runtimeVersion":"string","createdAt":"2026-01-01T00:00:00Z","createdBy":"string","createdVia":"string","decidedAt":"2026-01-01T00:00:00Z","decidedBy":"string","note":"string"},"draft":{"number":0,"state":"draft","config":{},"loader":{"snippetVersion":"string","sha384":"string"},"runtimeVersion":"string","createdAt":"2026-01-01T00:00:00Z","createdBy":"string","createdVia":"string","decidedAt":"2026-01-01T00:00:00Z","decidedBy":"string","note":"string"},"diff":{},"blockers":["string"],"versions":[{"number":0,"state":"draft","runtimeVersion":"string","loaderVersion":"string","createdAt":"2026-01-01T00:00:00Z","createdBy":"string","createdVia":"string","decidedAt":"2026-01-01T00:00:00Z","decidedBy":"string","note":"string"}],"runtime":{"version":"string","bytes":0}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/site-tags/{siteKey}/decline":{"post":{"operationId":"DeclineBloomreachSiteTagDraft","tags":["bloomreach"],"summary":"Decline Bloomreach Site Tag Draft","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"siteKey","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32}},{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"integer","minimum":1,"description":"The draft's version number."},"note":{"type":"string","maxLength":500}},"required":["version"]},"example":{"version":0,"note":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"siteKey":{"type":"string","description":"128 random bits, hex: public, in the tag."},"label":{"type":"string"},"origins":{"type":"array","items":{"type":"string"}},"mode":{"type":"string","description":"floating (pinned mode is phase P5)."},"currentVersion":{"type":"integer","nullable":true},"current":{"type":"object","properties":{"number":{"type":"integer"},"state":{"type":"string","enum":["draft","approved","superseded","declined"]},"config":{"type":"object","additionalProperties":true,"description":"The configuration (see SaveBloomreachSiteTagDraft), with the values Inferrex owns set: siteKey, global, sdk.token, sdk.target, sdk.track.default_properties, identifyIds."},"loader":{"type":"object","properties":{"snippetVersion":{"type":"string"},"sha384":{"type":"string"}},"required":["snippetVersion","sha384"],"nullable":true},"runtimeVersion":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdVia":{"type":"string","nullable":true,"description":"The agent that proposed it; null for a person in the app."},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decidedBy":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}},"required":["number","state","config","loader","runtimeVersion","createdAt","createdBy","createdVia","decidedAt","decidedBy","note"],"nullable":true,"description":"The approved version in force, or null."},"draft":{"type":"object","properties":{"number":{"type":"integer"},"state":{"type":"string","enum":["draft","approved","superseded","declined"]},"config":{"type":"object","additionalProperties":true,"description":"The configuration (see SaveBloomreachSiteTagDraft), with the values Inferrex owns set: siteKey, global, sdk.token, sdk.target, sdk.track.default_properties, identifyIds."},"loader":{"type":"object","properties":{"snippetVersion":{"type":"string"},"sha384":{"type":"string"}},"required":["snippetVersion","sha384"],"nullable":true},"runtimeVersion":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdVia":{"type":"string","nullable":true,"description":"The agent that proposed it; null for a person in the app."},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decidedBy":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}},"required":["number","state","config","loader","runtimeVersion","createdAt","createdBy","createdVia","decidedAt","decidedBy","note"],"nullable":true,"description":"The draft waiting for approval, or null."},"diff":{"type":"object","additionalProperties":true,"nullable":true,"description":"What the draft changes against the version in force: { bindings: { added, changed: [{ before, after }], removed }, events: { added, removed, changed }, settings: [{ path, before, after }], loader: { before, after } | null, runtime: { before, after } | null }."},"blockers":{"type":"array","items":{"type":"string"},"description":"What still stops the draft being approved."},"versions":{"type":"array","items":{"type":"object","properties":{"number":{"type":"integer"},"state":{"type":"string","enum":["draft","approved","superseded","declined"]},"runtimeVersion":{"type":"string"},"loaderVersion":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdVia":{"type":"string","nullable":true},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decidedBy":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}},"required":["number","state","runtimeVersion","loaderVersion","createdAt","createdBy","createdVia","decidedAt","decidedBy","note"]}},"runtime":{"type":"object","properties":{"version":{"type":"string"},"bytes":{"type":"integer","description":"The runtime's size, UTF-8 (design §P.7.6)."}},"required":["version","bytes"]}},"required":["connectionId","siteKey","label","origins","mode","currentVersion","current","draft","diff","blockers","versions","runtime"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","siteKey":"string","label":"string","origins":["string"],"mode":"string","currentVersion":0,"current":{"number":0,"state":"draft","config":{},"loader":{"snippetVersion":"string","sha384":"string"},"runtimeVersion":"string","createdAt":"2026-01-01T00:00:00Z","createdBy":"string","createdVia":"string","decidedAt":"2026-01-01T00:00:00Z","decidedBy":"string","note":"string"},"draft":{"number":0,"state":"draft","config":{},"loader":{"snippetVersion":"string","sha384":"string"},"runtimeVersion":"string","createdAt":"2026-01-01T00:00:00Z","createdBy":"string","createdVia":"string","decidedAt":"2026-01-01T00:00:00Z","decidedBy":"string","note":"string"},"diff":{},"blockers":["string"],"versions":[{"number":0,"state":"draft","runtimeVersion":"string","loaderVersion":"string","createdAt":"2026-01-01T00:00:00Z","createdBy":"string","createdVia":"string","decidedAt":"2026-01-01T00:00:00Z","decidedBy":"string","note":"string"}],"runtime":{"version":"string","bytes":0}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/site-tags/{siteKey}/file":{"get":{"operationId":"DownloadBloomreachSiteTagFile","tags":["bloomreach"],"summary":"Download Bloomreach Site Tag File","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"siteKey","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32}},{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"siteKey":{"type":"string"},"version":{"type":"integer"},"runtimeVersion":{"type":"string"},"loader":{"type":"object","properties":{"snippetVersion":{"type":"string"},"sha384":{"type":"string"}},"required":["snippetVersion","sha384"],"nullable":true},"fileName":{"type":"string"},"content":{"type":"string","description":"The JavaScript file."},"bytes":{"type":"integer"},"sha384":{"type":"string","description":"SHA-384 of the file, hex."},"runtimeBytes":{"type":"integer"},"generatedAt":{"type":"string","format":"date-time"}},"required":["connectionId","siteKey","version","runtimeVersion","loader","fileName","content","bytes","sha384","runtimeBytes","generatedAt"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","siteKey":"string","version":0,"runtimeVersion":"string","loader":{"snippetVersion":"string","sha384":"string"},"fileName":"string","content":"string","bytes":0,"sha384":"string","runtimeBytes":0,"generatedAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/site-tags/{siteKey}/loader":{"post":{"operationId":"PasteBloomreachSiteTagLoader","tags":["bloomreach"],"summary":"Paste Bloomreach Site Tag Loader","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"siteKey","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32}},{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":200000,"description":"The pasted text: <script> and <style> blocks as Bloomreach shows them, or the configuration object (JSON or a JavaScript object literal)."}},"required":["text"]},"example":{"text":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"siteKey":{"type":"string","description":"128 random bits, hex: public, in the tag."},"label":{"type":"string"},"origins":{"type":"array","items":{"type":"string"}},"mode":{"type":"string","description":"floating (pinned mode is phase P5)."},"currentVersion":{"type":"integer","nullable":true},"current":{"type":"object","properties":{"number":{"type":"integer"},"state":{"type":"string","enum":["draft","approved","superseded","declined"]},"config":{"type":"object","additionalProperties":true,"description":"The configuration (see SaveBloomreachSiteTagDraft), with the values Inferrex owns set: siteKey, global, sdk.token, sdk.target, sdk.track.default_properties, identifyIds."},"loader":{"type":"object","properties":{"snippetVersion":{"type":"string"},"sha384":{"type":"string"}},"required":["snippetVersion","sha384"],"nullable":true},"runtimeVersion":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdVia":{"type":"string","nullable":true,"description":"The agent that proposed it; null for a person in the app."},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decidedBy":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}},"required":["number","state","config","loader","runtimeVersion","createdAt","createdBy","createdVia","decidedAt","decidedBy","note"],"nullable":true,"description":"The approved version in force, or null."},"draft":{"type":"object","properties":{"number":{"type":"integer"},"state":{"type":"string","enum":["draft","approved","superseded","declined"]},"config":{"type":"object","additionalProperties":true,"description":"The configuration (see SaveBloomreachSiteTagDraft), with the values Inferrex owns set: siteKey, global, sdk.token, sdk.target, sdk.track.default_properties, identifyIds."},"loader":{"type":"object","properties":{"snippetVersion":{"type":"string"},"sha384":{"type":"string"}},"required":["snippetVersion","sha384"],"nullable":true},"runtimeVersion":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdVia":{"type":"string","nullable":true,"description":"The agent that proposed it; null for a person in the app."},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decidedBy":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}},"required":["number","state","config","loader","runtimeVersion","createdAt","createdBy","createdVia","decidedAt","decidedBy","note"],"nullable":true,"description":"The draft waiting for approval, or null."},"diff":{"type":"object","additionalProperties":true,"nullable":true,"description":"What the draft changes against the version in force: { bindings: { added, changed: [{ before, after }], removed }, events: { added, removed, changed }, settings: [{ path, before, after }], loader: { before, after } | null, runtime: { before, after } | null }."},"blockers":{"type":"array","items":{"type":"string"},"description":"What still stops the draft being approved."},"versions":{"type":"array","items":{"type":"object","properties":{"number":{"type":"integer"},"state":{"type":"string","enum":["draft","approved","superseded","declined"]},"runtimeVersion":{"type":"string"},"loaderVersion":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdVia":{"type":"string","nullable":true},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decidedBy":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}},"required":["number","state","runtimeVersion","loaderVersion","createdAt","createdBy","createdVia","decidedAt","decidedBy","note"]}},"runtime":{"type":"object","properties":{"version":{"type":"string"},"bytes":{"type":"integer","description":"The runtime's size, UTF-8 (design §P.7.6)."}},"required":["version","bytes"]},"paste":{"type":"object","properties":{"kind":{"type":"string","enum":["loader","config"]},"snippetVersion":{"type":"string","nullable":true},"sha384":{"type":"string","nullable":true},"replaced":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Values Inferrex owns that the paste held differently: { option, reason }."},"refused":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Options not kept: { option, reason }."},"notData":{"type":"array","items":{"type":"string"},"description":"Configuration keys whose value is not a literal, so not kept."},"dropped":{"type":"object","additionalProperties":true,"description":"{ startCalls, styles, comments }: what was recognised and dropped (the runtime calls start() and applies the hide class itself)."},"consentModeChanged":{"type":"boolean"}},"required":["kind","snippetVersion","sha384","replaced","refused","notData","dropped","consentModeChanged"]}},"required":["connectionId","siteKey","label","origins","mode","currentVersion","current","draft","diff","blockers","versions","runtime","paste"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","siteKey":"string","label":"string","origins":["string"],"mode":"string","currentVersion":0,"current":{"number":0,"state":"draft","config":{},"loader":{"snippetVersion":"string","sha384":"string"},"runtimeVersion":"string","createdAt":"2026-01-01T00:00:00Z","createdBy":"string","createdVia":"string","decidedAt":"2026-01-01T00:00:00Z","decidedBy":"string","note":"string"},"draft":{"number":0,"state":"draft","config":{},"loader":{"snippetVersion":"string","sha384":"string"},"runtimeVersion":"string","createdAt":"2026-01-01T00:00:00Z","createdBy":"string","createdVia":"string","decidedAt":"2026-01-01T00:00:00Z","decidedBy":"string","note":"string"},"diff":{},"blockers":["string"],"versions":[{"number":0,"state":"draft","runtimeVersion":"string","loaderVersion":"string","createdAt":"2026-01-01T00:00:00Z","createdBy":"string","createdVia":"string","decidedAt":"2026-01-01T00:00:00Z","decidedBy":"string","note":"string"}],"runtime":{"version":"string","bytes":0},"paste":{"kind":"loader","snippetVersion":"string","sha384":"string","replaced":[{}],"refused":[{}],"notData":["string"],"dropped":{},"consentModeChanged":true}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/bloomreach/tracking-kit":{"get":{"operationId":"GetBloomreachTrackingKit","tags":["bloomreach"],"summary":"Get Bloomreach Tracking Kit","security":[{"ApiKeyAuth":["bloomreach:read"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:read"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"planId":{"type":"string","format":"uuid","nullable":true,"description":"The plan in force the kit follows, or null when none is applied."},"generatedAt":{"type":"string","format":"date-time"},"flavour":{"type":"string","description":"legacy: the only one built."},"sdk":{"type":"string"},"sharedEventSource":{"type":"string","enum":["per-event-type","website","connected-system"],"description":"The workspace setting: who sends an event both the website and a connected system can send."},"settings":{"type":"object","properties":{"format":{"type":"integer"},"siteLabel":{"type":"string"},"webEvents":{"type":"array","items":{"type":"string"}},"sentBy":{"type":"object","additionalProperties":{"type":"string"}},"profileFields":{"type":"array","items":{"type":"string"}},"secondId":{"type":"string","nullable":true},"spa":{"type":"boolean"},"csp":{"type":"boolean"},"webPush":{"type":"boolean"},"consentViaSdk":{"type":"boolean"},"crossSubdomain":{"type":"boolean","description":"The visitor cookie spans the parent domain (false: the exact host)."}},"required":["format","siteLabel","webEvents","sentBy","profileFields","secondId","spa","csp","webPush","consentViaSdk","crossSubdomain"]},"suggestions":{"type":"object","properties":{"webEvents":{"type":"array","items":{"type":"string"},"description":"Bloomreach's recommended web events and the plan's event types."},"profileFields":{"type":"array","items":{"type":"string"}}},"required":["webEvents","profileFields"]},"web":{"type":"object","properties":{"loader":{"type":"object","properties":{"where":{"type":"string"},"paste":{"type":"string"},"source":{"type":"string"},"readOn":{"type":"string"}},"required":["where","paste","source","readOn"],"description":"Where the tenant copies the loader from: it is never generated."},"configCode":{"type":"string"},"consentCode":{"type":"string"},"identifyCode":{"type":"string"},"updateCode":{"type":"string","nullable":true},"events":{"type":"array","items":{"type":"object","properties":{"eventType":{"type":"string"},"shared":{"type":"boolean","description":"A connected system in the plan sends it too."},"connectedSources":{"type":"array","items":{"type":"string"}},"sentBy":{"type":"string","enum":["website","connected-system","undecided"]},"tracked":{"type":"boolean","description":"The website tracks it (the kit holds its call)."},"properties":{"type":"array","items":{"type":"string"}},"code":{"type":"string","nullable":true},"note":{"type":"string"}},"required":["eventType","shared","connectedSources","sentBy","tracked","properties","code","note"]}},"gtm":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"html":{"type":"string"},"fires":{"type":"string"},"after":{"type":"string","nullable":true}},"required":["name","html","fires","after"]}},"containerFile":{"type":"string","description":"A Google Tag Manager container import file (JSON)."},"fileName":{"type":"string"},"notes":{"type":"array","items":{"type":"string"}}},"required":["tags","containerFile","fileName","notes"]},"serviceWorker":{"type":"object","properties":{"fileName":{"type":"string"},"content":{"type":"string"},"note":{"type":"string"}},"required":["fileName","content","note"],"nullable":true},"options":{"type":"array","items":{"type":"object","properties":{"option":{"type":"string"},"value":{"type":"string"},"why":{"type":"string"},"doc":{"type":"string"}},"required":["option","value","why","doc"]}},"qa":{"type":"array","items":{"type":"object","properties":{"check":{"type":"string"},"source":{"type":"string","nullable":true}},"required":["check","source"]}}},"required":["loader","configCode","consentCode","identifyCode","updateCode","events","gtm","serviceWorker","options","qa"]},"mobile":{"type":"object","properties":{"android":{"type":"string"},"ios":{"type":"string"},"identify":{"type":"string"},"pushSteps":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string"},"steps":{"type":"array","items":{"type":"string"}},"source":{"type":"string"},"readOn":{"type":"string"}},"required":["platform","steps","source","readOn"]}}},"required":["android","ios","identify","pushSteps"]},"publicAccess":{"type":"object","properties":{"web":{"type":"array","items":{"type":"object","properties":{"area":{"type":"string"},"name":{"type":"string"},"permission":{"type":"string"},"why":{"type":"string"}},"required":["area","name","permission","why"]}},"mobile":{"type":"array","items":{"type":"object","properties":{"area":{"type":"string"},"name":{"type":"string"},"permission":{"type":"string"},"why":{"type":"string"}},"required":["area","name","permission","why"]}}},"required":["web","mobile"],"description":"The public key's permissions: one per event and property the website and the apps send."},"warnings":{"type":"array","items":{"type":"string"}},"facts":{"type":"array","items":{"type":"object","properties":{"fact":{"type":"string"},"verified":{"type":"boolean"},"source":{"type":"string"},"readOn":{"type":"string"}},"required":["fact","verified","source","readOn"]},"description":"What Bloomreach's pages say that the kit relies on, each with its page and the date it was read."},"fileName":{"type":"string"},"markdown":{"type":"string"}},"required":["connectionId","planId","generatedAt","flavour","sdk","sharedEventSource","settings","suggestions","web","mobile","publicAccess","warnings","facts","fileName","markdown"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","planId":"00000000-0000-0000-0000-000000000000","generatedAt":"2026-01-01T00:00:00Z","flavour":"string","sdk":"string","sharedEventSource":"per-event-type","settings":{"format":0,"siteLabel":"string","webEvents":["string"],"sentBy":{},"profileFields":["string"],"secondId":"string","spa":true,"csp":true,"webPush":true,"consentViaSdk":true,"crossSubdomain":true},"suggestions":{"webEvents":["string"],"profileFields":["string"]},"web":{"loader":{"where":"string","paste":"string","source":"string","readOn":"string"},"configCode":"string","consentCode":"string","identifyCode":"string","updateCode":"string","events":[{"eventType":"string","shared":true,"connectedSources":["string"],"sentBy":"website","tracked":true,"properties":["string"],"code":"string","note":"string"}],"gtm":{"tags":[{"name":"string","html":"string","fires":"string","after":"string"}],"containerFile":"string","fileName":"string","notes":["string"]},"serviceWorker":{"fileName":"string","content":"string","note":"string"},"options":[{"option":"string","value":"string","why":"string","doc":"string"}],"qa":[{"check":"string","source":"string"}]},"mobile":{"android":"string","ios":"string","identify":"string","pushSteps":[{"platform":"string","steps":["string"],"source":"string","readOn":"string"}]},"publicAccess":{"web":[{"area":"string","name":"string","permission":"string","why":"string"}],"mobile":[{"area":"string","name":"string","permission":"string","why":"string"}]},"warnings":["string"],"facts":[{"fact":"string","verified":true,"source":"string","readOn":"string"}],"fileName":"string","markdown":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"SetBloomreachTrackingKit","tags":["bloomreach"],"summary":"Set Bloomreach Tracking Kit","security":[{"ApiKeyAuth":["bloomreach:write"]},{"BearerAuth":[]},{"OAuth2":["bloomreach:write"]}],"parameters":[{"name":"engagementConnectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},"description":"The Bloomreach Engagement project to act on: its connection id, as GET /v1/bloomreach/connection lists it in `projects`. May be left out while the workspace has one project; with several, a call that names none is refused with 409 engagement_project_required."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"siteLabel":{"type":"string","minLength":1,"maxLength":100,"description":"The value of the \"source\" property on the website's events, like a connected system's label (e.g. \"website\")."},"webEvents":{"type":"array","items":{"type":"string"},"description":"Event types the website tracks (e.g. \"view_item\", \"cart_update\"). A letter, then letters, digits or underscores."},"sentBy":{"type":"object","additionalProperties":{"type":"string"},"description":"For an event a connected system in the setup also sends: \"website\" or \"connected-system\". Read when the workspace setting is to ask per event."},"profileFields":{"type":"array","items":{"type":"string"},"description":"Which of \"email\", \"phone\", \"language\", \"first_name\" and \"last_name\" the website sets. A property the setup already writes is left out."},"secondId":{"type":"string","maxLength":64,"nullable":true,"description":"A second customer id the website also identifies with (it must exist in the project), or null. Never \"inferrex_id\"."},"spa":{"type":"boolean","description":"The website is a single-page app."},"csp":{"type":"boolean","description":"The website has a Content Security Policy."},"webPush":{"type":"boolean","description":"Web push is in scope: the kit adds the service worker file."},"consentViaSdk":{"type":"boolean","description":"The website tracks consent events itself; the source label then goes on each call instead of on every event."},"crossSubdomain":{"type":"boolean","description":"The visitor cookie spans the parent domain and all its subdomains (cookies.cross_subdomain: true). Default false: the cookie stays on the exact host. Set it only when you own the parent domain and every site on it; on a shared parent domain it would give one visitor id to every business there."}},"required":["siteLabel","webEvents","profileFields","spa","csp","webPush","consentViaSdk"]},"example":{"siteLabel":"string","webEvents":["string"],"sentBy":{},"profileFields":["string"],"secondId":"string","spa":true,"csp":true,"webPush":true,"consentViaSdk":true,"crossSubdomain":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"planId":{"type":"string","format":"uuid","nullable":true,"description":"The plan in force the kit follows, or null when none is applied."},"generatedAt":{"type":"string","format":"date-time"},"flavour":{"type":"string","description":"legacy: the only one built."},"sdk":{"type":"string"},"sharedEventSource":{"type":"string","enum":["per-event-type","website","connected-system"],"description":"The workspace setting: who sends an event both the website and a connected system can send."},"settings":{"type":"object","properties":{"format":{"type":"integer"},"siteLabel":{"type":"string"},"webEvents":{"type":"array","items":{"type":"string"}},"sentBy":{"type":"object","additionalProperties":{"type":"string"}},"profileFields":{"type":"array","items":{"type":"string"}},"secondId":{"type":"string","nullable":true},"spa":{"type":"boolean"},"csp":{"type":"boolean"},"webPush":{"type":"boolean"},"consentViaSdk":{"type":"boolean"},"crossSubdomain":{"type":"boolean","description":"The visitor cookie spans the parent domain (false: the exact host)."}},"required":["format","siteLabel","webEvents","sentBy","profileFields","secondId","spa","csp","webPush","consentViaSdk","crossSubdomain"]},"suggestions":{"type":"object","properties":{"webEvents":{"type":"array","items":{"type":"string"},"description":"Bloomreach's recommended web events and the plan's event types."},"profileFields":{"type":"array","items":{"type":"string"}}},"required":["webEvents","profileFields"]},"web":{"type":"object","properties":{"loader":{"type":"object","properties":{"where":{"type":"string"},"paste":{"type":"string"},"source":{"type":"string"},"readOn":{"type":"string"}},"required":["where","paste","source","readOn"],"description":"Where the tenant copies the loader from: it is never generated."},"configCode":{"type":"string"},"consentCode":{"type":"string"},"identifyCode":{"type":"string"},"updateCode":{"type":"string","nullable":true},"events":{"type":"array","items":{"type":"object","properties":{"eventType":{"type":"string"},"shared":{"type":"boolean","description":"A connected system in the plan sends it too."},"connectedSources":{"type":"array","items":{"type":"string"}},"sentBy":{"type":"string","enum":["website","connected-system","undecided"]},"tracked":{"type":"boolean","description":"The website tracks it (the kit holds its call)."},"properties":{"type":"array","items":{"type":"string"}},"code":{"type":"string","nullable":true},"note":{"type":"string"}},"required":["eventType","shared","connectedSources","sentBy","tracked","properties","code","note"]}},"gtm":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"html":{"type":"string"},"fires":{"type":"string"},"after":{"type":"string","nullable":true}},"required":["name","html","fires","after"]}},"containerFile":{"type":"string","description":"A Google Tag Manager container import file (JSON)."},"fileName":{"type":"string"},"notes":{"type":"array","items":{"type":"string"}}},"required":["tags","containerFile","fileName","notes"]},"serviceWorker":{"type":"object","properties":{"fileName":{"type":"string"},"content":{"type":"string"},"note":{"type":"string"}},"required":["fileName","content","note"],"nullable":true},"options":{"type":"array","items":{"type":"object","properties":{"option":{"type":"string"},"value":{"type":"string"},"why":{"type":"string"},"doc":{"type":"string"}},"required":["option","value","why","doc"]}},"qa":{"type":"array","items":{"type":"object","properties":{"check":{"type":"string"},"source":{"type":"string","nullable":true}},"required":["check","source"]}}},"required":["loader","configCode","consentCode","identifyCode","updateCode","events","gtm","serviceWorker","options","qa"]},"mobile":{"type":"object","properties":{"android":{"type":"string"},"ios":{"type":"string"},"identify":{"type":"string"},"pushSteps":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string"},"steps":{"type":"array","items":{"type":"string"}},"source":{"type":"string"},"readOn":{"type":"string"}},"required":["platform","steps","source","readOn"]}}},"required":["android","ios","identify","pushSteps"]},"publicAccess":{"type":"object","properties":{"web":{"type":"array","items":{"type":"object","properties":{"area":{"type":"string"},"name":{"type":"string"},"permission":{"type":"string"},"why":{"type":"string"}},"required":["area","name","permission","why"]}},"mobile":{"type":"array","items":{"type":"object","properties":{"area":{"type":"string"},"name":{"type":"string"},"permission":{"type":"string"},"why":{"type":"string"}},"required":["area","name","permission","why"]}}},"required":["web","mobile"],"description":"The public key's permissions: one per event and property the website and the apps send."},"warnings":{"type":"array","items":{"type":"string"}},"facts":{"type":"array","items":{"type":"object","properties":{"fact":{"type":"string"},"verified":{"type":"boolean"},"source":{"type":"string"},"readOn":{"type":"string"}},"required":["fact","verified","source","readOn"]},"description":"What Bloomreach's pages say that the kit relies on, each with its page and the date it was read."},"fileName":{"type":"string"},"markdown":{"type":"string"}},"required":["connectionId","planId","generatedAt","flavour","sdk","sharedEventSource","settings","suggestions","web","mobile","publicAccess","warnings","facts","fileName","markdown"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","planId":"00000000-0000-0000-0000-000000000000","generatedAt":"2026-01-01T00:00:00Z","flavour":"string","sdk":"string","sharedEventSource":"per-event-type","settings":{"format":0,"siteLabel":"string","webEvents":["string"],"sentBy":{},"profileFields":["string"],"secondId":"string","spa":true,"csp":true,"webPush":true,"consentViaSdk":true,"crossSubdomain":true},"suggestions":{"webEvents":["string"],"profileFields":["string"]},"web":{"loader":{"where":"string","paste":"string","source":"string","readOn":"string"},"configCode":"string","consentCode":"string","identifyCode":"string","updateCode":"string","events":[{"eventType":"string","shared":true,"connectedSources":["string"],"sentBy":"website","tracked":true,"properties":["string"],"code":"string","note":"string"}],"gtm":{"tags":[{"name":"string","html":"string","fires":"string","after":"string"}],"containerFile":"string","fileName":"string","notes":["string"]},"serviceWorker":{"fileName":"string","content":"string","note":"string"},"options":[{"option":"string","value":"string","why":"string","doc":"string"}],"qa":[{"check":"string","source":"string"}]},"mobile":{"android":"string","ios":"string","identify":"string","pushSteps":[{"platform":"string","steps":["string"],"source":"string","readOn":"string"}]},"publicAccess":{"web":[{"area":"string","name":"string","permission":"string","why":"string"}],"mobile":[{"area":"string","name":"string","permission":"string","why":"string"}]},"warnings":["string"],"facts":[{"fact":"string","verified":true,"source":"string","readOn":"string"}],"fileName":"string","markdown":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/canonical-proposals":{"get":{"operationId":"CanonicalChangeProposalsList","tags":["golden_record"],"summary":"Canonical Change Proposals List","security":[{"ApiKeyAuth":["canonical-proposals:read"]},{"BearerAuth":[]},{"OAuth2":["canonical-proposals:read"]}],"description":"List your change proposals, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"entity_cluster_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only change proposals for this entity cluster. Pass its id."},"description":"Only change proposals for this entity cluster. Pass its id."},{"name":"entity_type","in":"query","required":false,"schema":{"type":"string","description":"Only change proposals whose entity type is exactly this."},"description":"Only change proposals whose entity type is exactly this."},{"name":"entity_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only change proposals whose entity type contains this text (upper and lower case are treated the same)."},"description":"Only change proposals whose entity type contains this text (upper and lower case are treated the same)."},{"name":"risk_level","in":"query","required":false,"schema":{"type":"string","description":"Only change proposals whose risk level is exactly this."},"description":"Only change proposals whose risk level is exactly this."},{"name":"risk_level_contains","in":"query","required":false,"schema":{"type":"string","description":"Only change proposals whose risk level contains this text (upper and lower case are treated the same)."},"description":"Only change proposals whose risk level contains this text (upper and lower case are treated the same)."},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Only change proposals whose status is exactly this."},"description":"Only change proposals whose status is exactly this."},{"name":"status_contains","in":"query","required":false,"schema":{"type":"string","description":"Only change proposals whose status contains this text (upper and lower case are treated the same)."},"description":"Only change proposals whose status contains this text (upper and lower case are treated the same)."},{"name":"approved_by","in":"query","required":false,"schema":{"type":"string","description":"Only change proposals whose approved by is exactly this."},"description":"Only change proposals whose approved by is exactly this."},{"name":"approved_by_contains","in":"query","required":false,"schema":{"type":"string","description":"Only change proposals whose approved by contains this text (upper and lower case are treated the same)."},"description":"Only change proposals whose approved by contains this text (upper and lower case are treated the same)."},{"name":"rejected_by","in":"query","required":false,"schema":{"type":"string","description":"Only change proposals whose rejected by is exactly this."},"description":"Only change proposals whose rejected by is exactly this."},{"name":"rejected_by_contains","in":"query","required":false,"schema":{"type":"string","description":"Only change proposals whose rejected by contains this text (upper and lower case are treated the same)."},"description":"Only change proposals whose rejected by contains this text (upper and lower case are treated the same)."},{"name":"rejection_reason","in":"query","required":false,"schema":{"type":"string","description":"Only change proposals whose rejection reason is exactly this."},"description":"Only change proposals whose rejection reason is exactly this."},{"name":"rejection_reason_contains","in":"query","required":false,"schema":{"type":"string","description":"Only change proposals whose rejection reason contains this text (upper and lower case are treated the same)."},"description":"Only change proposals whose rejection reason contains this text (upper and lower case are treated the same)."},{"name":"approved_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only change proposals whose approved time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only change proposals whose approved time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"approved_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only change proposals whose approved time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only change proposals whose approved time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"rejected_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only change proposals whose rejected time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only change proposals whose rejected time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"rejected_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only change proposals whose rejected time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only change proposals whose rejected time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"required_approvers_contains","in":"query","required":false,"schema":{"type":"string"}},{"name":"last_proposed_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only change proposals whose last proposed time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only change proposals whose last proposed time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"last_proposed_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only change proposals whose last proposed time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only change proposals whose last proposed time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many change proposals to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many change proposals to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many change proposals to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many change proposals to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","entity_cluster_id","entity_type","risk_level","status","approved_by","rejected_by","rejection_reason","approved_at","rejected_at","created_at","updated_at","last_proposed_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns change proposals where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns change proposals where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"entity_cluster_id":{"type":"string","format":"uuid"},"entity_type":{"type":"string"},"proposed_payload":{"type":"object","properties":{"fields":{"type":"object","additionalProperties":true,"description":"The merged values, keyed by field name. The customer's own data, so its keys and values are open."},"sourceAttribution":{"type":"object","additionalProperties":{"type":"object","properties":{"provider":{"type":"string","description":"Provider key of the system whose value won."},"connectionId":{"type":"string","format":"uuid","description":"The connection the winning value came from."},"externalId":{"type":"string","description":"The winning record's id in that system (drives write-back). Absent on records merged before 2026-07-04."},"recordVersion":{"type":"integer"},"observedAt":{"type":"string","format":"date-time","description":"When the field was resolved."},"strategy":{"type":"string","description":"The rule that picked the value. Today: provider_wins, freshest, most_complete, most_accurate, manual. Absent before 2026-07-04."},"ruleApplied":{"type":"boolean","description":"An explicit field authority rule matched (false = the default, freshest). Absent before 2026-07-04."},"confidence":{"type":"number","minimum":0,"maximum":1,"description":"Share of systems that agree with the winning value, reduced when contested. Absent before 2026-07-04."},"contested":{"type":"boolean","description":"Systems disagree on this field beyond the conflict threshold. Absent before 2026-07-04."}},"required":["provider","connectionId","recordVersion","observedAt"]},"description":"Per field of the record, keyed by field name: where the value came from."},"qualityScore":{"type":"number","minimum":0,"maximum":100,"description":"Completeness, source diversity and recency, weighted (0–100)."},"fieldCount":{"type":"integer"},"sourceCount":{"type":"integer","description":"Distinct sources (provider + connection) that contributed."},"retirement":{"type":"object","properties":{"reason":{"type":"string","description":"Today: sources_deleted (every record it was built from was deleted in its system), rebuilt (its records now make up other golden records), no_longer_built (not produced, and which records it held is not known). Open."},"members":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"provider":{"type":"string"},"externalId":{"type":"string","description":"The record's id in that system. Absent when the golden record predates source ids (2026-07-04)."},"state":{"type":"string","description":"deleted (no longer held for that system), moved (now part of another golden record, `nowIn`) or unknown."},"nowIn":{"type":"string","format":"uuid","description":"The golden record it now belongs to, when moved."}},"required":["connectionId","provider","state"]},"description":"The source records the golden record names as where its values came from, and what became of each."},"rebuiltAs":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The golden records its records now make up. Empty unless the reason is rebuilt."},"passesDeleteOn":{"type":"boolean","description":"True only when its sources deleted it: approving then passes the delete on to each destination it was sent to, as that destination's delete choice says. A rebuilt record still exists, so nothing is deleted anywhere."},"detectedAt":{"type":"string","format":"date-time"}},"required":["reason","members","rebuiltAs","passesDeleteOn","detectedAt"],"description":"Present when this proposal ARCHIVES the golden record instead of changing it: the build no longer produces it. Approving keeps its values and versions and takes it out of the current golden records; nothing is deleted. Absent on every other proposal."},"edit":{"type":"object","properties":{"kind":{"type":"string","description":"merge, split, restore or archive."},"target":{"type":"string","format":"uuid","description":"The golden record the edit was made on; it keeps its id."},"otherId":{"type":"string","format":"uuid","description":"merge: the golden record merged into the target and archived."},"move":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"sourceType":{"type":"string"},"externalId":{"type":"string"}},"required":["connectionId","sourceType","externalId"]},"description":"split: the source records moved out."},"note":{"type":"string","description":"Why, in the words of whoever proposed it."},"requestedBy":{"type":"string","description":"Who proposed it."},"requestedByUserId":{"type":"string","format":"uuid","nullable":true,"description":"Their workspace membership: they cannot also approve it when the policy names approvers."},"requestedAt":{"type":"string","format":"date-time"},"involved":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Every golden record the edit touches."},"results":{"type":"array","items":{"type":"object","properties":{"entityClusterId":{"type":"string","format":"uuid"},"role":{"type":"string","description":"target (the record the edit is on), moved_out, restored, changed (another record losing or gaining source records) or new. Open."},"isNew":{"type":"boolean"},"members":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"provider":{"type":"string"},"sourceType":{"type":"string","nullable":true},"externalId":{"type":"string"}},"required":["connectionId","provider","sourceType","externalId"]},"description":"The source records it is built from after the edit."},"fieldCount":{"type":"integer"},"fieldsChanged":{"type":"integer","description":"Fields added, changed or removed against its values now."}},"required":["entityClusterId","role","isNew","members","fieldCount","fieldsChanged"]},"description":"The golden records it writes, as planned when it was proposed."},"retires":{"type":"array","items":{"type":"object","properties":{"entityClusterId":{"type":"string","format":"uuid"},"reason":{"type":"string"},"rebuiltAs":{"type":"array","items":{"type":"string","format":"uuid"}}},"required":["entityClusterId","reason","rebuiltAs"]},"description":"Golden records it archives (kept, never deleted)."},"restores":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Archived golden records it brings back."},"links":{"type":"object","properties":{"together":{"type":"integer"},"apart":{"type":"integer"},"revoked":{"type":"integer"}},"required":["together","apart","revoked"],"description":"How many durable links it adds and revokes."}},"required":["kind","target","requestedBy","requestedAt","involved","results","retires","restores","links"],"description":"Present when a PERSON proposed this as a merge, split, restore or archive of golden records, instead of the build proposing new values. Approving re-plans it against the records as they are then and applies it: it writes the links the build keeps from then on, the new values of every golden record it changes, and archives or brings back records (never deleting one). Absent on every other proposal."}},"required":["fields","sourceAttribution","qualityScore","fieldCount","sourceCount"],"description":"The golden record this proposal would write (the \"new values\")."},"field_diffs":{"type":"array","items":{"type":"object","properties":{"fieldName":{"type":"string"},"changeType":{"type":"string","description":"Today: added, changed, removed."},"oldValue":{"description":"The current value. Absent when the field is added."},"newValue":{"description":"The proposed value. Absent when the field is removed."}},"required":["fieldName","changeType"]},"description":"One entry per field that would change."},"conflicts":{"type":"array","items":{"type":"object","properties":{"fieldName":{"type":"string"},"fieldType":{"type":"string","description":"How the values were compared. Today: string (edit distance), numeric (percent difference), other (equality)."},"providerValues":{"type":"array","items":{"type":"object","properties":{"provider":{"type":"string","description":"The system's key: a label to show, never what identifies it. Two connections to one vendor share it."},"connectionId":{"type":"string","format":"uuid","description":"The connection the value came from: what identifies the system (one per connection, never per vendor). Absent on proposals built before 2026-10-31."},"value":{},"observedAt":{"type":"string","format":"date-time"}},"required":["provider","value","observedAt"]},"description":"Every system's value for the field, including ones within the threshold."},"threshold":{"type":"number","description":"The allowed difference: characters for string, percent for numeric, 0 for other."},"distance":{"type":"number","description":"The largest difference between any two values, in the same unit."}},"required":["fieldName","fieldType","providerValues","threshold","distance"]},"description":"One entry per field the connected systems disagree on beyond the threshold."},"impact_analysis":{"type":"object","properties":{"fieldsChanged":{"type":"integer"},"fieldsAdded":{"type":"integer"},"fieldsRemoved":{"type":"integer"},"conflictCount":{"type":"integer"},"providersAffected":{"type":"array","items":{"type":"string"},"description":"Provider keys whose values change, sorted."},"connectionsAffected":{"type":"array","items":{"type":"string"},"description":"The connections whose values change, sorted: two connections to one vendor are two systems (Rule 37). Absent on changes proposed before 2026-11-09."},"qualityScoreDelta":{"type":"number","description":"Proposed quality score minus the current one (0–100 scale)."}},"required":["fieldsChanged","fieldsAdded","fieldsRemoved","conflictCount","providersAffected","qualityScoreDelta"],"description":"Counts of what changes, the systems affected and the quality score change."},"risk_level":{"type":"string"},"metadata":{"type":"object","properties":{"risk":{"type":"object","properties":{"level":{"type":"string","description":"low, medium or high: the level the reasons explain."},"reasons":{"type":"array","items":{"type":"string"}},"score":{"type":"integer","description":"0 to 100. Absent on proposals rated before 2026-11-10."},"components":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","description":"A to H, as golden authority note §6 names them."},"points":{"type":"integer"},"field":{"type":"string"},"text":{"type":"string"}}},"description":"What added to the score, one entry each."},"bands":{"type":"object","properties":{"medium":{"type":"integer"},"high":{"type":"integer"}}}},"description":"Why the proposal has its risk level."}},"description":"What Inferrex recorded about the proposal. `risk`: its level, the reasons, and the 0-100 score with its components and the bands it was read with."},"status":{"type":"string"},"approved_by":{"type":"string","nullable":true},"rejected_by":{"type":"string","nullable":true},"rejection_reason":{"type":"string","nullable":true},"approved_at":{"type":"string","nullable":true},"rejected_at":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"required_approvers":{"type":"array","items":{"type":"string"},"nullable":true,"description":"The roles or teams that must each approve this change, one person per entry, as the approval policies stood when it was proposed."},"last_proposed_at":{"type":"string","nullable":true,"description":"When Inferrex last proposed these values. Empty on older proposals, which were proposed when they were created."},"redacted_fields":{"type":"array","items":{"type":"string"},"description":"Dotted paths (<column>.<path>) of the values hidden from your role: pii, financial, credential or health data your role is not granted. Each is answered as null; the rest of the entry (which field, what kind of change) is still shown. Empty when nothing is hidden."}},"required":["customer_id","entity_cluster_id","entity_type","proposed_payload","redacted_fields"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","entity_cluster_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","proposed_payload":{"fields":{},"sourceAttribution":{},"qualityScore":0,"fieldCount":0,"sourceCount":0,"retirement":{"reason":"string","members":[{"connectionId":"00000000-0000-0000-0000-000000000000","provider":"string","externalId":"string","state":"string","nowIn":"00000000-0000-0000-0000-000000000000"}],"rebuiltAs":["00000000-0000-0000-0000-000000000000"],"passesDeleteOn":true,"detectedAt":"2026-01-01T00:00:00Z"},"edit":{"kind":"string","target":"00000000-0000-0000-0000-000000000000","otherId":"00000000-0000-0000-0000-000000000000","move":[{"connectionId":"00000000-0000-0000-0000-000000000000","sourceType":"string","externalId":"string"}],"note":"string","requestedBy":"string","requestedByUserId":"00000000-0000-0000-0000-000000000000","requestedAt":"2026-01-01T00:00:00Z","involved":["00000000-0000-0000-0000-000000000000"],"results":[{"entityClusterId":"00000000-0000-0000-0000-000000000000","role":"string","isNew":true,"members":[{"connectionId":"00000000-0000-0000-0000-000000000000","provider":"string","sourceType":"string","externalId":"string"}],"fieldCount":0,"fieldsChanged":0}],"retires":[{"entityClusterId":"00000000-0000-0000-0000-000000000000","reason":"string","rebuiltAs":["00000000-0000-0000-0000-000000000000"]}],"restores":["00000000-0000-0000-0000-000000000000"],"links":{"together":0,"apart":0,"revoked":0}}},"field_diffs":[{"fieldName":"string","changeType":"string","oldValue":null,"newValue":null}],"conflicts":[{"fieldName":"string","fieldType":"string","providerValues":[{"provider":"string","connectionId":"00000000-0000-0000-0000-000000000000","value":null,"observedAt":"2026-01-01T00:00:00Z"}],"threshold":0,"distance":0}],"impact_analysis":{"fieldsChanged":0,"fieldsAdded":0,"fieldsRemoved":0,"conflictCount":0,"providersAffected":["string"],"connectionsAffected":["string"],"qualityScoreDelta":0},"risk_level":"string","metadata":{"risk":{"level":"string","reasons":["string"],"score":0,"components":[{"code":"string","points":0,"field":"string","text":"string"}],"bands":{"medium":0,"high":0}}},"status":"string","approved_by":"string","rejected_by":"string","rejection_reason":"string","approved_at":"string","rejected_at":"string","created_at":"string","updated_at":"string","required_approvers":["string"],"last_proposed_at":"string","redacted_fields":["string"]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/canonical-proposals/{id}":{"get":{"operationId":"CanonicalChangeProposalsGet","tags":["golden_record"],"summary":"Canonical Change Proposals Get","security":[{"ApiKeyAuth":["canonical-proposals:read"]},{"BearerAuth":[]},{"OAuth2":["canonical-proposals:read"]}],"description":"Get one of your change proposals by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the change proposal."},"description":"The id of the change proposal."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"entity_cluster_id":{"type":"string","format":"uuid"},"entity_type":{"type":"string"},"proposed_payload":{"type":"object","properties":{"fields":{"type":"object","additionalProperties":true,"description":"The merged values, keyed by field name. The customer's own data, so its keys and values are open."},"sourceAttribution":{"type":"object","additionalProperties":{"type":"object","properties":{"provider":{"type":"string","description":"Provider key of the system whose value won."},"connectionId":{"type":"string","format":"uuid","description":"The connection the winning value came from."},"externalId":{"type":"string","description":"The winning record's id in that system (drives write-back). Absent on records merged before 2026-07-04."},"recordVersion":{"type":"integer"},"observedAt":{"type":"string","format":"date-time","description":"When the field was resolved."},"strategy":{"type":"string","description":"The rule that picked the value. Today: provider_wins, freshest, most_complete, most_accurate, manual. Absent before 2026-07-04."},"ruleApplied":{"type":"boolean","description":"An explicit field authority rule matched (false = the default, freshest). Absent before 2026-07-04."},"confidence":{"type":"number","minimum":0,"maximum":1,"description":"Share of systems that agree with the winning value, reduced when contested. Absent before 2026-07-04."},"contested":{"type":"boolean","description":"Systems disagree on this field beyond the conflict threshold. Absent before 2026-07-04."}},"required":["provider","connectionId","recordVersion","observedAt"]},"description":"Per field of the record, keyed by field name: where the value came from."},"qualityScore":{"type":"number","minimum":0,"maximum":100,"description":"Completeness, source diversity and recency, weighted (0–100)."},"fieldCount":{"type":"integer"},"sourceCount":{"type":"integer","description":"Distinct sources (provider + connection) that contributed."},"retirement":{"type":"object","properties":{"reason":{"type":"string","description":"Today: sources_deleted (every record it was built from was deleted in its system), rebuilt (its records now make up other golden records), no_longer_built (not produced, and which records it held is not known). Open."},"members":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"provider":{"type":"string"},"externalId":{"type":"string","description":"The record's id in that system. Absent when the golden record predates source ids (2026-07-04)."},"state":{"type":"string","description":"deleted (no longer held for that system), moved (now part of another golden record, `nowIn`) or unknown."},"nowIn":{"type":"string","format":"uuid","description":"The golden record it now belongs to, when moved."}},"required":["connectionId","provider","state"]},"description":"The source records the golden record names as where its values came from, and what became of each."},"rebuiltAs":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The golden records its records now make up. Empty unless the reason is rebuilt."},"passesDeleteOn":{"type":"boolean","description":"True only when its sources deleted it: approving then passes the delete on to each destination it was sent to, as that destination's delete choice says. A rebuilt record still exists, so nothing is deleted anywhere."},"detectedAt":{"type":"string","format":"date-time"}},"required":["reason","members","rebuiltAs","passesDeleteOn","detectedAt"],"description":"Present when this proposal ARCHIVES the golden record instead of changing it: the build no longer produces it. Approving keeps its values and versions and takes it out of the current golden records; nothing is deleted. Absent on every other proposal."},"edit":{"type":"object","properties":{"kind":{"type":"string","description":"merge, split, restore or archive."},"target":{"type":"string","format":"uuid","description":"The golden record the edit was made on; it keeps its id."},"otherId":{"type":"string","format":"uuid","description":"merge: the golden record merged into the target and archived."},"move":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"sourceType":{"type":"string"},"externalId":{"type":"string"}},"required":["connectionId","sourceType","externalId"]},"description":"split: the source records moved out."},"note":{"type":"string","description":"Why, in the words of whoever proposed it."},"requestedBy":{"type":"string","description":"Who proposed it."},"requestedByUserId":{"type":"string","format":"uuid","nullable":true,"description":"Their workspace membership: they cannot also approve it when the policy names approvers."},"requestedAt":{"type":"string","format":"date-time"},"involved":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Every golden record the edit touches."},"results":{"type":"array","items":{"type":"object","properties":{"entityClusterId":{"type":"string","format":"uuid"},"role":{"type":"string","description":"target (the record the edit is on), moved_out, restored, changed (another record losing or gaining source records) or new. Open."},"isNew":{"type":"boolean"},"members":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"provider":{"type":"string"},"sourceType":{"type":"string","nullable":true},"externalId":{"type":"string"}},"required":["connectionId","provider","sourceType","externalId"]},"description":"The source records it is built from after the edit."},"fieldCount":{"type":"integer"},"fieldsChanged":{"type":"integer","description":"Fields added, changed or removed against its values now."}},"required":["entityClusterId","role","isNew","members","fieldCount","fieldsChanged"]},"description":"The golden records it writes, as planned when it was proposed."},"retires":{"type":"array","items":{"type":"object","properties":{"entityClusterId":{"type":"string","format":"uuid"},"reason":{"type":"string"},"rebuiltAs":{"type":"array","items":{"type":"string","format":"uuid"}}},"required":["entityClusterId","reason","rebuiltAs"]},"description":"Golden records it archives (kept, never deleted)."},"restores":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Archived golden records it brings back."},"links":{"type":"object","properties":{"together":{"type":"integer"},"apart":{"type":"integer"},"revoked":{"type":"integer"}},"required":["together","apart","revoked"],"description":"How many durable links it adds and revokes."}},"required":["kind","target","requestedBy","requestedAt","involved","results","retires","restores","links"],"description":"Present when a PERSON proposed this as a merge, split, restore or archive of golden records, instead of the build proposing new values. Approving re-plans it against the records as they are then and applies it: it writes the links the build keeps from then on, the new values of every golden record it changes, and archives or brings back records (never deleting one). Absent on every other proposal."}},"required":["fields","sourceAttribution","qualityScore","fieldCount","sourceCount"],"description":"The golden record this proposal would write (the \"new values\")."},"field_diffs":{"type":"array","items":{"type":"object","properties":{"fieldName":{"type":"string"},"changeType":{"type":"string","description":"Today: added, changed, removed."},"oldValue":{"description":"The current value. Absent when the field is added."},"newValue":{"description":"The proposed value. Absent when the field is removed."}},"required":["fieldName","changeType"]},"description":"One entry per field that would change."},"conflicts":{"type":"array","items":{"type":"object","properties":{"fieldName":{"type":"string"},"fieldType":{"type":"string","description":"How the values were compared. Today: string (edit distance), numeric (percent difference), other (equality)."},"providerValues":{"type":"array","items":{"type":"object","properties":{"provider":{"type":"string","description":"The system's key: a label to show, never what identifies it. Two connections to one vendor share it."},"connectionId":{"type":"string","format":"uuid","description":"The connection the value came from: what identifies the system (one per connection, never per vendor). Absent on proposals built before 2026-10-31."},"value":{},"observedAt":{"type":"string","format":"date-time"}},"required":["provider","value","observedAt"]},"description":"Every system's value for the field, including ones within the threshold."},"threshold":{"type":"number","description":"The allowed difference: characters for string, percent for numeric, 0 for other."},"distance":{"type":"number","description":"The largest difference between any two values, in the same unit."}},"required":["fieldName","fieldType","providerValues","threshold","distance"]},"description":"One entry per field the connected systems disagree on beyond the threshold."},"impact_analysis":{"type":"object","properties":{"fieldsChanged":{"type":"integer"},"fieldsAdded":{"type":"integer"},"fieldsRemoved":{"type":"integer"},"conflictCount":{"type":"integer"},"providersAffected":{"type":"array","items":{"type":"string"},"description":"Provider keys whose values change, sorted."},"connectionsAffected":{"type":"array","items":{"type":"string"},"description":"The connections whose values change, sorted: two connections to one vendor are two systems (Rule 37). Absent on changes proposed before 2026-11-09."},"qualityScoreDelta":{"type":"number","description":"Proposed quality score minus the current one (0–100 scale)."}},"required":["fieldsChanged","fieldsAdded","fieldsRemoved","conflictCount","providersAffected","qualityScoreDelta"],"description":"Counts of what changes, the systems affected and the quality score change."},"risk_level":{"type":"string"},"metadata":{"type":"object","properties":{"risk":{"type":"object","properties":{"level":{"type":"string","description":"low, medium or high: the level the reasons explain."},"reasons":{"type":"array","items":{"type":"string"}},"score":{"type":"integer","description":"0 to 100. Absent on proposals rated before 2026-11-10."},"components":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","description":"A to H, as golden authority note §6 names them."},"points":{"type":"integer"},"field":{"type":"string"},"text":{"type":"string"}}},"description":"What added to the score, one entry each."},"bands":{"type":"object","properties":{"medium":{"type":"integer"},"high":{"type":"integer"}}}},"description":"Why the proposal has its risk level."}},"description":"What Inferrex recorded about the proposal. `risk`: its level, the reasons, and the 0-100 score with its components and the bands it was read with."},"status":{"type":"string"},"approved_by":{"type":"string","nullable":true},"rejected_by":{"type":"string","nullable":true},"rejection_reason":{"type":"string","nullable":true},"approved_at":{"type":"string","nullable":true},"rejected_at":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"required_approvers":{"type":"array","items":{"type":"string"},"nullable":true,"description":"The roles or teams that must each approve this change, one person per entry, as the approval policies stood when it was proposed."},"last_proposed_at":{"type":"string","nullable":true,"description":"When Inferrex last proposed these values. Empty on older proposals, which were proposed when they were created."},"redacted_fields":{"type":"array","items":{"type":"string"},"description":"Dotted paths (<column>.<path>) of the values hidden from your role: pii, financial, credential or health data your role is not granted. Each is answered as null; the rest of the entry (which field, what kind of change) is still shown. Empty when nothing is hidden."},"approvals":{"type":"object","properties":{"required":{"type":"array","items":{"type":"string"},"description":"The roles or teams that must each approve, one person per entry (an entry listed twice needs two people). Empty when no approval policy names approvers."},"received":{"type":"array","items":{"type":"object","properties":{"approver":{"type":"string","format":"uuid","nullable":true,"description":"The approving workspace member (workspace_users.id). Null when an API key or OAuth client approved a change that named no approvers."},"role":{"type":"string","nullable":true,"description":"The required entry this approval filled. Null when the change named no approvers."},"decidedAt":{"type":"string","format":"date-time"}},"required":["approver","role","decidedAt"]},"description":"The approvals recorded so far, oldest first."},"satisfied":{"type":"boolean","description":"True once the change has been approved (by people or automatically by a policy), or every required entry is filled."}},"required":["required","received","satisfied"],"description":"Who must approve this change and who has. Each `required` entry names a workspace role or a workspace team. A person fills an entry when it is their role, a role below theirs (owner fills admin), or a team they belong to. The change applies when every entry is filled by a different person, and the person who requested it cannot fill one. An empty `required` means one approval from anyone allowed to approve applies it."}},"required":["customer_id","entity_cluster_id","entity_type","proposed_payload","redacted_fields","approvals"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","entity_cluster_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","proposed_payload":{"fields":{},"sourceAttribution":{},"qualityScore":0,"fieldCount":0,"sourceCount":0,"retirement":{"reason":"string","members":[{"connectionId":"00000000-0000-0000-0000-000000000000","provider":"string","externalId":"string","state":"string","nowIn":"00000000-0000-0000-0000-000000000000"}],"rebuiltAs":["00000000-0000-0000-0000-000000000000"],"passesDeleteOn":true,"detectedAt":"2026-01-01T00:00:00Z"},"edit":{"kind":"string","target":"00000000-0000-0000-0000-000000000000","otherId":"00000000-0000-0000-0000-000000000000","move":[{"connectionId":"00000000-0000-0000-0000-000000000000","sourceType":"string","externalId":"string"}],"note":"string","requestedBy":"string","requestedByUserId":"00000000-0000-0000-0000-000000000000","requestedAt":"2026-01-01T00:00:00Z","involved":["00000000-0000-0000-0000-000000000000"],"results":[{"entityClusterId":"00000000-0000-0000-0000-000000000000","role":"string","isNew":true,"members":[{"connectionId":"00000000-0000-0000-0000-000000000000","provider":"string","sourceType":"string","externalId":"string"}],"fieldCount":0,"fieldsChanged":0}],"retires":[{"entityClusterId":"00000000-0000-0000-0000-000000000000","reason":"string","rebuiltAs":["00000000-0000-0000-0000-000000000000"]}],"restores":["00000000-0000-0000-0000-000000000000"],"links":{"together":0,"apart":0,"revoked":0}}},"field_diffs":[{"fieldName":"string","changeType":"string","oldValue":null,"newValue":null}],"conflicts":[{"fieldName":"string","fieldType":"string","providerValues":[{"provider":"string","connectionId":"00000000-0000-0000-0000-000000000000","value":null,"observedAt":"2026-01-01T00:00:00Z"}],"threshold":0,"distance":0}],"impact_analysis":{"fieldsChanged":0,"fieldsAdded":0,"fieldsRemoved":0,"conflictCount":0,"providersAffected":["string"],"connectionsAffected":["string"],"qualityScoreDelta":0},"risk_level":"string","metadata":{"risk":{"level":"string","reasons":["string"],"score":0,"components":[{"code":"string","points":0,"field":"string","text":"string"}],"bands":{"medium":0,"high":0}}},"status":"string","approved_by":"string","rejected_by":"string","rejection_reason":"string","approved_at":"string","rejected_at":"string","created_at":"string","updated_at":"string","required_approvers":["string"],"last_proposed_at":"string","redacted_fields":["string"],"approvals":{"required":["string"],"received":[{"approver":"00000000-0000-0000-0000-000000000000","role":"string","decidedAt":"2026-01-01T00:00:00Z"}],"satisfied":true}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/canonical-proposals/{id}/approve":{"post":{"operationId":"ApproveProposal","tags":["golden_record"],"summary":"Approve Proposal","security":[{"ApiKeyAuth":["canonical-proposals:write"]},{"BearerAuth":[]},{"OAuth2":["canonical-proposals:write"]}],"description":"Approve a proposed change to a golden record. When approvers are required, your approval is recorded and the change stays pending until every required approver has approved; the final approval applies it: Inferrex writes the golden record and sends the change back to the systems it came from. 403 when your workspace role and teams fill none of the approver places still open; 409 when you have already approved it, it is no longer pending, or it is out of date — a newer proposal exists for the same record (`details.newerProposalId`; review that one instead), or the record changed after it was proposed — because applying it would roll the record back.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the proposed change."},"description":"The id of the proposed change."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","description":"An optional note, kept with the decision."}}},"example":{"notes":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"proposalId":{"type":"string","format":"uuid"},"status":{"type":"string","description":"`approved` when this approval applied the change; `pending` when it still needs other approvers."},"approvedBy":{"type":"string","nullable":true,"description":"Who applied it (the final approver); null while it is still pending."},"approvals":{"type":"object","properties":{"required":{"type":"array","items":{"type":"string"},"description":"The roles or teams that must each approve, one person per entry (an entry listed twice needs two people). Empty when no approval policy names approvers."},"received":{"type":"array","items":{"type":"object","properties":{"approver":{"type":"string","format":"uuid","nullable":true,"description":"The approving workspace member (workspace_users.id). Null when an API key or OAuth client approved a change that named no approvers."},"role":{"type":"string","nullable":true,"description":"The required entry this approval filled. Null when the change named no approvers."},"decidedAt":{"type":"string","format":"date-time"}},"required":["approver","role","decidedAt"]},"description":"The approvals recorded so far, oldest first."},"satisfied":{"type":"boolean","description":"True once the change has been approved (by people or automatically by a policy), or every required entry is filled."}},"required":["required","received","satisfied"],"description":"Who must approve this change and who has. Each `required` entry names a workspace role or a workspace team. A person fills an entry when it is their role, a role below theirs (owner fills admin), or a team they belong to. The change applies when every entry is filled by a different person, and the person who requested it cannot fill one. An empty `required` means one approval from anyone allowed to approve applies it."}},"required":["proposalId","status","approvedBy","approvals"]},"example":{"proposalId":"00000000-0000-0000-0000-000000000000","status":"string","approvedBy":"string","approvals":{"required":["string"],"received":[{"approver":"00000000-0000-0000-0000-000000000000","role":"string","decidedAt":"2026-01-01T00:00:00Z"}],"satisfied":true}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/canonical-proposals/{id}/reject":{"post":{"operationId":"RejectProposal","tags":["golden_record"],"summary":"Reject Proposal","security":[{"ApiKeyAuth":["canonical-proposals:write"]},{"BearerAuth":[]},{"OAuth2":["canonical-proposals:write"]}],"description":"Reject a proposed change to a golden record. Nothing is written. A reason is required.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the proposed change."},"description":"The id of the proposed change."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","description":"Why you are rejecting it."}},"required":["reason"]},"example":{"reason":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"proposalId":{"type":"string","format":"uuid"},"status":{"type":"string"},"rejectedBy":{"type":"string"},"reason":{"type":"string"}},"required":["proposalId","status","rejectedBy","reason"]},"example":{"proposalId":"00000000-0000-0000-0000-000000000000","status":"string","rejectedBy":"string","reason":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/canonical-proposals/bulk-approve":{"post":{"operationId":"BulkApprove","tags":["golden_record"],"summary":"Bulk Approve","security":[{"ApiKeyAuth":["canonical-proposals:write"]},{"BearerAuth":[]},{"OAuth2":["canonical-proposals:write"]}],"description":"Approve several proposed golden-record changes at once. Returns how many were approved, which still need other approvers, and which were skipped because applying them would roll a record back to older values.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"proposalIds":{"type":"array","items":{"type":"string"},"description":"The ids of the proposed changes to approve."}},"required":["proposalIds"]},"example":{"proposalIds":["string"]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"integer","description":"How many changes this call applied."},"failed":{"type":"array","items":{"type":"string"},"description":"Always empty: the batch is one transaction, so a failure fails the whole call."},"pending":{"type":"array","items":{"type":"string"},"description":"Proposals whose approval was recorded but which still need other approvers."},"stale":{"type":"array","items":{"type":"object","properties":{"proposalId":{"type":"string","format":"uuid"},"reason":{"type":"string","description":"`superseded` when a newer proposal exists for the same record; `out_of_date` when the record changed after this proposal was made."},"newerProposalId":{"type":"string","format":"uuid","nullable":true,"description":"The newer proposal for the same record, when there is one."},"newerStatus":{"type":"string","nullable":true,"description":"That newer proposal's status; `pending` means it is the one to review."},"message":{"type":"string","description":"The reason in words."}},"required":["proposalId","reason","newerProposalId","newerStatus","message"]},"description":"Proposals skipped because they are out of date: nothing was applied or recorded for them."}},"required":["approved","failed","pending","stale"]},"example":{"approved":0,"failed":["string"],"pending":["string"],"stale":[{"proposalId":"00000000-0000-0000-0000-000000000000","reason":"string","newerProposalId":"00000000-0000-0000-0000-000000000000","newerStatus":"string","message":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/circuit-breaker-policies":{"get":{"operationId":"CircuitBreakerPoliciesList","tags":["monitoring"],"summary":"Circuit Breaker Policies List","security":[{"ApiKeyAuth":["circuit-breaker-policies:read"]},{"BearerAuth":[]},{"OAuth2":["circuit-breaker-policies:read"]}],"description":"List your circuit breaker policies, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"connection_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only circuit breaker policies for this connection. Pass its id."},"description":"Only circuit breaker policies for this connection. Pass its id."},{"name":"entity_type","in":"query","required":false,"schema":{"type":"string","description":"Only circuit breaker policies whose entity type is exactly this."},"description":"Only circuit breaker policies whose entity type is exactly this."},{"name":"entity_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only circuit breaker policies whose entity type contains this text (upper and lower case are treated the same)."},"description":"Only circuit breaker policies whose entity type contains this text (upper and lower case are treated the same)."},{"name":"rule_type","in":"query","required":false,"schema":{"type":"string","description":"Only circuit breaker policies whose rule type is exactly this."},"description":"Only circuit breaker policies whose rule type is exactly this."},{"name":"rule_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only circuit breaker policies whose rule type contains this text (upper and lower case are treated the same)."},"description":"Only circuit breaker policies whose rule type contains this text (upper and lower case are treated the same)."},{"name":"action","in":"query","required":false,"schema":{"type":"string","description":"Only circuit breaker policies whose action is exactly this."},"description":"Only circuit breaker policies whose action is exactly this."},{"name":"action_contains","in":"query","required":false,"schema":{"type":"string","description":"Only circuit breaker policies whose action contains this text (upper and lower case are treated the same)."},"description":"Only circuit breaker policies whose action contains this text (upper and lower case are treated the same)."},{"name":"auto_resolve_hours_gte","in":"query","required":false,"schema":{"type":"number","description":"Only circuit breaker policies whose auto resolve hours is this number or more."},"description":"Only circuit breaker policies whose auto resolve hours is this number or more."},{"name":"auto_resolve_hours_lte","in":"query","required":false,"schema":{"type":"number","description":"Only circuit breaker policies whose auto resolve hours is this number or less."},"description":"Only circuit breaker policies whose auto resolve hours is this number or less."},{"name":"enabled","in":"query","required":false,"schema":{"type":"boolean","description":"Only circuit breaker policies where enabled is true, or false for only those where it is false."},"description":"Only circuit breaker policies where enabled is true, or false for only those where it is false."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many circuit breaker policies to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many circuit breaker policies to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many circuit breaker policies to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many circuit breaker policies to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","connection_id","entity_type","rule_type","action","auto_resolve_hours","enabled","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns circuit breaker policies where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns circuit breaker policies where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid","nullable":true},"entity_type":{"type":"string","nullable":true},"rule_type":{"type":"string"},"threshold_config":{"type":"object","properties":{"threshold_percent":{"type":"number","description":"Trip when the anomaly passes this percentage of the batch. Every rule but schema_drift needs it; without it the sync detector skips the rule."},"always_trip":{"type":"boolean","description":"schema_drift: trip on any drift."}},"description":"The rule's threshold. The provisioned defaults and the sync detector use these two keys; the API stores whatever object it is sent, so other keys may be present."},"action":{"type":"string"},"auto_resolve_hours":{"type":"integer","nullable":true},"enabled":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","rule_type","threshold_config"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","rule_type":"string","threshold_config":{"threshold_percent":0,"always_trip":true},"action":"string","auto_resolve_hours":0,"enabled":true,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"CircuitBreakerPoliciesCreate","tags":["monitoring"],"summary":"Circuit Breaker Policies Create","security":[{"ApiKeyAuth":["circuit-breaker-policies:write"]},{"BearerAuth":[]},{"OAuth2":["circuit-breaker-policies:write"]}],"description":"Create a circuit breaker policy. Returns the new circuit breaker policy, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connection_id":{"type":"string","format":"uuid","nullable":true},"entity_type":{"type":"string","nullable":true},"rule_type":{"type":"string"},"threshold_config":{"type":"object","additionalProperties":true},"action":{"type":"string"},"auto_resolve_hours":{"type":"integer","nullable":true},"enabled":{"type":"boolean"}},"required":["rule_type","threshold_config"]},"example":{"connection_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","rule_type":"string","threshold_config":{},"action":"string","auto_resolve_hours":0,"enabled":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid","nullable":true},"entity_type":{"type":"string","nullable":true},"rule_type":{"type":"string"},"threshold_config":{"type":"object","properties":{"threshold_percent":{"type":"number","description":"Trip when the anomaly passes this percentage of the batch. Every rule but schema_drift needs it; without it the sync detector skips the rule."},"always_trip":{"type":"boolean","description":"schema_drift: trip on any drift."}},"description":"The rule's threshold. The provisioned defaults and the sync detector use these two keys; the API stores whatever object it is sent, so other keys may be present."},"action":{"type":"string"},"auto_resolve_hours":{"type":"integer","nullable":true},"enabled":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","rule_type","threshold_config"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","rule_type":"string","threshold_config":{"threshold_percent":0,"always_trip":true},"action":"string","auto_resolve_hours":0,"enabled":true,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/circuit-breaker-policies/{id}":{"delete":{"operationId":"CircuitBreakerPoliciesDelete","tags":["monitoring"],"summary":"Circuit Breaker Policies Delete","security":[{"ApiKeyAuth":["circuit-breaker-policies:delete"]},{"BearerAuth":[]},{"OAuth2":["circuit-breaker-policies:delete"]}],"description":"Delete a circuit breaker policy permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the circuit breaker policy."},"description":"The id of the circuit breaker policy."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"CircuitBreakerPoliciesGet","tags":["monitoring"],"summary":"Circuit Breaker Policies Get","security":[{"ApiKeyAuth":["circuit-breaker-policies:read"]},{"BearerAuth":[]},{"OAuth2":["circuit-breaker-policies:read"]}],"description":"Get one of your circuit breaker policies by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the circuit breaker policy."},"description":"The id of the circuit breaker policy."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid","nullable":true},"entity_type":{"type":"string","nullable":true},"rule_type":{"type":"string"},"threshold_config":{"type":"object","properties":{"threshold_percent":{"type":"number","description":"Trip when the anomaly passes this percentage of the batch. Every rule but schema_drift needs it; without it the sync detector skips the rule."},"always_trip":{"type":"boolean","description":"schema_drift: trip on any drift."}},"description":"The rule's threshold. The provisioned defaults and the sync detector use these two keys; the API stores whatever object it is sent, so other keys may be present."},"action":{"type":"string"},"auto_resolve_hours":{"type":"integer","nullable":true},"enabled":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","rule_type","threshold_config"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","rule_type":"string","threshold_config":{"threshold_percent":0,"always_trip":true},"action":"string","auto_resolve_hours":0,"enabled":true,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"CircuitBreakerPoliciesUpdate","tags":["monitoring"],"summary":"Circuit Breaker Policies Update","security":[{"ApiKeyAuth":["circuit-breaker-policies:write"]},{"BearerAuth":[]},{"OAuth2":["circuit-breaker-policies:write"]}],"description":"Change a circuit breaker policy. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the circuit breaker policy."},"description":"The id of the circuit breaker policy."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connection_id":{"type":"string","format":"uuid","nullable":true},"entity_type":{"type":"string","nullable":true},"rule_type":{"type":"string"},"threshold_config":{"type":"object","additionalProperties":true},"action":{"type":"string"},"auto_resolve_hours":{"type":"integer","nullable":true},"enabled":{"type":"boolean"}}},"example":{"connection_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","rule_type":"string","threshold_config":{},"action":"string","auto_resolve_hours":0,"enabled":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid","nullable":true},"entity_type":{"type":"string","nullable":true},"rule_type":{"type":"string"},"threshold_config":{"type":"object","properties":{"threshold_percent":{"type":"number","description":"Trip when the anomaly passes this percentage of the batch. Every rule but schema_drift needs it; without it the sync detector skips the rule."},"always_trip":{"type":"boolean","description":"schema_drift: trip on any drift."}},"description":"The rule's threshold. The provisioned defaults and the sync detector use these two keys; the API stores whatever object it is sent, so other keys may be present."},"action":{"type":"string"},"auto_resolve_hours":{"type":"integer","nullable":true},"enabled":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","rule_type","threshold_config"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","rule_type":"string","threshold_config":{"threshold_percent":0,"always_trip":true},"action":"string","auto_resolve_hours":0,"enabled":true,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/circuit-breakers":{"get":{"operationId":"StreamCircuitBreakersList","tags":["monitoring"],"summary":"Stream Circuit Breakers List","security":[{"ApiKeyAuth":["circuit-breakers:read"]},{"BearerAuth":[]},{"OAuth2":["circuit-breakers:read"]}],"description":"List your quarantined streams, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"connection_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only quarantined streams for this connection. Pass its id."},"description":"Only quarantined streams for this connection. Pass its id."},{"name":"entity_type","in":"query","required":false,"schema":{"type":"string","description":"Only quarantined streams whose entity type is exactly this."},"description":"Only quarantined streams whose entity type is exactly this."},{"name":"entity_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only quarantined streams whose entity type contains this text (upper and lower case are treated the same)."},"description":"Only quarantined streams whose entity type contains this text (upper and lower case are treated the same)."},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Only quarantined streams whose status is exactly this."},"description":"Only quarantined streams whose status is exactly this."},{"name":"status_contains","in":"query","required":false,"schema":{"type":"string","description":"Only quarantined streams whose status contains this text (upper and lower case are treated the same)."},"description":"Only quarantined streams whose status contains this text (upper and lower case are treated the same)."},{"name":"tripped_by","in":"query","required":false,"schema":{"type":"string","description":"Only quarantined streams whose tripped by is exactly this."},"description":"Only quarantined streams whose tripped by is exactly this."},{"name":"tripped_by_contains","in":"query","required":false,"schema":{"type":"string","description":"Only quarantined streams whose tripped by contains this text (upper and lower case are treated the same)."},"description":"Only quarantined streams whose tripped by contains this text (upper and lower case are treated the same)."},{"name":"severity","in":"query","required":false,"schema":{"type":"string","description":"Only quarantined streams whose severity is exactly this."},"description":"Only quarantined streams whose severity is exactly this."},{"name":"severity_contains","in":"query","required":false,"schema":{"type":"string","description":"Only quarantined streams whose severity contains this text (upper and lower case are treated the same)."},"description":"Only quarantined streams whose severity contains this text (upper and lower case are treated the same)."},{"name":"affected_records_gte","in":"query","required":false,"schema":{"type":"number","description":"Only quarantined streams whose affected records is this number or more."},"description":"Only quarantined streams whose affected records is this number or more."},{"name":"affected_records_lte","in":"query","required":false,"schema":{"type":"number","description":"Only quarantined streams whose affected records is this number or less."},"description":"Only quarantined streams whose affected records is this number or less."},{"name":"quarantined_data_key","in":"query","required":false,"schema":{"type":"string","description":"Only quarantined streams whose quarantined data key is exactly this."},"description":"Only quarantined streams whose quarantined data key is exactly this."},{"name":"quarantined_data_key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only quarantined streams whose quarantined data key contains this text (upper and lower case are treated the same)."},"description":"Only quarantined streams whose quarantined data key contains this text (upper and lower case are treated the same)."},{"name":"tripped_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only quarantined streams whose tripped time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only quarantined streams whose tripped time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"tripped_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only quarantined streams whose tripped time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only quarantined streams whose tripped time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"reviewed_by","in":"query","required":false,"schema":{"type":"string","description":"Only quarantined streams whose reviewed by is exactly this."},"description":"Only quarantined streams whose reviewed by is exactly this."},{"name":"reviewed_by_contains","in":"query","required":false,"schema":{"type":"string","description":"Only quarantined streams whose reviewed by contains this text (upper and lower case are treated the same)."},"description":"Only quarantined streams whose reviewed by contains this text (upper and lower case are treated the same)."},{"name":"reviewed_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only quarantined streams whose reviewed time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only quarantined streams whose reviewed time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"reviewed_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only quarantined streams whose reviewed time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only quarantined streams whose reviewed time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"resolution","in":"query","required":false,"schema":{"type":"string","description":"Only quarantined streams whose resolution is exactly this."},"description":"Only quarantined streams whose resolution is exactly this."},{"name":"resolution_contains","in":"query","required":false,"schema":{"type":"string","description":"Only quarantined streams whose resolution contains this text (upper and lower case are treated the same)."},"description":"Only quarantined streams whose resolution contains this text (upper and lower case are treated the same)."},{"name":"resolution_notes","in":"query","required":false,"schema":{"type":"string","description":"Only quarantined streams whose resolution notes is exactly this."},"description":"Only quarantined streams whose resolution notes is exactly this."},{"name":"resolution_notes_contains","in":"query","required":false,"schema":{"type":"string","description":"Only quarantined streams whose resolution notes contains this text (upper and lower case are treated the same)."},"description":"Only quarantined streams whose resolution notes contains this text (upper and lower case are treated the same)."},{"name":"resolved_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only quarantined streams whose resolved time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only quarantined streams whose resolved time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"resolved_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only quarantined streams whose resolved time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only quarantined streams whose resolved time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"auto_resolve_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only quarantined streams whose auto resolve time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only quarantined streams whose auto resolve time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"auto_resolve_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only quarantined streams whose auto resolve time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only quarantined streams whose auto resolve time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many quarantined streams to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many quarantined streams to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many quarantined streams to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many quarantined streams to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","connection_id","entity_type","status","tripped_by","severity","affected_records","quarantined_data_key","tripped_at","reviewed_by","reviewed_at","resolution","resolution_notes","resolved_at","auto_resolve_at"],"description":"The field to sort the list by.","default":"tripped_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns quarantined streams where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns quarantined streams where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid"},"entity_type":{"type":"string","nullable":true},"status":{"type":"string"},"tripped_by":{"type":"string"},"severity":{"type":"string"},"detection_details":{"type":"object","properties":{"policy_id":{"type":"string","format":"uuid","nullable":true,"description":"The circuit breaker policy that was violated."},"anomaly_type":{"type":"string","description":"The policy rule that fired. Today: bulk_deletion, volume_spike, schema_drift, error_burst."},"evaluation":{"type":"object","properties":{"violated":{"type":"boolean","description":"Always true on a trip."},"actualPercent":{"type":"number","description":"The measured value, as a percent: deletions per baseline volume, errors per record the batch tried to read (records read plus errors), growth over the baseline volume, or 100 for schema drift. Unrounded."},"details":{"type":"string","description":"One plain sentence: the value against the threshold, or for schema drift the new fields (up to 10, then \"+N more\")."}},"required":["violated","actualPercent","details"],"description":"The policy check that failed."},"reason":{"type":"string","description":"Generated text, \"Policy <policy id> violated\". Prefer evaluation.details for people."}},"required":["policy_id","anomaly_type","evaluation","reason"],"description":"What tripped the safety stop: the policy, the kind of anomaly and the measured value."},"affected_records":{"type":"integer","nullable":true},"quarantined_data_key":{"type":"string","nullable":true},"baseline_stats":{"type":"object","additionalProperties":true,"nullable":true},"tripped_at":{"type":"string"},"reviewed_by":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true},"resolution":{"type":"string","nullable":true},"resolution_notes":{"type":"string","nullable":true},"resolved_at":{"type":"string","nullable":true},"auto_resolve_at":{"type":"string","nullable":true}},"required":["customer_id","connection_id","tripped_by","severity","detection_details"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","status":"string","tripped_by":"string","severity":"string","detection_details":{"policy_id":"00000000-0000-0000-0000-000000000000","anomaly_type":"string","evaluation":{"violated":true,"actualPercent":0,"details":"string"},"reason":"string"},"affected_records":0,"quarantined_data_key":"string","baseline_stats":{},"tripped_at":"string","reviewed_by":"string","reviewed_at":"string","resolution":"string","resolution_notes":"string","resolved_at":"string","auto_resolve_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/circuit-breakers/{id}":{"get":{"operationId":"StreamCircuitBreakersGet","tags":["monitoring"],"summary":"Stream Circuit Breakers Get","security":[{"ApiKeyAuth":["circuit-breakers:read"]},{"BearerAuth":[]},{"OAuth2":["circuit-breakers:read"]}],"description":"Get one of your quarantined streams by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the quarantined stream."},"description":"The id of the quarantined stream."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid"},"entity_type":{"type":"string","nullable":true},"status":{"type":"string"},"tripped_by":{"type":"string"},"severity":{"type":"string"},"detection_details":{"type":"object","properties":{"policy_id":{"type":"string","format":"uuid","nullable":true,"description":"The circuit breaker policy that was violated."},"anomaly_type":{"type":"string","description":"The policy rule that fired. Today: bulk_deletion, volume_spike, schema_drift, error_burst."},"evaluation":{"type":"object","properties":{"violated":{"type":"boolean","description":"Always true on a trip."},"actualPercent":{"type":"number","description":"The measured value, as a percent: deletions per baseline volume, errors per record the batch tried to read (records read plus errors), growth over the baseline volume, or 100 for schema drift. Unrounded."},"details":{"type":"string","description":"One plain sentence: the value against the threshold, or for schema drift the new fields (up to 10, then \"+N more\")."}},"required":["violated","actualPercent","details"],"description":"The policy check that failed."},"reason":{"type":"string","description":"Generated text, \"Policy <policy id> violated\". Prefer evaluation.details for people."}},"required":["policy_id","anomaly_type","evaluation","reason"],"description":"What tripped the safety stop: the policy, the kind of anomaly and the measured value."},"affected_records":{"type":"integer","nullable":true},"quarantined_data_key":{"type":"string","nullable":true},"baseline_stats":{"type":"object","additionalProperties":true,"nullable":true},"tripped_at":{"type":"string"},"reviewed_by":{"type":"string","nullable":true},"reviewed_at":{"type":"string","nullable":true},"resolution":{"type":"string","nullable":true},"resolution_notes":{"type":"string","nullable":true},"resolved_at":{"type":"string","nullable":true},"auto_resolve_at":{"type":"string","nullable":true}},"required":["customer_id","connection_id","tripped_by","severity","detection_details"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","status":"string","tripped_by":"string","severity":"string","detection_details":{"policy_id":"00000000-0000-0000-0000-000000000000","anomaly_type":"string","evaluation":{"violated":true,"actualPercent":0,"details":"string"},"reason":"string"},"affected_records":0,"quarantined_data_key":"string","baseline_stats":{},"tripped_at":"string","reviewed_by":"string","reviewed_at":"string","resolution":"string","resolution_notes":"string","resolved_at":"string","auto_resolve_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/circuit-breakers/{id}/approve":{"post":{"operationId":"ApproveQuarantined","tags":["monitoring"],"summary":"Approve Quarantined","security":[{"ApiKeyAuth":["circuit-breakers:write"]},{"BearerAuth":[]},{"OAuth2":["circuit-breakers:write"]}],"description":"Approve a quarantine: you have checked the sync that looked wrong and are happy for syncing to carry on. The quarantine is closed as approved and the connection goes back to syncing normally.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the quarantine."},"description":"The id of the quarantine."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","description":"An optional note, kept with the decision."}}},"example":{"notes":"string"}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"releaseState":{"type":"string","description":"`queued`: a sync job is writing the held records, and the stop resolves when it is done. `already_queued`: the same release was already in flight. `already_released`: the stop was already resolved this way. `nothing_held`: the stop held no records and resolved now."},"releaseJobId":{"type":"string","format":"uuid","nullable":true,"description":"The sync job doing the release (GET /v1/jobs/:id); null when nothing was queued."}},"required":["success","releaseState"]},"example":{"success":true,"releaseState":"string","releaseJobId":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/circuit-breakers/{id}/force-close":{"post":{"operationId":"ForceClose","tags":["monitoring"],"summary":"Force Close","security":[{"ApiKeyAuth":["circuit-breakers:write"]},{"BearerAuth":[]},{"OAuth2":["circuit-breakers:write"]}],"description":"Close a quarantine straight away, whatever state it is in, and put the connection back to syncing normally.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the quarantine."},"description":"The id of the quarantine."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","description":"An optional note, kept with the decision."}}},"example":{"notes":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]},"example":{"success":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/circuit-breakers/{id}/hold-open":{"post":{"operationId":"HoldOpen","tags":["monitoring"],"summary":"Hold Open","security":[{"ApiKeyAuth":["circuit-breakers:write"]},{"BearerAuth":[]},{"OAuth2":["circuit-breakers:write"]}],"description":"Keep a connection stopped while you look into a suspicious sync. Nothing syncs on it until you approve, reject or close the quarantine.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the quarantine."},"description":"The id of the quarantine."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","description":"An optional note, kept with the decision."}}},"example":{"notes":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]},"example":{"success":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/circuit-breakers/{id}/partial-approve":{"post":{"operationId":"PartialApprove","tags":["monitoring"],"summary":"Partial Approve","security":[{"ApiKeyAuth":["circuit-breakers:write"]},{"BearerAuth":[]},{"OAuth2":["circuit-breakers:write"]}],"description":"Let through only the held-back records you choose: the normal sync writes them to the target and the rest are dropped from the release. The stop then closes and the connection syncs normally again, unless another open stop is still holding it.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the quarantine."},"description":"The id of the quarantine."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"approved_record_ids":{"type":"array","items":{"type":"string"},"description":"The ids of the held-back records you approve, as GET /v1/circuit-breakers/:id/records lists them (<entity_type>:<source_id>). At least one."},"notes":{"type":"string","description":"An optional note, kept with the decision."}},"required":["approved_record_ids"]},"example":{"approved_record_ids":["string"],"notes":"string"}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"releaseState":{"type":"string","description":"`queued`: a sync job is writing the held records, and the stop resolves when it is done. `already_queued`: the same release was already in flight. `already_released`: the stop was already resolved this way. `nothing_held`: the stop held no records and resolved now."},"releaseJobId":{"type":"string","format":"uuid","nullable":true,"description":"The sync job doing the release (GET /v1/jobs/:id); null when nothing was queued."}},"required":["success","releaseState"]},"example":{"success":true,"releaseState":"string","releaseJobId":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/circuit-breakers/{id}/records":{"get":{"operationId":"ListCircuitBreakerRecords","tags":["monitoring"],"summary":"List Circuit Breaker Records","security":[{"ApiKeyAuth":["circuit-breakers:read"]},{"BearerAuth":[]},{"OAuth2":["circuit-breakers:read"]}],"description":"The records a tripped safety stop is holding, read from the batch the sync worker stored when the stop tripped (stream_circuit_breakers.quarantined_data_key). Each record's `id` is unique within the stop and is the value `POST /v1/circuit-breakers/:id/partial-approve` takes in `approved_record_ids`. `heldState` says why a stop has no records: `none` when its policy only paused the sync (or the held batch could not be stored), `discarded` once the stop was rejected. A stop in another workspace answers 404. The whole held batch is read on every call (it is one stored object), so `q` and `sort` cover every held record, not just the page. A field whose name is sensitive (pii, financial, credential, health) and that the caller's role may not see is returned as null and named in the record's `redacted_fields`; `q` and `sort` see the redacted value, never the held one.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":200,"description":"Case-insensitive text match against the record id, entity and every field value the caller may see."},"description":"Case-insensitive text match against the record id, entity and every field value the caller may see."},{"name":"entity_type","in":"query","required":false,"schema":{"type":"string","maxLength":200,"description":"Only records of this source entity."},"description":"Only records of this source entity."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","maxLength":200,"description":"`position` (default: the order the sync read them), `id`, `entity_type`, or `fields.<name>` to sort by a record field."},"description":"`position` (default: the order the sync read them), `id`, `entity_type`, or `fields.<name>` to sort by a record field."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"default":"asc"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"breakerId":{"type":"string","format":"uuid"},"status":{"type":"string","description":"The stop's state: open, half_open, held_open or forced_closed."},"resolution":{"type":"string","nullable":true,"description":"approved, rejected, partial or auto_resolved once someone has acted; null while it waits."},"heldState":{"type":"string","description":"`held` when the batch is stored and listed here, `none` when the stop held no records, `discarded` when it was rejected."},"records":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"`<entity_type>:<source_id>`; `line:<n>` for a batch held before records carried their id. Pass it to partial-approve."},"source_id":{"type":"string","nullable":true,"description":"The record's id in the source system."},"entity_type":{"type":"string","nullable":true},"position":{"type":"integer","description":"Zero-based order in the held batch."},"fields":{"type":"object","additionalProperties":true,"description":"The record's fields as the sync read them, after scope exclusions. A field the caller may not see is null."},"redacted_fields":{"type":"array","items":{"type":"string"},"description":"Dotted paths of the fields redacted for this caller (`email`, `billing_details.phone`); empty when nothing was hidden."}},"required":["id","position","fields","redacted_fields"]}},"total":{"type":"integer","description":"Records matching q and entity_type."},"heldTotal":{"type":"integer","description":"Every record the stop holds."},"fieldNames":{"type":"array","items":{"type":"string"},"description":"Every field name across the held records, sorted — the table's columns."},"entityTypes":{"type":"array","items":{"type":"string"},"description":"Every entity among the held records, sorted — the entity filter's options."},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["breakerId","status","heldState","records","total","heldTotal","fieldNames","entityTypes","limit","offset"]},"example":{"breakerId":"00000000-0000-0000-0000-000000000000","status":"string","resolution":"string","heldState":"string","records":[{"id":"string","source_id":"string","entity_type":"string","position":0,"fields":{},"redacted_fields":["string"]}],"total":0,"heldTotal":0,"fieldNames":["string"],"entityTypes":["string"],"limit":0,"offset":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/circuit-breakers/{id}/reject":{"post":{"operationId":"RejectQuarantined","tags":["monitoring"],"summary":"Reject Quarantined","security":[{"ApiKeyAuth":["circuit-breakers:write"]},{"BearerAuth":[]},{"OAuth2":["circuit-breakers:write"]}],"description":"Reject the data held back from a suspicious sync. The held data is deleted, the quarantine is closed, and the connection goes back to syncing normally.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the quarantine."},"description":"The id of the quarantine."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","description":"An optional note, kept with the decision."}}},"example":{"notes":"string"}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]},"example":{"success":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/cli-snippets":{"get":{"operationId":"ListCliSnippets","tags":["cli_snippets"],"summary":"List Cli Snippets","security":[{"ApiKeyAuth":["cli-snippets:read"]},{"BearerAuth":[]},{"OAuth2":["cli-snippets:read"]}],"description":"Your saved cloud shell commands, plus the ones shared with your workspace if sharing is switched on in Settings → Adjustable settings. The response says whether sharing is on, so an app can offer it only when it is.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"snippets":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"command":{"type":"string"},"description":{"type":"string","nullable":true},"shared":{"type":"boolean"},"mine":{"type":"boolean"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","command","shared","mine","createdAt","updatedAt"]}},"sharedEnabled":{"type":"boolean"}},"required":["snippets","sharedEnabled"]},"example":{"snippets":[{"id":"string","name":"string","command":"string","description":"string","shared":true,"mine":true,"createdAt":"string","updatedAt":"string"}],"sharedEnabled":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"CreateCliSnippet","tags":["cli_snippets"],"summary":"Create Cli Snippet","security":[{"ApiKeyAuth":["cli-snippets:write"]},{"BearerAuth":[]},{"OAuth2":["cli-snippets:write"]}],"description":"Save a cloud shell command to reuse later. It must be a single line: line breaks and other control characters are refused, so a command can never run before you have read it. Sharing it with your workspace needs sharing to be switched on.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"A name for the command."},"command":{"type":"string","description":"The command itself, on one line."},"description":{"type":"string","description":"An optional note on what it does."},"shared":{"type":"boolean","description":"true to share it with your workspace. Needs sharing to be switched on."}},"required":["name","command"]},"example":{"name":"string","command":"string","description":"string","shared":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"command":{"type":"string"},"description":{"type":"string","nullable":true},"shared":{"type":"boolean"},"mine":{"type":"boolean"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","command","shared","mine","createdAt","updatedAt"]},"example":{"id":"string","name":"string","command":"string","description":"string","shared":true,"mine":true,"createdAt":"string","updatedAt":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/cli-snippets/{id}":{"delete":{"operationId":"DeleteCliSnippet","tags":["cli_snippets"],"summary":"Delete Cli Snippet","security":[{"ApiKeyAuth":["cli-snippets:delete"]},{"BearerAuth":[]},{"OAuth2":["cli-snippets:delete"]}],"description":"Delete one of your saved commands. Someone else’s command is reported as not found.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the saved command."},"description":"The id of the saved command."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"deleted":{"type":"boolean"}},"required":["id","deleted"]},"example":{"id":"string","deleted":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"operationId":"UpdateCliSnippet","tags":["cli_snippets"],"summary":"Update Cli Snippet","security":[{"ApiKeyAuth":["cli-snippets:write"]},{"BearerAuth":[]},{"OAuth2":["cli-snippets:write"]}],"description":"Change one of your saved commands. Someone else’s command is reported as not found, so personal commands stay private.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the saved command."},"description":"The id of the saved command."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"A new name."},"command":{"type":"string","description":"The new command, on one line."},"description":{"type":"string","description":"A new note."},"shared":{"type":"boolean","description":"true to share it with your workspace, false to make it private."}}},"example":{"name":"string","command":"string","description":"string","shared":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"command":{"type":"string"},"description":{"type":"string","nullable":true},"shared":{"type":"boolean"},"mine":{"type":"boolean"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","command","shared","mine","createdAt","updatedAt"]},"example":{"id":"string","name":"string","command":"string","description":"string","shared":true,"mine":true,"createdAt":"string","updatedAt":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/cli-socket-tickets":{"post":{"operationId":"CreateCliSocketTicket","tags":["cli_sockets"],"summary":"Create Cli Socket Ticket","security":[{"ApiKeyAuth":["cli-socket-tickets:write"]},{"BearerAuth":[]},{"OAuth2":["cli-socket-tickets:write"]}],"description":"Mint a ticket for ONE WebSocket upgrade on the gateway: `/ws/<sessionId>` (channel `terminal`) or `/ws/<sessionId>/browser` (channel `browser`). Offer it as the subprotocol `inferrex.ticket.<ticket>` next to `inferrex.v1`; the gateway accepts `inferrex.v1`. It is consumed by the first upgrade that presents it (a second is refused), expires after expiresInSeconds, and is refused on any other path, so it cannot open another session or the other channel. The session must also belong to the tenant, which cli-sandbox checks on the upgrade as before. Never put it in a URL.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sessionId":{"type":"string","format":"uuid","description":"The cloud shell session (ConnectCliSession's sessionId)."},"channel":{"type":"string","enum":["terminal","browser"],"description":"`terminal` — the shell; `browser` — the in-session browser's stream."}},"required":["sessionId","channel"]},"example":{"sessionId":"00000000-0000-0000-0000-000000000000","channel":"terminal"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ticket":{"type":"string","description":"Opaque, 64 hex characters. Send only as the subprotocol `inferrex.ticket.<ticket>`."},"expiresInSeconds":{"type":"integer"}},"required":["ticket","expiresInSeconds"]},"example":{"ticket":"string","expiresInSeconds":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/connection-environment-bindings":{"get":{"operationId":"ConnectionEnvironmentBindingsList","tags":["workspace"],"summary":"Connection Environment Bindings List","security":[{"ApiKeyAuth":["connection-environment-bindings:read"]},{"BearerAuth":[]},{"OAuth2":["connection-environment-bindings:read"]}],"description":"List your connection environment bindings, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"connection_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only connection environment bindings for this connection. Pass its id."},"description":"Only connection environment bindings for this connection. Pass its id."},{"name":"environment_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only connection environment bindings for this environment. Pass its id."},"description":"Only connection environment bindings for this environment. Pass its id."},{"name":"base_url","in":"query","required":false,"schema":{"type":"string","description":"Only connection environment bindings whose base url is exactly this."},"description":"Only connection environment bindings whose base url is exactly this."},{"name":"base_url_contains","in":"query","required":false,"schema":{"type":"string","description":"Only connection environment bindings whose base url contains this text (upper and lower case are treated the same)."},"description":"Only connection environment bindings whose base url contains this text (upper and lower case are treated the same)."},{"name":"label","in":"query","required":false,"schema":{"type":"string","description":"Only connection environment bindings whose label is exactly this."},"description":"Only connection environment bindings whose label is exactly this."},{"name":"label_contains","in":"query","required":false,"schema":{"type":"string","description":"Only connection environment bindings whose label contains this text (upper and lower case are treated the same)."},"description":"Only connection environment bindings whose label contains this text (upper and lower case are treated the same)."},{"name":"enabled","in":"query","required":false,"schema":{"type":"boolean","description":"Only connection environment bindings where enabled is true, or false for only those where it is false."},"description":"Only connection environment bindings where enabled is true, or false for only those where it is false."},{"name":"credentials_set_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only connection environment bindings whose credentials set time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only connection environment bindings whose credentials set time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"credentials_set_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only connection environment bindings whose credentials set time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only connection environment bindings whose credentials set time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many connection environment bindings to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many connection environment bindings to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many connection environment bindings to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many connection environment bindings to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","connection_id","environment_id","base_url","label","enabled","credentials_set_at","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns connection environment bindings where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns connection environment bindings where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid"},"environment_id":{"type":"string","format":"uuid"},"base_url":{"type":"string","nullable":true,"description":"Where this system lives in this environment. Empty = the connection’s own base URL."},"label":{"type":"string","nullable":true,"description":"Optional note, such as “sandbox org” or “UAT account 2”."},"enabled":{"type":"boolean","description":"Switched off, this entry is ignored: pipelines in that environment stop with an error, rather than use the wrong system, until you switch it back on."},"credentials_set_at":{"type":"string","nullable":true,"description":"When credentials were last stored for this binding. Empty = none stored yet."},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","connection_id","environment_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","environment_id":"00000000-0000-0000-0000-000000000000","base_url":"string","label":"string","enabled":true,"credentials_set_at":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"ConnectionEnvironmentBindingsCreate","tags":["workspace"],"summary":"Connection Environment Bindings Create","security":[{"ApiKeyAuth":["connection-environment-bindings:write"]},{"BearerAuth":[]},{"OAuth2":["connection-environment-bindings:write"]}],"description":"Create a connection environment binding. Returns the new connection environment binding, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connection_id":{"type":"string","format":"uuid"},"environment_id":{"type":"string","format":"uuid"},"base_url":{"type":"string","nullable":true,"description":"Where this system lives in this environment. Empty = the connection’s own base URL."},"label":{"type":"string","nullable":true,"description":"Optional note, such as “sandbox org” or “UAT account 2”."},"enabled":{"type":"boolean","description":"Switched off, this entry is ignored: pipelines in that environment stop with an error, rather than use the wrong system, until you switch it back on."}},"required":["connection_id","environment_id"]},"example":{"connection_id":"00000000-0000-0000-0000-000000000000","environment_id":"00000000-0000-0000-0000-000000000000","base_url":"string","label":"string","enabled":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid"},"environment_id":{"type":"string","format":"uuid"},"base_url":{"type":"string","nullable":true,"description":"Where this system lives in this environment. Empty = the connection’s own base URL."},"label":{"type":"string","nullable":true,"description":"Optional note, such as “sandbox org” or “UAT account 2”."},"enabled":{"type":"boolean","description":"Switched off, this entry is ignored: pipelines in that environment stop with an error, rather than use the wrong system, until you switch it back on."},"credentials_set_at":{"type":"string","nullable":true,"description":"When credentials were last stored for this binding. Empty = none stored yet."},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","connection_id","environment_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","environment_id":"00000000-0000-0000-0000-000000000000","base_url":"string","label":"string","enabled":true,"credentials_set_at":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connection-environment-bindings/{id}":{"delete":{"operationId":"ConnectionEnvironmentBindingsDelete","tags":["workspace"],"summary":"Connection Environment Bindings Delete","security":[{"ApiKeyAuth":["connection-environment-bindings:delete"]},{"BearerAuth":[]},{"OAuth2":["connection-environment-bindings:delete"]}],"description":"Delete a connection environment binding permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection environment binding."},"description":"The id of the connection environment binding."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"ConnectionEnvironmentBindingsGet","tags":["workspace"],"summary":"Connection Environment Bindings Get","security":[{"ApiKeyAuth":["connection-environment-bindings:read"]},{"BearerAuth":[]},{"OAuth2":["connection-environment-bindings:read"]}],"description":"Get one of your connection environment bindings by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection environment binding."},"description":"The id of the connection environment binding."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid"},"environment_id":{"type":"string","format":"uuid"},"base_url":{"type":"string","nullable":true,"description":"Where this system lives in this environment. Empty = the connection’s own base URL."},"label":{"type":"string","nullable":true,"description":"Optional note, such as “sandbox org” or “UAT account 2”."},"enabled":{"type":"boolean","description":"Switched off, this entry is ignored: pipelines in that environment stop with an error, rather than use the wrong system, until you switch it back on."},"credentials_set_at":{"type":"string","nullable":true,"description":"When credentials were last stored for this binding. Empty = none stored yet."},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","connection_id","environment_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","environment_id":"00000000-0000-0000-0000-000000000000","base_url":"string","label":"string","enabled":true,"credentials_set_at":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"ConnectionEnvironmentBindingsUpdate","tags":["workspace"],"summary":"Connection Environment Bindings Update","security":[{"ApiKeyAuth":["connection-environment-bindings:write"]},{"BearerAuth":[]},{"OAuth2":["connection-environment-bindings:write"]}],"description":"Change a connection environment binding. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection environment binding."},"description":"The id of the connection environment binding."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connection_id":{"type":"string","format":"uuid"},"environment_id":{"type":"string","format":"uuid"},"base_url":{"type":"string","nullable":true,"description":"Where this system lives in this environment. Empty = the connection’s own base URL."},"label":{"type":"string","nullable":true,"description":"Optional note, such as “sandbox org” or “UAT account 2”."},"enabled":{"type":"boolean","description":"Switched off, this entry is ignored: pipelines in that environment stop with an error, rather than use the wrong system, until you switch it back on."}}},"example":{"connection_id":"00000000-0000-0000-0000-000000000000","environment_id":"00000000-0000-0000-0000-000000000000","base_url":"string","label":"string","enabled":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid"},"environment_id":{"type":"string","format":"uuid"},"base_url":{"type":"string","nullable":true,"description":"Where this system lives in this environment. Empty = the connection’s own base URL."},"label":{"type":"string","nullable":true,"description":"Optional note, such as “sandbox org” or “UAT account 2”."},"enabled":{"type":"boolean","description":"Switched off, this entry is ignored: pipelines in that environment stop with an error, rather than use the wrong system, until you switch it back on."},"credentials_set_at":{"type":"string","nullable":true,"description":"When credentials were last stored for this binding. Empty = none stored yet."},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","connection_id","environment_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","environment_id":"00000000-0000-0000-0000-000000000000","base_url":"string","label":"string","enabled":true,"credentials_set_at":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections":{"get":{"operationId":"ListConnections","tags":["connections"],"summary":"List Connections","security":[{"ApiKeyAuth":["connections:read"]},{"BearerAuth":[]},{"OAuth2":["connections:read"]}],"description":"List your connected systems, newest first, with each one’s status and when it last synced. Archived connections are not included.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"display_name":{"type":"string"},"description":{"type":"string","nullable":true},"tags":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Labels the workspace gave the connection."},"base_url":{"type":"string"},"status":{"type":"string"},"credential_ref":{"type":"string","nullable":true,"description":"Key of the shared workspace secret the connection signs in with. Never the secret itself. Null does not mean the system needs no sign-in: a credential can also live in its path values or per-environment credentials, none of which this list shows."},"system_key":{"type":"string","nullable":true,"description":"A stable key for the kind of system this connection is, when Inferrex could tell; null otherwise."},"manifest_id":{"type":"string","format":"uuid","nullable":true},"created_at":{"type":"string","format":"date-time"},"approved_at":{"type":"string","format":"date-time","nullable":true},"last_synced_at":{"type":"string","format":"date-time","nullable":true},"proven_at":{"type":"string","format":"date-time","nullable":true,"description":"When a test of the connection's current sign-in last read data from it (POST /v1/connections/:id/test passing, a tested rotation or OAuth consent). Null until one passes: the connection is not proven, and approving it is refused (409 connection_not_proven)."},"reconnect_required_at":{"type":"string","format":"date-time","nullable":true,"description":"When Inferrex found the system's OAuth sign-in can no longer be renewed, so someone must sign in to the provider again. Null while it renews (GET /v1/connections/:id/sign-in-status has the detail)."},"reconnect_reason":{"type":"string","nullable":true,"description":"Why it must be signed in to again: refresh-refused, not-renewable or refresh-token-expired (open vocabulary). Null with reconnect_required_at."},"sign_in_notice_kind":{"type":"string","nullable":true,"description":"The last sign-in notice sent for the current tokens: expiring (the sign-in lapses soon) or reconnect. Cleared when the sign-in renews or someone signs in again."},"sign_in_noticed_at":{"type":"string","format":"date-time","nullable":true,"description":"When that notice was sent."},"paused_at":{"type":"string","format":"date-time","nullable":true,"description":"When a person paused the system (POST /v1/connections/:id/pause): its flows stay paused until it is resumed. Null while it is not paused."},"objectCount":{"type":"integer","nullable":true,"description":"Objects in the connection's current description — every one, included or not, as GET /v1/connections/:id/manifest returns them. Null while there is no description yet, or when it could not be read for this answer."},"fieldCount":{"type":"integer","nullable":true,"description":"Fields across those objects — every one, included or not (the review screen's \"N of M checked\" counts the same set). Null when objectCount is."},"flowCount":{"type":"integer","nullable":true,"description":"Flows (pipelines, not archived, in every environment) that read from this system or write to it, an extra destination included. Null when it could not be counted for this answer."},"liveFlowCount":{"type":"integer","nullable":true,"description":"Of those, how many are live (status active). Null when flowCount is."}},"required":["id","display_name","description","tags","base_url","status","credential_ref","system_key","manifest_id","created_at","approved_at","last_synced_at","proven_at","reconnect_required_at","reconnect_reason","sign_in_notice_kind","sign_in_noticed_at","paused_at","objectCount","fieldCount","flowCount","liveFlowCount"]},"example":{"id":"00000000-0000-0000-0000-000000000000","display_name":"string","description":"string","tags":["string"],"base_url":"string","status":"string","credential_ref":"string","system_key":"string","manifest_id":"00000000-0000-0000-0000-000000000000","created_at":"2026-01-01T00:00:00Z","approved_at":"2026-01-01T00:00:00Z","last_synced_at":"2026-01-01T00:00:00Z","proven_at":"2026-01-01T00:00:00Z","reconnect_required_at":"2026-01-01T00:00:00Z","reconnect_reason":"string","sign_in_notice_kind":"string","sign_in_noticed_at":"2026-01-01T00:00:00Z","paused_at":"2026-01-01T00:00:00Z","objectCount":0,"fieldCount":0,"flowCount":0,"liveFlowCount":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}":{"delete":{"operationId":"DeleteConnection","tags":["connections"],"summary":"Delete Connection","security":[{"ApiKeyAuth":["connections:delete"]},{"BearerAuth":[]},{"OAuth2":["connections:delete"]}],"description":"Archive a connection, so it no longer appears in your lists and cannot be picked for new pipelines. Its history is kept. If a pipeline still uses the connection, this is refused: archive or delete that pipeline first.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"status":{"type":"string"}},"required":["connectionId","status"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"operationId":"UpdateConnection","tags":["connections"],"summary":"Update Connection","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Change a connection’s name, description or tags, or which saved secret it signs in with. Several connections can share one secret, so updating that secret updates all of them.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"displayName":{"type":"string","maxLength":80,"description":"A new name for the connection."},"description":{"type":"string","maxLength":280,"nullable":true,"description":"A new note about the connection. null clears it."},"tags":{"type":"array","items":{"type":"string"},"description":"New labels for the connection. Replaces the current ones."},"credentialRef":{"type":"string","nullable":true,"description":"The name of the saved secret to sign in with. null stops using a saved secret."}}},"example":{"displayName":"string","description":"string","tags":["string"],"credentialRef":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"displayName":{"type":"string"},"description":{"type":"string","nullable":true},"tags":{"type":"array","items":{"type":"string"}},"credentialRef":{"type":"string","nullable":true},"status":{"type":"string"}},"required":["connectionId","displayName","tags","status"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","displayName":"string","description":"string","tags":["string"],"credentialRef":"string","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/approve":{"post":{"operationId":"ApproveConnection","tags":["connections"],"summary":"Approve Connection","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Approve what Inferrex learned about a connected system, once you have reviewed it. After approval the connection can be used in pipelines, and Inferrex starts looking for insights in its data. Only works while the connection is waiting for review, and only once a test of its sign-in has read data from it: until then the answer is 409 connection_not_proven, and POST /v1/connections/:id/test is the way to prove it.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customerId":{"type":"string","format":"uuid"},"connectionId":{"type":"string","format":"uuid","nullable":true},"manifestType":{"type":"string"},"version":{"type":"integer"},"manifest":{"type":"object","properties":{"id":{"type":"string"},"version":{"type":"number","description":"incremented on every update"},"customerId":{"type":"string"},"systemKey":{"type":"string","description":"matches connector library key if known"},"displayName":{"type":"string","description":"inferred or customer-confirmed"},"baseUrl":{"type":"string","description":"The address the connection was given, as typed: it may hold `{placeholders}` anywhere — host, path or query (2026-10-26) — filled per request from `pathParams` / `pathParamSecrets` by joinEndpointUrl, so a value is never stored in it."},"logoUrl":{"type":"string"},"entities":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"apiName":{"type":"string","description":"name in the API"},"displayName":{"type":"string","description":"Layer 4 human label"},"pluralDisplayName":{"type":"string"},"description":{"type":"string"},"fields":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"stable identifier within entity"},"apiName":{"type":"string","description":"name as it appears in the API"},"displayName":{"type":"string","description":"human-readable label (Layer 4 output)"},"description":{"type":"string","description":"Layer 4 business description"},"type":{"type":"string","description":"A label from the L2 taxonomy."},"required":{"type":"boolean"},"nullable":{"type":"boolean"},"role":{"type":"string","description":"Semantic role (what the field MEANS vs `type` = what it IS). Canonical role vocabulary; drives dynamic-UI emphasis + cross-system field matching. Layer 4 / deterministic role classifier."},"roleConfidence":{"type":"number"},"roleSource":{"type":"string","description":"Who set `role` — OPEN string like `source`: 'customer' when a person chose it on the review page (absent `role` then means a person said the field has none). A person's role carries forward on re-inference. Absent = a classifier set it."},"sensitivity":{"type":"string","description":"A PERSON's data-sensitivity decision, made on the review page: a SensitivityClass ('pii' | 'financial' | 'health' | 'credential') or 'none' when they cleared it. Absent = derived by the shared classifier (resolveFieldSensitivity: role, refinements and the identity-number name default). Present, it IS the field's class wherever that classifier is read — review page, tenant sensitivity map, matcher, warehouse sink — and it carries forward on re-inference."},"enumValues":{"type":"array","items":{"type":"string"},"description":"for select/multiselect"},"currencyCode":{"type":"string","description":"for currency fields"},"scale":{"type":"number","description":"Minor-unit exponent: 2 = cents, 0 = major units. Set ONLY when the source format DECLARES it; carried into the routing transform so a cents field auto-reconciles with a dollars field."},"relatedEntityId":{"type":"string","description":"for relation fields"},"typeConfidence":{"type":"number","description":"0-1 (Layer 2 output)"},"typeRationale":{"type":"string","description":"plain language explanation for customer"},"requiresCustomerReview":{"type":"boolean"},"authority":{"type":"string","description":"Known values: provider-wins, native-only, native-override, latest-wins, merge."},"conflictStrategy":{"type":"string","description":"Known values: latest-timestamp, highest-authority, flag-for-review."},"exampleValues":{"type":"array","items":{}},"wireType":{"type":"string","description":"The type the SOURCE declares on the wire (OpenAPI `type`, OData Edm type, GraphQL scalar, SQL column type) — what the API says it sends, kept separately from `type` (what Inferrex infers it MEANS). Was dropped at assembly, so a model classifying the residual never saw it and a reviewer could not tell an inferred `string` from a declared `integer`. Absent on manifests inferred before 2026-09-27."},"wireFormat":{"type":"string","description":"The source's format hint for the wire type (OpenAPI `format`: date-time, uuid, int64, email, …). Absent when the source declares none."},"refTarget":{"type":"string","description":"The entity this field DECLARES a reference to in the spec ($ref leaf, OData navigation/Collection type, GraphQL object type); `[]` suffix marks an array of refs. Spec-declared, never inferred."},"source":{"type":"string","description":"Where the classification came from — OPEN string: 'spine' (deterministic rule), 'corpus' (known-vendor prior), 'cache', 'ai' (model, see typeRationale for the provider), 'customer' (a person set it). Lets the review UI and the A/B comparison tell a rule from a guess from a correction."},"group":{"type":"string","description":"Field group — an OPEN, tenant-defined label (audit §1.4, §Q.2b task 8). It is what makes fan-out usable at scale: \"everything financial also goes to the warehouse\" is one decision over a group, not forty over forty fields. Recommendations are DETERMINISTIC, derived from signals the platform already produces (semantic role, L2 type, L4 archetype) — no new inference, no new model, and the same field always lands in the same place, which a tenant can predict. Absent = ungrouped; a tenant's own label is treated identically to a recommended one."},"included":{"type":"boolean","description":"Schema-level include/exclude (audit §1.3). Absent = INCLUDED — the default is opt-out, so an existing manifest keeps every field. `false` is a tenant decision that the field is not wanted at all: it is dropped from the manifests L16 cross-system matching ever sees, so no mapping is ever proposed for it and nothing downstream (sync, archival, sensitivity map) can reach it. Distinct from FieldMapping.omitted, which declines ONE proposed link after the fact."},"nullRate":{"type":"number","description":"0-1, from data profiling"},"uniqueRate":{"type":"number","description":"0-1"},"lastSeen":{"type":"string","description":"ISO timestamp"},"valueProfile":{"type":"object","properties":{"sampleCount":{"type":"number"},"nullRate":{"type":"number"},"distinctCount":{"type":"number"},"formatHits":{"type":"object","additionalProperties":{"type":"number"}},"minLen":{"type":"number"},"maxLen":{"type":"number"}},"required":["sampleCount","nullRate","distinctCount","formatHits","minLen","maxLen"],"description":"Statistics over ONE page of live records read at introspection (value sampling, plan step 19, 2026-09-27): rows seen, null share, distinct count, how many values matched each format detector, string length range. Never raw values — those are in exampleValues (≤3) and stay on the tenant manifest. Absent when sampling did not run or the field was not in the page."},"refinements":{"type":"object","additionalProperties":true,"description":"Open refinement map — manifest-driven refinement layers write their label here, gated on deterministic-spine residual. Open by design: a new layer adds a key, no schema edit."}},"required":["id","apiName","displayName","type","required","nullable","typeConfidence","typeRationale","requiresCustomerReview","authority","conflictStrategy","exampleValues","nullRate","uniqueRate","lastSeen"]}},"relationships":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Known values: belongsTo, hasMany, hasOne, references."},"targetEntityId":{"type":"string","description":"entity ID within same manifest"},"throughField":{"type":"string","description":"which field carries the FK"},"confidence":{"type":"number"},"rationale":{"type":"string"}},"required":["type","targetEntityId","throughField","confidence","rationale"]}},"category":{"type":"string","description":"Structural tier: only 'domain' entities surface in the dynamic UI + golden data layer; the rest are API plumbing and filtered out. Known values: domain, operation, transport, descriptor, collection, error, enum."},"archetype":{"type":"string","description":"Domain tier: the cross-system domain category that unifies the same concept across providers."},"archetypeConfidence":{"type":"number"},"endpoints":{"type":"object","properties":{"list":{"type":"string"},"get":{"type":"string"},"create":{"type":"string"},"update":{"type":"string"},"delete":{"type":"string"},"search":{"type":"string"}}},"postRead":{"type":"object","properties":{"path":{"type":"string","description":"The read endpoint, relative to the connection base URL; may hold `{placeholders}` filled from the path values (`/v2/workspaces/{workspace}/records/search`)."},"body":{"type":"object","additionalProperties":true,"description":"The JSON body sent with every page, as declared (no placeholders are filled in it). Absent = `{}`."},"paging":{"type":"string","description":"Absent = 'none': one request. 'body-offset' = the page size and the number of rows to skip go in the body (`limitField`, `offsetField`); the read stops on a short or empty page or at the page cap. Known values: none, body-offset."},"pageSize":{"type":"number","description":"body-offset: rows per page. Absent = 100."},"limitField":{"type":"string","description":"body-offset: the top-level body key for the page size. Absent = `limit`."},"offsetField":{"type":"string","description":"body-offset: the top-level body key for the rows to skip. Absent = `offset`."},"recordsPath":{"type":"string","description":"Dotted path to the records in the answer. Absent = the shared list-response reader finds them ('objects'), or `data` ('table')."},"rowShape":{"type":"string","description":"Absent = 'objects': an array of records. 'table' = columns and rows apart, `{ fields: [...], data: [[...]] }`; each row is zipped with the column names. A column descriptor is a string, or an object named by the key its `type` names (`{ type: 'property', property: 'email' }` → `email`), else its `name` or `id`. Known values: objects, table."},"columnsPath":{"type":"string","description":"table: dotted path to the column descriptors. Absent = `fields`."},"successField":{"type":"string","description":"Dotted path to a boolean success flag; `false` there is a failed read. Absent = `success`, checked when present."},"updatedAtField":{"type":"string","description":"A record field holding when it last changed, for the sync's sourceUpdatedAt. Absent = none: every POST read is a full read."}},"required":["path"],"description":"How to list this entity when its API reads by POST (2026-10-26; generic — any API whose reads are POSTs, no vendor or source system assumed). Used only when the connection's `listVia` is 'post' — two keys, so an inferred entity alone can never cause a POST. Read by the shared reader @inferrex/utils/post-read.js in the sync worker, the value sampler and the mapping sample. Absent = the entity lists through its GET list endpoint. Carried forward on re-inference by entity api name. Nothing sets it from a spec yet: a provider profile or a tenant setting supplies it (follow-up)."},"updateVia":{"type":"string","description":"How a sync updates one record it created before (target-id memory, 2026-10-08). Absent = 'patch' to the update endpoint. 'put' for APIs that only take PUT on an item (the Acme demo mocks). 'post-to-get' POSTs to the get endpoint's path: Stripe updates /v1/customers/{customer} that way and declares no update endpoint. Set with PATCH /v1/connections/:id/entities/:entityId/update-via; carried forward on re-inference. Known values: patch, put, post-to-get."},"deletion":{"type":"object","properties":{"field":{"type":"string","description":"Dotted path to the marker in the record (`deleted`, `meta.is_deleted`)."},"value":{"type":"string","description":"The value that marks a deletion, as text: a scalar in the record matches when it reads the same (`'true'` matches `true`, `'1'` matches `1`, `'deleted'` matches `\"deleted\"`). An object, an array or null never matches."},"whenPresent":{"type":"boolean","description":"true = any non-null value marks a deletion (`deleted_at`)."},"source":{"type":"string","description":"Where it came from — OPEN string: 'spec' (inferred from the description), 'customer' (a person set it)."}},"required":["field"],"description":"How a record of this entity says it was deleted (2026-10-28; generic — any API that lists its deletions as records, no vendor assumed). Read by the sync worker (services/sync/src/batch-signals.ts): a record that matches is a DELETE — counted as a deletion for the safety stop and tombstoned in record_versions, the op erasure writes — and is never versioned, mapped or written as a sparse record. Set by inference from a record | tombstone union in the spec (`deleted: false` on the record, `deleted: true` on its tombstone). Absent = no record is a deletion; a deletion is seen only as an absence from a full listing, as before."},"incremental":{"type":"object","properties":{"param":{"type":"string","description":"The query parameter (`updated_since`)."},"format":{"type":"string","description":"How the time is written — OPEN string: 'date-time' (ISO 8601, the absent default), 'date' (YYYY-MM-DD), 'unix' (epoch seconds), 'unix-ms'. An unknown format is sent as ISO 8601."},"source":{"type":"string","description":"Where it came from — OPEN string: 'spec', 'customer'."}},"required":["param"],"description":"The query parameter this entity's list read takes to return only what changed since a time (2026-10-28; generic). The sync worker sends it with the entity's `since` on an incremental run instead of its fixed `modified_since` guess, and drops it, reading in full, if the source answers 400/422. Set by inference from a date-time query parameter on the list operation whose name or description reads as changes-since (updated_since, modified_since, changed_since, since, …). Absent = the old guess."},"embeddedIn":{"type":"string","description":"The api name of the record this entity is only ever read inside (2026-10-28): an order's lines when the spec writes the line as an inline object (RawEntity.embeddedIn). It has no endpoint of its own; the record's field that holds it is a collection with a hasMany edge to it, which is how setup options list its fields (itemFields). Set by inference, kept by the AI merge. Absent = an entity read through its own endpoints."},"write":{"type":"object","properties":{"successField":{"type":"string","description":"Dotted path to a boolean in a 2xx answer; `false` there is a REFUSED write (quarantined, never counted as written). Bloomreach Engagement answers `200 { success: false, errors }` to a command it will not process, and retrying it fails again. Absent = the status alone decides."},"errorsField":{"type":"string","description":"Dotted path to the API's own reasons in a refused answer, quoted (capped) in the quarantine reason. Absent = the whole answer, capped."},"keyPlaceholder":{"type":"string","description":"The one placeholder of the create endpoint that is the record's OWN id, filled per record from the source record's id (a keyed upsert: `/catalogs/{catalogId}/items/{itemId}/partial-update`). Absent = a create endpoint with an unfilled placeholder is refused, as before."},"keyForbiddenChars":{"type":"string","description":"Characters a record id may not hold when it fills `keyPlaceholder`; such a record is refused (quarantined) rather than sent. Engagement serves catalog item edits only for ids without `/`."},"maxPerMinute":{"type":"number","description":"Most write REQUESTS per minute sent to this entity (a batch call is one request; every retry is one more). Since 2026-10-27 (phase 9) a budget SHARED by every writer in its `rateScope` — sync jobs, workers and replicas, and the golden write-back — kept in Redis (@inferrex/utils/rate-budget.js); while Redis is unreachable each process paces itself and logs a warning. Absent = not paced."},"rateScope":{"type":"string","description":"Which writers share `maxPerMinute` (2026-10-27, phase 9). OPEN string: 'entity' (absent = this; one connection's entity), 'connection' (every entity of the connection), 'tenant' (every connection of one tenant to the same host), 'destination-host' (every tenant and worker writing to the same host — a destination that limits per caller IP, as Inferrex calls from one egress). An unknown value is read as 'entity'."},"idempotent":{"type":"boolean","description":"Sending the same write twice leaves the destination as sending it once (a keyed upsert; a property SET carrying its own update time). Declared by a reviewed profile, never inferred. Lets the writer retry a failure that may already have been applied (a timeout, a 503). Absent = false: such a failure is never retried; only a 429 or a request that provably never left (connection refused) is."},"idempotencyKeyHeader":{"type":"string","description":"A request header the destination de-duplicates writes by. The writer sends a key derived from the record and its content, the same on every attempt, so a retried write lands at most once; it makes retries as safe as `idempotent`. Absent = no key is sent."},"retryOn":{"type":"array","items":{"type":"number"},"description":"HTTP statuses this destination answers for a TRANSIENT failure besides 429 and 503 (e.g. 502, 504). Retried like a 503: only when the write is idempotent. Absent = 429 and 503 only."},"batch":{"type":"object","properties":{"path":{"type":"string","description":"The batch endpoint, relative to the connection's base URL; `{placeholders}` are filled from the connection's path values."},"method":{"type":"string","description":"Absent = 'POST'. Known values: POST, PUT."},"commandsField":{"type":"string","description":"Top-level body key holding the list of commands (`commands`)."},"commandName":{"type":"string","description":"The constant every command of this entity carries as its kind (`customers/events`). Absent = no name is set."},"commandNameField":{"type":"string","description":"The command key `commandName` goes in. Absent = `name`."},"commandDataField":{"type":"string","description":"The command key the record's own body goes in (`data`). Absent = the record's body IS the command."},"commandIdField":{"type":"string","description":"A command key the writer fills with an id unique within the call (`command_id`), so a result can name its command."},"maxCommands":{"type":"number","description":"Most commands in one call."},"maxCommandBytes":{"type":"number","description":"Most bytes one command may take, as JSON. A record over it is refused (quarantined) without being sent."},"maxRequestBytes":{"type":"number","description":"Most bytes one whole request body may take, as JSON. Calls are closed before they would pass it."},"resultsField":{"type":"string","description":"Dotted path to the list of per-command results in a 2xx answer (`results`)."},"resultIdField":{"type":"string","description":"The result key that echoes `commandIdField`. Absent = results are in command order. A command with no result is a FAILED write (its outcome is unknown), never a written one."},"resultSuccessField":{"type":"string","description":"Dotted path to a boolean in one result; `false` is that command refused. Absent = `success`."},"resultErrorsField":{"type":"string","description":"Dotted path to that command's reasons, quoted (capped) in its quarantine reason. Absent = the whole result."},"separateBy":{"type":"string","description":"Dotted path in a record's body: two commands with the same value there never share a call, because the destination may run one call's commands out of order (Engagement, partner ask P3). A later call is sent only after the earlier one is answered."}},"required":["path","commandsField","maxCommands","resultsField"],"description":"How this entity's creates go many to a call (2026-10-27, phase 9; generic). The writer groups creates within the declared count and byte limits and reads one result per command, so each record succeeds, fails with its reason, or is quarantined on its own. Absent = one request per record, exactly as before. Not used with `keyPlaceholder` (a per-record address cannot share a call)."},"addedBy":{"type":"string","description":"Set when the entity was ADDED to the manifest by an approved destination setup plan (`destination-setup-plan:<plan id>`), not inferred: a re-inference carries the whole entity forward, because no spec or crawl will find it again. OPEN string."},"allowance":{"type":"object","properties":{"maxPerMinuteTunable":{"type":"string","description":"The tunable whose tenant value may raise `maxPerMinute` (as the tenant's own budget). Absent = the rate is never raised."},"maxCommandsTunable":{"type":"string","description":"The tunable whose tenant value may raise `batch.maxCommands`. Absent = the batch size is never raised."}},"description":"A per-tenant partner allowance above `maxPerMinute` and `batch.maxCommands` (2026-10-28, generic): the platform tunables holding the tenant's own values, read by the writer at each write (@inferrex/utils/write-allowance.js). A tenant value above the contract's limit replaces it for that tenant's writes; a raised rate is the tenant's own budget for the host (rate scope 'tenant'), never the shared one. A value at or below the contract's is ignored, so it only raises. Stamped by a setup plan from the destination profile's allowance. Absent = the declared limits."},"requiredValues":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Dotted path in the record's body as written (`properties.action`). Empty text counts as absent."},"when":{"type":"object","properties":{"field":{"type":"string","description":"Dotted path in the body."},"equals":{"type":"string","description":"Holds when the value, as text, equals this."}},"required":["field","equals"],"description":"Only required when this holds (`properties.action` equals `accept`). Absent = always required."},"why":{"type":"string","description":"Why it is required, in words a person can act on; quoted in the hold's reason."}},"required":["field"]},"description":"Values a record must carry, read from its body as written (dotted paths), or it is HELD BACK: quarantined with the reason and never sent, by every writer (the sync writer, a history file, the one-record writer), and a released record is checked again (2026-10-28, generic; Bloomreach Engagement phase 10: a consent event missing its action, category or, for an accept, its expiry is not sent, because Engagement revokes consent on an invalid one). Set from a reviewed profile by an approved setup plan; nothing infers it. Absent = no check."},"sendWhen":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Dotted path in the body as written (`properties.region`)."},"op":{"type":"string","description":"The test. Known values: equals, not-equals, in, exists, missing, gt, gte, lt, lte, contains."},"value":{"type":"string","description":"The one value of `equals`, `not-equals`, `contains` (text) and `gt`, `gte`, `lt`, `lte` (a number, written as text). Absent for `in`, `exists` and `missing`."},"values":{"type":"array","items":{"type":"string"},"description":"The texts of `in`. Absent otherwise."}},"required":["field","op"]},"description":"Which records go to this destination at all (2026-10-28, generic; several destination projects, design §N.4.2): conditions on the record's body as written (dotted paths), every one of which must hold. A record that does not meet them is SKIPPED and counted by every writer that checks `requiredValues` (the sync writer, a history file, the one-record writer), never quarantined: it was never meant for this destination. Set by an approved setup plan from the tenant's own rule; nothing infers it. Absent = every record."}},"description":"How a write to this entity is judged and paced beyond its HTTP status (2026-10-27, Bloomreach Engagement phase 1; generic — any API that answers 200 to a refused write, or keys a create by the record's own id). Read by the sync writer (services/sync/src/logic.ts) and the golden write-back (reverse-sync-provider-client.ts). Absent = a 2xx is success, a create endpoint is POSTed as is, and writes are not paced. Carried forward on re-inference (an entity a setup plan added is kept whole: `addedBy`)."},"overallConfidence":{"type":"number"},"requiresCustomerReview":{"type":"boolean"},"reviewableFields":{"type":"array","items":{"type":"string"},"description":"field IDs needing review"},"refinements":{"type":"object","additionalProperties":true,"description":"Open refinement map — entity-scope refinement layers (e.g. entity-namer archetype) write here, gated on deterministic-spine residual."}},"required":["id","apiName","displayName","pluralDisplayName","description","fields","relationships","endpoints","overallConfidence","requiresCustomerReview","reviewableFields"]}},"auth":{"type":"object","properties":{"method":{"type":"string","description":"Known values: oauth2, api-key, basic, bearer, aws-sigv4, jwt, mtls, custom, none."},"scheme":{"type":"string","description":"The fine-grained auth scheme from L11 auth-scheme-classifier (OPEN: oauth2_authorization_code, oauth2_client_credentials, jwt, hmac_signature, mtls, …) — refines the coarse `method` with the OAuth flow / transport distinction. A novel scheme flows through as a string."},"oauth2":{"type":"object","properties":{"authorizeEndpoint":{"type":"string"},"tokenEndpoint":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"pkce":{"type":"boolean"},"refreshable":{"type":"boolean"}},"required":["tokenEndpoint","pkce","refreshable"]},"apiKey":{"type":"object","properties":{"headerName":{"type":"string"},"prefix":{"type":"string"}},"required":["headerName"]}},"required":["method"]},"pagination":{"type":"object","properties":{"style":{"type":"string","description":"Known values: offset-limit, cursor, page-number, link-header, none."},"pageSize":{"type":"number"},"pageSizeParam":{"type":"string"},"offsetParam":{"type":"string"},"pageParam":{"type":"string","description":"page-number style: the query parameter carrying the 1-based page (from the spec, plan step 39). Absent = `page`."},"cursorParam":{"type":"string","description":"cursor style: the query parameter the next cursor is sent in. Absent = `cursor`. Manifests inferred before 2026-09-27 carried this in cursorField."},"cursorField":{"type":"string","description":"cursor style: the response field (dotted path) holding the next cursor; the sync worker also tries the common names (next_cursor, nextCursor, meta.next_cursor, paging.next, pageInfo.endCursor, …)."},"totalField":{"type":"string"}},"required":["style","pageSize"]},"rateLimit":{"type":"object","properties":{"requestsPerMinute":{"type":"number"},"requestsPerDay":{"type":"number"},"burstLimit":{"type":"number"},"retryAfterHeader":{"type":"string"}},"required":["requestsPerMinute","retryAfterHeader"]},"inferredAt":{"type":"string"},"inferredBy":{"type":"string","description":"model version"},"overallConfidence":{"type":"number"},"requiresReview":{"type":"array","items":{"type":"string"},"description":"field/entity IDs needing customer input"},"specSource":{"type":"string","description":"URL if spec was found"},"userSpecUrl":{"type":"string","description":"The vendor's spec or API reference URL the tenant gave at connect or re-infer (2026-10-09). Distinct from specSource, which is where inference actually found a spec: this is what the tenant asked it to read. Discovery fetches it first, through the shared SSRF guard, and uses it when it is an OpenAPI or Swagger document; an HTML docs page is recorded but not scraped. Carried forward on re-inference when no new one is given; a re-infer with specUrl null clears it."},"documentationSource":{"type":"string","description":"URL of primary docs used"},"inferenceMethod":{"type":"string","description":"How discovery read the API. soap = a WSDL (?wsdl, or the spec URL); grpc = a .proto; asyncapi / json-schema / avro = that description at a well-known path or the spec URL; jsonapi = a JSON:API service crawled from its links; probed = a crawl of HAL links, Link headers and well-known paths. Known values: openapi, graphql, odata, mcp, documentation, probed, library, cli, soap, grpc, asyncapi, json-schema, avro, jsonapi."},"status":{"type":"string","description":"Known values: inferring, awaiting-review, approved, active, error."},"customerApprovedAt":{"type":"string"},"customerApprovedBy":{"type":"string"},"previousVersionId":{"type":"string"},"changeReason":{"type":"string"},"systemDescription":{"type":"string","description":"L6 (semantic interpretation): what this system is, in a sentence. Computed on every run since L6 shipped and discarded until 2026-09-27; now persisted so the review page and the match prompt can use it."},"industryClassification":{"type":"string","description":"L6: the industry the system serves (OPEN string; 'unknown' when the layer did not run). For a known vendor v2 takes it from the lake's provider summary instead of a model call."},"complianceRelevance":{"type":"array","items":{"type":"string"},"description":"L6: compliance regimes the data plausibly falls under (GDPR, PCI-DSS, HIPAA, SOX, …) — OPEN strings, advisory only; the deterministic sensitivity rules remain the enforcement."},"corpusPrior":{"type":"object","properties":{"providerKey":{"type":"string"},"capturedAt":{"type":"string"},"ageDays":{"type":"number"},"stale":{"type":"boolean"},"fieldsTyped":{"type":"number"},"fieldsEnriched":{"type":"number"},"edgesAdded":{"type":"number"},"authApplied":{"type":"boolean"},"paginationApplied":{"type":"boolean"}},"required":["providerKey","stale","fieldsTyped","fieldsEnriched","edgesAdded","authApplied","paginationApplied"],"description":"Set when the v2 spine seeded this manifest from the connector library and its sidecar for a KNOWN vendor (2026-09-27). `capturedAt` is the sidecar generatedAt — how old the library snapshot is; `stale` means older than inference.corpusPrior.maxAgeDays, in which case the prior confidence was lowered and the review page says so. The live spec always overrode the prior where it declared something different."},"baseline":{"type":"object","properties":{"providerKey":{"type":"string"},"entitiesMatched":{"type":"number"},"entitiesNew":{"type":"number"},"fieldsMatched":{"type":"number"},"fieldsNew":{"type":"number"},"fieldsChanged":{"type":"number"}},"required":["providerKey","entitiesMatched","entitiesNew","fieldsMatched","fieldsNew","fieldsChanged"],"description":"Set when the vendor has a verified baseline (2026-10-09): a person-approved manifest from an earlier connection, promoted and released into the connector library. Fields the baseline knows with the same declared type were typed from it and not sent to the AI; `fieldsNew` and `fieldsChanged` were, with every entity the baseline does not know (`entitiesNew`). Absent when the vendor has no baseline. Never names the connection the baseline came from: that is another tenant's (2026-10-11)."},"verifiedBaseline":{"type":"object","properties":{"providerKey":{"type":"string"},"approvedAt":{"type":"string"},"promotedAt":{"type":"string"}},"required":["providerKey","approvedAt","promotedAt"],"description":"Only on a connector-library manifest that IS a vendor baseline (2026-10-09): when the connection it was promoted from was approved, and when it was promoted. Never names that connection — the library is read by every tenant; the source connection and tenant stay on connector_library.promotion_staging (2026-10-11). Structure only — built by toBaselineManifest, which drops every value and tenant choice. Its presence is what tells inference to type known fields from it."},"valueSampling":{"type":"object","properties":{"entitiesSampled":{"type":"number"},"entitiesFailed":{"type":"number"},"rowsFetched":{"type":"number"},"fieldsProfiled":{"type":"number"},"fieldsTyped":{"type":"number"},"sampledAt":{"type":"string"},"durationMs":{"type":"number"},"errors":{"type":"array","items":{"type":"string"}},"notSampled":{"type":"array","items":{"type":"string"}}},"required":["entitiesSampled","entitiesFailed","rowsFetched","fieldsProfiled","fieldsTyped","sampledAt","durationMs"],"description":"Set when introspection read a page of live records per entity (value sampling, plan step 19, 2026-09-27) — how much was seen and how many fields it typed that the spec and the rules had left open. The values themselves live on the fields (exampleValues, valueProfile), never here. `errors` (2026-10-08): up to 10 `entity: reason` lines for the entities that could not be read — an HTTP status or a token failure — so a failed sample says what to fix. `notSampled` (2026-10-13): up to 10 `entity: reason` lines for the entities deliberately not sampled — those read from an MCP server, whose tools are never called while sampling (a tool can change data) and whose resources are not HTTP endpoints. Not failures, so not counted in entitiesFailed."},"engine":{"type":"string","description":"Which inference engine produced this manifest (engine-switch decision, 2026-09-27): 'v1' | 'v2' | 'v2-proprietary'. Absent on manifests inferred before the switch existed."},"engineArm":{"type":"string","description":"How the engine was chosen — the A/B arm for grouping runs: 'v1', 'v2', 'ab:v2', 'override:v2', …"},"engineFallbackReason":{"type":"string","description":"Set when the selected engine could not serve and the run fell back to v1 (engine-not-available | engine-unavailable | engine-error | budget | timeout)."},"writeEncoding":{"type":"string","description":"How the API takes a write's request body (2026-10-08). Absent = JSON. 'form' = application/x-www-form-urlencoded with bracket keys for nested values (`metadata[key]=v`, `items[0][price]=p`) — Stripe's contract, which rejects JSON bodies. Detected from a spec whose write operations accept only form bodies; a tenant sets it with PATCH /v1/connections/:id/write-encoding; carried forward on re-inference. Known values: json, form."},"reread":{"type":"object","properties":{"scope":{"type":"string"},"confidenceBelow":{"type":"number"},"fields":{"type":"array","items":{"type":"object","properties":{"entity":{"type":"string"},"field":{"type":"string"}},"required":["entity","field"]}},"notFound":{"type":"array","items":{"type":"object","properties":{"entity":{"type":"string"},"field":{"type":"string"}},"required":["entity","field"]}},"fromManifestId":{"type":"string"},"readAt":{"type":"string"}},"required":["scope","fields","notFound","fromManifestId","readAt"],"description":"Set on a version made by a PART re-read (Aaron, 2026-10-12: only re-read fields that are lower confidence or not mapped). `scope` is the choice (low-confidence, unmapped, low-confidence-or-unmapped — an OPEN string); `fields` are the fields read again and replaced, by object and field API name; `notFound` were selected but not shown by the API this time and were kept; every other field, object and setting is the version `fromManifestId` unchanged. Absent on a full read."},"listVia":{"type":"string","description":"How a read lists an entity's records (DEBT-191, 2026-10-09). Absent = 'endpoint': GET the entity's list endpoint and follow the manifest's pagination. 'soql' = Salesforce REST, where GET /sobjects/{X} returns the object's metadata and recentItems, not its records: the sync worker, the value sampler and the mapping sample describe the object (/sobjects/{X}/describe) for its queryable fields, query them with GET /query?q=SELECT … FROM X, and follow each page's nextRecordsUrl until done. Detected at inference from the API's shape (detectListVia in @inferrex/utils/soql-read.js: a /services/data/vNN.N base, or a spec declaring GET /query?q= beside /sobjects/ resources), so a re-inference sets or clears it. 'post' (2026-10-26, generic) = an API whose reads are POSTs: each entity that declares `postRead` is listed by POSTing that declared body to that declared read endpoint (@inferrex/utils/post-read.js), the rest through their GET list endpoint. No spec shape detects it; it is set with the entities' `postRead` declarations and carried forward on re-inference while detection finds nothing else. Known values: endpoint, soql, post."},"authError":{"type":"string","description":"Set when inference could not get an access token for this connection (2026-10-08) — the OAuth token endpoint's refusal, e.g. `OAuth client_credentials token request to x.my.salesforce.com failed: invalid_client`. The run then probed unauthenticated, so its entities read 'not confirmed'. Absent when the token was issued or the auth type needs none."},"pathParams":{"type":"object","additionalProperties":{"type":"string"},"description":"Values for the endpoint placeholders that are not a record id — Bloomreach DataConnect's `{account_name}`, `{catalog_name}`, `{environment_name}` (2026-09-28). Only the tenant knows them; set with PATCH /v1/connections/:id/path-params, carried forward on re-inference, filled into every request by joinEndpointUrl. A request whose endpoint still holds a placeholder is refused rather than sent."},"pathParamSecrets":{"type":"object","additionalProperties":{"type":"string"},"description":"Placeholders whose value is kept in a saved workspace secret rather than on the manifest (2026-10-26, Aaron: \"store that placeholder as a secret so it can be reused\"): placeholder name → the `inferrex.tenant_secrets.key` of a workspace-shared secret. The value is read only at the moment of a request (resolvePathValues in @inferrex/infra/path-values.js) and is never stored here, returned or logged. A name is in `pathParams` or here, never both. Set on connect (POST /v1/connections/infer `pathParams` with `{ secretRef }`), re-read, or PATCH /v1/connections/:id/path-params; carried forward on re-inference like `pathParams`."},"readPaths":{"type":"array","items":{"type":"string"},"description":"Endpoint paths the tenant asked Inferrex to read (2026-10-26, Aaron: \"This should be configurable so someone can build the URL themselves\"), relative to `baseUrl`, each possibly holding `{placeholders}` filled from `pathParams` / `pathParamSecrets` — `/data/v2/projects/{projectToken}/catalogs`. Discovery tries them first when the API publishes no description (they seed the spec-less crawl), and records each as its template, never with a value filled in. Carried forward on re-inference unless the re-read gives new ones."},"readProfile":{"type":"string","description":"The provider read profile this connection reads with (2026-10-27, Bloomreach Engagement phase 4): the key of a profile in @inferrex/service-schema read-profiles.ts — reviewed data for the reads no spec or crawl finds. Its POST reads become entities carrying `postRead` (one page read at inference teaches their fields) and set `listVia: 'post'`; its GET reads name the entity the crawl finds on that path. Set by the module that connects the system (the Bloomreach module), or found from the address when it is one of a profile's known hosts; a re-inference keeps it. Absent = no profile."},"aiLane":{"type":"object","properties":{"lane":{"type":"string","description":"'scheduled-batch' today."},"state":{"type":"string","description":"scheduled (waiting for the tenant's window) | submitted (the batch is with Azure) | applied (its answers are on this manifest) | failed (nothing could be submitted or applied; the residual stays for review)."},"scheduledFor":{"type":"string","description":"ISO time the residual will be submitted (state scheduled)."},"batchId":{"type":"string"},"submittedAt":{"type":"string"},"appliedAt":{"type":"string"},"entitiesSubmitted":{"type":"number"},"entitiesApplied":{"type":"number"},"reservedTokens":{"type":"number","description":"Budget tokens reserved against the tenant's daily hosted-model budget at submit: the estimated input tokens, weighted by the Batch/interactive price ratio from the Foundry cost card when ai.batchLane.costWeightedBudget is on; reconciled in the same units when the batch is applied."},"detail":{"type":"string","description":"Why the lane stopped (state failed), or the batch terminal status when applied (completed | cancelled | expired)."}},"required":["lane","state"],"description":"Set when this manifest's AI step runs in a lane other than the interactive one (2026-10-09, decision 2026-10-09-async-ai-pipeline-step §5): the scheduled Azure OpenAI Batch lane. The manifest is the deterministic one until the batch is applied; the residual stays flagged for review meanwhile. Absent = the interactive lane."}},"required":["id","version","customerId","displayName","baseUrl","entities","auth","pagination","rateLimit","inferredAt","inferredBy","overallConfidence","requiresReview","inferenceMethod","status"],"description":"The stored inferred description that was approved. Field corrections from review are not applied to this copy; read GET /v1/connections/:id/manifest for that."},"status":{"type":"string","description":"approved"},"parentId":{"type":"string","format":"uuid","nullable":true},"createdBy":{"type":"string"},"createdAt":{"type":"string"}},"required":["id","customerId","manifestType","version","manifest","status","createdBy","createdAt"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customerId":"00000000-0000-0000-0000-000000000000","connectionId":"00000000-0000-0000-0000-000000000000","manifestType":"string","version":0,"manifest":{"id":"string","version":0,"customerId":"string","systemKey":"string","displayName":"string","baseUrl":"string","logoUrl":"string","entities":[{"id":"string","apiName":"string","displayName":"string","pluralDisplayName":"string","description":"string","fields":[{"id":"string","apiName":"string","displayName":"string","description":"string","type":"string","required":true,"nullable":true,"role":"string","roleConfidence":0,"roleSource":"string","sensitivity":"string","enumValues":["string"],"currencyCode":"string","scale":0,"relatedEntityId":"string","typeConfidence":0,"typeRationale":"string","requiresCustomerReview":true,"authority":"string","conflictStrategy":"string","exampleValues":[],"wireType":"string","wireFormat":"string","refTarget":"string","source":"string","group":"string","included":true,"nullRate":0,"uniqueRate":0,"lastSeen":"string","valueProfile":{"sampleCount":0,"nullRate":0,"distinctCount":0,"formatHits":{},"minLen":0,"maxLen":0},"refinements":{}}],"relationships":[{"type":"string","targetEntityId":"string","throughField":"string","confidence":0,"rationale":"string"}],"category":"string","archetype":"string","archetypeConfidence":0,"endpoints":{"list":"string","get":"string","create":"string","update":"string","delete":"string","search":"string"},"postRead":{"path":"string","body":{},"paging":"string","pageSize":0,"limitField":"string","offsetField":"string","recordsPath":"string","rowShape":"string","columnsPath":"string","successField":"string","updatedAtField":"string"},"updateVia":"string","deletion":{"field":"string","value":"string","whenPresent":true,"source":"string"},"incremental":{"param":"string","format":"string","source":"string"},"embeddedIn":"string","write":{"successField":"string","errorsField":"string","keyPlaceholder":"string","keyForbiddenChars":"string","maxPerMinute":0,"rateScope":"string","idempotent":true,"idempotencyKeyHeader":"string","retryOn":[0],"batch":{"path":"string","method":"string","commandsField":"string","commandName":"string","commandNameField":"string","commandDataField":"string","commandIdField":"string","maxCommands":0,"maxCommandBytes":0,"maxRequestBytes":0,"resultsField":"string","resultIdField":"string","resultSuccessField":"string","resultErrorsField":"string","separateBy":"string"},"addedBy":"string","allowance":{"maxPerMinuteTunable":"string","maxCommandsTunable":"string"},"requiredValues":[{"field":"string","when":{"field":"string","equals":"string"},"why":"string"}],"sendWhen":[{"field":"string","op":"string","value":"string","values":["string"]}]},"overallConfidence":0,"requiresCustomerReview":true,"reviewableFields":["string"],"refinements":{}}],"auth":{"method":"string","scheme":"string","oauth2":{"authorizeEndpoint":"string","tokenEndpoint":"string","scopes":["string"],"pkce":true,"refreshable":true},"apiKey":{"headerName":"string","prefix":"string"}},"pagination":{"style":"string","pageSize":0,"pageSizeParam":"string","offsetParam":"string","pageParam":"string","cursorParam":"string","cursorField":"string","totalField":"string"},"rateLimit":{"requestsPerMinute":0,"requestsPerDay":0,"burstLimit":0,"retryAfterHeader":"string"},"inferredAt":"string","inferredBy":"string","overallConfidence":0,"requiresReview":["string"],"specSource":"string","userSpecUrl":"string","documentationSource":"string","inferenceMethod":"string","status":"string","customerApprovedAt":"string","customerApprovedBy":"string","previousVersionId":"string","changeReason":"string","systemDescription":"string","industryClassification":"string","complianceRelevance":["string"],"corpusPrior":{"providerKey":"string","capturedAt":"string","ageDays":0,"stale":true,"fieldsTyped":0,"fieldsEnriched":0,"edgesAdded":0,"authApplied":true,"paginationApplied":true},"baseline":{"providerKey":"string","entitiesMatched":0,"entitiesNew":0,"fieldsMatched":0,"fieldsNew":0,"fieldsChanged":0},"verifiedBaseline":{"providerKey":"string","approvedAt":"string","promotedAt":"string"},"valueSampling":{"entitiesSampled":0,"entitiesFailed":0,"rowsFetched":0,"fieldsProfiled":0,"fieldsTyped":0,"sampledAt":"string","durationMs":0,"errors":["string"],"notSampled":["string"]},"engine":"string","engineArm":"string","engineFallbackReason":"string","writeEncoding":"string","reread":{"scope":"string","confidenceBelow":0,"fields":[{"entity":"string","field":"string"}],"notFound":[{"entity":"string","field":"string"}],"fromManifestId":"string","readAt":"string"},"listVia":"string","authError":"string","pathParams":{},"pathParamSecrets":{},"readPaths":["string"],"readProfile":"string","aiLane":{"lane":"string","state":"string","scheduledFor":"string","batchId":"string","submittedAt":"string","appliedAt":"string","entitiesSubmitted":0,"entitiesApplied":0,"reservedTokens":0,"detail":"string"}},"status":"string","parentId":"00000000-0000-0000-0000-000000000000","createdBy":"string","createdAt":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/approve-field":{"post":{"operationId":"ApproveField","tags":["connections"],"summary":"Approve Field","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Accept or correct one field Inferrex found in a connected system. You can correct its type, name, description, which system is trusted for it, what it represents (for example an identifier or a contact detail) and how sensitive its data is. Your corrections take priority over Inferrex’s own judgement, including its default of treating tax and company registration numbers as personal data, and they are kept when the API is read again. A role that does not suit the field’s type is refused.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fieldPath":{"type":"string","description":"Which field: the kind of record and the field, as <entityId>.<fieldId>."},"approved":{"type":"boolean","description":"true to accept the field, false to reject it."},"correctedType":{"type":"string","description":"The field’s correct data type, if Inferrex got it wrong."},"correctedDisplayName":{"type":"string","description":"A better name for the field."},"correctedDescription":{"type":"string","description":"A better description of the field."},"correctedAuthority":{"type":"string","description":"Which system should be trusted for this field’s value."},"correctedRole":{"type":"string","maximum":64,"description":"What the field represents, such as identifier, contact-point or quantity. Send none if it has no particular role."},"correctedSensitivity":{"type":"string","description":"How sensitive the field’s data is: none, pii (personal data), financial, health or credential. none clears any sensitivity set before."},"reason":{"type":"string","description":"An optional note on why you made this decision."}},"required":["fieldPath","approved"]},"example":{"fieldPath":"string","approved":true,"correctedType":"string","correctedDisplayName":"string","correctedDescription":"string","correctedAuthority":"string","correctedRole":"string","correctedSensitivity":"string","reason":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"manifestId":{"type":"string","format":"uuid"},"fieldPath":{"type":"string"},"approved":{"type":"boolean"},"role":{"type":"string","nullable":true,"description":"The field's role after this verdict (null = none)."},"sensitivity":{"type":"string","nullable":true,"description":"The field's effective data sensitivity after this verdict (null = not sensitive)."}},"required":["connectionId","manifestId","fieldPath","approved"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","manifestId":"00000000-0000-0000-0000-000000000000","fieldPath":"string","approved":true,"role":"string","sensitivity":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/assess-scope":{"post":{"operationId":"AssessScope","tags":["connections"],"summary":"Assess Scope","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Estimate how much data a connection holds before you load it. For each kind of record you have chosen to sync, Inferrex asks the API how many records there are, signing in with the connection’s saved credentials as a sync does. It then estimates the storage they need, how long a first full load would take, how many API calls it would make, and how it would affect your storage allowance. Where the system does not report a count, a fixed estimate is used and marked as approximate, for that kind of record and on the totals.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connection_id":{"type":"string","format":"uuid"},"assessed_at":{"type":"string","format":"date-time"},"credentials_used":{"type":"boolean","description":"False when the connection has no stored credentials, or they could not be read: the system was probed without them, so most counts are estimates."},"entities":{"type":"array","items":{"type":"object","properties":{"entity_type":{"type":"string","description":"The object's api name."},"included":{"type":"boolean"},"estimated_records":{"type":"number","description":"The count the system reported, or a fixed estimate (10,000; 1,000 with no list endpoint) when it did not."},"estimated_size_gb":{"type":"number"},"field_count":{"type":"integer","description":"Fields left after the scope's exclusions."},"excluded_fields":{"type":"array","items":{"type":"string"}},"estimated_load_time_minutes":{"type":"number"},"estimated_api_calls":{"type":"integer"},"approximate":{"type":"boolean","description":"True when the system did not report a count and the figure is estimated."}},"required":["entity_type","included","estimated_records","estimated_size_gb","field_count","excluded_fields","estimated_load_time_minutes","estimated_api_calls","approximate"]},"description":"One row per object included in the sync scope."},"totals":{"type":"object","properties":{"total_records":{"type":"number"},"total_storage_gb":{"type":"number"},"estimated_load_time_minutes":{"type":"number"},"total_api_calls":{"type":"integer"},"approximate":{"type":"boolean","description":"True when any object's count is an estimate, so these totals are estimates too."},"storage_quota_impact":{"type":"object","properties":{"current_usage_gb":{"type":"number"},"included_gb":{"type":"number"},"after_load_gb":{"type":"number"},"remaining_gb":{"type":"number"}},"required":["current_usage_gb","included_gb","after_load_gb","remaining_gb"],"description":"Storage used before and after a full load, against the workspace's included storage."}},"required":["total_records","total_storage_gb","estimated_load_time_minutes","total_api_calls","approximate","storage_quota_impact"]}},"required":["connection_id","assessed_at","credentials_used","entities","totals"]},"example":{"connection_id":"00000000-0000-0000-0000-000000000000","assessed_at":"2026-01-01T00:00:00Z","credentials_used":true,"entities":[{"entity_type":"string","included":true,"estimated_records":0,"estimated_size_gb":0,"field_count":0,"excluded_fields":["string"],"estimated_load_time_minutes":0,"estimated_api_calls":0,"approximate":true}],"totals":{"total_records":0,"total_storage_gb":0,"estimated_load_time_minutes":0,"total_api_calls":0,"approximate":true,"storage_quota_impact":{"current_usage_gb":0,"included_gb":0,"after_load_gb":0,"remaining_gb":0}}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/audit":{"get":{"operationId":"GetConnectionAudit","tags":["connections"],"summary":"Get Connection Audit","security":[{"ApiKeyAuth":["connections:read"]},{"BearerAuth":[]},{"OAuth2":["connections:read"]}],"description":"The history of this connection, newest first: its sign-ins, tests, pauses and secrets, and what Inferrex learned about it across every version and re-read, each change of status and each field you reviewed.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"manifestId":{"type":"string","format":"uuid","nullable":true},"audit":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"entityType":{"type":"string"},"entityId":{"type":"string","format":"uuid","description":"The manifest version (row) the entry concerns."},"action":{"type":"string","description":"Known values: created, updated, approved, status_changed, field_reviewed."},"actor":{"type":"string","nullable":true,"description":"The id of the user who acted, when one was recorded."},"beforeState":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"string"}],"nullable":true,"description":"By action — created and field_reviewed: null; updated: the whole stored inferred description before the edit (a ConnectionManifest); approved and status_changed: the previous status, as a string."},"afterState":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"string"}],"nullable":true,"description":"By action — created and updated: the whole stored inferred description (a ConnectionManifest); approved and status_changed: the new status, as a string; field_reviewed: the decision — fieldPath (`<entityId>.<fieldId>`), approved, and whichever of correctedType, correctedDisplayName, correctedDescription, correctedAuthority, correctedRole, correctedSensitivity and reason were given."},"createdAt":{"type":"string","format":"date-time"}},"required":["id","entityType","entityId","action","createdAt"]}}},"required":["connectionId","audit"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","manifestId":"00000000-0000-0000-0000-000000000000","audit":[{"id":"00000000-0000-0000-0000-000000000000","entityType":"string","entityId":"00000000-0000-0000-0000-000000000000","action":"string","actor":"string","beforeState":null,"afterState":null,"createdAt":"2026-01-01T00:00:00Z"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/cadence":{"get":{"operationId":"GetConnectionCadence","tags":["connections"],"summary":"Get Connection Cadence","security":[{"ApiKeyAuth":["connections:read"]},{"BearerAuth":[]},{"OAuth2":["connections:read"]}],"description":"How often this connected system syncs. Empty until you set a frequency. You can set one frequency for the whole connection and different ones for particular kinds of record; Inferrex then checks at the most frequent of them and syncs each kind of record only when it is due. A kind of record set to real time is sent to Inferrex rather than fetched, so while anything else on the connection is still fetched on a schedule, it is left out of those checks. When the connection or any kind of record is set to real time, the response includes the address for sending records in (ingestPath) and whether a token for it is set, with its last four characters and when it was issued (ingestTokenSet, ingestTokenHint, ingestTokenIssuedAt). The token itself is shown only once, by the call that issued it; to get a new one, rotate it (POST /v1/connections/:id/change-feed/secret), which stops the old one working. The response also shows when each kind of record last synced and when it is next due.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"preset":{"type":"string","enum":["realtime","5m","15m","hourly","daily","weekly","manual"],"nullable":true},"scheduleType":{"type":"string","nullable":true},"scheduleCron":{"type":"string","nullable":true},"entities":{"type":"object","additionalProperties":{"type":"string"},"description":"Entity key → cadence preset, keyed as written (entity id or api name). Empty when only a connection-wide cadence is set."},"entitySync":{"type":"object","additionalProperties":{"type":"object","additionalProperties":true},"description":"Entity api name → { lastSyncedAt, cadence, nextDueAt }: its last successful sync on a pipeline reading this connection, the effective cadence it ran under, and when it is next due (null: manual, or no cadence so every run). The soonest due across pipelines. Empty until an entity has synced."},"ingestPath":{"type":"string","nullable":true},"ingestTokenSet":{"type":"boolean","description":"real time only: an ingest token is set. A read never returns the token; Absent unless something on the connection is real time."},"ingestTokenHint":{"type":"string","nullable":true,"description":"real time only: the last four characters of the ingest token, to tell tokens apart; null when none is set."},"ingestTokenIssuedAt":{"type":"string","format":"date-time","nullable":true,"description":"real time only: when the ingest token was issued; null when none is set."}},"required":["connectionId","entities","entitySync"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","preset":"realtime","scheduleType":"string","scheduleCron":"string","entities":{},"entitySync":{},"ingestPath":"string","ingestTokenSet":true,"ingestTokenHint":"string","ingestTokenIssuedAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"SetConnectionCadence","tags":["connections"],"summary":"Set Connection Cadence","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Set how often this connected system syncs, from real time to weekly or manual only. It applies to the connection and to every pipeline that reads from it, including pipelines you create later. Setting one kind of record to real time does not stop the others being fetched on a schedule: Inferrex checks at the most frequent of their frequencies (the connection-wide frequency covers any kind of record you do not name). A connection is real time throughout only when nothing on it is fetched on a schedule. Choosing real time issues the connection's push token when it has none and returns it once, as ingestToken; when one is already set, ingestToken is null and the token is not shown again (rotate it with POST /v1/connections/:id/change-feed/secret to get a new one).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"preset":{"type":"string","enum":["realtime","5m","15m","hourly","daily","weekly","manual"],"description":"How often to sync: realtime, 5m, 15m, hourly, daily, weekly, or manual (only when you start it)."},"entities":{"type":"object","additionalProperties":true,"description":"Different frequencies for particular kinds of record, by record kind, for example {\"invoices\": \"hourly\"}. Send the whole set each time."}},"required":["preset"]},"example":{"preset":"realtime","entities":{}}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"preset":{"type":"string"},"scheduleType":{"type":"string"},"scheduleCron":{"type":"string","nullable":true},"pipelines":{"type":"integer"},"ingestPath":{"type":"string","nullable":true},"ingestToken":{"type":"string","nullable":true,"description":"Only when this call issued the connection's first push token: shown once, never returned again."},"ingestTokenSet":{"type":"boolean","description":"real time only: an ingest token is set. A read never returns the token; Absent unless something on the connection is real time."},"ingestTokenHint":{"type":"string","nullable":true,"description":"real time only: the last four characters of the ingest token, to tell tokens apart; null when none is set."},"ingestTokenIssuedAt":{"type":"string","format":"date-time","nullable":true,"description":"real time only: when the ingest token was issued; null when none is set."}},"required":["connectionId","preset","scheduleType","pipelines"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","preset":"string","scheduleType":"string","scheduleCron":"string","pipelines":0,"ingestPath":"string","ingestToken":"string","ingestTokenSet":true,"ingestTokenHint":"string","ingestTokenIssuedAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/change-feed":{"get":{"operationId":"GetConnectionChangeFeed","tags":["connections"],"summary":"Get Connection Change Feed","security":[{"ApiKeyAuth":["connections:read"]},{"BearerAuth":[]},{"OAuth2":["connections:read"]}],"description":"The connection's change feed (real-time inbound phase 1, decision D1): `mode` is poll, vendor-webhook or push. For vendor-webhook, `endpoint` holds the receive path (prefix it with the API host), its status (pending_verification until the first verified delivery, then active; failing after inbound.badSignatureThreshold refused deliveries in a row), and whether a signing secret is stored — never the secret. `profiles` lists only the webhook senders this system may use (the ones it matches, and the one its endpoint uses), with their setup steps, never another vendor's; `suggestedProfile` is the one matching this system. `reconcile` is the poll cadence that catches what the feed missed. For push, `ingestPath` is the address to push to, and `ingestTokenSet`, `ingestTokenHint` (its last four characters) and `ingestTokenIssuedAt` describe the token. This read never returns a secret: `ingestToken` and `issuedSecret` are always null here. Each is shown once, by the call that issued it (setting the feed, or POST /v1/connections/:id/change-feed/secret).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"mode":{"type":"string","description":"poll, vendor-webhook or push."},"suggestedProfile":{"type":"string","nullable":true,"description":"The webhook profile matching this connection's system, when there is one."},"profiles":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"displayName":{"type":"string"},"endpointKinds":{"type":"array","items":{"type":"string"},"description":"per-connection and/or platform-app, the default first."},"secretLabel":{"type":"string","description":"What the vendor calls the signing secret to paste."},"secretSource":{"type":"string","description":"vendor: the vendor issues the secret and you paste it here. generated: Inferrex issues it (shown once, when the address is set up or the secret replaced) and you paste it into the vendor."},"secretHeader":{"type":"string","nullable":true,"description":"For a vendor that sends the secret itself rather than a signature: the header it may send it in (Authorization Bearer or Basic also work). Null otherwise."},"accessTokenScope":{"type":"string","nullable":true,"description":"For a vendor that can authenticate with OAuth 2.0 client credentials instead of the secret: the one scope an API key needs for its access tokens (from POST /v1/oauth/token) to be accepted, once acceptAccessToken is turned on. Null otherwise."},"instructions":{"type":"array","items":{"type":"string"},"description":"Steps to set the webhook up in the vendor's console."},"events":{"type":"array","items":{"type":"string"},"description":"The vendor event types Inferrex reads."}},"required":["key","displayName","endpointKinds","secretLabel","secretSource","instructions","events"]},"description":"The webhook senders this system may use: the ones its own system matches, and the one its endpoint already uses. Never another vendor's; empty when the system sends no webhooks Inferrex reads (2026-11-07)."},"endpoint":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"profileKey":{"type":"string"},"kind":{"type":"string","description":"per-connection or platform-app."},"status":{"type":"string","description":"pending_verification, active, failing or disabled."},"receivePath":{"type":"string","description":"Where the vendor posts, relative to the API host."},"vendorAccountId":{"type":"string","nullable":true},"secretSet":{"type":"boolean","description":"A signing secret is stored (it is never returned)."},"accessTokenAccepted":{"type":"boolean","description":"The address also accepts an Inferrex access token for this workspace carrying the profile's accessTokenScope, beside the secret. False for a profile without one."},"verifiedAt":{"type":"string","format":"date-time","nullable":true},"lastEventAt":{"type":"string","format":"date-time","nullable":true},"badSignatureCount":{"type":"integer","description":"Deliveries refused for their signature since the last verified one."}},"required":["id","profileKey","kind","status","receivePath","secretSet","accessTokenAccepted","badSignatureCount"],"nullable":true,"description":"The vendor-webhook receive endpoint; null unless mode is vendor-webhook."},"reconcile":{"type":"string","nullable":true,"description":"The poll cadence preset; for a connection with a change feed, the reconcile that catches what the feed missed."},"ingestPath":{"type":"string","nullable":true,"description":"push only: where your own code posts records."},"ingestToken":{"type":"string","nullable":true,"description":"Only on the answer that issued it: the token your own code sends with its pushes, when switching to push issued the connection's first one or POST /v1/connections/:id/change-feed/secret rotated it. Shown once and never returned again; null on every other answer, every read included."},"ingestTokenSet":{"type":"boolean","description":"push only: an ingest token is set. A read never returns the token; false for other modes."},"ingestTokenHint":{"type":"string","nullable":true,"description":"push only: the last four characters of the ingest token, to tell tokens apart; null when none is set."},"ingestTokenIssuedAt":{"type":"string","format":"date-time","nullable":true,"description":"push only: when the ingest token was issued; null when none is set."},"issuedSecret":{"type":"string","nullable":true,"description":"Only on the answer that issued it: the secret Inferrex generated for a vendor whose secret it issues (secretSource generated), when the address was set up or the secret replaced. Shown once and never returned again; null on every other answer."}},"required":["connectionId","mode","profiles","ingestTokenSet"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","mode":"string","suggestedProfile":"string","profiles":[{"key":"string","displayName":"string","endpointKinds":["string"],"secretLabel":"string","secretSource":"string","secretHeader":"string","accessTokenScope":"string","instructions":["string"],"events":["string"]}],"endpoint":{"id":"00000000-0000-0000-0000-000000000000","profileKey":"string","kind":"string","status":"string","receivePath":"string","vendorAccountId":"string","secretSet":true,"accessTokenAccepted":true,"verifiedAt":"2026-01-01T00:00:00Z","lastEventAt":"2026-01-01T00:00:00Z","badSignatureCount":0},"reconcile":"string","ingestPath":"string","ingestToken":"string","ingestTokenSet":true,"ingestTokenHint":"string","ingestTokenIssuedAt":"2026-01-01T00:00:00Z","issuedSecret":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"SetConnectionChangeFeed","tags":["connections"],"summary":"Set Connection Change Feed","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Set the connection's change feed. `poll`: Inferrex reads on the cadence only; webhook endpoints are disabled. `push`: your own code pushes to the ingest address; when the connection has no token yet one is issued and returned once, as `ingestToken` (null when one was already set: rotate it to get a new one). `vendor-webhook`: the vendor posts its own webhooks; `profileKey` names the vendor (defaults to the one matching the connection's system), `kind` is per-connection (the vendor account or app is the tenant's own; give its signing secret as `secret`, except for a profile whose secretSource is generated: Inferrex then issues the secret the first time and returns it once as `issuedSecret`) or platform-app (Xero through Inferrex's app; give the vendor account id as `vendorAccountId`). `reconcile` sets the poll cadence that catches what the feed misses; for vendor-webhook it defaults to daily when switching to it (decision D1), and realtime is not a reconcile cadence. A secret is stored encrypted and never returned.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","description":"poll, vendor-webhook or push."},"profileKey":{"type":"string","description":"vendor-webhook: a key from `profiles` of GET /v1/connections/:id/change-feed (stripe, shopify, xero; bloomreach-engagement-scenario for a workspace with the Bloomreach Engagement module)."},"kind":{"type":"string","enum":["per-connection","platform-app"]},"secret":{"type":"string","maximum":512,"description":"vendor-webhook, per-connection: the signing secret the vendor issued. Required the first time; omit to keep the stored one. Refused for a profile whose secret Inferrex issues."},"acceptAccessToken":{"type":"boolean","description":"vendor-webhook, per-connection, for a profile with an accessTokenScope: true also accepts an Inferrex OAuth 2.0 access token (POST /v1/oauth/token) for this workspace carrying that scope, beside the secret; false accepts the secret only. Omit to keep the current choice. Choosing another vendor turns it off."},"vendorAccountId":{"type":"string","maximum":200,"description":"vendor-webhook, platform-app: the vendor account whose events are this connection's (Xero: the organisation's tenant id)."},"reconcile":{"type":"string","enum":["5m","15m","hourly","daily","weekly","manual"]}},"required":["mode"]},"example":{"mode":"string","profileKey":"string","kind":"per-connection","secret":"string","acceptAccessToken":true,"vendorAccountId":"string","reconcile":"5m"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"mode":{"type":"string","description":"poll, vendor-webhook or push."},"suggestedProfile":{"type":"string","nullable":true,"description":"The webhook profile matching this connection's system, when there is one."},"profiles":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"displayName":{"type":"string"},"endpointKinds":{"type":"array","items":{"type":"string"},"description":"per-connection and/or platform-app, the default first."},"secretLabel":{"type":"string","description":"What the vendor calls the signing secret to paste."},"secretSource":{"type":"string","description":"vendor: the vendor issues the secret and you paste it here. generated: Inferrex issues it (shown once, when the address is set up or the secret replaced) and you paste it into the vendor."},"secretHeader":{"type":"string","nullable":true,"description":"For a vendor that sends the secret itself rather than a signature: the header it may send it in (Authorization Bearer or Basic also work). Null otherwise."},"accessTokenScope":{"type":"string","nullable":true,"description":"For a vendor that can authenticate with OAuth 2.0 client credentials instead of the secret: the one scope an API key needs for its access tokens (from POST /v1/oauth/token) to be accepted, once acceptAccessToken is turned on. Null otherwise."},"instructions":{"type":"array","items":{"type":"string"},"description":"Steps to set the webhook up in the vendor's console."},"events":{"type":"array","items":{"type":"string"},"description":"The vendor event types Inferrex reads."}},"required":["key","displayName","endpointKinds","secretLabel","secretSource","instructions","events"]},"description":"The webhook senders this system may use: the ones its own system matches, and the one its endpoint already uses. Never another vendor's; empty when the system sends no webhooks Inferrex reads (2026-11-07)."},"endpoint":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"profileKey":{"type":"string"},"kind":{"type":"string","description":"per-connection or platform-app."},"status":{"type":"string","description":"pending_verification, active, failing or disabled."},"receivePath":{"type":"string","description":"Where the vendor posts, relative to the API host."},"vendorAccountId":{"type":"string","nullable":true},"secretSet":{"type":"boolean","description":"A signing secret is stored (it is never returned)."},"accessTokenAccepted":{"type":"boolean","description":"The address also accepts an Inferrex access token for this workspace carrying the profile's accessTokenScope, beside the secret. False for a profile without one."},"verifiedAt":{"type":"string","format":"date-time","nullable":true},"lastEventAt":{"type":"string","format":"date-time","nullable":true},"badSignatureCount":{"type":"integer","description":"Deliveries refused for their signature since the last verified one."}},"required":["id","profileKey","kind","status","receivePath","secretSet","accessTokenAccepted","badSignatureCount"],"nullable":true,"description":"The vendor-webhook receive endpoint; null unless mode is vendor-webhook."},"reconcile":{"type":"string","nullable":true,"description":"The poll cadence preset; for a connection with a change feed, the reconcile that catches what the feed missed."},"ingestPath":{"type":"string","nullable":true,"description":"push only: where your own code posts records."},"ingestToken":{"type":"string","nullable":true,"description":"Only on the answer that issued it: the token your own code sends with its pushes, when switching to push issued the connection's first one or POST /v1/connections/:id/change-feed/secret rotated it. Shown once and never returned again; null on every other answer, every read included."},"ingestTokenSet":{"type":"boolean","description":"push only: an ingest token is set. A read never returns the token; false for other modes."},"ingestTokenHint":{"type":"string","nullable":true,"description":"push only: the last four characters of the ingest token, to tell tokens apart; null when none is set."},"ingestTokenIssuedAt":{"type":"string","format":"date-time","nullable":true,"description":"push only: when the ingest token was issued; null when none is set."},"issuedSecret":{"type":"string","nullable":true,"description":"Only on the answer that issued it: the secret Inferrex generated for a vendor whose secret it issues (secretSource generated), when the address was set up or the secret replaced. Shown once and never returned again; null on every other answer."}},"required":["connectionId","mode","profiles","ingestTokenSet"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","mode":"string","suggestedProfile":"string","profiles":[{"key":"string","displayName":"string","endpointKinds":["string"],"secretLabel":"string","secretSource":"string","secretHeader":"string","accessTokenScope":"string","instructions":["string"],"events":["string"]}],"endpoint":{"id":"00000000-0000-0000-0000-000000000000","profileKey":"string","kind":"string","status":"string","receivePath":"string","vendorAccountId":"string","secretSet":true,"accessTokenAccepted":true,"verifiedAt":"2026-01-01T00:00:00Z","lastEventAt":"2026-01-01T00:00:00Z","badSignatureCount":0},"reconcile":"string","ingestPath":"string","ingestToken":"string","ingestTokenSet":true,"ingestTokenHint":"string","ingestTokenIssuedAt":"2026-01-01T00:00:00Z","issuedSecret":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/change-feed/secret":{"post":{"operationId":"RotateConnectionChangeFeedSecret","tags":["connections"],"summary":"Rotate Connection Change Feed Secret","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"For a push connection: send no `secret`; Inferrex issues a new ingest token (or the first, if none is set), returns it once as `ingestToken`, and refuses the old one from that moment. For a vendor-webhook connection: store a new signing secret for its endpoint (per-connection kind). The current secret becomes the previous one and is accepted until the profile's rotation overlap ends (Shopify: 1 hour; Stripe, Xero and Bloomreach Engagement scenarios: 24 hours). For a profile whose secretSource is generated, send no `secret`: Inferrex issues the new one and returns it once as `issuedSecret`. Otherwise neither secret is ever returned.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"secret":{"type":"string","maximum":512,"description":"The new secret the vendor issued. Required unless Inferrex issues this vendor's secret; refused then."}}},"example":{"secret":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"mode":{"type":"string","description":"poll, vendor-webhook or push."},"suggestedProfile":{"type":"string","nullable":true,"description":"The webhook profile matching this connection's system, when there is one."},"profiles":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"displayName":{"type":"string"},"endpointKinds":{"type":"array","items":{"type":"string"},"description":"per-connection and/or platform-app, the default first."},"secretLabel":{"type":"string","description":"What the vendor calls the signing secret to paste."},"secretSource":{"type":"string","description":"vendor: the vendor issues the secret and you paste it here. generated: Inferrex issues it (shown once, when the address is set up or the secret replaced) and you paste it into the vendor."},"secretHeader":{"type":"string","nullable":true,"description":"For a vendor that sends the secret itself rather than a signature: the header it may send it in (Authorization Bearer or Basic also work). Null otherwise."},"accessTokenScope":{"type":"string","nullable":true,"description":"For a vendor that can authenticate with OAuth 2.0 client credentials instead of the secret: the one scope an API key needs for its access tokens (from POST /v1/oauth/token) to be accepted, once acceptAccessToken is turned on. Null otherwise."},"instructions":{"type":"array","items":{"type":"string"},"description":"Steps to set the webhook up in the vendor's console."},"events":{"type":"array","items":{"type":"string"},"description":"The vendor event types Inferrex reads."}},"required":["key","displayName","endpointKinds","secretLabel","secretSource","instructions","events"]},"description":"The webhook senders this system may use: the ones its own system matches, and the one its endpoint already uses. Never another vendor's; empty when the system sends no webhooks Inferrex reads (2026-11-07)."},"endpoint":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"profileKey":{"type":"string"},"kind":{"type":"string","description":"per-connection or platform-app."},"status":{"type":"string","description":"pending_verification, active, failing or disabled."},"receivePath":{"type":"string","description":"Where the vendor posts, relative to the API host."},"vendorAccountId":{"type":"string","nullable":true},"secretSet":{"type":"boolean","description":"A signing secret is stored (it is never returned)."},"accessTokenAccepted":{"type":"boolean","description":"The address also accepts an Inferrex access token for this workspace carrying the profile's accessTokenScope, beside the secret. False for a profile without one."},"verifiedAt":{"type":"string","format":"date-time","nullable":true},"lastEventAt":{"type":"string","format":"date-time","nullable":true},"badSignatureCount":{"type":"integer","description":"Deliveries refused for their signature since the last verified one."}},"required":["id","profileKey","kind","status","receivePath","secretSet","accessTokenAccepted","badSignatureCount"],"nullable":true,"description":"The vendor-webhook receive endpoint; null unless mode is vendor-webhook."},"reconcile":{"type":"string","nullable":true,"description":"The poll cadence preset; for a connection with a change feed, the reconcile that catches what the feed missed."},"ingestPath":{"type":"string","nullable":true,"description":"push only: where your own code posts records."},"ingestToken":{"type":"string","nullable":true,"description":"Only on the answer that issued it: the token your own code sends with its pushes, when switching to push issued the connection's first one or POST /v1/connections/:id/change-feed/secret rotated it. Shown once and never returned again; null on every other answer, every read included."},"ingestTokenSet":{"type":"boolean","description":"push only: an ingest token is set. A read never returns the token; false for other modes."},"ingestTokenHint":{"type":"string","nullable":true,"description":"push only: the last four characters of the ingest token, to tell tokens apart; null when none is set."},"ingestTokenIssuedAt":{"type":"string","format":"date-time","nullable":true,"description":"push only: when the ingest token was issued; null when none is set."},"issuedSecret":{"type":"string","nullable":true,"description":"Only on the answer that issued it: the secret Inferrex generated for a vendor whose secret it issues (secretSource generated), when the address was set up or the secret replaced. Shown once and never returned again; null on every other answer."}},"required":["connectionId","mode","profiles","ingestTokenSet"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","mode":"string","suggestedProfile":"string","profiles":[{"key":"string","displayName":"string","endpointKinds":["string"],"secretLabel":"string","secretSource":"string","secretHeader":"string","accessTokenScope":"string","instructions":["string"],"events":["string"]}],"endpoint":{"id":"00000000-0000-0000-0000-000000000000","profileKey":"string","kind":"string","status":"string","receivePath":"string","vendorAccountId":"string","secretSet":true,"accessTokenAccepted":true,"verifiedAt":"2026-01-01T00:00:00Z","lastEventAt":"2026-01-01T00:00:00Z","badSignatureCount":0},"reconcile":"string","ingestPath":"string","ingestToken":"string","ingestTokenSet":true,"ingestTokenHint":"string","ingestTokenIssuedAt":"2026-01-01T00:00:00Z","issuedSecret":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/credentials":{"delete":{"operationId":"RevokeCredentials","tags":["credentials"],"summary":"Revoke Credentials","security":[{"ApiKeyAuth":["connections:delete"]},{"BearerAuth":[]},{"OAuth2":["connections:delete"]}],"description":"Delete one saved credential, or all of them, for a connection in one environment (its main sign-in unless you pass environmentId). Other environments are never affected, so clearing a test environment cannot touch your live one.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"credentialKey":{"type":"string","description":"The credential to delete, by name. Leave out to delete all of them in this environment."},"environmentId":{"type":"string","format":"uuid","description":"The environment to delete them from. Leave out for the connection’s main credentials."}}},"example":{"credentialKey":"string","environmentId":"00000000-0000-0000-0000-000000000000"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"}},"required":["connectionId"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"ListCredentials","tags":["credentials"],"summary":"List Credentials","security":[{"ApiKeyAuth":["connections:read"]},{"BearerAuth":[]},{"OAuth2":["connections:read"]}],"description":"Which credentials are saved for a connection, for its main sign-in and for each environment: their names, sign-in method and when they were saved. The values themselves are never returned.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"credentials":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"authType":{"type":"string"},"expiresAt":{"type":"string","format":"date-time","nullable":true},"rotatedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"environmentId":{"type":"string","format":"uuid","nullable":true,"description":"Null = the connection’s own (default-environment) credentials."}},"required":["key","authType","createdAt","updatedAt"]}}},"required":["connectionId","credentials"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","credentials":[{"key":"string","authType":"string","expiresAt":"2026-01-01T00:00:00Z","rotatedAt":"2026-01-01T00:00:00Z","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z","environmentId":"00000000-0000-0000-0000-000000000000"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"StoreCredentials","tags":["credentials"],"summary":"Store Credentials","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Save the credentials a connection signs in with. They are encrypted before they are stored and can never be read back. For the connection’s main sign-in (no environmentId), Inferrex tests the new credentials against the system straight away and only starts using them if the system accepts them; otherwise the previous ones stay in use and the answer says why. Pass force: true to use them anyway. Replacing a key never reads the system again and never changes its status or pipelines. To keep separate credentials for, say, a sandbox and your live system, pass environmentId: the same connection can then sign in differently in each environment. The connection must already be set up in the environment you name.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"credentials":{"type":"object","additionalProperties":true,"description":"The credential values, by name, such as {\"apiKey\": \"…\"}."},"authType":{"type":"string","enum":["oauth2","api-key","basic","bearer","aws-sigv4","jwt","mtls","custom","none","service-account"],"description":"The sign-in method these credentials are for."},"expiresAt":{"type":"string","format":"date-time","description":"When the credentials expire, if they do (ISO 8601)."},"environmentId":{"type":"string","format":"uuid","description":"Save these credentials for one environment only. Leave out to save the connection’s main credentials."},"force":{"type":"boolean","description":"Main sign-in only: use the new credentials even if the test does not pass."}},"required":["credentials","authType"]},"example":{"credentials":{},"authType":"oauth2","expiresAt":"2026-01-01T00:00:00Z","environmentId":"00000000-0000-0000-0000-000000000000","force":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"storedKeys":{"type":"array","items":{"type":"string"}},"authType":{"type":"string"},"expiresAt":{"type":"string","nullable":true},"environmentId":{"type":"string","format":"uuid","nullable":true,"description":"The environment scope the keys were stored under; null = the connection’s default credentials."},"rotation":{"type":"object","properties":{"key":{"type":"string","description":"The secret now holding the new value: the live secret's name when it went live, else the stand-by copy's."},"live":{"type":"boolean","description":"Whether the new value is now in use."},"forced":{"type":"boolean","description":"It went live only because force was set."},"outcome":{"type":"string","description":"The worst test answer: accepted, refused, inconclusive, or untested."},"message":{"type":"string"},"previousKey":{"type":"string","nullable":true,"description":"Where the replaced value is kept, so it can be put back."},"candidateKey":{"type":"string","nullable":true,"description":"The new value's stand-by copy while it waits for a passing test; null once it is live."},"tests":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"connectionName":{"type":"string"},"testOutcome":{"type":"string","description":"The connection test's own answer: signed-in, credentials-rejected, forbidden, not-found, unreachable, redirect or not-testable."},"outcome":{"type":"string","description":"What it means for the secret. accepted: the API took it — a signed-in read of a declared endpoint answered 2xx with data (testOutcome signed-in). refused: 401 or 403. inconclusive: anything else, any 404 and the bare base address included."},"httpStatus":{"type":"integer","nullable":true},"detail":{"type":"string","description":"The answer in plain words. A refusal names the secret, its purpose and who saved it when; never its value."},"testedUrlTemplate":{"type":"string"},"provedBy":{"type":"string","nullable":true,"description":"The endpoint whose answer proved the read; null unless accepted."}},"required":["connectionId","connectionName","testOutcome","outcome","httpStatus","detail","testedUrlTemplate","provedBy"]}}},"required":["key","live","forced","outcome","message","previousKey","candidateKey","tests"],"description":"Main sign-in only: the test of the new credentials and whether they are in use."}},"required":["connectionId","storedKeys","authType"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","storedKeys":["string"],"authType":"string","expiresAt":"string","environmentId":"00000000-0000-0000-0000-000000000000","rotation":{"key":"string","live":true,"forced":true,"outcome":"string","message":"string","previousKey":"string","candidateKey":"string","tests":[{"connectionId":"00000000-0000-0000-0000-000000000000","connectionName":"string","testOutcome":"string","outcome":"string","httpStatus":0,"detail":"string","testedUrlTemplate":"string","provedBy":"string"}]}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/credentials/rotate":{"post":{"operationId":"RotateCredentials","tags":["credentials"],"summary":"Rotate Credentials","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Mark all of a connection’s saved credentials as needing replacement, in every environment. If the connection is active it goes back to waiting for review until new credentials are saved. Nothing new is generated or returned: save the new values with the store credentials call.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"rotatedKeys":{"type":"array","items":{"type":"string"}},"authType":{"type":"string"},"message":{"type":"string"}},"required":["connectionId","rotatedKeys","authType","message"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","rotatedKeys":["string"],"authType":"string","message":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/emit/{protocol}":{"get":{"operationId":"EmitConnection","tags":["connections"],"summary":"Emit Connection","security":[{"ApiKeyAuth":["connections:read"]},{"BearerAuth":[]},{"OAuth2":["connections:read"]}],"description":"Describe a connected system’s data in another format, such as a GraphQL or OpenAPI schema, built from what Inferrex learned when it read the API. Useful when another tool needs that system’s data shape in a format it understands.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"protocol","in":"path","required":true,"schema":{"type":"string","description":"The format to describe the data in, such as graphql or openapi."},"description":"The format to describe the data in, such as graphql or openapi."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string"},"protocol":{"type":"string"},"schema":{"type":"string"}},"required":["connectionId","protocol","schema"]},"example":{"connectionId":"string","protocol":"string","schema":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/entities/{entityId}/update-via":{"patch":{"operationId":"SetEntityUpdateVia","tags":["connections"],"summary":"Set Entity Update Via","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Choose how Inferrex updates a record it has already written to this system. Most APIs take a partial update (patch, the default). Some only accept a full replacement (put), and a few, such as Stripe, take updates as a POST to the record’s own address (post-to-get). Refused if the API has no address for the method you pick. The choice is kept when the API is read again.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","description":"The kind of record this applies to."},"description":"The kind of record this applies to."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"updateVia":{"type":"string","enum":["patch","put","post-to-get"],"description":"patch (partial update, the default), put (full replacement) or post-to-get (POST to the record’s own address)."}},"required":["updateVia"]},"example":{"updateVia":"patch"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"manifestId":{"type":"string","format":"uuid"},"entityId":{"type":"string"},"updateVia":{"type":"string"}},"required":["connectionId","manifestId","entityId","updateVia"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","manifestId":"00000000-0000-0000-0000-000000000000","entityId":"string","updateVia":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/field-group-recommendations":{"get":{"operationId":"GetFieldGroupRecommendations","tags":["connections"],"summary":"Get Field Group Recommendations","security":[{"ApiKeyAuth":["connections:read"]},{"BearerAuth":[]},{"OAuth2":["connections:read"]}],"description":"Suggested groups for this connection’s fields, based on what each field represents and the kind of record it belongs to. The same field always gets the same suggestion, and each one comes with a short reason. Fields you have already grouped are skipped unless you set includeGrouped.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"includeGrouped","in":"query","required":false,"schema":{"type":"boolean","description":"Also suggest groups for fields you have already grouped, to compare.","default":false},"description":"Also suggest groups for fields you have already grouped, to compare."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"manifestId":{"type":"string","format":"uuid"},"recommendations":{"type":"array","items":{"type":"object","properties":{"entityId":{"type":"string"},"entityName":{"type":"string"},"fieldId":{"type":"string"},"group":{"type":"string","description":"A group key from `catalogue`."},"basis":{"type":"string","description":"What the recommendation rests on. Known values: role, type."},"why":{"type":"string","description":"A plain-language reason to show the user."},"archetypeCorroborated":{"type":"boolean","description":"The object's kind agreed with the recommendation."}},"required":["entityId","entityName","fieldId","group","basis","why","archetypeCorroborated"]}},"recommendationCount":{"type":"integer"},"groups":{"type":"array","items":{"type":"string"},"description":"Groups already in use — a picker should offer these first."},"catalogue":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"}},"required":["key","label","description"]},"description":"The full recommendable set, so a picker can also offer groups not yet used."}},"required":["connectionId","manifestId","recommendations","recommendationCount","groups","catalogue"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","manifestId":"00000000-0000-0000-0000-000000000000","recommendations":[{"entityId":"string","entityName":"string","fieldId":"string","group":"string","basis":"string","why":"string","archetypeCorroborated":true}],"recommendationCount":0,"groups":["string"],"catalogue":[{"key":"string","label":"string","description":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/field-groups":{"patch":{"operationId":"SetFieldGroups","tags":["connections"],"summary":"Set Field Groups","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Put fields from a connected system into groups, such as “financial” or “contact details”, so you can make one decision for the whole group (for example, send everything financial to your data warehouse) instead of one per field. You can use the suggested group names or your own. Send group: null to take a field out of its group.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fields":{"type":"array","items":{"type":"object","additionalProperties":true},"maximum":500,"description":"One entry per field: {entityId, fieldId, group}. Send several at once to group a whole kind of record in one go."}},"required":["fields"]},"example":{"fields":[{}]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"manifestId":{"type":"string","format":"uuid"},"updated":{"type":"integer"},"groups":{"type":"array","items":{"type":"string"},"description":"Every group in use across the manifest after this change — the tenant's actual vocabulary."}},"required":["connectionId","manifestId","updated","groups"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","manifestId":"00000000-0000-0000-0000-000000000000","updated":0,"groups":["string"]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/field-inclusion":{"patch":{"operationId":"SetFieldInclusion","tags":["connections"],"summary":"Set Field Inclusion","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Include or leave out fields from a connected system. A field you leave out is ignored from then on: it is never suggested for mapping, never synced, never archived and never shown in your sensitive-data map. Each change is saved as a new version, so you can see it in the history and undo it.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fields":{"type":"array","items":{"type":"object","additionalProperties":true},"maximum":500,"description":"One entry per field: {entityId, fieldId, included}. Send several at once to include or leave out a whole kind of record in one go."}},"required":["fields"]},"example":{"fields":[{}]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"manifestId":{"type":"string","format":"uuid"},"updated":{"type":"integer"},"excludedCount":{"type":"integer","description":"Fields excluded across the whole manifest after this change."}},"required":["connectionId","manifestId","updated","excludedCount"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","manifestId":"00000000-0000-0000-0000-000000000000","updated":0,"excludedCount":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/inbound-events":{"get":{"operationId":"ListConnectionInboundEvents","tags":["connections"],"summary":"List Connection Inbound Events","security":[{"ApiKeyAuth":["connections:read"]},{"BearerAuth":[]},{"OAuth2":["connections:read"]}],"description":"The connection's inbound log, newest first. Metadata only — the payload is stored encrypted and is not returned. Status: accepted (waiting), queued (sent to `pipelines` pipelines), delivered (written through a pipeline, or, for a profile that feeds the golden record, kept with the golden records it belongs to; `error` then names any record not kept), ignored (valid, but its event type is not mapped, it is a delete, which is recorded and not propagated, or none of its records could join a golden record), no_pipeline (nothing on the connection takes it yet), coalesced (a later event for the same record replaced it), failed (`error` says why). Rows are deleted after inbound.payloadRetentionDays.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"profileKey":{"type":"string"},"vendorEventId":{"type":"string","nullable":true},"eventType":{"type":"string","nullable":true},"status":{"type":"string"},"error":{"type":"string","nullable":true},"payloadBytes":{"type":"integer"},"pipelines":{"type":"integer"},"receivedAt":{"type":"string","format":"date-time"},"processedAt":{"type":"string","format":"date-time","nullable":true}},"required":["id","profileKey","status","payloadBytes","pipelines","receivedAt"]}}},"required":["connectionId","events"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","events":[{"id":"00000000-0000-0000-0000-000000000000","profileKey":"string","vendorEventId":"string","eventType":"string","status":"string","error":"string","payloadBytes":0,"pipelines":0,"receivedAt":"2026-01-01T00:00:00Z","processedAt":"2026-01-01T00:00:00Z"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/ingest":{"post":{"operationId":"IngestConnectionEvents","tags":["connections"],"summary":"Ingest Connection Events","security":[],"description":"Send records to Inferrex yourself. Sign the request with the connection’s ingest token — shown once, when it was issued or rotated — as a Bearer token or in the X-Inferrex-Ingest-Token header. The records are stored encrypted in the connection’s inbound log and accepted at once (202). Pipelines are fed from that log, so Inferrex fetches nothing from the system. The records reach every active pipeline on the connection that takes records sent to it (its change feed is not poll; choosing the real-time frequency switches it to push). If no pipeline takes them, they are still accepted and logged as no_pipeline. A request whose token checks out but which carries no records (no body, an empty list, or any other shape without records or data) is the sender checking the address: it is answered with status test and nothing is stored. Add an X-Inferrex-Event-Id header to make a repeated delivery do nothing. At most 200 records a request.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"records":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"The records to send, as a list. Leave it out (or send an empty list or no body) to check the address and token: the answer is status test and nothing is stored."}}},"example":{"records":[{}]}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"accepted":{"type":"boolean"},"eventId":{"type":"string","format":"uuid","nullable":true,"description":"The inbound log entry; null for a repeated X-Inferrex-Event-Id."},"status":{"type":"string","description":"Known values: accepted (queued for the pipelines), no_pipeline (logged; nothing on this connection takes pushes yet), duplicate (this X-Inferrex-Event-Id was already received), test (the token checked out and the request carried no records; nothing stored)."},"pipelines":{"type":"integer","description":"Active pipelines the records will feed."},"records":{"type":"integer"}},"required":["accepted","status","pipelines","records"]},"example":{"accepted":true,"eventId":"00000000-0000-0000-0000-000000000000","status":"string","pipelines":0,"records":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/manifest":{"get":{"operationId":"GetConnectionManifest","tags":["connections"],"summary":"Get Connection Manifest","security":[{"ApiKeyAuth":["connections:read"]},{"BearerAuth":[]},{"OAuth2":["connections:read"]}],"description":"Get what Inferrex learned about a connected system: every kind of record it holds, their fields and how they relate, along with the version and review status of that description.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customerId":{"type":"string","format":"uuid"},"connectionId":{"type":"string","format":"uuid","nullable":true},"manifestType":{"type":"string"},"version":{"type":"integer"},"manifest":{"type":"object","properties":{"id":{"type":"string"},"version":{"type":"number","description":"incremented on every update"},"customerId":{"type":"string"},"systemKey":{"type":"string","description":"matches connector library key if known"},"displayName":{"type":"string","description":"inferred or customer-confirmed"},"baseUrl":{"type":"string","description":"The address the connection was given, as typed: it may hold `{placeholders}` anywhere — host, path or query (2026-10-26) — filled per request from `pathParams` / `pathParamSecrets` by joinEndpointUrl, so a value is never stored in it."},"logoUrl":{"type":"string"},"entities":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"apiName":{"type":"string","description":"name in the API"},"displayName":{"type":"string","description":"Layer 4 human label"},"pluralDisplayName":{"type":"string"},"description":{"type":"string"},"fields":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"stable identifier within entity"},"apiName":{"type":"string","description":"name as it appears in the API"},"displayName":{"type":"string","description":"human-readable label (Layer 4 output)"},"description":{"type":"string","description":"Layer 4 business description"},"type":{"type":"string","description":"A label from the L2 taxonomy."},"required":{"type":"boolean"},"nullable":{"type":"boolean"},"role":{"type":"string","description":"Semantic role (what the field MEANS vs `type` = what it IS). Canonical role vocabulary; drives dynamic-UI emphasis + cross-system field matching. Layer 4 / deterministic role classifier."},"roleConfidence":{"type":"number"},"roleSource":{"type":"string","description":"Who set `role` — OPEN string like `source`: 'customer' when a person chose it on the review page (absent `role` then means a person said the field has none). A person's role carries forward on re-inference. Absent = a classifier set it."},"sensitivity":{"type":"string","description":"A PERSON's data-sensitivity decision, made on the review page: a SensitivityClass ('pii' | 'financial' | 'health' | 'credential') or 'none' when they cleared it. Absent = derived by the shared classifier (resolveFieldSensitivity: role, refinements and the identity-number name default). Present, it IS the field's class wherever that classifier is read — review page, tenant sensitivity map, matcher, warehouse sink — and it carries forward on re-inference."},"enumValues":{"type":"array","items":{"type":"string"},"description":"for select/multiselect"},"currencyCode":{"type":"string","description":"for currency fields"},"scale":{"type":"number","description":"Minor-unit exponent: 2 = cents, 0 = major units. Set ONLY when the source format DECLARES it; carried into the routing transform so a cents field auto-reconciles with a dollars field."},"relatedEntityId":{"type":"string","description":"for relation fields"},"typeConfidence":{"type":"number","description":"0-1 (Layer 2 output)"},"typeRationale":{"type":"string","description":"plain language explanation for customer"},"requiresCustomerReview":{"type":"boolean"},"authority":{"type":"string","description":"Known values: provider-wins, native-only, native-override, latest-wins, merge."},"conflictStrategy":{"type":"string","description":"Known values: latest-timestamp, highest-authority, flag-for-review."},"exampleValues":{"type":"array","items":{}},"wireType":{"type":"string","description":"The type the SOURCE declares on the wire (OpenAPI `type`, OData Edm type, GraphQL scalar, SQL column type) — what the API says it sends, kept separately from `type` (what Inferrex infers it MEANS). Was dropped at assembly, so a model classifying the residual never saw it and a reviewer could not tell an inferred `string` from a declared `integer`. Absent on manifests inferred before 2026-09-27."},"wireFormat":{"type":"string","description":"The source's format hint for the wire type (OpenAPI `format`: date-time, uuid, int64, email, …). Absent when the source declares none."},"refTarget":{"type":"string","description":"The entity this field DECLARES a reference to in the spec ($ref leaf, OData navigation/Collection type, GraphQL object type); `[]` suffix marks an array of refs. Spec-declared, never inferred."},"source":{"type":"string","description":"Where the classification came from — OPEN string: 'spine' (deterministic rule), 'corpus' (known-vendor prior), 'cache', 'ai' (model, see typeRationale for the provider), 'customer' (a person set it). Lets the review UI and the A/B comparison tell a rule from a guess from a correction."},"group":{"type":"string","description":"Field group — an OPEN, tenant-defined label (audit §1.4, §Q.2b task 8). It is what makes fan-out usable at scale: \"everything financial also goes to the warehouse\" is one decision over a group, not forty over forty fields. Recommendations are DETERMINISTIC, derived from signals the platform already produces (semantic role, L2 type, L4 archetype) — no new inference, no new model, and the same field always lands in the same place, which a tenant can predict. Absent = ungrouped; a tenant's own label is treated identically to a recommended one."},"included":{"type":"boolean","description":"Schema-level include/exclude (audit §1.3). Absent = INCLUDED — the default is opt-out, so an existing manifest keeps every field. `false` is a tenant decision that the field is not wanted at all: it is dropped from the manifests L16 cross-system matching ever sees, so no mapping is ever proposed for it and nothing downstream (sync, archival, sensitivity map) can reach it. Distinct from FieldMapping.omitted, which declines ONE proposed link after the fact."},"nullRate":{"type":"number","description":"0-1, from data profiling"},"uniqueRate":{"type":"number","description":"0-1"},"lastSeen":{"type":"string","description":"ISO timestamp"},"valueProfile":{"type":"object","properties":{"sampleCount":{"type":"number"},"nullRate":{"type":"number"},"distinctCount":{"type":"number"},"formatHits":{"type":"object","additionalProperties":{"type":"number"}},"minLen":{"type":"number"},"maxLen":{"type":"number"}},"required":["sampleCount","nullRate","distinctCount","formatHits","minLen","maxLen"],"description":"Statistics over ONE page of live records read at introspection (value sampling, plan step 19, 2026-09-27): rows seen, null share, distinct count, how many values matched each format detector, string length range. Never raw values — those are in exampleValues (≤3) and stay on the tenant manifest. Absent when sampling did not run or the field was not in the page."},"refinements":{"type":"object","additionalProperties":true,"description":"Open refinement map — manifest-driven refinement layers write their label here, gated on deterministic-spine residual. Open by design: a new layer adds a key, no schema edit."}},"required":["id","apiName","displayName","type","required","nullable","typeConfidence","typeRationale","requiresCustomerReview","authority","conflictStrategy","exampleValues","nullRate","uniqueRate","lastSeen"]}},"relationships":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Known values: belongsTo, hasMany, hasOne, references."},"targetEntityId":{"type":"string","description":"entity ID within same manifest"},"throughField":{"type":"string","description":"which field carries the FK"},"confidence":{"type":"number"},"rationale":{"type":"string"}},"required":["type","targetEntityId","throughField","confidence","rationale"]}},"category":{"type":"string","description":"Structural tier: only 'domain' entities surface in the dynamic UI + golden data layer; the rest are API plumbing and filtered out. Known values: domain, operation, transport, descriptor, collection, error, enum."},"archetype":{"type":"string","description":"Domain tier: the cross-system domain category that unifies the same concept across providers."},"archetypeConfidence":{"type":"number"},"endpoints":{"type":"object","properties":{"list":{"type":"string"},"get":{"type":"string"},"create":{"type":"string"},"update":{"type":"string"},"delete":{"type":"string"},"search":{"type":"string"}}},"postRead":{"type":"object","properties":{"path":{"type":"string","description":"The read endpoint, relative to the connection base URL; may hold `{placeholders}` filled from the path values (`/v2/workspaces/{workspace}/records/search`)."},"body":{"type":"object","additionalProperties":true,"description":"The JSON body sent with every page, as declared (no placeholders are filled in it). Absent = `{}`."},"paging":{"type":"string","description":"Absent = 'none': one request. 'body-offset' = the page size and the number of rows to skip go in the body (`limitField`, `offsetField`); the read stops on a short or empty page or at the page cap. Known values: none, body-offset."},"pageSize":{"type":"number","description":"body-offset: rows per page. Absent = 100."},"limitField":{"type":"string","description":"body-offset: the top-level body key for the page size. Absent = `limit`."},"offsetField":{"type":"string","description":"body-offset: the top-level body key for the rows to skip. Absent = `offset`."},"recordsPath":{"type":"string","description":"Dotted path to the records in the answer. Absent = the shared list-response reader finds them ('objects'), or `data` ('table')."},"rowShape":{"type":"string","description":"Absent = 'objects': an array of records. 'table' = columns and rows apart, `{ fields: [...], data: [[...]] }`; each row is zipped with the column names. A column descriptor is a string, or an object named by the key its `type` names (`{ type: 'property', property: 'email' }` → `email`), else its `name` or `id`. Known values: objects, table."},"columnsPath":{"type":"string","description":"table: dotted path to the column descriptors. Absent = `fields`."},"successField":{"type":"string","description":"Dotted path to a boolean success flag; `false` there is a failed read. Absent = `success`, checked when present."},"updatedAtField":{"type":"string","description":"A record field holding when it last changed, for the sync's sourceUpdatedAt. Absent = none: every POST read is a full read."}},"required":["path"],"description":"How to list this entity when its API reads by POST (2026-10-26; generic — any API whose reads are POSTs, no vendor or source system assumed). Used only when the connection's `listVia` is 'post' — two keys, so an inferred entity alone can never cause a POST. Read by the shared reader @inferrex/utils/post-read.js in the sync worker, the value sampler and the mapping sample. Absent = the entity lists through its GET list endpoint. Carried forward on re-inference by entity api name. Nothing sets it from a spec yet: a provider profile or a tenant setting supplies it (follow-up)."},"updateVia":{"type":"string","description":"How a sync updates one record it created before (target-id memory, 2026-10-08). Absent = 'patch' to the update endpoint. 'put' for APIs that only take PUT on an item (the Acme demo mocks). 'post-to-get' POSTs to the get endpoint's path: Stripe updates /v1/customers/{customer} that way and declares no update endpoint. Set with PATCH /v1/connections/:id/entities/:entityId/update-via; carried forward on re-inference. Known values: patch, put, post-to-get."},"deletion":{"type":"object","properties":{"field":{"type":"string","description":"Dotted path to the marker in the record (`deleted`, `meta.is_deleted`)."},"value":{"type":"string","description":"The value that marks a deletion, as text: a scalar in the record matches when it reads the same (`'true'` matches `true`, `'1'` matches `1`, `'deleted'` matches `\"deleted\"`). An object, an array or null never matches."},"whenPresent":{"type":"boolean","description":"true = any non-null value marks a deletion (`deleted_at`)."},"source":{"type":"string","description":"Where it came from — OPEN string: 'spec' (inferred from the description), 'customer' (a person set it)."}},"required":["field"],"description":"How a record of this entity says it was deleted (2026-10-28; generic — any API that lists its deletions as records, no vendor assumed). Read by the sync worker (services/sync/src/batch-signals.ts): a record that matches is a DELETE — counted as a deletion for the safety stop and tombstoned in record_versions, the op erasure writes — and is never versioned, mapped or written as a sparse record. Set by inference from a record | tombstone union in the spec (`deleted: false` on the record, `deleted: true` on its tombstone). Absent = no record is a deletion; a deletion is seen only as an absence from a full listing, as before."},"incremental":{"type":"object","properties":{"param":{"type":"string","description":"The query parameter (`updated_since`)."},"format":{"type":"string","description":"How the time is written — OPEN string: 'date-time' (ISO 8601, the absent default), 'date' (YYYY-MM-DD), 'unix' (epoch seconds), 'unix-ms'. An unknown format is sent as ISO 8601."},"source":{"type":"string","description":"Where it came from — OPEN string: 'spec', 'customer'."}},"required":["param"],"description":"The query parameter this entity's list read takes to return only what changed since a time (2026-10-28; generic). The sync worker sends it with the entity's `since` on an incremental run instead of its fixed `modified_since` guess, and drops it, reading in full, if the source answers 400/422. Set by inference from a date-time query parameter on the list operation whose name or description reads as changes-since (updated_since, modified_since, changed_since, since, …). Absent = the old guess."},"embeddedIn":{"type":"string","description":"The api name of the record this entity is only ever read inside (2026-10-28): an order's lines when the spec writes the line as an inline object (RawEntity.embeddedIn). It has no endpoint of its own; the record's field that holds it is a collection with a hasMany edge to it, which is how setup options list its fields (itemFields). Set by inference, kept by the AI merge. Absent = an entity read through its own endpoints."},"write":{"type":"object","properties":{"successField":{"type":"string","description":"Dotted path to a boolean in a 2xx answer; `false` there is a REFUSED write (quarantined, never counted as written). Bloomreach Engagement answers `200 { success: false, errors }` to a command it will not process, and retrying it fails again. Absent = the status alone decides."},"errorsField":{"type":"string","description":"Dotted path to the API's own reasons in a refused answer, quoted (capped) in the quarantine reason. Absent = the whole answer, capped."},"keyPlaceholder":{"type":"string","description":"The one placeholder of the create endpoint that is the record's OWN id, filled per record from the source record's id (a keyed upsert: `/catalogs/{catalogId}/items/{itemId}/partial-update`). Absent = a create endpoint with an unfilled placeholder is refused, as before."},"keyForbiddenChars":{"type":"string","description":"Characters a record id may not hold when it fills `keyPlaceholder`; such a record is refused (quarantined) rather than sent. Engagement serves catalog item edits only for ids without `/`."},"maxPerMinute":{"type":"number","description":"Most write REQUESTS per minute sent to this entity (a batch call is one request; every retry is one more). Since 2026-10-27 (phase 9) a budget SHARED by every writer in its `rateScope` — sync jobs, workers and replicas, and the golden write-back — kept in Redis (@inferrex/utils/rate-budget.js); while Redis is unreachable each process paces itself and logs a warning. Absent = not paced."},"rateScope":{"type":"string","description":"Which writers share `maxPerMinute` (2026-10-27, phase 9). OPEN string: 'entity' (absent = this; one connection's entity), 'connection' (every entity of the connection), 'tenant' (every connection of one tenant to the same host), 'destination-host' (every tenant and worker writing to the same host — a destination that limits per caller IP, as Inferrex calls from one egress). An unknown value is read as 'entity'."},"idempotent":{"type":"boolean","description":"Sending the same write twice leaves the destination as sending it once (a keyed upsert; a property SET carrying its own update time). Declared by a reviewed profile, never inferred. Lets the writer retry a failure that may already have been applied (a timeout, a 503). Absent = false: such a failure is never retried; only a 429 or a request that provably never left (connection refused) is."},"idempotencyKeyHeader":{"type":"string","description":"A request header the destination de-duplicates writes by. The writer sends a key derived from the record and its content, the same on every attempt, so a retried write lands at most once; it makes retries as safe as `idempotent`. Absent = no key is sent."},"retryOn":{"type":"array","items":{"type":"number"},"description":"HTTP statuses this destination answers for a TRANSIENT failure besides 429 and 503 (e.g. 502, 504). Retried like a 503: only when the write is idempotent. Absent = 429 and 503 only."},"batch":{"type":"object","properties":{"path":{"type":"string","description":"The batch endpoint, relative to the connection's base URL; `{placeholders}` are filled from the connection's path values."},"method":{"type":"string","description":"Absent = 'POST'. Known values: POST, PUT."},"commandsField":{"type":"string","description":"Top-level body key holding the list of commands (`commands`)."},"commandName":{"type":"string","description":"The constant every command of this entity carries as its kind (`customers/events`). Absent = no name is set."},"commandNameField":{"type":"string","description":"The command key `commandName` goes in. Absent = `name`."},"commandDataField":{"type":"string","description":"The command key the record's own body goes in (`data`). Absent = the record's body IS the command."},"commandIdField":{"type":"string","description":"A command key the writer fills with an id unique within the call (`command_id`), so a result can name its command."},"maxCommands":{"type":"number","description":"Most commands in one call."},"maxCommandBytes":{"type":"number","description":"Most bytes one command may take, as JSON. A record over it is refused (quarantined) without being sent."},"maxRequestBytes":{"type":"number","description":"Most bytes one whole request body may take, as JSON. Calls are closed before they would pass it."},"resultsField":{"type":"string","description":"Dotted path to the list of per-command results in a 2xx answer (`results`)."},"resultIdField":{"type":"string","description":"The result key that echoes `commandIdField`. Absent = results are in command order. A command with no result is a FAILED write (its outcome is unknown), never a written one."},"resultSuccessField":{"type":"string","description":"Dotted path to a boolean in one result; `false` is that command refused. Absent = `success`."},"resultErrorsField":{"type":"string","description":"Dotted path to that command's reasons, quoted (capped) in its quarantine reason. Absent = the whole result."},"separateBy":{"type":"string","description":"Dotted path in a record's body: two commands with the same value there never share a call, because the destination may run one call's commands out of order (Engagement, partner ask P3). A later call is sent only after the earlier one is answered."}},"required":["path","commandsField","maxCommands","resultsField"],"description":"How this entity's creates go many to a call (2026-10-27, phase 9; generic). The writer groups creates within the declared count and byte limits and reads one result per command, so each record succeeds, fails with its reason, or is quarantined on its own. Absent = one request per record, exactly as before. Not used with `keyPlaceholder` (a per-record address cannot share a call)."},"addedBy":{"type":"string","description":"Set when the entity was ADDED to the manifest by an approved destination setup plan (`destination-setup-plan:<plan id>`), not inferred: a re-inference carries the whole entity forward, because no spec or crawl will find it again. OPEN string."},"allowance":{"type":"object","properties":{"maxPerMinuteTunable":{"type":"string","description":"The tunable whose tenant value may raise `maxPerMinute` (as the tenant's own budget). Absent = the rate is never raised."},"maxCommandsTunable":{"type":"string","description":"The tunable whose tenant value may raise `batch.maxCommands`. Absent = the batch size is never raised."}},"description":"A per-tenant partner allowance above `maxPerMinute` and `batch.maxCommands` (2026-10-28, generic): the platform tunables holding the tenant's own values, read by the writer at each write (@inferrex/utils/write-allowance.js). A tenant value above the contract's limit replaces it for that tenant's writes; a raised rate is the tenant's own budget for the host (rate scope 'tenant'), never the shared one. A value at or below the contract's is ignored, so it only raises. Stamped by a setup plan from the destination profile's allowance. Absent = the declared limits."},"requiredValues":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Dotted path in the record's body as written (`properties.action`). Empty text counts as absent."},"when":{"type":"object","properties":{"field":{"type":"string","description":"Dotted path in the body."},"equals":{"type":"string","description":"Holds when the value, as text, equals this."}},"required":["field","equals"],"description":"Only required when this holds (`properties.action` equals `accept`). Absent = always required."},"why":{"type":"string","description":"Why it is required, in words a person can act on; quoted in the hold's reason."}},"required":["field"]},"description":"Values a record must carry, read from its body as written (dotted paths), or it is HELD BACK: quarantined with the reason and never sent, by every writer (the sync writer, a history file, the one-record writer), and a released record is checked again (2026-10-28, generic; Bloomreach Engagement phase 10: a consent event missing its action, category or, for an accept, its expiry is not sent, because Engagement revokes consent on an invalid one). Set from a reviewed profile by an approved setup plan; nothing infers it. Absent = no check."},"sendWhen":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Dotted path in the body as written (`properties.region`)."},"op":{"type":"string","description":"The test. Known values: equals, not-equals, in, exists, missing, gt, gte, lt, lte, contains."},"value":{"type":"string","description":"The one value of `equals`, `not-equals`, `contains` (text) and `gt`, `gte`, `lt`, `lte` (a number, written as text). Absent for `in`, `exists` and `missing`."},"values":{"type":"array","items":{"type":"string"},"description":"The texts of `in`. Absent otherwise."}},"required":["field","op"]},"description":"Which records go to this destination at all (2026-10-28, generic; several destination projects, design §N.4.2): conditions on the record's body as written (dotted paths), every one of which must hold. A record that does not meet them is SKIPPED and counted by every writer that checks `requiredValues` (the sync writer, a history file, the one-record writer), never quarantined: it was never meant for this destination. Set by an approved setup plan from the tenant's own rule; nothing infers it. Absent = every record."}},"description":"How a write to this entity is judged and paced beyond its HTTP status (2026-10-27, Bloomreach Engagement phase 1; generic — any API that answers 200 to a refused write, or keys a create by the record's own id). Read by the sync writer (services/sync/src/logic.ts) and the golden write-back (reverse-sync-provider-client.ts). Absent = a 2xx is success, a create endpoint is POSTed as is, and writes are not paced. Carried forward on re-inference (an entity a setup plan added is kept whole: `addedBy`)."},"overallConfidence":{"type":"number"},"requiresCustomerReview":{"type":"boolean"},"reviewableFields":{"type":"array","items":{"type":"string"},"description":"field IDs needing review"},"refinements":{"type":"object","additionalProperties":true,"description":"Open refinement map — entity-scope refinement layers (e.g. entity-namer archetype) write here, gated on deterministic-spine residual."}},"required":["id","apiName","displayName","pluralDisplayName","description","fields","relationships","endpoints","overallConfidence","requiresCustomerReview","reviewableFields"]}},"auth":{"type":"object","properties":{"method":{"type":"string","description":"Known values: oauth2, api-key, basic, bearer, aws-sigv4, jwt, mtls, custom, none."},"scheme":{"type":"string","description":"The fine-grained auth scheme from L11 auth-scheme-classifier (OPEN: oauth2_authorization_code, oauth2_client_credentials, jwt, hmac_signature, mtls, …) — refines the coarse `method` with the OAuth flow / transport distinction. A novel scheme flows through as a string."},"oauth2":{"type":"object","properties":{"authorizeEndpoint":{"type":"string"},"tokenEndpoint":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"pkce":{"type":"boolean"},"refreshable":{"type":"boolean"}},"required":["tokenEndpoint","pkce","refreshable"]},"apiKey":{"type":"object","properties":{"headerName":{"type":"string"},"prefix":{"type":"string"}},"required":["headerName"]}},"required":["method"]},"pagination":{"type":"object","properties":{"style":{"type":"string","description":"Known values: offset-limit, cursor, page-number, link-header, none."},"pageSize":{"type":"number"},"pageSizeParam":{"type":"string"},"offsetParam":{"type":"string"},"pageParam":{"type":"string","description":"page-number style: the query parameter carrying the 1-based page (from the spec, plan step 39). Absent = `page`."},"cursorParam":{"type":"string","description":"cursor style: the query parameter the next cursor is sent in. Absent = `cursor`. Manifests inferred before 2026-09-27 carried this in cursorField."},"cursorField":{"type":"string","description":"cursor style: the response field (dotted path) holding the next cursor; the sync worker also tries the common names (next_cursor, nextCursor, meta.next_cursor, paging.next, pageInfo.endCursor, …)."},"totalField":{"type":"string"}},"required":["style","pageSize"]},"rateLimit":{"type":"object","properties":{"requestsPerMinute":{"type":"number"},"requestsPerDay":{"type":"number"},"burstLimit":{"type":"number"},"retryAfterHeader":{"type":"string"}},"required":["requestsPerMinute","retryAfterHeader"]},"inferredAt":{"type":"string"},"inferredBy":{"type":"string","description":"model version"},"overallConfidence":{"type":"number"},"requiresReview":{"type":"array","items":{"type":"string"},"description":"field/entity IDs needing customer input"},"specSource":{"type":"string","description":"URL if spec was found"},"userSpecUrl":{"type":"string","description":"The vendor's spec or API reference URL the tenant gave at connect or re-infer (2026-10-09). Distinct from specSource, which is where inference actually found a spec: this is what the tenant asked it to read. Discovery fetches it first, through the shared SSRF guard, and uses it when it is an OpenAPI or Swagger document; an HTML docs page is recorded but not scraped. Carried forward on re-inference when no new one is given; a re-infer with specUrl null clears it."},"documentationSource":{"type":"string","description":"URL of primary docs used"},"inferenceMethod":{"type":"string","description":"How discovery read the API. soap = a WSDL (?wsdl, or the spec URL); grpc = a .proto; asyncapi / json-schema / avro = that description at a well-known path or the spec URL; jsonapi = a JSON:API service crawled from its links; probed = a crawl of HAL links, Link headers and well-known paths. Known values: openapi, graphql, odata, mcp, documentation, probed, library, cli, soap, grpc, asyncapi, json-schema, avro, jsonapi."},"status":{"type":"string","description":"Known values: inferring, awaiting-review, approved, active, error."},"customerApprovedAt":{"type":"string"},"customerApprovedBy":{"type":"string"},"previousVersionId":{"type":"string"},"changeReason":{"type":"string"},"systemDescription":{"type":"string","description":"L6 (semantic interpretation): what this system is, in a sentence. Computed on every run since L6 shipped and discarded until 2026-09-27; now persisted so the review page and the match prompt can use it."},"industryClassification":{"type":"string","description":"L6: the industry the system serves (OPEN string; 'unknown' when the layer did not run). For a known vendor v2 takes it from the lake's provider summary instead of a model call."},"complianceRelevance":{"type":"array","items":{"type":"string"},"description":"L6: compliance regimes the data plausibly falls under (GDPR, PCI-DSS, HIPAA, SOX, …) — OPEN strings, advisory only; the deterministic sensitivity rules remain the enforcement."},"corpusPrior":{"type":"object","properties":{"providerKey":{"type":"string"},"capturedAt":{"type":"string"},"ageDays":{"type":"number"},"stale":{"type":"boolean"},"fieldsTyped":{"type":"number"},"fieldsEnriched":{"type":"number"},"edgesAdded":{"type":"number"},"authApplied":{"type":"boolean"},"paginationApplied":{"type":"boolean"}},"required":["providerKey","stale","fieldsTyped","fieldsEnriched","edgesAdded","authApplied","paginationApplied"],"description":"Set when the v2 spine seeded this manifest from the connector library and its sidecar for a KNOWN vendor (2026-09-27). `capturedAt` is the sidecar generatedAt — how old the library snapshot is; `stale` means older than inference.corpusPrior.maxAgeDays, in which case the prior confidence was lowered and the review page says so. The live spec always overrode the prior where it declared something different."},"baseline":{"type":"object","properties":{"providerKey":{"type":"string"},"entitiesMatched":{"type":"number"},"entitiesNew":{"type":"number"},"fieldsMatched":{"type":"number"},"fieldsNew":{"type":"number"},"fieldsChanged":{"type":"number"}},"required":["providerKey","entitiesMatched","entitiesNew","fieldsMatched","fieldsNew","fieldsChanged"],"description":"Set when the vendor has a verified baseline (2026-10-09): a person-approved manifest from an earlier connection, promoted and released into the connector library. Fields the baseline knows with the same declared type were typed from it and not sent to the AI; `fieldsNew` and `fieldsChanged` were, with every entity the baseline does not know (`entitiesNew`). Absent when the vendor has no baseline. Never names the connection the baseline came from: that is another tenant's (2026-10-11)."},"verifiedBaseline":{"type":"object","properties":{"providerKey":{"type":"string"},"approvedAt":{"type":"string"},"promotedAt":{"type":"string"}},"required":["providerKey","approvedAt","promotedAt"],"description":"Only on a connector-library manifest that IS a vendor baseline (2026-10-09): when the connection it was promoted from was approved, and when it was promoted. Never names that connection — the library is read by every tenant; the source connection and tenant stay on connector_library.promotion_staging (2026-10-11). Structure only — built by toBaselineManifest, which drops every value and tenant choice. Its presence is what tells inference to type known fields from it."},"valueSampling":{"type":"object","properties":{"entitiesSampled":{"type":"number"},"entitiesFailed":{"type":"number"},"rowsFetched":{"type":"number"},"fieldsProfiled":{"type":"number"},"fieldsTyped":{"type":"number"},"sampledAt":{"type":"string"},"durationMs":{"type":"number"},"errors":{"type":"array","items":{"type":"string"}},"notSampled":{"type":"array","items":{"type":"string"}}},"required":["entitiesSampled","entitiesFailed","rowsFetched","fieldsProfiled","fieldsTyped","sampledAt","durationMs"],"description":"Set when introspection read a page of live records per entity (value sampling, plan step 19, 2026-09-27) — how much was seen and how many fields it typed that the spec and the rules had left open. The values themselves live on the fields (exampleValues, valueProfile), never here. `errors` (2026-10-08): up to 10 `entity: reason` lines for the entities that could not be read — an HTTP status or a token failure — so a failed sample says what to fix. `notSampled` (2026-10-13): up to 10 `entity: reason` lines for the entities deliberately not sampled — those read from an MCP server, whose tools are never called while sampling (a tool can change data) and whose resources are not HTTP endpoints. Not failures, so not counted in entitiesFailed."},"engine":{"type":"string","description":"Which inference engine produced this manifest (engine-switch decision, 2026-09-27): 'v1' | 'v2' | 'v2-proprietary'. Absent on manifests inferred before the switch existed."},"engineArm":{"type":"string","description":"How the engine was chosen — the A/B arm for grouping runs: 'v1', 'v2', 'ab:v2', 'override:v2', …"},"engineFallbackReason":{"type":"string","description":"Set when the selected engine could not serve and the run fell back to v1 (engine-not-available | engine-unavailable | engine-error | budget | timeout)."},"writeEncoding":{"type":"string","description":"How the API takes a write's request body (2026-10-08). Absent = JSON. 'form' = application/x-www-form-urlencoded with bracket keys for nested values (`metadata[key]=v`, `items[0][price]=p`) — Stripe's contract, which rejects JSON bodies. Detected from a spec whose write operations accept only form bodies; a tenant sets it with PATCH /v1/connections/:id/write-encoding; carried forward on re-inference. Known values: json, form."},"reread":{"type":"object","properties":{"scope":{"type":"string"},"confidenceBelow":{"type":"number"},"fields":{"type":"array","items":{"type":"object","properties":{"entity":{"type":"string"},"field":{"type":"string"}},"required":["entity","field"]}},"notFound":{"type":"array","items":{"type":"object","properties":{"entity":{"type":"string"},"field":{"type":"string"}},"required":["entity","field"]}},"fromManifestId":{"type":"string"},"readAt":{"type":"string"}},"required":["scope","fields","notFound","fromManifestId","readAt"],"description":"Set on a version made by a PART re-read (Aaron, 2026-10-12: only re-read fields that are lower confidence or not mapped). `scope` is the choice (low-confidence, unmapped, low-confidence-or-unmapped — an OPEN string); `fields` are the fields read again and replaced, by object and field API name; `notFound` were selected but not shown by the API this time and were kept; every other field, object and setting is the version `fromManifestId` unchanged. Absent on a full read."},"listVia":{"type":"string","description":"How a read lists an entity's records (DEBT-191, 2026-10-09). Absent = 'endpoint': GET the entity's list endpoint and follow the manifest's pagination. 'soql' = Salesforce REST, where GET /sobjects/{X} returns the object's metadata and recentItems, not its records: the sync worker, the value sampler and the mapping sample describe the object (/sobjects/{X}/describe) for its queryable fields, query them with GET /query?q=SELECT … FROM X, and follow each page's nextRecordsUrl until done. Detected at inference from the API's shape (detectListVia in @inferrex/utils/soql-read.js: a /services/data/vNN.N base, or a spec declaring GET /query?q= beside /sobjects/ resources), so a re-inference sets or clears it. 'post' (2026-10-26, generic) = an API whose reads are POSTs: each entity that declares `postRead` is listed by POSTing that declared body to that declared read endpoint (@inferrex/utils/post-read.js), the rest through their GET list endpoint. No spec shape detects it; it is set with the entities' `postRead` declarations and carried forward on re-inference while detection finds nothing else. Known values: endpoint, soql, post."},"authError":{"type":"string","description":"Set when inference could not get an access token for this connection (2026-10-08) — the OAuth token endpoint's refusal, e.g. `OAuth client_credentials token request to x.my.salesforce.com failed: invalid_client`. The run then probed unauthenticated, so its entities read 'not confirmed'. Absent when the token was issued or the auth type needs none."},"pathParams":{"type":"object","additionalProperties":{"type":"string"},"description":"Values for the endpoint placeholders that are not a record id — Bloomreach DataConnect's `{account_name}`, `{catalog_name}`, `{environment_name}` (2026-09-28). Only the tenant knows them; set with PATCH /v1/connections/:id/path-params, carried forward on re-inference, filled into every request by joinEndpointUrl. A request whose endpoint still holds a placeholder is refused rather than sent."},"pathParamSecrets":{"type":"object","additionalProperties":{"type":"string"},"description":"Placeholders whose value is kept in a saved workspace secret rather than on the manifest (2026-10-26, Aaron: \"store that placeholder as a secret so it can be reused\"): placeholder name → the `inferrex.tenant_secrets.key` of a workspace-shared secret. The value is read only at the moment of a request (resolvePathValues in @inferrex/infra/path-values.js) and is never stored here, returned or logged. A name is in `pathParams` or here, never both. Set on connect (POST /v1/connections/infer `pathParams` with `{ secretRef }`), re-read, or PATCH /v1/connections/:id/path-params; carried forward on re-inference like `pathParams`."},"readPaths":{"type":"array","items":{"type":"string"},"description":"Endpoint paths the tenant asked Inferrex to read (2026-10-26, Aaron: \"This should be configurable so someone can build the URL themselves\"), relative to `baseUrl`, each possibly holding `{placeholders}` filled from `pathParams` / `pathParamSecrets` — `/data/v2/projects/{projectToken}/catalogs`. Discovery tries them first when the API publishes no description (they seed the spec-less crawl), and records each as its template, never with a value filled in. Carried forward on re-inference unless the re-read gives new ones."},"readProfile":{"type":"string","description":"The provider read profile this connection reads with (2026-10-27, Bloomreach Engagement phase 4): the key of a profile in @inferrex/service-schema read-profiles.ts — reviewed data for the reads no spec or crawl finds. Its POST reads become entities carrying `postRead` (one page read at inference teaches their fields) and set `listVia: 'post'`; its GET reads name the entity the crawl finds on that path. Set by the module that connects the system (the Bloomreach module), or found from the address when it is one of a profile's known hosts; a re-inference keeps it. Absent = no profile."},"aiLane":{"type":"object","properties":{"lane":{"type":"string","description":"'scheduled-batch' today."},"state":{"type":"string","description":"scheduled (waiting for the tenant's window) | submitted (the batch is with Azure) | applied (its answers are on this manifest) | failed (nothing could be submitted or applied; the residual stays for review)."},"scheduledFor":{"type":"string","description":"ISO time the residual will be submitted (state scheduled)."},"batchId":{"type":"string"},"submittedAt":{"type":"string"},"appliedAt":{"type":"string"},"entitiesSubmitted":{"type":"number"},"entitiesApplied":{"type":"number"},"reservedTokens":{"type":"number","description":"Budget tokens reserved against the tenant's daily hosted-model budget at submit: the estimated input tokens, weighted by the Batch/interactive price ratio from the Foundry cost card when ai.batchLane.costWeightedBudget is on; reconciled in the same units when the batch is applied."},"detail":{"type":"string","description":"Why the lane stopped (state failed), or the batch terminal status when applied (completed | cancelled | expired)."}},"required":["lane","state"],"description":"Set when this manifest's AI step runs in a lane other than the interactive one (2026-10-09, decision 2026-10-09-async-ai-pipeline-step §5): the scheduled Azure OpenAI Batch lane. The manifest is the deterministic one until the batch is applied; the residual stays flagged for review meanwhile. Absent = the interactive lane."}},"required":["id","version","customerId","displayName","baseUrl","entities","auth","pagination","rateLimit","inferredAt","inferredBy","overallConfidence","requiresReview","inferenceMethod","status"],"description":"What Inferrex understood about the system, with every reviewer correction applied on top: its objects (`entities`), each with its fields (type, role, sensitivity, confidence, whether it needs review). A field is addressed as `<entity id>.<field id>`, the path the review routes take."},"status":{"type":"string"},"parentId":{"type":"string","format":"uuid","nullable":true},"createdBy":{"type":"string"},"createdAt":{"type":"string"},"fieldReviews":{"type":"object","properties":{"reviewed":{"type":"integer","description":"Review rows considered."},"approved":{"type":"integer","description":"Fields a person approved as inferred."},"corrected":{"type":"integer","description":"Fields whose type, name or description a person changed."},"rejected":{"type":"integer","description":"Fields a person rejected without a correction; they are flagged for review again."},"unmatched":{"type":"integer","description":"Reviews whose field no longer exists on this version (renamed or excluded)."}},"required":["reviewed","approved","corrected","rejected","unmatched"],"description":"Present only when people have reviewed fields on this manifest or a version it was edited from: how those reviews were applied to the copy returned."},"fieldReviewStates":{"type":"object","additionalProperties":{"type":"object","properties":{"state":{"type":"string","enum":["approved","rejected","unreviewed"],"description":"`approved`: a person approved it, as inferred or with a correction. `rejected`: a person said it is wrong without correcting it. `unreviewed`: nobody has decided."},"at":{"type":"string","format":"date-time","description":"When the decision was recorded. Absent while unreviewed."},"by":{"type":"string","format":"uuid","description":"The reviewer's user id. Absent while unreviewed, and for a decision whose audit entry names no user (one made before reviews were audited, 2026-10-11)."}},"required":["state"]},"description":"Every field of `manifest`, keyed `<entity id>.<field id>` (the path the review routes take), with whether a person has decided on it. Lets a screen count what is still to approve: an included field with typeConfidence ≥ 0.9, not flagged, whose state is `unreviewed`. Absent only when the review records could not be read for this answer — then nothing is known about who approved what."}},"required":["id","customerId","manifestType","version","manifest","status","createdBy","createdAt"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customerId":"00000000-0000-0000-0000-000000000000","connectionId":"00000000-0000-0000-0000-000000000000","manifestType":"string","version":0,"manifest":{"id":"string","version":0,"customerId":"string","systemKey":"string","displayName":"string","baseUrl":"string","logoUrl":"string","entities":[{"id":"string","apiName":"string","displayName":"string","pluralDisplayName":"string","description":"string","fields":[{"id":"string","apiName":"string","displayName":"string","description":"string","type":"string","required":true,"nullable":true,"role":"string","roleConfidence":0,"roleSource":"string","sensitivity":"string","enumValues":["string"],"currencyCode":"string","scale":0,"relatedEntityId":"string","typeConfidence":0,"typeRationale":"string","requiresCustomerReview":true,"authority":"string","conflictStrategy":"string","exampleValues":[],"wireType":"string","wireFormat":"string","refTarget":"string","source":"string","group":"string","included":true,"nullRate":0,"uniqueRate":0,"lastSeen":"string","valueProfile":{"sampleCount":0,"nullRate":0,"distinctCount":0,"formatHits":{},"minLen":0,"maxLen":0},"refinements":{}}],"relationships":[{"type":"string","targetEntityId":"string","throughField":"string","confidence":0,"rationale":"string"}],"category":"string","archetype":"string","archetypeConfidence":0,"endpoints":{"list":"string","get":"string","create":"string","update":"string","delete":"string","search":"string"},"postRead":{"path":"string","body":{},"paging":"string","pageSize":0,"limitField":"string","offsetField":"string","recordsPath":"string","rowShape":"string","columnsPath":"string","successField":"string","updatedAtField":"string"},"updateVia":"string","deletion":{"field":"string","value":"string","whenPresent":true,"source":"string"},"incremental":{"param":"string","format":"string","source":"string"},"embeddedIn":"string","write":{"successField":"string","errorsField":"string","keyPlaceholder":"string","keyForbiddenChars":"string","maxPerMinute":0,"rateScope":"string","idempotent":true,"idempotencyKeyHeader":"string","retryOn":[0],"batch":{"path":"string","method":"string","commandsField":"string","commandName":"string","commandNameField":"string","commandDataField":"string","commandIdField":"string","maxCommands":0,"maxCommandBytes":0,"maxRequestBytes":0,"resultsField":"string","resultIdField":"string","resultSuccessField":"string","resultErrorsField":"string","separateBy":"string"},"addedBy":"string","allowance":{"maxPerMinuteTunable":"string","maxCommandsTunable":"string"},"requiredValues":[{"field":"string","when":{"field":"string","equals":"string"},"why":"string"}],"sendWhen":[{"field":"string","op":"string","value":"string","values":["string"]}]},"overallConfidence":0,"requiresCustomerReview":true,"reviewableFields":["string"],"refinements":{}}],"auth":{"method":"string","scheme":"string","oauth2":{"authorizeEndpoint":"string","tokenEndpoint":"string","scopes":["string"],"pkce":true,"refreshable":true},"apiKey":{"headerName":"string","prefix":"string"}},"pagination":{"style":"string","pageSize":0,"pageSizeParam":"string","offsetParam":"string","pageParam":"string","cursorParam":"string","cursorField":"string","totalField":"string"},"rateLimit":{"requestsPerMinute":0,"requestsPerDay":0,"burstLimit":0,"retryAfterHeader":"string"},"inferredAt":"string","inferredBy":"string","overallConfidence":0,"requiresReview":["string"],"specSource":"string","userSpecUrl":"string","documentationSource":"string","inferenceMethod":"string","status":"string","customerApprovedAt":"string","customerApprovedBy":"string","previousVersionId":"string","changeReason":"string","systemDescription":"string","industryClassification":"string","complianceRelevance":["string"],"corpusPrior":{"providerKey":"string","capturedAt":"string","ageDays":0,"stale":true,"fieldsTyped":0,"fieldsEnriched":0,"edgesAdded":0,"authApplied":true,"paginationApplied":true},"baseline":{"providerKey":"string","entitiesMatched":0,"entitiesNew":0,"fieldsMatched":0,"fieldsNew":0,"fieldsChanged":0},"verifiedBaseline":{"providerKey":"string","approvedAt":"string","promotedAt":"string"},"valueSampling":{"entitiesSampled":0,"entitiesFailed":0,"rowsFetched":0,"fieldsProfiled":0,"fieldsTyped":0,"sampledAt":"string","durationMs":0,"errors":["string"],"notSampled":["string"]},"engine":"string","engineArm":"string","engineFallbackReason":"string","writeEncoding":"string","reread":{"scope":"string","confidenceBelow":0,"fields":[{"entity":"string","field":"string"}],"notFound":[{"entity":"string","field":"string"}],"fromManifestId":"string","readAt":"string"},"listVia":"string","authError":"string","pathParams":{},"pathParamSecrets":{},"readPaths":["string"],"readProfile":"string","aiLane":{"lane":"string","state":"string","scheduledFor":"string","batchId":"string","submittedAt":"string","appliedAt":"string","entitiesSubmitted":0,"entitiesApplied":0,"reservedTokens":0,"detail":"string"}},"status":"string","parentId":"00000000-0000-0000-0000-000000000000","createdBy":"string","createdAt":"string","fieldReviews":{"reviewed":0,"approved":0,"corrected":0,"rejected":0,"unmatched":0},"fieldReviewStates":{}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/match":{"post":{"operationId":"MatchConnections","tags":["connections"],"summary":"Match Connections","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Work out how the data in this connection lines up with another connected system: which kinds of record correspond and which fields match. The result is a mapping for you to review. By default the call waits for the mapping and returns its id. If it takes longer, or you ask not to wait (respondAsync, or the header Prefer: respond-async), it returns a job id at once: check it with the job status call and read the mapping id when it has succeeded.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetConnectionId":{"type":"string","format":"uuid","description":"The other connection to match this one with."},"engine":{"type":"string","enum":["v1","v2","v2-proprietary"],"description":"Which matching engine to use for this run. Only honoured for API keys; otherwise your workspace’s setting applies."},"respondAsync":{"type":"boolean","description":"true to get a job id straight away instead of waiting for the mapping. Same as sending the header Prefer: respond-async."},"steerNotes":{"type":"string","maxLength":2000,"description":"Free-text guidance for this match from the person reviewing the mapping, e.g. which entities to prefer. Used by the v2 match engines as guidance among the candidates they already found; ignored when the match runs on v1. Not stored."}},"required":["targetConnectionId"]},"example":{"targetConnectionId":"00000000-0000-0000-0000-000000000000","engine":"v1","respondAsync":true,"steerNotes":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"mappingId":{"type":"string","format":"uuid","nullable":true,"description":"Set on 201: the stored mapping. Null on 202 — read it from GET /v1/jobs/:id when the job succeeds."},"jobId":{"type":"string","format":"uuid","description":"The match job. Poll GET /v1/jobs/:id; result.mappingId on success."},"runId":{"type":"string","format":"uuid","description":"Alias of jobId — the manifests.inference_pipeline_runs row id (phase 2)."},"status":{"type":"string","description":"succeeded on 201; queued or running on 202."},"sourceConnectionId":{"type":"string","format":"uuid"},"targetConnectionId":{"type":"string","format":"uuid"}},"required":["jobId","runId","status","sourceConnectionId","targetConnectionId"]},"example":{"mappingId":"00000000-0000-0000-0000-000000000000","jobId":"00000000-0000-0000-0000-000000000000","runId":"00000000-0000-0000-0000-000000000000","status":"string","sourceConnectionId":"00000000-0000-0000-0000-000000000000","targetConnectionId":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"mappingId":{"type":"string","format":"uuid","nullable":true,"description":"Set on 201: the stored mapping. Null on 202 — read it from GET /v1/jobs/:id when the job succeeds."},"jobId":{"type":"string","format":"uuid","description":"The match job. Poll GET /v1/jobs/:id; result.mappingId on success."},"runId":{"type":"string","format":"uuid","description":"Alias of jobId — the manifests.inference_pipeline_runs row id (phase 2)."},"status":{"type":"string","description":"succeeded on 201; queued or running on 202."},"sourceConnectionId":{"type":"string","format":"uuid"},"targetConnectionId":{"type":"string","format":"uuid"}},"required":["jobId","runId","status","sourceConnectionId","targetConnectionId"]},"example":{"mappingId":"00000000-0000-0000-0000-000000000000","jobId":"00000000-0000-0000-0000-000000000000","runId":"00000000-0000-0000-0000-000000000000","status":"string","sourceConnectionId":"00000000-0000-0000-0000-000000000000","targetConnectionId":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/mcp":{"get":{"operationId":"GetMcpConnection","tags":["connections"],"summary":"Get Mcp Connection","security":[{"ApiKeyAuth":["connections:read"]},{"BearerAuth":[]},{"OAuth2":["connections:read"]}],"description":"The MCP server behind a custom connector and its OAuth sign-in state (`oauthStatus`: none, authorized or sign-in-required). For a connection not made from an MCP server address, `endpointUrl` is null and both statuses are `none`. 404 when the connection is not yours.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"endpointUrl":{"type":"string","nullable":true,"description":"Null when the connection was not made from an MCP server address."},"authMode":{"type":"string"},"oauthStatus":{"type":"string"},"issuer":{"type":"string","nullable":true},"registration":{"type":"string","nullable":true},"scopes":{"type":"string","nullable":true},"tokenExpiresAt":{"type":"string","nullable":true,"description":"ISO 8601."},"authorizedAt":{"type":"string","nullable":true,"description":"ISO 8601."}},"required":["connectionId","endpointUrl","authMode","oauthStatus","issuer","registration","scopes","tokenExpiresAt","authorizedAt"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","endpointUrl":"string","authMode":"string","oauthStatus":"string","issuer":"string","registration":"string","scopes":"string","tokenExpiresAt":"string","authorizedAt":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/mcp/authorize":{"post":{"operationId":"AuthorizeMcpConnection","tags":["connections"],"summary":"Authorize Mcp Connection","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Re-run the MCP authorization flow for a connection created by ConnectMcpServer: discovery, client registration (re-using the client already registered when the authorization server is unchanged) and a fresh PKCE S256 authorize URL. Returns `authorization_required` with the URL, or `client_id_required` as ConnectMcpServer does. 404 for a connection that is not yours or not an MCP connection.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clientId":{"type":"string","maxLength":512},"clientSecret":{"type":"string","maxLength":2048}}},"example":{"clientId":"string","clientSecret":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["connected","authorization_required","client_id_required"]},"message":{"type":"string"},"connectionId":{"type":"string","format":"uuid"},"authorizeUrl":{"type":"string"},"issuer":{"type":"string"},"registration":{"type":"string"}},"required":["status","message"]},"example":{"status":"connected","message":"string","connectionId":"00000000-0000-0000-0000-000000000000","authorizeUrl":"string","issuer":"string","registration":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/oauth-organisations/{pick}":{"get":{"operationId":"GetOAuthOrganisations","tags":["connections"],"summary":"Get OAuth Organisations","security":[{"ApiKeyAuth":["connections:read"]},{"BearerAuth":[]},{"OAuth2":["connections:read"]}],"description":"The organisations (provider accounts) an OAuth sign-in covers, while it waits for a choice. Held for 15 minutes after the sign-in and only for the connection it was started for. `choice` is `several` for a system's main sign-in (each organisation chosen becomes its own connection) and `one` for one environment of a system. 404 when the sign-in has expired or was already used. No token is returned.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The connection the sign-in was started for."},"description":"The connection the sign-in was started for."},{"name":"pick","in":"path","required":true,"schema":{"type":"string","maxLength":64,"description":"The single-use handle of the held sign-in, from the address the sign-in landed on."},"description":"The single-use handle of the held sign-in, from the address the sign-in landed on."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"providerKey":{"type":"string"},"providerName":{"type":"string","description":"The provider as a person reads it, e.g. Xero."},"environmentId":{"type":"string","format":"uuid","nullable":true,"description":"The environment the sign-in is for; null for the system's main sign-in."},"choice":{"type":"string","enum":["one","several"],"description":"How many organisations may be chosen."},"organisations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The provider's id for the organisation."},"name":{"type":"string","nullable":true,"description":"The provider's name for it; null when it gives none."}},"required":["id","name"]}},"expiresAt":{"type":"string","format":"date-time","description":"When the held sign-in is gone."}},"required":["connectionId","providerKey","providerName","environmentId","choice","organisations","expiresAt"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","providerKey":"string","providerName":"string","environmentId":"00000000-0000-0000-0000-000000000000","choice":"one","organisations":[{"id":"string","name":"string"}],"expiresAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"ChooseOAuthOrganisations","tags":["connections"],"summary":"Choose OAuth Organisations","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Choose which organisations an OAuth sign-in connects. One connection per organisation: the first chosen signs in this connection, and each other becomes a new connection of the same system, named after the organisation. Every sign-in is tested with a signed read before it is used: it goes live when the read is proven, or when there is no working sign-in to keep, and the outcome is recorded either way. An organisation the provider refuses is not connected. A sign-in for one environment of a system takes exactly one organisation. 404 when the held sign-in has expired or was already used; a choice that is not valid does not use it up.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The connection the sign-in was started for."},"description":"The connection the sign-in was started for."},{"name":"pick","in":"path","required":true,"schema":{"type":"string","maxLength":64,"description":"The single-use handle of the held sign-in."},"description":"The single-use handle of the held sign-in."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"organisationIds":{"type":"array","items":{"type":"string"},"maximum":50,"description":"The organisations to connect, by the provider's id, the first being the one this connection signs in to."}},"required":["organisationIds"]},"example":{"organisationIds":["string"]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"What happened, in plain words."},"connections":{"type":"array","items":{"type":"object","properties":{"organisationId":{"type":"string"},"organisationName":{"type":"string","nullable":true},"connectionId":{"type":"string","format":"uuid","nullable":true,"description":"The existing or allocated connection id; with an unknown outcome, creation may not have completed. Null when no connection id was allocated."},"created":{"type":"boolean","nullable":true,"description":"A new connection was made for this organisation. Null when creation was interrupted and its outcome is unknown."},"readStarted":{"type":"boolean","nullable":true,"description":"For a new connection: its first read was started. Null otherwise."},"live":{"type":"boolean","nullable":true,"description":"The sign-in is the connection's sign-in now. Null when an interrupted operation may have stored it but completion was not confirmed."},"outcome":{"type":"string","description":"accepted (a proven read), refused, inconclusive, untested (one environment), unknown (interrupted; may have committed), or not-attempted (stopped after an earlier interruption). Review existing systems before starting fresh; the choice is single-use."},"testOutcome":{"type":"string","nullable":true,"description":"The connection test's own outcome, as POST /v1/connections/:id/test answers it."},"httpStatus":{"type":"integer","nullable":true},"detail":{"type":"string","description":"What the test found, in plain words. Never a credential."},"provedBy":{"type":"string","nullable":true,"description":"The endpoint whose answer proved the read; null unless accepted."}},"required":["organisationId","organisationName","connectionId","created","readStarted","live","outcome","testOutcome","httpStatus","detail","provedBy"]},"description":"One row per organisation chosen, in the order chosen."}},"required":["message","connections"]},"example":{"message":"string","connections":[{"organisationId":"string","organisationName":"string","connectionId":"00000000-0000-0000-0000-000000000000","created":true,"readStarted":true,"live":true,"outcome":"string","testOutcome":"string","httpStatus":0,"detail":"string","provedBy":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/path-params":{"patch":{"operationId":"SetConnectionPathParams","tags":["connections"],"summary":"Set Connection Path Params","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Fill in the values an API needs in its addresses that only you know, such as an account or catalogue name. Inferrex uses them in every request to that API, and will not call an address while one of its values is still missing. A value can instead come from a secret saved in this workspace ({\"secretRef\":\"<name>\"}): it then stays in the secret, is read only when a request is made, and is never shown. New values are added to the ones already saved (send null to remove one), and they are kept when the API is read again. The response lists every value the API’s addresses need and which are still unset.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pathParams":{"type":"object","additionalProperties":true,"description":"Each value to fill in, by name, for example {\"account_name\":\"acme\",\"catalog_name\":\"main\"}, or {\"secretRef\":\"<name>\"} to take it from a saved workspace secret. null removes a value."}},"required":["pathParams"]},"example":{"pathParams":{}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"manifestId":{"type":"string","format":"uuid"},"pathParams":{"type":"object","additionalProperties":{"type":"string"},"description":"The values now stored on the connection: placeholder name → value. Values kept in a saved secret are not here."},"pathParamSecrets":{"type":"object","additionalProperties":{"type":"string"},"description":"Placeholders whose value comes from a saved workspace secret: placeholder name → the secret's name. The values are never returned."},"required":{"type":"array","items":{"type":"string"},"description":"Every placeholder in the address and in the endpoints sync calls: each entity's list endpoint and its write endpoint."},"missing":{"type":"array","items":{"type":"string"},"description":"Required placeholders that still have no value."}},"required":["connectionId","manifestId","pathParams","pathParamSecrets","required","missing"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","manifestId":"00000000-0000-0000-0000-000000000000","pathParams":{},"pathParamSecrets":{},"required":["string"],"missing":["string"]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/pause":{"post":{"operationId":"PauseConnection","tags":["connections"],"summary":"Pause Connection","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Pause everything that moves data with this system. Every live flow that reads from it or writes to it pauses; flows already paused stay as they are. Nothing is deleted, and records wait in their source until the system is resumed. While it is paused, turning on one of its flows is refused (409 connection_paused).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"pausedAt":{"type":"string","format":"date-time"},"alreadyPaused":{"type":"boolean","description":"The system was already paused; nothing changed."},"flows":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","nullable":true}},"required":["id","name"]},"description":"The flows this pause stopped."}},"required":["connectionId","pausedAt","alreadyPaused","flows"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","pausedAt":"2026-01-01T00:00:00Z","alreadyPaused":true,"flows":[{"id":"00000000-0000-0000-0000-000000000000","name":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/reinfer":{"post":{"operationId":"ReinferConnection","tags":["connections"],"summary":"Reinfer Connection","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Read a connection’s API again, with a corrected address, sign-in method or secret if needed, instead of connecting it a second time. The connection keeps its id and your settings. Leave the credentials out to keep the current ones. A connection not yet in use is read again in place, and the result is a new version for you to review (proposed: false). For a connection in use (approved or active), the result is a new reading kept beside the live version (proposed: true): everything the connection runs on stays as it is, and a secret you supply is kept for the new reading only. GET /v1/connections/:id/reinference shows the new reading, POST /v1/connections/:id/reinference/approve makes it the current version and DELETE /v1/connections/:id/reinference drops it. Only one new reading at a time: while one is running or ready for review, another request is refused (409 reading_open), so a reading a colleague may be reviewing is never swapped underneath them; discard it first. Archived connections cannot be read again (409 connection_not_reinferable). If you can wait for the result (over a weekend, say), the scheduled lane costs less for a connection not yet in use; a connection in use is always read straight away.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"The corrected address of the API. Leave out to keep the current one."},"authType":{"type":"string","enum":["oauth2","api-key","basic","bearer","aws-sigv4","jwt","mtls","custom","none","service-account"],"description":"How the API expects you to sign in."},"credentials":{"type":"object","additionalProperties":true,"description":"New credential values. Leave out, with credentialRef, to keep the current secret."},"credentialRef":{"type":"string","description":"The name of a saved secret to sign in with instead."},"specUrl":{"type":"string","format":"uri","maxLength":2048,"nullable":true,"description":"Where the API publishes its own description (an OpenAPI or Swagger document, or its API reference page). Leave out to keep the current one, or send null to stop using it."},"readPaths":{"type":"array","items":{"type":"string"},"maximum":20,"description":"Endpoint paths to read first, as on connect. Leave out to keep the current ones; send an empty list to stop using them."},"pathParams":{"type":"object","additionalProperties":true,"description":"Values for the {placeholders} in the address or the paths to read, as on connect: a value, or {\"secretRef\":\"<name>\"} for a saved secret. Added to the values already saved (a name given here replaces the saved one)."},"aiLane":{"type":"string","maxLength":64,"description":"When the AI part of the work runs. interactive (the default) runs it now. scheduled-batch costs less and uses less of your daily AI allowance: Inferrex saves what it can work out straight away, so you can start reviewing, and finishes the rest in your workspace’s batch window (for example over a weekend), adding it as a new version. Refused when the scheduled lane is switched off, and for a connection already in use."},"scope":{"type":"string","maxLength":64,"description":"Which fields to read again (an open vocabulary, 2026-10-12). 'all' (default) reads everything, as before. 'low-confidence' reads only fields Inferrex is unsure about: flagged 'Needs a look', or typed with less confidence than confidenceBelow. 'unmapped' reads only fields no live mapping uses (as a link's source or target, a concatenate part, a fan-out destination or a group destination; archived mappings and mappings with an archived system do not count). 'low-confidence-or-unmapped' reads either. A part re-read never re-reads a field a person approved or corrected, never adds or removes a field or object, and keeps every other field, object and setting exactly as the current version has them; it needs a current version (409 no_current_version) and at least one matching field (409 nothing_to_reread), and runs interactively (not on the scheduled Batch lane). On a system in use the result is a new reading for review, as for a full re-read. GET /v1/connections/:id/reinference/scope counts each choice."},"confidenceBelow":{"type":"number","minimum":0,"maximum":1,"description":"For scope low-confidence (and its 'or unmapped' form): a field typed with less confidence than this (0–1) is read again. Default: the workspace's field classification threshold (inference.fieldClassificationMinConfidence) — the threshold that decides 'Needs a look' when a system is read."}},"required":["authType"]},"example":{"url":"https://example.com","authType":"oauth2","credentials":{},"credentialRef":"string","specUrl":"https://example.com","readPaths":["string"],"pathParams":{},"aiLane":"string","scope":"string","confidenceBelow":0}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"jobId":{"type":"string"},"estimatedTimeSeconds":{"type":"integer"},"proposed":{"type":"boolean","description":"true when the connection is in use: the result is a new reading offered for review, and the live connection is unchanged until it is approved. false when the connection itself was re-read."},"scope":{"type":"string","description":"What is read again: all, or the part re-read scope asked for."},"fieldsToRead":{"type":"integer","description":"For a part re-read: how many fields were selected to read again."}},"required":["connectionId","jobId","estimatedTimeSeconds","proposed","scope"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","jobId":"string","estimatedTimeSeconds":0,"proposed":true,"scope":"string","fieldsToRead":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/reinference":{"delete":{"operationId":"DiscardConnectionReinference","tags":["connections"],"summary":"Discard Connection Reinference","security":[{"ApiKeyAuth":["connections:delete"]},{"BearerAuth":[]},{"OAuth2":["connections:delete"]}],"description":"Discard the open new reading of a connection in use, in any state. Its stored manifest is kept as `discarded` (history; never the current version) and a secret supplied only for the reading is removed. A reading still running finds itself discarded and drops its own result. 409 no_reading when there is none.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"discarded":{"type":"boolean"}},"required":["connectionId","discarded"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","discarded":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"GetConnectionReinference","tags":["connections"],"summary":"Get Connection Reinference","security":[{"ApiKeyAuth":["connections:read"]},{"BearerAuth":[]},{"OAuth2":["connections:read"]}],"description":"The open new reading of a connection in use (started by POST /v1/connections/:id/reinfer on an approved or active connection). `state` is none, reading, ready or failed (an open vocabulary). Once ready, `changes` compares it with the live version by entity and field API name, in counts and object by object (`changes.objects`). The live connection is unchanged throughout.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"state":{"type":"string","description":"none — no reading; reading — the API is being read; ready — waiting for a person to approve or discard it; failed — it did not finish (see `error`)."},"requestedAt":{"type":"string","format":"date-time"},"requestedBy":{"type":"string","description":"Who asked: a user id, or an email when no user id was known."},"completedAt":{"type":"string","format":"date-time"},"error":{"type":"string","description":"Why a failed reading did not finish."},"address":{"type":"string","description":"The base URL the reading reads."},"addressChanged":{"type":"boolean","description":"The reading reads a different base URL from the live one; approving it switches the connection to it."},"authType":{"type":"string"},"signInChanged":{"type":"boolean","description":"The reading signs in a different way from the live version."},"secretChanged":{"type":"boolean","description":"The reading uses a different secret; approving it switches the connection to that secret."},"changes":{"type":"object","properties":{"objectCount":{"type":"integer"},"fieldCount":{"type":"integer"},"objectsAdded":{"type":"array","items":{"type":"string"},"description":"Objects the live version lacks (display names, at most 20)."},"objectsRemoved":{"type":"array","items":{"type":"string"},"description":"Objects the reading no longer has (display names, at most 20)."},"fieldsAdded":{"type":"integer"},"fieldsRemoved":{"type":"integer"},"fieldsRetyped":{"type":"integer","description":"Fields in both whose type differs."},"fieldsChanged":{"type":"integer","description":"Fields in both whose type, display name or description differs."},"objects":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string","description":"Display name, else API name."},"apiName":{"type":"string"},"change":{"type":"string","description":"added, removed or changed."},"fieldsAdded":{"type":"integer"},"fieldsRemoved":{"type":"integer"},"fieldsChanged":{"type":"integer"},"fields":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"The field's name in the API."},"name":{"type":"string"},"change":{"type":"string","description":"added, removed or changed."},"what":{"type":"array","items":{"type":"string"},"description":"For a changed field: type, name, description."},"typeWas":{"type":"string"},"typeNow":{"type":"string"},"nameWas":{"type":"string"},"nameNow":{"type":"string"}},"required":["field","name","change","what","typeWas","typeNow","nameWas","nameNow"]},"description":"The differing fields of a changed object."}},"required":["object","apiName","change","fieldsAdded","fieldsRemoved","fieldsChanged","fields"]},"description":"The draft against the approved version, object by object: only objects that differ (at most 200), with at most 500 field rows across them. An added or removed object lists no fields; its counts say how many."},"truncated":{"type":"boolean","description":"Objects or field rows were left out of `objects` by its limits; the counts are whole."}},"required":["objectCount","fieldCount","objectsAdded","objectsRemoved","fieldsAdded","fieldsRemoved","fieldsRetyped","fieldsChanged","objects","truncated"],"nullable":true,"description":"Present once the reading is ready: what it would change."},"scope":{"type":"string","description":"What the reading reads again: all, or a part re-read scope (low-confidence, unmapped, low-confidence-or-unmapped)."},"fieldsToRead":{"type":"integer","description":"For a part re-read: how many fields were selected."},"reread":{"type":"object","properties":{"fieldsReread":{"type":"integer","description":"Fields read again."},"fieldsChanged":{"type":"integer","description":"Of those, how many have a different type, name or description."},"notFound":{"type":"integer","description":"Selected fields the API did not show this time; kept as they are."},"changedFields":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string"},"field":{"type":"string","description":"The field's name in the API."},"what":{"type":"array","items":{"type":"string"},"description":"What changed: type, name, description."},"typeWas":{"type":"string"},"typeNow":{"type":"string"},"nameWas":{"type":"string"},"nameNow":{"type":"string"}},"required":["object","field","what","typeWas","typeNow","nameWas","nameNow"]},"description":"The changed fields (at most 50)."}},"required":["fieldsReread","fieldsChanged","notFound","changedFields"],"nullable":true,"description":"Present once a PART re-read is ready: only the fields it read again can differ from the current version, and these are they."}},"required":["connectionId","state"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","state":"string","requestedAt":"2026-01-01T00:00:00Z","requestedBy":"string","completedAt":"2026-01-01T00:00:00Z","error":"string","address":"string","addressChanged":true,"authType":"string","signInChanged":true,"secretChanged":true,"changes":{"objectCount":0,"fieldCount":0,"objectsAdded":["string"],"objectsRemoved":["string"],"fieldsAdded":0,"fieldsRemoved":0,"fieldsRetyped":0,"fieldsChanged":0,"objects":[{"object":"string","apiName":"string","change":"string","fieldsAdded":0,"fieldsRemoved":0,"fieldsChanged":0,"fields":[{"field":"string","name":"string","change":"string","what":["string"],"typeWas":"string","typeNow":"string","nameWas":"string","nameNow":"string"}]}],"truncated":true},"scope":"string","fieldsToRead":0,"reread":{"fieldsReread":0,"fieldsChanged":0,"notFound":0,"changedFields":[{"object":"string","field":"string","what":["string"],"typeWas":"string","typeNow":"string","nameWas":"string","nameNow":"string"}]}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/reinference/approve":{"post":{"operationId":"ApproveConnectionReinference","tags":["connections"],"summary":"Approve Connection Reinference","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Promote the ready new reading of a connection in use. The reading becomes a new approved manifest version (the tenant's path values, write encoding, update methods and role / sensitivity decisions are carried from the version live at this moment), and its base URL, secret and provider key replace the connection's in one statement. Pipelines read the new version on their next run. 409 no_reading_to_approve when nothing is ready; 409 reading_approval_in_progress when another approval holds it; 409 connection_not_proven when no test of the connection's current sign-in has read data from it yet (POST /v1/connections/:id/test proves it). Separate from POST /v1/connections/:id/approve, which approves a connection still awaiting review: on a connection in use that route would act on the live version, so the reading is approved by name.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"status":{"type":"string","description":"The connection's status — unchanged by the approval."},"manifestId":{"type":"string","format":"uuid","description":"The new current manifest version."},"manifestVersion":{"type":"integer"}},"required":["connectionId","status","manifestId","manifestVersion"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","status":"string","manifestId":"00000000-0000-0000-0000-000000000000","manifestVersion":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/reinference/scope":{"get":{"operationId":"GetConnectionRereadScope","tags":["connections"],"summary":"Get Connection Reread Scope","security":[{"ApiKeyAuth":["connections:read"]},{"BearerAuth":[]},{"OAuth2":["connections:read"]}],"description":"Field counts for each re-read scope over the connection's current version (corrections applied): all, lowConfidence (flagged \"Needs a look\" or typed with less confidence than confidenceBelow), unmapped (used by no live mapping) and lowConfidenceOrUnmapped. Fields a person approved or corrected (personChecked) are counted only in all, because a part re-read keeps them as they are. `available` is false when the connection has no current version, so only a full re-read is possible.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"confidenceBelow","in":"query","required":false,"schema":{"type":"number","minimum":0,"maximum":1,"description":"Default: the workspace's field classification threshold."},"description":"Default: the workspace's field classification threshold."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"available":{"type":"boolean","description":"false when there is no current version: only a full re-read is possible."},"confidenceBelow":{"type":"number","nullable":true,"description":"The threshold the counts used."},"all":{"type":"integer"},"lowConfidence":{"type":"integer"},"unmapped":{"type":"integer"},"lowConfidenceOrUnmapped":{"type":"integer"},"personChecked":{"type":"integer","description":"Fields a person approved or corrected; only a full re-read reads them again."}},"required":["connectionId","available","all","lowConfidence","unmapped","lowConfidenceOrUnmapped","personChecked"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","available":true,"confidenceBelow":0,"all":0,"lowConfidence":0,"unmapped":0,"lowConfidenceOrUnmapped":0,"personChecked":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/resume":{"post":{"operationId":"ResumeConnection","tags":["connections"],"summary":"Resume Connection","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Resume a paused system. The flows its pause stopped go live again and sync on their usual timing; a flow that also uses another paused system waits for that one. Flows paused for any other reason stay paused.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"wasPaused":{"type":"boolean","description":"The system was paused before this call."},"flows":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","nullable":true}},"required":["id","name"]},"description":"The flows that went live again."},"stillPaused":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","nullable":true},"pausedBySystem":{"type":"string","format":"uuid","description":"The other paused system that now holds the flow."}},"required":["id","name","pausedBySystem"]},"description":"Flows this pause had stopped that stay paused because another system they use is paused."}},"required":["connectionId","wasPaused","flows","stillPaused"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","wasPaused":true,"flows":[{"id":"00000000-0000-0000-0000-000000000000","name":"string"}],"stillPaused":[{"id":"00000000-0000-0000-0000-000000000000","name":"string","pausedBySystem":"00000000-0000-0000-0000-000000000000"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/schema-contribution/preview":{"get":{"operationId":"GetSchemaContributionPreview","tags":["connections"],"summary":"Get Schema Contribution Preview","security":[{"ApiKeyAuth":["connections:read"]},{"BearerAuth":[]},{"OAuth2":["connections:read"]}],"description":"The top-level payload previews the schema a new request would share, excluding internal catalogue and comparison metadata. An existing request is reviewed only through open.payload; null means the stored payload is unavailable and approval is refused. Another workspace connection returns 404.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"version","in":"query","required":false,"schema":{"type":"string","maxLength":500,"description":"An apiVersionId from the schema comparison. Default: the library's current version, else the newest confirmed."},"description":"An apiVersionId from the schema comparison. Default: the library's current version, else the newest confirmed."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"payload":{"type":"object","properties":{"objects":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"required":{"type":"boolean","nullable":true},"nullable":{"type":"boolean","nullable":true},"refTarget":{"type":"string","nullable":true},"types":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"format":{"type":"string","nullable":true},"type_source":{"type":"string","enum":["declared","inferred"]}},"required":["type","type_source"]}}},"required":["name","required","nullable","refTarget","types"]}},"endpoints":{"type":"array","items":{"type":"object","properties":{"operation":{"type":"string","enum":["list","get","create","update","delete","search"]},"path":{"type":"string"}},"required":["operation","path"]}}},"required":["name","fields","endpoints"]}}},"required":["objects"],"nullable":true,"description":"The structural schema a request would share, without internal catalogue or comparison metadata. Null when there is nothing to send (`reason`)."},"reason":{"type":"string","enum":["not-read","catalogue-unavailable","nothing-standard"],"nullable":true,"description":"not-read: Inferrex has not finished reading the system; catalogue-unavailable: the vendor standard could not be read just now; nothing-standard: every object is custom or not in the vendor standard."},"open":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"state":{"type":"string","enum":["requested","approved","declined"]},"stagedAt":{"type":"string","format":"date-time"},"payload":{"type":"object","properties":{"objects":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"required":{"type":"boolean","nullable":true},"nullable":{"type":"boolean","nullable":true},"refTarget":{"type":"string","nullable":true},"types":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"format":{"type":"string","nullable":true},"type_source":{"type":"string","enum":["declared","inferred"]}},"required":["type","type_source"]}}},"required":["name","required","nullable","refTarget","types"]}},"endpoints":{"type":"array","items":{"type":"object","properties":{"operation":{"type":"string","enum":["list","get","create","update","delete","search"]},"path":{"type":"string"}},"required":["operation","path"]}}},"required":["name","fields","endpoints"]}}},"required":["objects"],"nullable":true,"description":"The structural schema stored with this request, without internal catalogue or comparison metadata, not today's fresh preview. Null when missing or malformed; approval is refused."}},"required":["id","state","stagedAt","payload"],"nullable":true,"description":"This connection's contribution that is still open (requested, or approved and with Inferrex), if any. Only one can be open at a time."}},"required":["connectionId","payload","reason","open"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","payload":{"objects":[{"name":"string","fields":[{"name":"string","required":true,"nullable":true,"refTarget":"string","types":[{"type":"string","format":"string","type_source":"declared"}]}],"endpoints":[{"operation":"list","path":"string"}]}]},"reason":"not-read","open":{"id":"00000000-0000-0000-0000-000000000000","state":"requested","stagedAt":"2026-01-01T00:00:00Z","payload":{"objects":[{"name":"string","fields":[{"name":"string","required":true,"nullable":true,"refTarget":"string","types":[{"type":"string","format":"string","type_source":"declared"}]}],"endpoints":[{"operation":"list","path":"string"}]}]}}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/secrets":{"get":{"operationId":"ListConnectionSecrets","tags":["credentials"],"summary":"List Connection Secrets","security":[{"ApiKeyAuth":["connections:read"]},{"BearerAuth":[]},{"OAuth2":["connections:read"]}],"description":"The secrets a connected system uses, with who each one is and whether its API last accepted it. Values are never returned.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"liveKey":{"type":"string","nullable":true,"description":"The name of the secret it signs in with now."},"secrets":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string"},"source":{"type":"string","description":"vault (kept by Inferrex, encrypted), external (your own vault), or connection (kept with its system)."},"purpose":{"type":"string","nullable":true},"identitySource":{"type":"string","description":"recorded, derived or unknown."},"ownerConnectionId":{"type":"string","format":"uuid","nullable":true},"apiBaseUrl":{"type":"string","nullable":true},"authMethod":{"type":"string","nullable":true},"tags":{"type":"array","items":{"type":"string"}},"valueSavedAt":{"type":"string","format":"date-time","nullable":true},"valueSavedBy":{"type":"string","nullable":true},"lastUsedAt":{"type":"string","format":"date-time","nullable":true},"lastOutcome":{"type":"string","nullable":true},"lastOutcomeAt":{"type":"string","format":"date-time","nullable":true},"lastOutcomeStatus":{"type":"integer","nullable":true},"lastOutcomeDetail":{"type":"string","nullable":true},"lastOutcomeSource":{"type":"string","nullable":true},"lastOutcomeConnectionId":{"type":"string","format":"uuid","nullable":true},"lastTestedAt":{"type":"string","format":"date-time","nullable":true},"failingSince":{"type":"string","format":"date-time","nullable":true},"rotationRole":{"type":"string","nullable":true,"description":"candidate (saved, not in use until a test passes) or previous (the value a rotation replaced)."},"rotationOf":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"use":{"type":"string","description":"in-use (its sign-in now), used (read another way, such as a project token in its address), stand-by, or not-in-use."},"sharedWith":{"type":"array","items":{"type":"string"},"description":"Other systems that sign in with it."}},"required":["id","key","source","purpose","identitySource","ownerConnectionId","apiBaseUrl","authMethod","tags","valueSavedAt","valueSavedBy","lastUsedAt","lastOutcome","lastOutcomeAt","lastOutcomeStatus","lastOutcomeDetail","lastOutcomeSource","lastOutcomeConnectionId","lastTestedAt","failingSince","rotationRole","rotationOf","createdAt","use","sharedWith"]}},"inbound":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"purpose":{"type":"string"},"savedAt":{"type":"string","format":"date-time"}},"required":["key","purpose","savedAt"]},"description":"Secrets that prove deliveries TO Inferrex, by name only."}},"required":["connectionId","liveKey","secrets","inbound"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","liveKey":"string","secrets":[{"id":"00000000-0000-0000-0000-000000000000","key":"string","source":"string","purpose":"string","identitySource":"string","ownerConnectionId":"00000000-0000-0000-0000-000000000000","apiBaseUrl":"string","authMethod":"string","tags":["string"],"valueSavedAt":"2026-01-01T00:00:00Z","valueSavedBy":"string","lastUsedAt":"2026-01-01T00:00:00Z","lastOutcome":"string","lastOutcomeAt":"2026-01-01T00:00:00Z","lastOutcomeStatus":0,"lastOutcomeDetail":"string","lastOutcomeSource":"string","lastOutcomeConnectionId":"00000000-0000-0000-0000-000000000000","lastTestedAt":"2026-01-01T00:00:00Z","failingSince":"2026-01-01T00:00:00Z","rotationRole":"string","rotationOf":"string","createdAt":"2026-01-01T00:00:00Z","use":"string","sharedWith":["string"]}],"inbound":[{"key":"string","purpose":"string","savedAt":"2026-01-01T00:00:00Z"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/sign-in-status":{"get":{"operationId":"GetConnectionSignInStatus","tags":["credentials"],"summary":"Get Connection Sign In Status","security":[{"ApiKeyAuth":["connections:read"]},{"BearerAuth":[]},{"OAuth2":["connections:read"]}],"description":"Whether this system's \"Sign in with …\" keeps renewing itself, when it would lapse, and whether you need to sign in again. Token values are never returned.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"state":{"type":"string","description":"not-oauth (no renewable OAuth sign-in), ok, expiring (lapses within the warning window) or reconnect (someone must sign in again). Open vocabulary."},"renewable":{"type":"boolean","description":"The main sign-in is an OAuth grant with a refresh token."},"provider":{"type":"string","nullable":true,"description":"The provider's name when Inferrex has a registered app for it (for \"Sign in with Xero again\")."},"tokensIssuedAt":{"type":"string","format":"date-time","nullable":true,"description":"When the provider last issued tokens to this sign-in: the consent or the last renewal."},"lifetimeDays":{"type":"number","nullable":true,"description":"How many days the refresh token lives unused; null when it is assumed not to lapse."},"lifetimeSource":{"type":"string","nullable":true,"description":"provider (declared by Inferrex's registered app) or default (the workspace's assumed lifetime)."},"lapsesAt":{"type":"string","format":"date-time","nullable":true,"description":"When the refresh token lapses if it is not renewed before then."},"warnDays":{"type":"number","description":"How many days before the lapse Inferrex renews it, or warns."},"reconnect":{"type":"object","properties":{"since":{"type":"string","format":"date-time"},"reason":{"type":"string","description":"refresh-refused, not-renewable or refresh-token-expired (open vocabulary)."},"message":{"type":"string","description":"What happened and what to do, as a sentence."}},"required":["since","reason","message"],"nullable":true,"description":"Present when someone must sign in to the provider again."},"noticeSentAt":{"type":"string","format":"date-time","nullable":true,"description":"When the workspace was last told about this sign-in."}},"required":["connectionId","state","renewable","provider","tokensIssuedAt","lifetimeDays","lifetimeSource","lapsesAt","warnDays","reconnect","noticeSentAt"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","state":"string","renewable":true,"provider":"string","tokensIssuedAt":"2026-01-01T00:00:00Z","lifetimeDays":0,"lifetimeSource":"string","lapsesAt":"2026-01-01T00:00:00Z","warnDays":0,"reconnect":{"since":"2026-01-01T00:00:00Z","reason":"string","message":"string"},"noticeSentAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/source-delete-action":{"put":{"operationId":"SetConnectionSourceDeleteAction","tags":["golden_record"],"summary":"Set Connection Source Delete Action","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Set the connection's delete choice. `action` is keep, mark_deleted, delete_now or retention; null clears it, so the default (retention) applies. Mark deleted needs the destination to declare a deletion marker on the object, and delete now needs it to declare a delete endpoint; where it declares neither the delete is recorded as not supported and nothing is sent. A delete of a Bloomreach Engagement customer is an anonymisation, which Inferrex sends only through a data subject request, never as a passed-on delete. Recorded in the audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","nullable":true,"description":"keep, mark_deleted, delete_now or retention; null for the default."}},"required":["action"]},"example":{"action":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"action":{"type":"string","nullable":true},"effectiveAction":{"type":"string"}},"required":["connectionId","effectiveAction"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","action":"string","effectiveAction":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/status":{"get":{"operationId":"GetConnectionStatus","tags":["connections"],"summary":"Get Connection Status","security":[{"ApiKeyAuth":["connections:read"]},{"BearerAuth":[]},{"OAuth2":["connections:read"]}],"description":"Check where a connection is in its setup: whether Inferrex is still reading the API, it is waiting for your review, or it is approved. Also returns the version and review status of what Inferrex learned. Call it again while the API is being read.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"status":{"type":"string"},"createdAt":{"type":"string"},"manifestId":{"type":"string","format":"uuid","nullable":true},"manifestStatus":{"type":"string","nullable":true},"manifestVersion":{"type":"integer","nullable":true},"overallConfidence":{"type":"number","nullable":true}},"required":["connectionId","status","createdAt"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","status":"string","createdAt":"string","manifestId":"00000000-0000-0000-0000-000000000000","manifestStatus":"string","manifestVersion":0,"overallConfidence":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/test":{"post":{"operationId":"TestSavedConnection","tags":["connections"],"summary":"Test Saved Connection","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Check that a connected system's address and saved sign-in still work. Inferrex makes signed-in GET requests to its provider's test path, its saved paths to read and the list endpoints of objects it knows, and passes only when one answers 2xx with data (JSON or XML); provedBy names that endpoint. A 404, a redirect, an HTML or sign-in page, an error body, or an answer from the bare address never passes. Nothing changes. The result never repeats a credential, a secret or a placeholder's value.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"outcome":{"type":"string","description":"Passes only on a real read (2026-10-30). signed-in: a request carrying the sign-in, to a declared read endpoint, answered 2xx with data (a JSON object or array, or XML) — provedBy names the endpoint. read-without-sign-in: the same, for an API that takes no sign-in. Never a pass: credentials-rejected: it refused the sign-in details (401), or the token URL refused the client ID and secret. forbidden: it refused this request (403); the sign-in may be right but not allowed here. organisation-not-selected: a 403 when the sign-in names no organisation the provider requires on every call (Xero's xero-tenant-id); sign in with the provider again to choose one — not a refusal of the key. not-found: nothing at this address (404). not-a-read: a 2xx, but an HTML page (often a sign-in page), an empty body or an error message rather than data. api-error: any other status (400, 429, 5xx). unverified: no read endpoint is declared, so only the base address could be tried, and an answer there proves nothing. unreachable: no answer (host not found, TLS, timeout, connection refused, or not a public https address). redirect: it answered with a redirect, which is not followed. not-testable: this sign-in cannot be tested with one request, or a value it needs is not set."},"httpStatus":{"type":"integer","nullable":true,"description":"The status the API answered with; null when nothing answered."},"testedUrlTemplate":{"type":"string","description":"The address called, with its placeholders as {name}: never their values."},"detail":{"type":"string","description":"What the result means, in plain words. It may quote the API's own message, with any credential or placeholder value hidden."},"durationMs":{"type":"integer"},"provedBy":{"type":"string","nullable":true,"description":"The endpoint whose answer proved the read, with its placeholders as {name}; null unless the test passed."},"endpointSource":{"type":"string","description":"How the endpoint in testedUrlTemplate was chosen: requested, provider-test-path, read-path, object-list, or base when no read endpoint is declared."}},"required":["outcome","httpStatus","testedUrlTemplate","detail","durationMs","provedBy","endpointSource"]},"example":{"outcome":"string","httpStatus":0,"testedUrlTemplate":"string","detail":"string","durationMs":0,"provedBy":"string","endpointSource":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/{id}/write-encoding":{"patch":{"operationId":"SetConnectionWriteEncoding","tags":["connections"],"summary":"Set Connection Write Encoding","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Choose how Inferrex sends data when it writes to this system: as JSON (the default) or as form data, which some APIs such as Stripe require. Inferrex cannot always tell this from the API itself, so you can set it here. The choice is kept when the API is read again.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"writeEncoding":{"type":"string","enum":["json","form"],"description":"json (the default) or form."}},"required":["writeEncoding"]},"example":{"writeEncoding":"json"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"manifestId":{"type":"string","format":"uuid"},"writeEncoding":{"type":"string"}},"required":["connectionId","manifestId","writeEncoding"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","manifestId":"00000000-0000-0000-0000-000000000000","writeEncoding":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/detect-auth":{"post":{"operationId":"DetectAuth","tags":["connections"],"summary":"Detect Auth","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Find out how an API expects you to sign in before you connect it, so you are asked for the right credentials. Inferrex asks the API itself, without a credential, and reports what it answered. Returns the sign-in method, the credential fields to fill in and how sure it is; unknown when the API did not say.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"endpoint":{"type":"string","format":"uri","description":"The address of the API you want to connect."}},"required":["endpoint"]},"example":{"endpoint":"https://example.com"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"endpoint":{"type":"string"},"authType":{"type":"string","description":"The sign-in method to start on: api-key, bearer, basic, oauth2, or unknown (neither the API nor Inferrex can say; it does NOT mean the API is open). The API's own answer (`probe`) wins when it gives one; the person can choose any other."},"credentialFields":{"type":"array","items":{"type":"string"}},"confidence":{"type":"number"},"fieldValues":{"type":"object","properties":{"headerName":{"type":"string","description":"The header an API key is sent in."},"tokenUrl":{"type":"string","description":"The OAuth token address."},"scopes":{"type":"array","items":{"type":"string"},"description":"OAuth scopes to ask for."}},"description":"Values to pre-fill for the method in `authType`, each editable; empty when there are none (2026-11-07, D39)."},"probe":{"type":"object","properties":{"outcome":{"type":"string","description":"challenge (it asked for a credential) or open (that one address answered without asking; the API's own endpoints may still need one, so never read it as \"no sign-in\")."},"status":{"type":"integer"},"authType":{"type":"string","nullable":true},"credentialFields":{"type":"array","items":{"type":"string"}}},"required":["outcome","status","credentialFields"],"nullable":true,"description":"What the API said when asked without a credential; null when it could not be reached."},"addressCorrection":{"type":"string","nullable":true,"description":"The API address to use instead, when the address given is the vendor's website or documentation rather than its API (2026-11-07, D39); null otherwise. Offered as one plain correction, never a list."},"signInWithProvider":{"type":"object","properties":{"provider":{"type":"string","description":"The provider's name for the button, for example Xero."},"providerKey":{"type":"string","description":"What POST /v1/oauth/initiate takes as providerKey, and the last part of its callback address."}},"required":["provider","providerKey"],"nullable":true,"description":"Set when Inferrex has its own app with the provider whose API lives at this address, so you can sign in on the provider's own page (\"Sign in with <provider>\", POST /v1/oauth/initiate); null otherwise."}},"required":["endpoint","authType","credentialFields","confidence","fieldValues","addressCorrection"]},"example":{"endpoint":"string","authType":"string","credentialFields":["string"],"confidence":0,"fieldValues":{"headerName":"string","tokenUrl":"string","scopes":["string"]},"probe":{"outcome":"string","status":0,"authType":"string","credentialFields":["string"]},"addressCorrection":"string","signInWithProvider":{"provider":"string","providerKey":"string"}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/infer":{"post":{"operationId":"InferConnection","tags":["connections"],"summary":"Infer Connection","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Connect a new system. Give the API’s address and how to sign in, and Inferrex reads the API to work out what data it holds: its kinds of record, their fields and how they relate. This takes a minute or two, so it returns at once with the new connection’s id and a job id to check on. When it finishes, the connection is ready for you to review and approve.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"The address of the API to connect (its base URL)."},"authType":{"type":"string","enum":["oauth2","api-key","basic","bearer","aws-sigv4","jwt","mtls","custom","none","service-account"],"description":"How the API expects you to sign in."},"credentials":{"type":"object","additionalProperties":true,"description":"The credential values to sign in with, such as an API key. They are encrypted before they are stored. Leave out if you use credentialRef."},"credentialRef":{"type":"string","description":"The name of a secret you have already saved, to sign in with instead of sending credentials."},"displayName":{"type":"string","maxLength":80,"description":"A name for the connection. Defaults to one taken from the API’s address."},"description":{"type":"string","maxLength":280,"description":"An optional note about what this connection is for."},"tags":{"type":"array","items":{"type":"string"},"description":"Optional labels to help you find and group connections."},"existingMcpServer":{"type":"string","format":"uri","maxLength":2048,"description":"If the system already has an MCP server, the address of its SSE endpoint. Inferrex reads the system's tools and resources through it instead of probing the API's address. It must be https on a public host."},"cliSessionId":{"type":"string","description":"For a system reached through a command-line tool: the cloud shell session to use."},"cliBinary":{"type":"string","description":"For a system reached through a command-line tool: the tool’s name."},"specUrl":{"type":"string","format":"uri","maxLength":2048,"description":"Where the API publishes its own description (an OpenAPI or Swagger document, or its API reference page). Inferrex reads it first, which gives a more complete result. Must be a public https address."},"readPaths":{"type":"array","items":{"type":"string"},"maximum":20,"description":"Endpoint paths to read first, for an API that publishes no description: each starts with /, is relative to the address, and may hold {placeholders}, for example /data/v2/projects/{projectToken}/catalogs. Up to 20, each up to 512 characters, with no query string."},"pathParams":{"type":"object","additionalProperties":true,"description":"A value for each {placeholder} in the address or the paths to read, by name, for example {\"projectToken\":\"abc\"}. Instead of a value, give {\"secretRef\":\"<name>\"} to use a secret saved in this workspace: the value then stays in the secret and can be reused. Placeholders may sit anywhere in the address, including its host ({subdomain}.example.com), whose filled address must be a public https host. Up to 20."},"priority":{"type":"string","enum":["high","normal","low"],"description":"How soon to read the API compared with your other requests: high, normal or low.","default":"normal"},"engine":{"type":"string","enum":["v1","v2","v2-proprietary"],"description":"Which reading engine to use for this run. Only honoured for API keys; otherwise your workspace’s setting applies."}},"required":["url","authType"]},"example":{"url":"https://example.com","authType":"oauth2","credentials":{},"credentialRef":"string","displayName":"string","description":"string","tags":["string"],"existingMcpServer":"https://example.com","cliSessionId":"string","cliBinary":"string","specUrl":"https://example.com","readPaths":["string"],"pathParams":{},"priority":"high","engine":"v1"}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"jobId":{"type":"string"},"estimatedTimeSeconds":{"type":"integer"}},"required":["connectionId","jobId","estimatedTimeSeconds"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","jobId":"string","estimatedTimeSeconds":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/mcp":{"post":{"operationId":"ConnectMcpServer","tags":["connections"],"summary":"Connect Mcp Server","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Add a custom MCP connector from a name and a server URL. The URL must be https on a public host. Inferrex sends the server an MCP initialize request with no credential: an answer means no sign-in is needed, and the connection is created and its tools read (status `connected`). A 401 means OAuth: Inferrex reads the server's protected-resource metadata (RFC 9728, from the WWW-Authenticate resource_metadata or the well-known address), then its authorization server's metadata (RFC 8414 or OpenID Connect), refuses a server that does not advertise PKCE S256, registers a client in the MCP spec's order — a pre-registered Inferrex app, then Inferrex's Client ID Metadata Document, then dynamic client registration (RFC 7591), then the `clientId` supplied here — and answers `authorization_required` with the address to send the browser to (PKCE S256, single-use state, RFC 8707 `resource`). When no client can be had and none was supplied, it answers `client_id_required`: ask the person for a client id registered with that vendor, with https://api.inferrex.com/oauth/mcp/callback as its redirect address.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":80,"description":"What people here call this connector."},"serverUrl":{"type":"string","format":"uri","maxLength":2048,"description":"The MCP server address (streamable HTTP, or the older SSE endpoint). https only, public hosts only."},"clientId":{"type":"string","maxLength":512,"description":"An OAuth client id registered with the server's authorization server, used only when the server offers no other way to get one."},"clientSecret":{"type":"string","maxLength":2048,"description":"That client's secret, when it has one. Stored encrypted; never shown again."}},"required":["name","serverUrl"]},"example":{"name":"string","serverUrl":"https://example.com","clientId":"string","clientSecret":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["connected","authorization_required","client_id_required"]},"message":{"type":"string","description":"What happened, in plain words."},"connectionId":{"type":"string","format":"uuid","description":"Set when `connected`."},"jobId":{"type":"string","description":"The job reading the server's tools, when `connected`."},"authorizeUrl":{"type":"string","description":"Set when `authorization_required`: send the browser here."},"issuer":{"type":"string","description":"The authorization server the sign-in is with."},"registration":{"type":"string","description":"How Inferrex's client was registered with it: pre-registered, client-id-metadata-document, dynamic or workspace."}},"required":["status","message"]},"example":{"status":"connected","message":"string","connectionId":"00000000-0000-0000-0000-000000000000","jobId":"string","authorizeUrl":"string","issuer":"string","registration":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/route":{"post":{"operationId":"RouteRecord","tags":["connections"],"summary":"Route Record","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Convert one record from one connected system’s format into another’s, without sending it anywhere. Inferrex matches the kind of record and its fields across the two systems and converts values where they are stored differently (a date as a number or as text, for example). Anything that could not be converted exactly is listed, so you can check it.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"from":{"type":"string","format":"uuid","description":"The connection the record comes from."},"to":{"type":"string","format":"uuid","description":"The connection whose format to convert it into."},"entity":{"type":"string","description":"The kind of record, in the source system. Worked out from the record if you leave it out."},"record":{"type":"object","additionalProperties":true,"description":"The record’s values, as the source system holds them."}},"required":["from","to","record"]},"example":{"from":"00000000-0000-0000-0000-000000000000","to":"00000000-0000-0000-0000-000000000000","entity":"string","record":{}}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"fromEntity":{"type":"string"},"toEntity":{"type":"string"},"record":{"type":"object","additionalProperties":true,"description":"The record in the target system's shape: its keys are that system's field names, so it has no fixed shape."},"mappings":{"type":"array","items":{"type":"object","properties":{"from":{"type":"string","description":"Source field path (dotted for nested fields)."},"to":{"type":"string","description":"Target field path."},"role":{"type":"string","description":"The canonical role the two fields share."},"fidelity":{"type":"string","description":"Known values: exact, lossy."},"note":{"type":"string","description":"What the conversion does, e.g. \"array→scalar (first element kept)\". Absent when the conversion has none."}},"required":["from","to","role","fidelity"]},"description":"One entry per field paired by its canonical role."}},"required":["from","to","fromEntity","toEntity","record","mappings"]},"example":{"from":"string","to":"string","fromEntity":"string","toEntity":"string","record":{},"mappings":[{"from":"string","to":"string","role":"string","fidelity":"string","note":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/connections/test":{"post":{"operationId":"TestConnection","tags":["connections"],"summary":"Test Connection","security":[{"ApiKeyAuth":["connections:write"]},{"BearerAuth":[]},{"OAuth2":["connections:write"]}],"description":"Check that an API's address and sign-in work, without connecting it. Inferrex makes signed-in GET requests to the path you give and the paths to read, and passes only when one of them answers 2xx with data (JSON or XML); provedBy names that endpoint. A 404, a redirect, an HTML or sign-in page, an error body, or an answer from the bare address never passes. Nothing is stored. The result never repeats a credential, a secret or a placeholder's value: the address tested is returned with its placeholders as {name}.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"The address of the API (its base URL). It may hold {placeholders}."},"authType":{"type":"string","enum":["oauth2","api-key","basic","bearer","aws-sigv4","jwt","mtls","custom","none","service-account"],"description":"How the API expects you to sign in."},"credentials":{"type":"object","additionalProperties":true,"description":"The credential values to sign in with, such as an API key. Used for this test only, never stored. Leave out if you use credentialRef."},"credentialRef":{"type":"string","description":"The name of a secret already saved in this workspace, to sign in with instead."},"readPaths":{"type":"array","items":{"type":"string"},"maximum":20,"description":"Endpoint paths to read, as on connect. The first is the one tested."},"path":{"type":"string","maxLength":512,"description":"One path to test instead of the first of readPaths: it starts with /, is relative to the address, and may hold {placeholders}."},"pathParams":{"type":"object","additionalProperties":true,"description":"A value for each {placeholder} in the address or the path, as on connect: the value, or {\"secretRef\":\"<name>\"} for a secret saved in this workspace."}},"required":["url","authType"]},"example":{"url":"https://example.com","authType":"oauth2","credentials":{},"credentialRef":"string","readPaths":["string"],"path":"string","pathParams":{}}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"outcome":{"type":"string","description":"Passes only on a real read (2026-10-30). signed-in: a request carrying the sign-in, to a declared read endpoint, answered 2xx with data (a JSON object or array, or XML) — provedBy names the endpoint. read-without-sign-in: the same, for an API that takes no sign-in. Never a pass: credentials-rejected: it refused the sign-in details (401), or the token URL refused the client ID and secret. forbidden: it refused this request (403); the sign-in may be right but not allowed here. organisation-not-selected: a 403 when the sign-in names no organisation the provider requires on every call (Xero's xero-tenant-id); sign in with the provider again to choose one — not a refusal of the key. not-found: nothing at this address (404). not-a-read: a 2xx, but an HTML page (often a sign-in page), an empty body or an error message rather than data. api-error: any other status (400, 429, 5xx). unverified: no read endpoint is declared, so only the base address could be tried, and an answer there proves nothing. unreachable: no answer (host not found, TLS, timeout, connection refused, or not a public https address). redirect: it answered with a redirect, which is not followed. not-testable: this sign-in cannot be tested with one request, or a value it needs is not set."},"httpStatus":{"type":"integer","nullable":true,"description":"The status the API answered with; null when nothing answered."},"testedUrlTemplate":{"type":"string","description":"The address called, with its placeholders as {name}: never their values."},"detail":{"type":"string","description":"What the result means, in plain words. It may quote the API's own message, with any credential or placeholder value hidden."},"durationMs":{"type":"integer"},"provedBy":{"type":"string","nullable":true,"description":"The endpoint whose answer proved the read, with its placeholders as {name}; null unless the test passed."},"endpointSource":{"type":"string","description":"How the endpoint in testedUrlTemplate was chosen: requested, provider-test-path, read-path, object-list, or base when no read endpoint is declared."}},"required":["outcome","httpStatus","testedUrlTemplate","detail","durationMs","provedBy","endpointSource"]},"example":{"outcome":"string","httpStatus":0,"testedUrlTemplate":"string","detail":"string","durationMs":0,"provedBy":"string","endpointSource":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/contact":{"post":{"operationId":"SubmitContactForm","tags":["contact"],"summary":"Submit Contact Form","security":[],"description":"Send a message to the Inferrex team. Limited to 5 messages an hour from each internet address.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"email":{"type":"string","format":"email","maxLength":320},"company":{"type":"string","minLength":1,"maxLength":255},"jobTitle":{"type":"string","maxLength":255},"companySize":{"type":"string","enum":["1-10","11-50","51-200","201-1000","1000+"]},"interest":{"type":"string","enum":["pilot","cloud","enterprise","sovereign","exploring","beta"]},"systems":{"type":"string","maxLength":1000},"systemsCount":{"type":"string","enum":["1-5","6-20","21-50","50+"]},"message":{"type":"string","minLength":1,"maxLength":5000}},"required":["name","email","company","message"]},"example":{"name":"string","email":"user@example.com","company":"string","jobTitle":"string","companySize":"1-10","interest":"pilot","systems":"string","systemsCount":"1-5","message":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"message":{"type":"string"}},"required":["id","message"]},"example":{"id":"00000000-0000-0000-0000-000000000000","message":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/destination-feeds/{customerId}/{feedKey}":{"get":{"operationId":"GetBloomreachFeedFile","tags":["bloomreach"],"summary":"Get Bloomreach Feed File","security":[{"Handler_basic":[]}],"description":"A feed file for an Engagement scheduled URL import (phase 12): the newest build of the feed, RFC 4180 CSV, UTF-8, CRLF. Requires Authorization: Basic with the feed key as the user name and the feed's password; a password in the URL is not accepted. 404 when the workspace has no Bloomreach Engagement module, the feed is unknown or stopped, or no file is built yet; 401 when the password is missing or wrong.","parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"feedKey","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"File","content":{"text/csv":{"schema":{"type":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/events/stream":{"get":{"operationId":"EventStream","tags":["events"],"summary":"Event Stream","security":[{"ApiKeyAuth":["events:read"]},{"BearerAuth":[]},{"OAuth2":["events:read"]}],"description":"A live stream of updates from your workspace (Server-Sent Events), so an app can react as things happen instead of asking repeatedly. API keys need the events:read scope. Get a short-lived ticket first and pass it as ticket, so your credentials never appear in the stream’s address.","parameters":[{"name":"ticket","in":"query","required":false,"schema":{"type":"string","description":"A single-use ticket from the stream ticket call. The recommended way to sign in to the stream."},"description":"A single-use ticket from the stream ticket call. The recommended way to sign in to the stream."},{"name":"token","in":"query","required":false,"schema":{"type":"string","description":"Your sign-in token. Older method: prefer ticket, so the token does not appear in the address."},"description":"Your sign-in token. Older method: prefer ticket, so the token does not appear in the address."}],"responses":{"200":{"description":"Server-Sent Events stream","content":{"text/event-stream":{"schema":{"type":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/events/stream-ticket":{"post":{"operationId":"EventStreamTicket","tags":["events"],"summary":"Event Stream Ticket","security":[{"ApiKeyAuth":["events:write"]},{"BearerAuth":[]},{"OAuth2":["events:write"]}],"description":"Get a single-use ticket, valid for 60 seconds, to open the live event stream. Call this with your API key or sign-in token, then open the stream with ?ticket=. API keys need the events:write scope.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Server-Sent Events stream","content":{"text/event-stream":{"schema":{"type":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/field-authority-rules":{"get":{"operationId":"FieldAuthorityRulesList","tags":["golden_record"],"summary":"Field Authority Rules List","security":[{"ApiKeyAuth":["field-authority-rules:read"]},{"BearerAuth":[]},{"OAuth2":["field-authority-rules:read"]}],"description":"List your field authority rules, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"entity_type","in":"query","required":false,"schema":{"type":"string","description":"Only field authority rules whose entity type is exactly this."},"description":"Only field authority rules whose entity type is exactly this."},{"name":"entity_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only field authority rules whose entity type contains this text (upper and lower case are treated the same)."},"description":"Only field authority rules whose entity type contains this text (upper and lower case are treated the same)."},{"name":"field_name","in":"query","required":false,"schema":{"type":"string","description":"Only field authority rules whose field name is exactly this."},"description":"Only field authority rules whose field name is exactly this."},{"name":"field_name_contains","in":"query","required":false,"schema":{"type":"string","description":"Only field authority rules whose field name contains this text (upper and lower case are treated the same)."},"description":"Only field authority rules whose field name contains this text (upper and lower case are treated the same)."},{"name":"strategy","in":"query","required":false,"schema":{"type":"string","description":"Only field authority rules whose strategy is exactly this."},"description":"Only field authority rules whose strategy is exactly this."},{"name":"strategy_contains","in":"query","required":false,"schema":{"type":"string","description":"Only field authority rules whose strategy contains this text (upper and lower case are treated the same)."},"description":"Only field authority rules whose strategy contains this text (upper and lower case are treated the same)."},{"name":"connection_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only field authority rules for this connection. Pass its id."},"description":"Only field authority rules for this connection. Pass its id."},{"name":"vendor_key","in":"query","required":false,"schema":{"type":"string","description":"Only field authority rules whose vendor key is exactly this."},"description":"Only field authority rules whose vendor key is exactly this."},{"name":"vendor_key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only field authority rules whose vendor key contains this text (upper and lower case are treated the same)."},"description":"Only field authority rules whose vendor key contains this text (upper and lower case are treated the same)."},{"name":"service_key","in":"query","required":false,"schema":{"type":"string","description":"Only field authority rules whose service key is exactly this."},"description":"Only field authority rules whose service key is exactly this."},{"name":"service_key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only field authority rules whose service key contains this text (upper and lower case are treated the same)."},"description":"Only field authority rules whose service key contains this text (upper and lower case are treated the same)."},{"name":"priority_gte","in":"query","required":false,"schema":{"type":"number","description":"Only field authority rules whose priority is this number or more."},"description":"Only field authority rules whose priority is this number or more."},{"name":"priority_lte","in":"query","required":false,"schema":{"type":"number","description":"Only field authority rules whose priority is this number or less."},"description":"Only field authority rules whose priority is this number or less."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many field authority rules to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many field authority rules to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many field authority rules to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many field authority rules to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","entity_type","field_name","strategy","connection_id","vendor_key","service_key","priority","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns field authority rules where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns field authority rules where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"entity_type":{"type":"string"},"field_name":{"type":"string"},"strategy":{"type":"string","description":"How the winning value is chosen when providers disagree on this field."},"connection_id":{"type":"string","format":"uuid","nullable":true,"description":"When a chosen system wins: the connected system whose value wins, by its connection id. Required for that way of choosing, empty for every other."},"vendor_key":{"type":"string","nullable":true},"service_key":{"type":"string","nullable":true},"priority":{"type":"integer","description":"Evaluation order when several rules match the same field."},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","entity_type","field_name","strategy"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","field_name":"string","strategy":"string","connection_id":"00000000-0000-0000-0000-000000000000","vendor_key":"string","service_key":"string","priority":0,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"FieldAuthorityRulesCreate","tags":["golden_record"],"summary":"Field Authority Rules Create","security":[{"ApiKeyAuth":["field-authority-rules:write"]},{"BearerAuth":[]},{"OAuth2":["field-authority-rules:write"]}],"description":"Create a field authority rule. Returns the new field authority rule, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"entity_type":{"type":"string"},"field_name":{"type":"string"},"strategy":{"type":"string","description":"How the winning value is chosen when providers disagree on this field."},"connection_id":{"type":"string","format":"uuid","nullable":true,"description":"When a chosen system wins: the connected system whose value wins, by its connection id. Required for that way of choosing, empty for every other."},"vendor_key":{"type":"string","nullable":true},"service_key":{"type":"string","nullable":true},"priority":{"type":"integer","description":"Evaluation order when several rules match the same field."}},"required":["entity_type","field_name","strategy"]},"example":{"entity_type":"string","field_name":"string","strategy":"string","connection_id":"00000000-0000-0000-0000-000000000000","vendor_key":"string","service_key":"string","priority":0}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"entity_type":{"type":"string"},"field_name":{"type":"string"},"strategy":{"type":"string","description":"How the winning value is chosen when providers disagree on this field."},"connection_id":{"type":"string","format":"uuid","nullable":true,"description":"When a chosen system wins: the connected system whose value wins, by its connection id. Required for that way of choosing, empty for every other."},"vendor_key":{"type":"string","nullable":true},"service_key":{"type":"string","nullable":true},"priority":{"type":"integer","description":"Evaluation order when several rules match the same field."},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","entity_type","field_name","strategy"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","field_name":"string","strategy":"string","connection_id":"00000000-0000-0000-0000-000000000000","vendor_key":"string","service_key":"string","priority":0,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/field-authority-rules/{id}":{"delete":{"operationId":"FieldAuthorityRulesDelete","tags":["golden_record"],"summary":"Field Authority Rules Delete","security":[{"ApiKeyAuth":["field-authority-rules:delete"]},{"BearerAuth":[]},{"OAuth2":["field-authority-rules:delete"]}],"description":"Delete a field authority rule permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the field authority rule."},"description":"The id of the field authority rule."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"FieldAuthorityRulesGet","tags":["golden_record"],"summary":"Field Authority Rules Get","security":[{"ApiKeyAuth":["field-authority-rules:read"]},{"BearerAuth":[]},{"OAuth2":["field-authority-rules:read"]}],"description":"Get one of your field authority rules by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the field authority rule."},"description":"The id of the field authority rule."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"entity_type":{"type":"string"},"field_name":{"type":"string"},"strategy":{"type":"string","description":"How the winning value is chosen when providers disagree on this field."},"connection_id":{"type":"string","format":"uuid","nullable":true,"description":"When a chosen system wins: the connected system whose value wins, by its connection id. Required for that way of choosing, empty for every other."},"vendor_key":{"type":"string","nullable":true},"service_key":{"type":"string","nullable":true},"priority":{"type":"integer","description":"Evaluation order when several rules match the same field."},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","entity_type","field_name","strategy"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","field_name":"string","strategy":"string","connection_id":"00000000-0000-0000-0000-000000000000","vendor_key":"string","service_key":"string","priority":0,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"FieldAuthorityRulesUpdate","tags":["golden_record"],"summary":"Field Authority Rules Update","security":[{"ApiKeyAuth":["field-authority-rules:write"]},{"BearerAuth":[]},{"OAuth2":["field-authority-rules:write"]}],"description":"Change a field authority rule. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the field authority rule."},"description":"The id of the field authority rule."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"entity_type":{"type":"string"},"field_name":{"type":"string"},"strategy":{"type":"string","description":"How the winning value is chosen when providers disagree on this field."},"connection_id":{"type":"string","format":"uuid","nullable":true,"description":"When a chosen system wins: the connected system whose value wins, by its connection id. Required for that way of choosing, empty for every other."},"vendor_key":{"type":"string","nullable":true},"service_key":{"type":"string","nullable":true},"priority":{"type":"integer","description":"Evaluation order when several rules match the same field."}}},"example":{"entity_type":"string","field_name":"string","strategy":"string","connection_id":"00000000-0000-0000-0000-000000000000","vendor_key":"string","service_key":"string","priority":0}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"entity_type":{"type":"string"},"field_name":{"type":"string"},"strategy":{"type":"string","description":"How the winning value is chosen when providers disagree on this field."},"connection_id":{"type":"string","format":"uuid","nullable":true,"description":"When a chosen system wins: the connected system whose value wins, by its connection id. Required for that way of choosing, empty for every other."},"vendor_key":{"type":"string","nullable":true},"service_key":{"type":"string","nullable":true},"priority":{"type":"integer","description":"Evaluation order when several rules match the same field."},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","entity_type","field_name","strategy"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","field_name":"string","strategy":"string","connection_id":"00000000-0000-0000-0000-000000000000","vendor_key":"string","service_key":"string","priority":0,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/gamification/embed/{embedId}":{"get":{"operationId":"GetGamificationEmbed","tags":["gamification"],"summary":"Get Gamification Embed","security":[{"Handler_player":[]}],"description":"Payload contract v1 (`v: 1`): what an embedded widget shows one player — their metrics, progress to the next level, the leaderboard (others by rank and points; a name only for the player themself, from the token's optional `n` claim; and the player's own rank, also outside the top ten) and recent awards, as the program's delivery settings choose, plus the appearance the program set. Within v1 changes are additive only: clients ignore fields they do not know. Requires Authorization: Player <token>; URL tokens are not accepted. 404 unless the workspace has the gamification add-on, the program is published and its widget is on; 403 unless the Origin is an allowed website; 401 unless the player token verifies and has not expired.","parameters":[{"name":"embedId","in":"path","required":true,"schema":{"type":"string","maxLength":64}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"v":{"type":"integer","minimum":1,"maximum":1,"description":"The payload contract version. Always 1 here."},"asOf":{"type":"string","format":"date-time","description":"When this answer was read."},"program":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["live","paused","suspended"],"description":"A paused program still shows progress; it scores nothing new until it is resumed."},"publishedVersion":{"type":"integer","description":"Rises with each publish; a client that sees it change re-reads."},"notice":{"type":"string","nullable":true,"description":"A notice the tenant shows players while the program is not live. Null: none is set."}},"required":["key","name","status","publishedVersion","notice"]},"player":{"type":"object","properties":{"id":{"type":"string","description":"The player id the token carries (its `p` claim)."},"displayName":{"type":"string","nullable":true,"description":"The token's optional `n` claim."},"anonymous":{"type":"boolean","description":"Always false: anonymous players need the tracking setup step, which is not built."}},"required":["id","displayName","anonymous"]},"widgets":{"type":"array","items":{"type":"string"},"description":"What the program shows. Open vocabulary; known values: progress, leaderboard, recent-awards. A client ignores values it does not know."},"appearance":{"type":"object","properties":{"theme":{"type":"object","additionalProperties":{"type":"string"},"description":"CSS custom property (--ifx-*) → value, from the program's look: --ifx-scheme (light | dark), --ifx-radius and --ifx-button-radius (square corners), --ifx-font and --ifx-accent. A value that is not a plain CSS value (a url(), a declaration break) is left out."},"copy":{"type":"object","additionalProperties":{"type":"string"},"description":"Text slot → text. Empty until the builder sets copy."},"layout":{"type":"object","additionalProperties":{"type":"string"},"description":"Widget → inline | corner | modal. Empty until the builder sets layout."},"sounds":{"type":"object","properties":{"enabled":{"type":"boolean"},"events":{"type":"object","additionalProperties":{"type":"string"},"description":"Event type → https sound URL."}},"required":["enabled","events"]},"locale":{"type":"string","nullable":true,"description":"The locale copy is resolved for. Null: none is set, so a client formats in the page's own language."}},"required":["theme","copy","layout","sounds","locale"]},"termsUrl":{"type":"string","nullable":true},"metrics":{"type":"array","items":{"type":"object","properties":{"metric":{"type":"string"},"value":{"type":"number"},"level":{"type":"string","nullable":true}},"required":["metric","value","level"]}},"progress":{"type":"object","properties":{"metric":{"type":"string"},"value":{"type":"number"},"level":{"type":"string","nullable":true},"next":{"type":"object","properties":{"level":{"type":"string"},"threshold":{"type":"number"},"remaining":{"type":"number"}},"required":["level","threshold","remaining"],"nullable":true}},"required":["metric","value","level","next"],"nullable":true,"description":"Null unless the program shows progress and has levels."},"leaderboard":{"type":"object","properties":{"metric":{"type":"string"},"entries":{"type":"array","items":{"type":"object","properties":{"rank":{"type":"integer"},"value":{"type":"number"},"level":{"type":"string","nullable":true},"you":{"type":"boolean"},"displayName":{"type":"string","nullable":true,"description":"Only on the player's own row (their token's `n` claim). Other players' external ids are never sent."}},"required":["rank","value","level","you","displayName"]}},"self":{"type":"object","properties":{"rank":{"type":"integer","minimum":1},"value":{"type":"number"},"level":{"type":"string","nullable":true}},"required":["rank","value","level"],"nullable":true,"description":"The player's own place on the whole board, also when they are outside the top ten. Ranked in the board's order, so it matches their entry when they are in it. Null: they have no score on the level metric yet. Added within v1, so an older server leaves it out."}},"required":["metric","entries"],"nullable":true,"description":"Null unless the program shows the leaderboard and has levels. The top ten on the level metric, and the player's own place (self)."},"recentAwards":{"type":"array","items":{"type":"object","properties":{"metric":{"type":"string"},"value":{"type":"number","nullable":true},"manual":{"type":"boolean"},"at":{"type":"string","format":"date-time"}},"required":["metric","value","manual","at"]},"nullable":true,"description":"Null unless the program shows recent awards. The player's last five."}},"required":["v","asOf","program","player","widgets","appearance","termsUrl","metrics"]},"example":{"v":0,"asOf":"2026-01-01T00:00:00Z","program":{"key":"string","name":"string","status":"live","publishedVersion":0,"notice":"string"},"player":{"id":"string","displayName":"string","anonymous":true},"widgets":["string"],"appearance":{"theme":{},"copy":{},"layout":{},"sounds":{"enabled":true,"events":{}},"locale":"string"},"termsUrl":"string","metrics":[{"metric":"string","value":0,"level":"string"}],"progress":{"metric":"string","value":0,"level":"string","next":{"level":"string","threshold":0,"remaining":0}},"leaderboard":{"metric":"string","entries":[{"rank":0,"value":0,"level":"string","you":true,"displayName":"string"}],"self":{"rank":0,"value":0,"level":"string"}},"recentAwards":[{"metric":"string","value":0,"manual":true,"at":"2026-01-01T00:00:00Z"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/embed/{embedId}/events":{"post":{"operationId":"IngestGamificationEmbedEvents","tags":["gamification"],"summary":"Ingest Gamification Embed Events","security":[{"Handler_player":[]}],"description":"Payload contract v1 (`v: 1`). Requires Authorization: Player <token>; 404 unless the workspace has the gamification add-on, the program is published and its widget is on; 403 unless the Origin is an allowed website; 401 unless the player token verifies and has not expired; 429 with Retry-After past the per-website-address or per-player rate (platform tunables gamification.ingest.*); 503 with Retry-After when the rate limiter cannot be reached (nothing is accepted). Each event is answered in exactly one list: `accepted` (new: stored, scored and metered once), `duplicate` (its eventId was already accepted for this player and program: nothing happens again) or `rejected` with a reason (open vocabulary; known: invalid-event, invalid-event-id, invalid-name, invalid-at, invalid-properties, too-many-properties, properties-too-large, invalid-page-path, repeated-in-request, program-paused, program-not-live, usage-limit-reached). The server's receive time is the event's time; `at` is advisory. These events are trust client: only rules whose trigger accepts client events score them.","parameters":[{"name":"embedId","in":"path","required":true,"schema":{"type":"string","maxLength":64}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"v":{"type":"integer","minimum":1,"maximum":1,"description":"The payload contract version. Always 1."},"events":{"type":"array","items":{"type":"object","properties":{"eventId":{"type":"string","format":"uuid","description":"A UUID the client makes per event: the idempotency key, unique per program and player."},"name":{"type":"string","maxLength":63,"description":"Open vocabulary: `^[a-z][a-z0-9_.-]{0,62}$`, e.g. page_view, game.played, deposit."},"at":{"type":"string","format":"date-time","description":"When it happened, by the client's clock. Advisory: kept for reading, never used to time anything."},"properties":{"type":"object","additionalProperties":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]},"description":"Flat properties: at most 20 keys (`^[A-Za-z_][A-Za-z0-9_.-]{0,62}$`), 2 KB as JSON, values text, finite numbers or true/false. Do not put personal data here."},"page":{"type":"object","properties":{"path":{"type":"string","maxLength":1000,"description":"The page path only, starting with /: no query string, no fragment."}},"required":["path"]}},"required":["eventId","name"]},"description":"One to 20 events, handled in order."}},"required":["v","events"]},"example":{"v":0,"events":[{"eventId":"00000000-0000-0000-0000-000000000000","name":"string","at":"2026-01-01T00:00:00Z","properties":{},"page":{"path":"string"}}]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"v":{"type":"integer","minimum":1,"maximum":1,"description":"The payload contract version. Always 1 here."},"accepted":{"type":"array","items":{"type":"string"},"description":"The eventIds stored, scored and metered by this request."},"duplicate":{"type":"array","items":{"type":"string"},"description":"The eventIds already accepted earlier for this player and program: not scored or metered again."},"rejected":{"type":"array","items":{"type":"object","properties":{"eventId":{"type":"string","description":"As sent (empty when none was)."},"reason":{"type":"string","description":"Open vocabulary; a client ignores reasons it does not know."}},"required":["eventId","reason"]}}},"required":["v","accepted","duplicate","rejected"]},"example":{"v":0,"accepted":["string"],"duplicate":["string"],"rejected":[{"eventId":"string","reason":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/player-events":{"post":{"operationId":"IngestGamificationPlayerEvents","tags":["gamification"],"summary":"Ingest Gamification Player Events","security":[{"ApiKeyAuth":["gamification:write"]},{"BearerAuth":[]},{"OAuth2":["gamification:write"]}],"description":"Payload contract v1 (`v: 1`), the same events and answer as POST /v1/gamification/embed/:embedId/events, with these events marked trust server. 404 unless the program exists in this workspace; 409 when it is archived or not yet published. A paused program answers each event rejected with program-paused. Each event is answered in exactly one of accepted, duplicate or rejected (reasons as on the browser route).","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"v":{"type":"integer","minimum":1,"maximum":1,"description":"The payload contract version. Always 1."},"programKey":{"type":"string","maxLength":63,"description":"The program the events are for."},"playerId":{"type":"string","minLength":1,"maxLength":500,"description":"The player, as your systems identify them: the same id your player tokens carry as `p`."},"events":{"type":"array","items":{"type":"object","properties":{"eventId":{"type":"string","format":"uuid","description":"A UUID per event: the idempotency key, unique per program and player."},"name":{"type":"string","maxLength":63,"description":"Open vocabulary: `^[a-z][a-z0-9_.-]{0,62}$`, e.g. deposit."},"at":{"type":"string","format":"date-time","description":"When it happened, by your clock. Advisory."},"properties":{"type":"object","additionalProperties":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]},"description":"Flat properties: at most 20 keys, 2 KB as JSON, values text, finite numbers or true/false."},"page":{"type":"object","properties":{"path":{"type":"string","maxLength":1000,"description":"A page path only, starting with /: no query string, no fragment."}},"required":["path"]}},"required":["eventId","name"]},"description":"One to 20 events, handled in order."}},"required":["v","programKey","playerId","events"]},"example":{"v":0,"programKey":"string","playerId":"string","events":[{"eventId":"00000000-0000-0000-0000-000000000000","name":"string","at":"2026-01-01T00:00:00Z","properties":{},"page":{"path":"string"}}]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"v":{"type":"integer","minimum":1,"maximum":1},"accepted":{"type":"array","items":{"type":"string"}},"duplicate":{"type":"array","items":{"type":"string"}},"rejected":{"type":"array","items":{"type":"object","properties":{"eventId":{"type":"string"},"reason":{"type":"string"}},"required":["eventId","reason"]}}},"required":["v","accepted","duplicate","rejected"]},"example":{"v":0,"accepted":["string"],"duplicate":["string"],"rejected":[{"eventId":"string","reason":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/players/{playerId}":{"get":{"operationId":"GetGamificationPlayer","tags":["gamification"],"summary":"Get Gamification Player","security":[{"ApiKeyAuth":["gamification:read"]},{"BearerAuth":[]},{"OAuth2":["gamification:read"]}],"parameters":[{"name":"playerId","in":"path","required":true,"schema":{"type":"string","maxLength":500,"description":"The id the player has in your systems."},"description":"The id the player has in your systems."},{"name":"program","in":"query","required":false,"schema":{"type":"string","maxLength":63,"description":"Only this program."},"description":"Only this program."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"description":"Awards per page. Default 100."},"description":"Awards per page. Default 100."},{"name":"before","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"The previous page's nextBefore."},"description":"The previous page's nextBefore."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"playerId":{"type":"string"},"metrics":{"type":"array","items":{"type":"object","properties":{"programKey":{"type":"string","nullable":true,"description":"null for the platform's own schemes."},"metric":{"type":"string","description":"As the program names it, e.g. points."},"storedMetric":{"type":"string"},"value":{"type":"number"},"level":{"type":"string","nullable":true},"updatedAt":{"type":"string","format":"date-time"}},"required":["programKey","metric","storedMetric","value","level","updatedAt"]}},"awards":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"programKey":{"type":"string","nullable":true},"metric":{"type":"string"},"eventType":{"type":"string","description":"Known values: manual.adjustment; otherwise the event that scored."},"value":{"type":"number","nullable":true},"manual":{"type":"boolean"},"sourceEventId":{"type":"string"},"actorType":{"type":"string","nullable":true},"actorId":{"type":"string","nullable":true},"detail":{"type":"object","properties":{"reason":{"type":"string"},"adjustedBy":{"type":"string"},"entityType":{"type":"string"},"field":{"type":"string"},"event":{"type":"string","description":"A player-event award: the event's name."},"trust":{"type":"string","description":"A player-event award: client (the player's browser) or server (the tenant's server)."},"pagePath":{"type":"string","description":"A player-event award: the page path the event named."}},"nullable":true,"description":"A manual adjustment carries reason and adjustedBy; a scored award, the kind of record and field it came from, or (a player event) the event name, who reported it and its page. Other keys may be present."},"at":{"type":"string","format":"date-time"}},"required":["id","programKey","metric","eventType","value","manual","sourceEventId","actorType","actorId","detail","at"]},"description":"Newest first."},"nextBefore":{"type":"string","nullable":true}},"required":["playerId","metrics","awards"]},"example":{"playerId":"string","metrics":[{"programKey":"string","metric":"string","storedMetric":"string","value":0,"level":"string","updatedAt":"2026-01-01T00:00:00Z"}],"awards":[{"id":"00000000-0000-0000-0000-000000000000","programKey":"string","metric":"string","eventType":"string","value":0,"manual":true,"sourceEventId":"string","actorType":"string","actorId":"string","detail":{"reason":"string","adjustedBy":"string","entityType":"string","field":"string","event":"string","trust":"string","pagePath":"string"},"at":"2026-01-01T00:00:00Z"}],"nextBefore":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/players/{playerId}/adjust":{"post":{"operationId":"AdjustGamificationPlayer","tags":["gamification"],"summary":"Adjust Gamification Player","security":[{"ApiKeyAuth":["gamification:write"]},{"BearerAuth":[]},{"OAuth2":["gamification:write"]}],"parameters":[{"name":"playerId","in":"path","required":true,"schema":{"type":"string","maxLength":500}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"program":{"type":"string","maxLength":63,"description":"The program key."},"metric":{"type":"string","maxLength":63,"description":"A metric the program's published rules accrue, e.g. points."},"delta":{"type":"integer","description":"Points to add (positive) or remove (negative). Never below zero in total."},"reason":{"type":"string","minLength":3,"maxLength":500}},"required":["program","metric","delta","reason"]},"example":{"program":"string","metric":"string","delta":0,"reason":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"playerId":{"type":"string"},"programKey":{"type":"string"},"metric":{"type":"string"},"delta":{"type":"integer"},"value":{"type":"integer"},"level":{"type":"string","nullable":true},"ledgerEventId":{"type":"string","format":"uuid"}},"required":["playerId","programKey","metric","delta","value","ledgerEventId"]},"example":{"playerId":"string","programKey":"string","metric":"string","delta":0,"value":0,"level":"string","ledgerEventId":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/programs":{"get":{"operationId":"ListGamificationPrograms","tags":["gamification"],"summary":"List Gamification Programs","security":[{"ApiKeyAuth":["gamification:read"]},{"BearerAuth":[]},{"OAuth2":["gamification:read"]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["draft","live","paused","archived"],"description":"Only programs in this state."},"description":"Only programs in this state."},{"name":"environmentId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only programs in this environment."},"description":"Only programs in this environment."},{"name":"includeArchived","in":"query","required":false,"schema":{"type":"boolean","description":"Include archived programs."},"description":"Include archived programs."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"programs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string"},"name":{"type":"string"},"template":{"type":"string"},"stage":{"type":"string","nullable":true,"description":"The journey stage (open vocabulary). Known values: acquisition, purchase, retention, winback."},"status":{"type":"string","description":"Known values: draft, live, paused, archived."},"environmentId":{"type":"string","format":"uuid","nullable":true,"description":"null = the workspace default environment."},"playerKind":{"type":"string","nullable":true},"draft":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"]},"draftRevision":{"type":"integer"},"published":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"],"nullable":true,"description":"The definition last published; null until the first publish."},"publishedRevision":{"type":"integer","nullable":true},"publishedVersion":{"type":"integer"},"publishedAt":{"type":"string","format":"date-time","nullable":true},"publishedBy":{"type":"string","nullable":true},"hasUnpublishedChanges":{"type":"boolean","description":"A draft has been saved since the last publish."},"pausedAt":{"type":"string","format":"date-time","nullable":true},"archivedAt":{"type":"string","format":"date-time","nullable":true},"archivedBy":{"type":"string","nullable":true},"duplicatedFromProgramId":{"type":"string","format":"uuid","nullable":true},"promotedFromProgramId":{"type":"string","format":"uuid","nullable":true},"delivery":{"type":"object","properties":{"widget":{"type":"object","properties":{"enabled":{"type":"boolean"},"show":{"type":"array","items":{"type":"string"},"description":"Known values: progress, leaderboard, recent-awards."}},"required":["enabled","show"]},"look":{"type":"object","additionalProperties":{"type":"string"},"description":"Known keys: theme, corners, font, accent."},"allowedOrigins":{"type":"array","items":{"type":"string"}},"showOtherPlayerNames":{"type":"boolean"},"termsUrl":{"type":"string","nullable":true}},"required":["widget","look","allowedOrigins","showOtherPlayerNames","termsUrl"]},"levelDestinations":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Known values: webhook, connection."},"webhookSubscriptionId":{"type":"string","format":"uuid","description":"webhook: the subscription."},"connectionId":{"type":"string","format":"uuid","description":"connection: the connected system written to."},"entity":{"type":"string","description":"connection: the object (api name) each outcome is written as."},"on":{"type":"array","items":{"type":"string"},"description":"connection: which outcomes it receives. Known values: level-reached, award."},"fields":{"type":"array","items":{"type":"object","properties":{"target":{"type":"string","description":"The field written, dotted for a nested one."},"from":{"type":"string","description":"Known values: player, program, metric, value, level, points, rule, outcome, at."},"value":{"type":"string","description":"A fixed text, sent on every record."},"format":{"type":"string","description":"Known values: unix-seconds (for at)."}},"required":["target"]},"description":"connection: the record's fields, each filled from a value of the outcome or a fixed text."}},"required":["type"]},"description":"Where the program's outcomes go. A webhook receives level-ups; a connection receives the outcomes in `on` as records of one of its objects."},"embed":{"type":"object","properties":{"embedId":{"type":"string","nullable":true,"description":"The program's embed id, which the Play SDK and the paste-in snippet name. There is no hosted widget address: hosted Play is deferred (2026-11-09)."},"snippet":{"type":"string","nullable":true,"description":"A paste-in HTML + script widget for the program, calling the embed route (v1 read) with the player token from window.myobosAccount (playerToken, else token), else the div's data-player-token; on a 401 it asks window.myobosAccount.getToken() once for a fresh token. Null until the program has an embed id."},"secretRotatedAt":{"type":"string","format":"date-time","nullable":true}},"required":["embedId","snippet","secretRotatedAt"],"description":"The secret itself is never returned after the rotation that made it."},"players":{"type":"integer","description":"Distinct players it has scored."},"createdBy":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","key","name","template","stage","status","environmentId","playerKind","draft","draftRevision","published","publishedRevision","publishedVersion","publishedAt","publishedBy","hasUnpublishedChanges","pausedAt","archivedAt","archivedBy","duplicatedFromProgramId","promotedFromProgramId","delivery","levelDestinations","embed","players","createdBy","createdAt","updatedAt"]}},"templates":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Pass as `template` to create a program from it."},"name":{"type":"string"},"description":{"type":"string"},"stage":{"type":"string","nullable":true},"ruleCount":{"type":"integer"},"notYetScorable":{"type":"array","items":{"type":"string"},"description":"Mechanics this stage is known for that the scoring engine does not run yet, in words."},"scoresArchetypes":{"type":"array","items":{"type":"string"},"description":"The kinds of object (an object's archetype) whose records this template scores, best first; empty when it has no preference. A new program pre-picks an object of one of these kinds."}},"required":["key","name","description","stage","ruleCount","notYetScorable","scoresArchetypes"]}}},"required":["programs","templates"]},"example":{"programs":[{"id":"00000000-0000-0000-0000-000000000000","key":"string","name":"string","template":"string","stage":"string","status":"string","environmentId":"00000000-0000-0000-0000-000000000000","playerKind":"string","draft":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"draftRevision":0,"published":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"publishedRevision":0,"publishedVersion":0,"publishedAt":"2026-01-01T00:00:00Z","publishedBy":"string","hasUnpublishedChanges":true,"pausedAt":"2026-01-01T00:00:00Z","archivedAt":"2026-01-01T00:00:00Z","archivedBy":"string","duplicatedFromProgramId":"00000000-0000-0000-0000-000000000000","promotedFromProgramId":"00000000-0000-0000-0000-000000000000","delivery":{"widget":{"enabled":true,"show":["string"]},"look":{},"allowedOrigins":["string"],"showOtherPlayerNames":true,"termsUrl":"string"},"levelDestinations":[{"type":"string","webhookSubscriptionId":"00000000-0000-0000-0000-000000000000","connectionId":"00000000-0000-0000-0000-000000000000","entity":"string","on":["string"],"fields":[{"target":"string","from":"string","value":"string","format":"string"}]}],"embed":{"embedId":"string","snippet":"string","secretRotatedAt":"2026-01-01T00:00:00Z"},"players":0,"createdBy":"string","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z"}],"templates":[{"key":"string","name":"string","description":"string","stage":"string","ruleCount":0,"notYetScorable":["string"],"scoresArchetypes":["string"]}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"CreateGamificationProgram","tags":["gamification"],"summary":"Create Gamification Program","security":[{"ApiKeyAuth":["gamification:write"]},{"BearerAuth":[]},{"OAuth2":["gamification:write"]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"template":{"type":"string","maxLength":63,"description":"The template key, from the list response."},"key":{"type":"string","maxLength":63,"description":"Lower-case letters, digits and hyphens. Derived from the name when absent."},"playerKind":{"type":"string","maxLength":60,"description":"What a player is: any kind of golden record, e.g. account, person, driver, device."},"environmentId":{"type":"string","format":"uuid","description":"The environment whose pipelines feed it. Absent = the workspace default."}},"required":["name","template"]},"example":{"name":"string","template":"string","key":"string","playerKind":"string","environmentId":"00000000-0000-0000-0000-000000000000"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"program":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string"},"name":{"type":"string"},"template":{"type":"string"},"stage":{"type":"string","nullable":true,"description":"The journey stage (open vocabulary). Known values: acquisition, purchase, retention, winback."},"status":{"type":"string","description":"Known values: draft, live, paused, archived."},"environmentId":{"type":"string","format":"uuid","nullable":true,"description":"null = the workspace default environment."},"playerKind":{"type":"string","nullable":true},"draft":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"]},"draftRevision":{"type":"integer"},"published":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"],"nullable":true,"description":"The definition last published; null until the first publish."},"publishedRevision":{"type":"integer","nullable":true},"publishedVersion":{"type":"integer"},"publishedAt":{"type":"string","format":"date-time","nullable":true},"publishedBy":{"type":"string","nullable":true},"hasUnpublishedChanges":{"type":"boolean","description":"A draft has been saved since the last publish."},"pausedAt":{"type":"string","format":"date-time","nullable":true},"archivedAt":{"type":"string","format":"date-time","nullable":true},"archivedBy":{"type":"string","nullable":true},"duplicatedFromProgramId":{"type":"string","format":"uuid","nullable":true},"promotedFromProgramId":{"type":"string","format":"uuid","nullable":true},"delivery":{"type":"object","properties":{"widget":{"type":"object","properties":{"enabled":{"type":"boolean"},"show":{"type":"array","items":{"type":"string"},"description":"Known values: progress, leaderboard, recent-awards."}},"required":["enabled","show"]},"look":{"type":"object","additionalProperties":{"type":"string"},"description":"Known keys: theme, corners, font, accent."},"allowedOrigins":{"type":"array","items":{"type":"string"}},"showOtherPlayerNames":{"type":"boolean"},"termsUrl":{"type":"string","nullable":true}},"required":["widget","look","allowedOrigins","showOtherPlayerNames","termsUrl"]},"levelDestinations":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Known values: webhook, connection."},"webhookSubscriptionId":{"type":"string","format":"uuid","description":"webhook: the subscription."},"connectionId":{"type":"string","format":"uuid","description":"connection: the connected system written to."},"entity":{"type":"string","description":"connection: the object (api name) each outcome is written as."},"on":{"type":"array","items":{"type":"string"},"description":"connection: which outcomes it receives. Known values: level-reached, award."},"fields":{"type":"array","items":{"type":"object","properties":{"target":{"type":"string","description":"The field written, dotted for a nested one."},"from":{"type":"string","description":"Known values: player, program, metric, value, level, points, rule, outcome, at."},"value":{"type":"string","description":"A fixed text, sent on every record."},"format":{"type":"string","description":"Known values: unix-seconds (for at)."}},"required":["target"]},"description":"connection: the record's fields, each filled from a value of the outcome or a fixed text."}},"required":["type"]},"description":"Where the program's outcomes go. A webhook receives level-ups; a connection receives the outcomes in `on` as records of one of its objects."},"embed":{"type":"object","properties":{"embedId":{"type":"string","nullable":true,"description":"The program's embed id, which the Play SDK and the paste-in snippet name. There is no hosted widget address: hosted Play is deferred (2026-11-09)."},"snippet":{"type":"string","nullable":true,"description":"A paste-in HTML + script widget for the program, calling the embed route (v1 read) with the player token from window.myobosAccount (playerToken, else token), else the div's data-player-token; on a 401 it asks window.myobosAccount.getToken() once for a fresh token. Null until the program has an embed id."},"secretRotatedAt":{"type":"string","format":"date-time","nullable":true}},"required":["embedId","snippet","secretRotatedAt"],"description":"The secret itself is never returned after the rotation that made it."},"players":{"type":"integer","description":"Distinct players it has scored."},"createdBy":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","key","name","template","stage","status","environmentId","playerKind","draft","draftRevision","published","publishedRevision","publishedVersion","publishedAt","publishedBy","hasUnpublishedChanges","pausedAt","archivedAt","archivedBy","duplicatedFromProgramId","promotedFromProgramId","delivery","levelDestinations","embed","players","createdBy","createdAt","updatedAt"]}},"required":["program"]},"example":{"program":{"id":"00000000-0000-0000-0000-000000000000","key":"string","name":"string","template":"string","stage":"string","status":"string","environmentId":"00000000-0000-0000-0000-000000000000","playerKind":"string","draft":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"draftRevision":0,"published":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"publishedRevision":0,"publishedVersion":0,"publishedAt":"2026-01-01T00:00:00Z","publishedBy":"string","hasUnpublishedChanges":true,"pausedAt":"2026-01-01T00:00:00Z","archivedAt":"2026-01-01T00:00:00Z","archivedBy":"string","duplicatedFromProgramId":"00000000-0000-0000-0000-000000000000","promotedFromProgramId":"00000000-0000-0000-0000-000000000000","delivery":{"widget":{"enabled":true,"show":["string"]},"look":{},"allowedOrigins":["string"],"showOtherPlayerNames":true,"termsUrl":"string"},"levelDestinations":[{"type":"string","webhookSubscriptionId":"00000000-0000-0000-0000-000000000000","connectionId":"00000000-0000-0000-0000-000000000000","entity":"string","on":["string"],"fields":[{"target":"string","from":"string","value":"string","format":"string"}]}],"embed":{"embedId":"string","snippet":"string","secretRotatedAt":"2026-01-01T00:00:00Z"},"players":0,"createdBy":"string","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/programs/{key}":{"delete":{"operationId":"ArchiveGamificationProgram","tags":["gamification"],"summary":"Archive Gamification Program","security":[{"ApiKeyAuth":["gamification:delete"]},{"BearerAuth":[]},{"OAuth2":["gamification:delete"]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":63}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"program":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string"},"name":{"type":"string"},"template":{"type":"string"},"stage":{"type":"string","nullable":true,"description":"The journey stage (open vocabulary). Known values: acquisition, purchase, retention, winback."},"status":{"type":"string","description":"Known values: draft, live, paused, archived."},"environmentId":{"type":"string","format":"uuid","nullable":true,"description":"null = the workspace default environment."},"playerKind":{"type":"string","nullable":true},"draft":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"]},"draftRevision":{"type":"integer"},"published":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"],"nullable":true,"description":"The definition last published; null until the first publish."},"publishedRevision":{"type":"integer","nullable":true},"publishedVersion":{"type":"integer"},"publishedAt":{"type":"string","format":"date-time","nullable":true},"publishedBy":{"type":"string","nullable":true},"hasUnpublishedChanges":{"type":"boolean","description":"A draft has been saved since the last publish."},"pausedAt":{"type":"string","format":"date-time","nullable":true},"archivedAt":{"type":"string","format":"date-time","nullable":true},"archivedBy":{"type":"string","nullable":true},"duplicatedFromProgramId":{"type":"string","format":"uuid","nullable":true},"promotedFromProgramId":{"type":"string","format":"uuid","nullable":true},"delivery":{"type":"object","properties":{"widget":{"type":"object","properties":{"enabled":{"type":"boolean"},"show":{"type":"array","items":{"type":"string"},"description":"Known values: progress, leaderboard, recent-awards."}},"required":["enabled","show"]},"look":{"type":"object","additionalProperties":{"type":"string"},"description":"Known keys: theme, corners, font, accent."},"allowedOrigins":{"type":"array","items":{"type":"string"}},"showOtherPlayerNames":{"type":"boolean"},"termsUrl":{"type":"string","nullable":true}},"required":["widget","look","allowedOrigins","showOtherPlayerNames","termsUrl"]},"levelDestinations":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Known values: webhook, connection."},"webhookSubscriptionId":{"type":"string","format":"uuid","description":"webhook: the subscription."},"connectionId":{"type":"string","format":"uuid","description":"connection: the connected system written to."},"entity":{"type":"string","description":"connection: the object (api name) each outcome is written as."},"on":{"type":"array","items":{"type":"string"},"description":"connection: which outcomes it receives. Known values: level-reached, award."},"fields":{"type":"array","items":{"type":"object","properties":{"target":{"type":"string","description":"The field written, dotted for a nested one."},"from":{"type":"string","description":"Known values: player, program, metric, value, level, points, rule, outcome, at."},"value":{"type":"string","description":"A fixed text, sent on every record."},"format":{"type":"string","description":"Known values: unix-seconds (for at)."}},"required":["target"]},"description":"connection: the record's fields, each filled from a value of the outcome or a fixed text."}},"required":["type"]},"description":"Where the program's outcomes go. A webhook receives level-ups; a connection receives the outcomes in `on` as records of one of its objects."},"embed":{"type":"object","properties":{"embedId":{"type":"string","nullable":true,"description":"The program's embed id, which the Play SDK and the paste-in snippet name. There is no hosted widget address: hosted Play is deferred (2026-11-09)."},"snippet":{"type":"string","nullable":true,"description":"A paste-in HTML + script widget for the program, calling the embed route (v1 read) with the player token from window.myobosAccount (playerToken, else token), else the div's data-player-token; on a 401 it asks window.myobosAccount.getToken() once for a fresh token. Null until the program has an embed id."},"secretRotatedAt":{"type":"string","format":"date-time","nullable":true}},"required":["embedId","snippet","secretRotatedAt"],"description":"The secret itself is never returned after the rotation that made it."},"players":{"type":"integer","description":"Distinct players it has scored."},"createdBy":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","key","name","template","stage","status","environmentId","playerKind","draft","draftRevision","published","publishedRevision","publishedVersion","publishedAt","publishedBy","hasUnpublishedChanges","pausedAt","archivedAt","archivedBy","duplicatedFromProgramId","promotedFromProgramId","delivery","levelDestinations","embed","players","createdBy","createdAt","updatedAt"]}},"required":["program"]},"example":{"program":{"id":"00000000-0000-0000-0000-000000000000","key":"string","name":"string","template":"string","stage":"string","status":"string","environmentId":"00000000-0000-0000-0000-000000000000","playerKind":"string","draft":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"draftRevision":0,"published":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"publishedRevision":0,"publishedVersion":0,"publishedAt":"2026-01-01T00:00:00Z","publishedBy":"string","hasUnpublishedChanges":true,"pausedAt":"2026-01-01T00:00:00Z","archivedAt":"2026-01-01T00:00:00Z","archivedBy":"string","duplicatedFromProgramId":"00000000-0000-0000-0000-000000000000","promotedFromProgramId":"00000000-0000-0000-0000-000000000000","delivery":{"widget":{"enabled":true,"show":["string"]},"look":{},"allowedOrigins":["string"],"showOtherPlayerNames":true,"termsUrl":"string"},"levelDestinations":[{"type":"string","webhookSubscriptionId":"00000000-0000-0000-0000-000000000000","connectionId":"00000000-0000-0000-0000-000000000000","entity":"string","on":["string"],"fields":[{"target":"string","from":"string","value":"string","format":"string"}]}],"embed":{"embedId":"string","snippet":"string","secretRotatedAt":"2026-01-01T00:00:00Z"},"players":0,"createdBy":"string","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"GetGamificationProgram","tags":["gamification"],"summary":"Get Gamification Program","security":[{"ApiKeyAuth":["gamification:read"]},{"BearerAuth":[]},{"OAuth2":["gamification:read"]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":63}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"program":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string"},"name":{"type":"string"},"template":{"type":"string"},"stage":{"type":"string","nullable":true,"description":"The journey stage (open vocabulary). Known values: acquisition, purchase, retention, winback."},"status":{"type":"string","description":"Known values: draft, live, paused, archived."},"environmentId":{"type":"string","format":"uuid","nullable":true,"description":"null = the workspace default environment."},"playerKind":{"type":"string","nullable":true},"draft":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"]},"draftRevision":{"type":"integer"},"published":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"],"nullable":true,"description":"The definition last published; null until the first publish."},"publishedRevision":{"type":"integer","nullable":true},"publishedVersion":{"type":"integer"},"publishedAt":{"type":"string","format":"date-time","nullable":true},"publishedBy":{"type":"string","nullable":true},"hasUnpublishedChanges":{"type":"boolean","description":"A draft has been saved since the last publish."},"pausedAt":{"type":"string","format":"date-time","nullable":true},"archivedAt":{"type":"string","format":"date-time","nullable":true},"archivedBy":{"type":"string","nullable":true},"duplicatedFromProgramId":{"type":"string","format":"uuid","nullable":true},"promotedFromProgramId":{"type":"string","format":"uuid","nullable":true},"delivery":{"type":"object","properties":{"widget":{"type":"object","properties":{"enabled":{"type":"boolean"},"show":{"type":"array","items":{"type":"string"},"description":"Known values: progress, leaderboard, recent-awards."}},"required":["enabled","show"]},"look":{"type":"object","additionalProperties":{"type":"string"},"description":"Known keys: theme, corners, font, accent."},"allowedOrigins":{"type":"array","items":{"type":"string"}},"showOtherPlayerNames":{"type":"boolean"},"termsUrl":{"type":"string","nullable":true}},"required":["widget","look","allowedOrigins","showOtherPlayerNames","termsUrl"]},"levelDestinations":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Known values: webhook, connection."},"webhookSubscriptionId":{"type":"string","format":"uuid","description":"webhook: the subscription."},"connectionId":{"type":"string","format":"uuid","description":"connection: the connected system written to."},"entity":{"type":"string","description":"connection: the object (api name) each outcome is written as."},"on":{"type":"array","items":{"type":"string"},"description":"connection: which outcomes it receives. Known values: level-reached, award."},"fields":{"type":"array","items":{"type":"object","properties":{"target":{"type":"string","description":"The field written, dotted for a nested one."},"from":{"type":"string","description":"Known values: player, program, metric, value, level, points, rule, outcome, at."},"value":{"type":"string","description":"A fixed text, sent on every record."},"format":{"type":"string","description":"Known values: unix-seconds (for at)."}},"required":["target"]},"description":"connection: the record's fields, each filled from a value of the outcome or a fixed text."}},"required":["type"]},"description":"Where the program's outcomes go. A webhook receives level-ups; a connection receives the outcomes in `on` as records of one of its objects."},"embed":{"type":"object","properties":{"embedId":{"type":"string","nullable":true,"description":"The program's embed id, which the Play SDK and the paste-in snippet name. There is no hosted widget address: hosted Play is deferred (2026-11-09)."},"snippet":{"type":"string","nullable":true,"description":"A paste-in HTML + script widget for the program, calling the embed route (v1 read) with the player token from window.myobosAccount (playerToken, else token), else the div's data-player-token; on a 401 it asks window.myobosAccount.getToken() once for a fresh token. Null until the program has an embed id."},"secretRotatedAt":{"type":"string","format":"date-time","nullable":true}},"required":["embedId","snippet","secretRotatedAt"],"description":"The secret itself is never returned after the rotation that made it."},"players":{"type":"integer","description":"Distinct players it has scored."},"createdBy":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","key","name","template","stage","status","environmentId","playerKind","draft","draftRevision","published","publishedRevision","publishedVersion","publishedAt","publishedBy","hasUnpublishedChanges","pausedAt","archivedAt","archivedBy","duplicatedFromProgramId","promotedFromProgramId","delivery","levelDestinations","embed","players","createdBy","createdAt","updatedAt"]}},"required":["program"]},"example":{"program":{"id":"00000000-0000-0000-0000-000000000000","key":"string","name":"string","template":"string","stage":"string","status":"string","environmentId":"00000000-0000-0000-0000-000000000000","playerKind":"string","draft":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"draftRevision":0,"published":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"publishedRevision":0,"publishedVersion":0,"publishedAt":"2026-01-01T00:00:00Z","publishedBy":"string","hasUnpublishedChanges":true,"pausedAt":"2026-01-01T00:00:00Z","archivedAt":"2026-01-01T00:00:00Z","archivedBy":"string","duplicatedFromProgramId":"00000000-0000-0000-0000-000000000000","promotedFromProgramId":"00000000-0000-0000-0000-000000000000","delivery":{"widget":{"enabled":true,"show":["string"]},"look":{},"allowedOrigins":["string"],"showOtherPlayerNames":true,"termsUrl":"string"},"levelDestinations":[{"type":"string","webhookSubscriptionId":"00000000-0000-0000-0000-000000000000","connectionId":"00000000-0000-0000-0000-000000000000","entity":"string","on":["string"],"fields":[{"target":"string","from":"string","value":"string","format":"string"}]}],"embed":{"embedId":"string","snippet":"string","secretRotatedAt":"2026-01-01T00:00:00Z"},"players":0,"createdBy":"string","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/programs/{key}/backtest":{"post":{"operationId":"BacktestGamificationProgram","tags":["gamification"],"summary":"Backtest Gamification Program","security":[{"ApiKeyAuth":["gamification:write"]},{"BearerAuth":[]},{"OAuth2":["gamification:write"]}],"description":"Read-only. Replays each version of a source record synced into the program's environment within `days`, matched against that connection's classified fields with the producer's own matcher, and scored by the draft compiled with the shared compiler. Every player starts the window at zero. At most 50,000 record versions are read; `truncated` says when there were more.","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":63}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"days":{"type":"integer","minimum":1,"maximum":365,"description":"How far back to replay. Default 90."}}},"example":{"days":0}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"},"draftRevision":{"type":"integer","description":"The draft revision that was replayed."},"days":{"type":"integer"},"connections":{"type":"integer","description":"Systems whose records were replayed: the sources of the pipelines in the program's environment."},"recordsScanned":{"type":"integer"},"truncated":{"type":"boolean"},"basis":{"type":"string","description":"What was replayed, in a sentence."},"awards":{"type":"object","properties":{"count":{"type":"integer"},"points":{"type":"number"},"byRule":{"type":"array","items":{"type":"object","properties":{"ruleKey":{"type":"string"},"awards":{"type":"integer"},"points":{"type":"number"},"players":{"type":"integer"}},"required":["ruleKey","awards","points","players"]}}},"required":["count","points","byRule"]},"players":{"type":"integer"},"levelMetric":{"type":"string","nullable":true},"levelDistribution":{"type":"array","items":{"type":"object","properties":{"level":{"type":"string","nullable":true},"players":{"type":"integer"}},"required":["level","players"]},"description":"Players on each level at the end of the window, lowest first; level null = below the first."},"perWeek":{"type":"array","items":{"type":"object","properties":{"weekStart":{"type":"string","description":"Monday, YYYY-MM-DD (UTC)."},"awards":{"type":"integer"},"points":{"type":"number"},"players":{"type":"integer"}},"required":["weekStart","awards","points","players"]}},"typicalPointsPerPlayerPerWeek":{"type":"number","description":"The median a player who earned anything in a week earned that week."},"levels":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"number"},"players":{"type":"integer"},"estimatedWeeksToReach":{"type":"integer","nullable":true,"description":"At the typical weekly rate — an estimate, not a measurement."}},"required":["name","threshold","players","estimatedWeeksToReach"]}}},"required":["key","draftRevision","days","connections","recordsScanned","truncated","basis","awards","players","levelMetric","levelDistribution","perWeek","typicalPointsPerPlayerPerWeek","levels"]},"example":{"key":"string","draftRevision":0,"days":0,"connections":0,"recordsScanned":0,"truncated":true,"basis":"string","awards":{"count":0,"points":0,"byRule":[{"ruleKey":"string","awards":0,"points":0,"players":0}]},"players":0,"levelMetric":"string","levelDistribution":[{"level":"string","players":0}],"perWeek":[{"weekStart":"string","awards":0,"points":0,"players":0}],"typicalPointsPerPlayerPerWeek":0,"levels":[{"name":"string","threshold":0,"players":0,"estimatedWeeksToReach":0}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/programs/{key}/delivery":{"put":{"operationId":"SetGamificationProgramDelivery","tags":["gamification"],"summary":"Set Gamification Program Delivery","security":[{"ApiKeyAuth":["gamification:write"]},{"BearerAuth":[]},{"OAuth2":["gamification:write"]}],"description":"Replaces the delivery settings. The widget can show progress, leaderboard and recent-awards. Allowed websites are https origins; an enabled widget needs at least one, and is refused on every other site. The embed read never sends another player's external id: the leaderboard shows other players by rank and points, and showOtherPlayerNames is kept for when players' display names are stored.","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":63}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"widget":{"type":"object","additionalProperties":true,"description":"{ enabled, show: [\"progress\" | \"leaderboard\" | \"recent-awards\"] }"},"look":{"type":"object","additionalProperties":true,"description":"theme, corners, font, accent — text the widget reads."},"allowedOrigins":{"type":"array","items":{"type":"string"},"description":"https origins, e.g. https://portal.example.com"},"showOtherPlayerNames":{"type":"boolean"},"termsUrl":{"type":"string","maxLength":2000,"nullable":true}}},"example":{"widget":{},"look":{},"allowedOrigins":["string"],"showOtherPlayerNames":true,"termsUrl":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"program":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string"},"name":{"type":"string"},"template":{"type":"string"},"stage":{"type":"string","nullable":true,"description":"The journey stage (open vocabulary). Known values: acquisition, purchase, retention, winback."},"status":{"type":"string","description":"Known values: draft, live, paused, archived."},"environmentId":{"type":"string","format":"uuid","nullable":true,"description":"null = the workspace default environment."},"playerKind":{"type":"string","nullable":true},"draft":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"]},"draftRevision":{"type":"integer"},"published":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"],"nullable":true,"description":"The definition last published; null until the first publish."},"publishedRevision":{"type":"integer","nullable":true},"publishedVersion":{"type":"integer"},"publishedAt":{"type":"string","format":"date-time","nullable":true},"publishedBy":{"type":"string","nullable":true},"hasUnpublishedChanges":{"type":"boolean","description":"A draft has been saved since the last publish."},"pausedAt":{"type":"string","format":"date-time","nullable":true},"archivedAt":{"type":"string","format":"date-time","nullable":true},"archivedBy":{"type":"string","nullable":true},"duplicatedFromProgramId":{"type":"string","format":"uuid","nullable":true},"promotedFromProgramId":{"type":"string","format":"uuid","nullable":true},"delivery":{"type":"object","properties":{"widget":{"type":"object","properties":{"enabled":{"type":"boolean"},"show":{"type":"array","items":{"type":"string"},"description":"Known values: progress, leaderboard, recent-awards."}},"required":["enabled","show"]},"look":{"type":"object","additionalProperties":{"type":"string"},"description":"Known keys: theme, corners, font, accent."},"allowedOrigins":{"type":"array","items":{"type":"string"}},"showOtherPlayerNames":{"type":"boolean"},"termsUrl":{"type":"string","nullable":true}},"required":["widget","look","allowedOrigins","showOtherPlayerNames","termsUrl"]},"levelDestinations":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Known values: webhook, connection."},"webhookSubscriptionId":{"type":"string","format":"uuid","description":"webhook: the subscription."},"connectionId":{"type":"string","format":"uuid","description":"connection: the connected system written to."},"entity":{"type":"string","description":"connection: the object (api name) each outcome is written as."},"on":{"type":"array","items":{"type":"string"},"description":"connection: which outcomes it receives. Known values: level-reached, award."},"fields":{"type":"array","items":{"type":"object","properties":{"target":{"type":"string","description":"The field written, dotted for a nested one."},"from":{"type":"string","description":"Known values: player, program, metric, value, level, points, rule, outcome, at."},"value":{"type":"string","description":"A fixed text, sent on every record."},"format":{"type":"string","description":"Known values: unix-seconds (for at)."}},"required":["target"]},"description":"connection: the record's fields, each filled from a value of the outcome or a fixed text."}},"required":["type"]},"description":"Where the program's outcomes go. A webhook receives level-ups; a connection receives the outcomes in `on` as records of one of its objects."},"embed":{"type":"object","properties":{"embedId":{"type":"string","nullable":true,"description":"The program's embed id, which the Play SDK and the paste-in snippet name. There is no hosted widget address: hosted Play is deferred (2026-11-09)."},"snippet":{"type":"string","nullable":true,"description":"A paste-in HTML + script widget for the program, calling the embed route (v1 read) with the player token from window.myobosAccount (playerToken, else token), else the div's data-player-token; on a 401 it asks window.myobosAccount.getToken() once for a fresh token. Null until the program has an embed id."},"secretRotatedAt":{"type":"string","format":"date-time","nullable":true}},"required":["embedId","snippet","secretRotatedAt"],"description":"The secret itself is never returned after the rotation that made it."},"players":{"type":"integer","description":"Distinct players it has scored."},"createdBy":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","key","name","template","stage","status","environmentId","playerKind","draft","draftRevision","published","publishedRevision","publishedVersion","publishedAt","publishedBy","hasUnpublishedChanges","pausedAt","archivedAt","archivedBy","duplicatedFromProgramId","promotedFromProgramId","delivery","levelDestinations","embed","players","createdBy","createdAt","updatedAt"]}},"required":["program"]},"example":{"program":{"id":"00000000-0000-0000-0000-000000000000","key":"string","name":"string","template":"string","stage":"string","status":"string","environmentId":"00000000-0000-0000-0000-000000000000","playerKind":"string","draft":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"draftRevision":0,"published":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"publishedRevision":0,"publishedVersion":0,"publishedAt":"2026-01-01T00:00:00Z","publishedBy":"string","hasUnpublishedChanges":true,"pausedAt":"2026-01-01T00:00:00Z","archivedAt":"2026-01-01T00:00:00Z","archivedBy":"string","duplicatedFromProgramId":"00000000-0000-0000-0000-000000000000","promotedFromProgramId":"00000000-0000-0000-0000-000000000000","delivery":{"widget":{"enabled":true,"show":["string"]},"look":{},"allowedOrigins":["string"],"showOtherPlayerNames":true,"termsUrl":"string"},"levelDestinations":[{"type":"string","webhookSubscriptionId":"00000000-0000-0000-0000-000000000000","connectionId":"00000000-0000-0000-0000-000000000000","entity":"string","on":["string"],"fields":[{"target":"string","from":"string","value":"string","format":"string"}]}],"embed":{"embedId":"string","snippet":"string","secretRotatedAt":"2026-01-01T00:00:00Z"},"players":0,"createdBy":"string","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/programs/{key}/draft":{"put":{"operationId":"SaveGamificationProgramDraft","tags":["gamification"],"summary":"Save Gamification Program Draft","security":[{"ApiKeyAuth":["gamification:write"]},{"BearerAuth":[]},{"OAuth2":["gamification:write"]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":63}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"definition":{"type":"object","additionalProperties":true,"description":"players, rules and levels. Every rule is checked; all problems are returned together."},"name":{"type":"string","minLength":1,"maxLength":120},"baseRevision":{"type":"integer","minimum":1,"description":"The draft revision the editor loaded. A save over a newer revision is refused instead of overwriting someone else's edit."}},"required":["definition"]},"example":{"definition":{},"name":"string","baseRevision":0}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"program":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string"},"name":{"type":"string"},"template":{"type":"string"},"stage":{"type":"string","nullable":true,"description":"The journey stage (open vocabulary). Known values: acquisition, purchase, retention, winback."},"status":{"type":"string","description":"Known values: draft, live, paused, archived."},"environmentId":{"type":"string","format":"uuid","nullable":true,"description":"null = the workspace default environment."},"playerKind":{"type":"string","nullable":true},"draft":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"]},"draftRevision":{"type":"integer"},"published":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"],"nullable":true,"description":"The definition last published; null until the first publish."},"publishedRevision":{"type":"integer","nullable":true},"publishedVersion":{"type":"integer"},"publishedAt":{"type":"string","format":"date-time","nullable":true},"publishedBy":{"type":"string","nullable":true},"hasUnpublishedChanges":{"type":"boolean","description":"A draft has been saved since the last publish."},"pausedAt":{"type":"string","format":"date-time","nullable":true},"archivedAt":{"type":"string","format":"date-time","nullable":true},"archivedBy":{"type":"string","nullable":true},"duplicatedFromProgramId":{"type":"string","format":"uuid","nullable":true},"promotedFromProgramId":{"type":"string","format":"uuid","nullable":true},"delivery":{"type":"object","properties":{"widget":{"type":"object","properties":{"enabled":{"type":"boolean"},"show":{"type":"array","items":{"type":"string"},"description":"Known values: progress, leaderboard, recent-awards."}},"required":["enabled","show"]},"look":{"type":"object","additionalProperties":{"type":"string"},"description":"Known keys: theme, corners, font, accent."},"allowedOrigins":{"type":"array","items":{"type":"string"}},"showOtherPlayerNames":{"type":"boolean"},"termsUrl":{"type":"string","nullable":true}},"required":["widget","look","allowedOrigins","showOtherPlayerNames","termsUrl"]},"levelDestinations":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Known values: webhook, connection."},"webhookSubscriptionId":{"type":"string","format":"uuid","description":"webhook: the subscription."},"connectionId":{"type":"string","format":"uuid","description":"connection: the connected system written to."},"entity":{"type":"string","description":"connection: the object (api name) each outcome is written as."},"on":{"type":"array","items":{"type":"string"},"description":"connection: which outcomes it receives. Known values: level-reached, award."},"fields":{"type":"array","items":{"type":"object","properties":{"target":{"type":"string","description":"The field written, dotted for a nested one."},"from":{"type":"string","description":"Known values: player, program, metric, value, level, points, rule, outcome, at."},"value":{"type":"string","description":"A fixed text, sent on every record."},"format":{"type":"string","description":"Known values: unix-seconds (for at)."}},"required":["target"]},"description":"connection: the record's fields, each filled from a value of the outcome or a fixed text."}},"required":["type"]},"description":"Where the program's outcomes go. A webhook receives level-ups; a connection receives the outcomes in `on` as records of one of its objects."},"embed":{"type":"object","properties":{"embedId":{"type":"string","nullable":true,"description":"The program's embed id, which the Play SDK and the paste-in snippet name. There is no hosted widget address: hosted Play is deferred (2026-11-09)."},"snippet":{"type":"string","nullable":true,"description":"A paste-in HTML + script widget for the program, calling the embed route (v1 read) with the player token from window.myobosAccount (playerToken, else token), else the div's data-player-token; on a 401 it asks window.myobosAccount.getToken() once for a fresh token. Null until the program has an embed id."},"secretRotatedAt":{"type":"string","format":"date-time","nullable":true}},"required":["embedId","snippet","secretRotatedAt"],"description":"The secret itself is never returned after the rotation that made it."},"players":{"type":"integer","description":"Distinct players it has scored."},"createdBy":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","key","name","template","stage","status","environmentId","playerKind","draft","draftRevision","published","publishedRevision","publishedVersion","publishedAt","publishedBy","hasUnpublishedChanges","pausedAt","archivedAt","archivedBy","duplicatedFromProgramId","promotedFromProgramId","delivery","levelDestinations","embed","players","createdBy","createdAt","updatedAt"]}},"required":["program"]},"example":{"program":{"id":"00000000-0000-0000-0000-000000000000","key":"string","name":"string","template":"string","stage":"string","status":"string","environmentId":"00000000-0000-0000-0000-000000000000","playerKind":"string","draft":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"draftRevision":0,"published":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"publishedRevision":0,"publishedVersion":0,"publishedAt":"2026-01-01T00:00:00Z","publishedBy":"string","hasUnpublishedChanges":true,"pausedAt":"2026-01-01T00:00:00Z","archivedAt":"2026-01-01T00:00:00Z","archivedBy":"string","duplicatedFromProgramId":"00000000-0000-0000-0000-000000000000","promotedFromProgramId":"00000000-0000-0000-0000-000000000000","delivery":{"widget":{"enabled":true,"show":["string"]},"look":{},"allowedOrigins":["string"],"showOtherPlayerNames":true,"termsUrl":"string"},"levelDestinations":[{"type":"string","webhookSubscriptionId":"00000000-0000-0000-0000-000000000000","connectionId":"00000000-0000-0000-0000-000000000000","entity":"string","on":["string"],"fields":[{"target":"string","from":"string","value":"string","format":"string"}]}],"embed":{"embedId":"string","snippet":"string","secretRotatedAt":"2026-01-01T00:00:00Z"},"players":0,"createdBy":"string","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/programs/{key}/duplicate":{"post":{"operationId":"DuplicateGamificationProgram","tags":["gamification"],"summary":"Duplicate Gamification Program","security":[{"ApiKeyAuth":["gamification:write"]},{"BearerAuth":[]},{"OAuth2":["gamification:write"]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":63}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120,"description":"Absent = \"Copy of <name>\"."},"newKey":{"type":"string","maxLength":63,"description":"The copy's key. Derived from its name when absent."}}},"example":{"name":"string","newKey":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"program":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string"},"name":{"type":"string"},"template":{"type":"string"},"stage":{"type":"string","nullable":true,"description":"The journey stage (open vocabulary). Known values: acquisition, purchase, retention, winback."},"status":{"type":"string","description":"Known values: draft, live, paused, archived."},"environmentId":{"type":"string","format":"uuid","nullable":true,"description":"null = the workspace default environment."},"playerKind":{"type":"string","nullable":true},"draft":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"]},"draftRevision":{"type":"integer"},"published":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"],"nullable":true,"description":"The definition last published; null until the first publish."},"publishedRevision":{"type":"integer","nullable":true},"publishedVersion":{"type":"integer"},"publishedAt":{"type":"string","format":"date-time","nullable":true},"publishedBy":{"type":"string","nullable":true},"hasUnpublishedChanges":{"type":"boolean","description":"A draft has been saved since the last publish."},"pausedAt":{"type":"string","format":"date-time","nullable":true},"archivedAt":{"type":"string","format":"date-time","nullable":true},"archivedBy":{"type":"string","nullable":true},"duplicatedFromProgramId":{"type":"string","format":"uuid","nullable":true},"promotedFromProgramId":{"type":"string","format":"uuid","nullable":true},"delivery":{"type":"object","properties":{"widget":{"type":"object","properties":{"enabled":{"type":"boolean"},"show":{"type":"array","items":{"type":"string"},"description":"Known values: progress, leaderboard, recent-awards."}},"required":["enabled","show"]},"look":{"type":"object","additionalProperties":{"type":"string"},"description":"Known keys: theme, corners, font, accent."},"allowedOrigins":{"type":"array","items":{"type":"string"}},"showOtherPlayerNames":{"type":"boolean"},"termsUrl":{"type":"string","nullable":true}},"required":["widget","look","allowedOrigins","showOtherPlayerNames","termsUrl"]},"levelDestinations":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Known values: webhook, connection."},"webhookSubscriptionId":{"type":"string","format":"uuid","description":"webhook: the subscription."},"connectionId":{"type":"string","format":"uuid","description":"connection: the connected system written to."},"entity":{"type":"string","description":"connection: the object (api name) each outcome is written as."},"on":{"type":"array","items":{"type":"string"},"description":"connection: which outcomes it receives. Known values: level-reached, award."},"fields":{"type":"array","items":{"type":"object","properties":{"target":{"type":"string","description":"The field written, dotted for a nested one."},"from":{"type":"string","description":"Known values: player, program, metric, value, level, points, rule, outcome, at."},"value":{"type":"string","description":"A fixed text, sent on every record."},"format":{"type":"string","description":"Known values: unix-seconds (for at)."}},"required":["target"]},"description":"connection: the record's fields, each filled from a value of the outcome or a fixed text."}},"required":["type"]},"description":"Where the program's outcomes go. A webhook receives level-ups; a connection receives the outcomes in `on` as records of one of its objects."},"embed":{"type":"object","properties":{"embedId":{"type":"string","nullable":true,"description":"The program's embed id, which the Play SDK and the paste-in snippet name. There is no hosted widget address: hosted Play is deferred (2026-11-09)."},"snippet":{"type":"string","nullable":true,"description":"A paste-in HTML + script widget for the program, calling the embed route (v1 read) with the player token from window.myobosAccount (playerToken, else token), else the div's data-player-token; on a 401 it asks window.myobosAccount.getToken() once for a fresh token. Null until the program has an embed id."},"secretRotatedAt":{"type":"string","format":"date-time","nullable":true}},"required":["embedId","snippet","secretRotatedAt"],"description":"The secret itself is never returned after the rotation that made it."},"players":{"type":"integer","description":"Distinct players it has scored."},"createdBy":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","key","name","template","stage","status","environmentId","playerKind","draft","draftRevision","published","publishedRevision","publishedVersion","publishedAt","publishedBy","hasUnpublishedChanges","pausedAt","archivedAt","archivedBy","duplicatedFromProgramId","promotedFromProgramId","delivery","levelDestinations","embed","players","createdBy","createdAt","updatedAt"]}},"required":["program"]},"example":{"program":{"id":"00000000-0000-0000-0000-000000000000","key":"string","name":"string","template":"string","stage":"string","status":"string","environmentId":"00000000-0000-0000-0000-000000000000","playerKind":"string","draft":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"draftRevision":0,"published":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"publishedRevision":0,"publishedVersion":0,"publishedAt":"2026-01-01T00:00:00Z","publishedBy":"string","hasUnpublishedChanges":true,"pausedAt":"2026-01-01T00:00:00Z","archivedAt":"2026-01-01T00:00:00Z","archivedBy":"string","duplicatedFromProgramId":"00000000-0000-0000-0000-000000000000","promotedFromProgramId":"00000000-0000-0000-0000-000000000000","delivery":{"widget":{"enabled":true,"show":["string"]},"look":{},"allowedOrigins":["string"],"showOtherPlayerNames":true,"termsUrl":"string"},"levelDestinations":[{"type":"string","webhookSubscriptionId":"00000000-0000-0000-0000-000000000000","connectionId":"00000000-0000-0000-0000-000000000000","entity":"string","on":["string"],"fields":[{"target":"string","from":"string","value":"string","format":"string"}]}],"embed":{"embedId":"string","snippet":"string","secretRotatedAt":"2026-01-01T00:00:00Z"},"players":0,"createdBy":"string","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/programs/{key}/embed-secret":{"post":{"operationId":"RotateGamificationEmbedSecret","tags":["gamification"],"summary":"Rotate Gamification Embed Secret","security":[{"ApiKeyAuth":["gamification:write"]},{"BearerAuth":[]},{"OAuth2":["gamification:write"]}],"description":"Your server signs a player token with this secret: base64url(JSON {\"p\": <player id>, \"exp\": <unix seconds, at most 7 days ahead>}) + \".\" + base64url(HMAC-SHA256(secret, <first part>)). Send it to the embed API in Authorization: Player <token>, never in a URL. Shown once — store it now; it is never returned again.","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":63}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"embedId":{"type":"string"},"secret":{"type":"string","description":"Shown once."},"secretRotatedAt":{"type":"string","format":"date-time"}},"required":["embedId","secret","secretRotatedAt"]},"example":{"embedId":"string","secret":"string","secretRotatedAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/programs/{key}/install-check":{"post":{"operationId":"CheckGamificationInstall","tags":["gamification"],"summary":"Check Gamification Install","security":[{"ApiKeyAuth":["gamification:write"]},{"BearerAuth":[]},{"OAuth2":["gamification:write"]}],"description":"The page is read over the platform's outbound guard: https only, every resolved address public (no private, loopback, link-local or metadata address, re-checked at connect time and after each redirect), at most 3 redirects, a 10-second deadline and a 2 MB cap. Its text is searched for the program's embed id; nothing on it is run, so a page that builds itself in the browser is reported as such. Refused (400) unless the address is on one of the program's allowed websites; 409 for an archived program; 429 after 6 checks of one program in a minute. A website that cannot be read is a verdict (unreachable), not an error.","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":63}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":2000,"description":"The page the widget should be on, e.g. https://shop.example.com/account."},"platform":{"type":"string","maxLength":40,"nullable":true,"description":"Where the site is built, to word the fixes: html, tag-manager or myobos."},"windowMinutes":{"type":"integer","minimum":5,"maximum":1440,"description":"How far back \"receiving events\" looks. Default 60."}},"required":["url"]},"example":{"url":"string","platform":"string","windowMinutes":0}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"programKey":{"type":"string"},"platform":{"type":"string","nullable":true,"description":"Where the customer said the site is built. Known values: html, tag-manager, myobos."},"url":{"type":"string","description":"The page read, without its query string or fragment."},"origin":{"type":"string","description":"The website, one of the program's allowed websites."},"verdict":{"type":"string","description":"Known values: working (the snippet is on the page or in its tag manager, and the program received events), installed-no-events, receiving-events (events arrive; the page builds itself in the browser, so its widget cannot be seen from outside), not-visible, not-found, wrong-program, not-ready, redirected, unreachable. Open: a client shows the headline for a value it does not know."},"headline":{"type":"string","description":"The verdict in one sentence."},"fixes":{"type":"array","items":{"type":"string"},"description":"What to fix, most important first. Empty when it is working."},"page":{"type":"object","properties":{"reached":{"type":"boolean","description":"The page answered 2xx."},"status":{"type":"integer","nullable":true,"description":"Its HTTP status; null when no answer came."},"finalUrl":{"type":"string","nullable":true,"description":"The address that answered, after redirects."},"error":{"type":"string","nullable":true,"description":"Why it could not be read, in words."},"contentType":{"type":"string","nullable":true},"redirectedElsewhere":{"type":"boolean","description":"It redirected to another website than the one asked about."},"tagFound":{"type":"boolean","description":"This program's snippet (its embed id) is on the page or in a tag manager container it loads."},"foundIn":{"type":"string","nullable":true,"description":"Known values: page, tag-manager."},"tagManagerContainers":{"type":"array","items":{"type":"string"},"description":"Google Tag Manager containers the page loads (GTM-…), each read for the snippet."},"otherEmbedIds":{"type":"array","items":{"type":"string"},"description":"Embed ids of other programs on the page, when this program's is not there."},"rendersInBrowser":{"type":"boolean","description":"The page builds its content in the browser, so a widget it adds cannot be seen from outside."}},"required":["reached","status","finalUrl","error","contentType","redirectedElsewhere","tagFound","foundIn","tagManagerContainers","otherEmbedIds","rendersInBrowser"],"description":"What the page showed. It is read as text and never run."},"program":{"type":"object","properties":{"status":{"type":"string","description":"Known values: draft, live, paused, archived."},"published":{"type":"boolean"},"widgetEnabled":{"type":"boolean"},"secretMade":{"type":"boolean","description":"An embed secret has been made. The secret itself is never returned."},"embedId":{"type":"string","nullable":true},"ready":{"type":"boolean"}},"required":["status","published","widgetEnabled","secretMade","embedId","ready"],"description":"Whether the program can be shown on a website at all."},"events":{"type":"object","properties":{"windowMinutes":{"type":"integer"},"received":{"type":"integer","description":"Awards scored in the last windowMinutes."},"playerEvents":{"type":"integer","description":"Player events accepted in the last windowMinutes, from browsers and servers, scored or not."},"fromThisSite":{"type":"integer","description":"Of those player events, the ones a browser sent from this website."},"lastAt":{"type":"string","format":"date-time","nullable":true,"description":"The newest scored award or accepted player event ever."},"note":{"type":"string"}},"required":["windowMinutes","received","playerEvents","fromThisSite","lastAt","note"],"description":"What reached the program: scored awards (manual adjustments are not counted) and accepted player events."},"checkedAt":{"type":"string","format":"date-time"},"checkedBy":{"type":"string","nullable":true}},"required":["id","programKey","platform","url","origin","verdict","headline","fixes","page","program","events","checkedAt","checkedBy"]},"example":{"id":"00000000-0000-0000-0000-000000000000","programKey":"string","platform":"string","url":"string","origin":"string","verdict":"string","headline":"string","fixes":["string"],"page":{"reached":true,"status":0,"finalUrl":"string","error":"string","contentType":"string","redirectedElsewhere":true,"tagFound":true,"foundIn":"string","tagManagerContainers":["string"],"otherEmbedIds":["string"],"rendersInBrowser":true},"program":{"status":"string","published":true,"widgetEnabled":true,"secretMade":true,"embedId":"string","ready":true},"events":{"windowMinutes":0,"received":0,"playerEvents":0,"fromThisSite":0,"lastAt":"2026-01-01T00:00:00Z","note":"string"},"checkedAt":"2026-01-01T00:00:00Z","checkedBy":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/programs/{key}/install-checks":{"get":{"operationId":"ListGamificationInstallChecks","tags":["gamification"],"summary":"List Gamification Install Checks","security":[{"ApiKeyAuth":["gamification:read"]},{"BearerAuth":[]},{"OAuth2":["gamification:read"]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":63}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"description":"Default 20."},"description":"Default 20."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":100000}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"checks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"programKey":{"type":"string"},"platform":{"type":"string","nullable":true,"description":"Where the customer said the site is built. Known values: html, tag-manager, myobos."},"url":{"type":"string","description":"The page read, without its query string or fragment."},"origin":{"type":"string","description":"The website, one of the program's allowed websites."},"verdict":{"type":"string","description":"Known values: working (the snippet is on the page or in its tag manager, and the program received events), installed-no-events, receiving-events (events arrive; the page builds itself in the browser, so its widget cannot be seen from outside), not-visible, not-found, wrong-program, not-ready, redirected, unreachable. Open: a client shows the headline for a value it does not know."},"headline":{"type":"string","description":"The verdict in one sentence."},"fixes":{"type":"array","items":{"type":"string"},"description":"What to fix, most important first. Empty when it is working."},"page":{"type":"object","properties":{"reached":{"type":"boolean","description":"The page answered 2xx."},"status":{"type":"integer","nullable":true,"description":"Its HTTP status; null when no answer came."},"finalUrl":{"type":"string","nullable":true,"description":"The address that answered, after redirects."},"error":{"type":"string","nullable":true,"description":"Why it could not be read, in words."},"contentType":{"type":"string","nullable":true},"redirectedElsewhere":{"type":"boolean","description":"It redirected to another website than the one asked about."},"tagFound":{"type":"boolean","description":"This program's snippet (its embed id) is on the page or in a tag manager container it loads."},"foundIn":{"type":"string","nullable":true,"description":"Known values: page, tag-manager."},"tagManagerContainers":{"type":"array","items":{"type":"string"},"description":"Google Tag Manager containers the page loads (GTM-…), each read for the snippet."},"otherEmbedIds":{"type":"array","items":{"type":"string"},"description":"Embed ids of other programs on the page, when this program's is not there."},"rendersInBrowser":{"type":"boolean","description":"The page builds its content in the browser, so a widget it adds cannot be seen from outside."}},"required":["reached","status","finalUrl","error","contentType","redirectedElsewhere","tagFound","foundIn","tagManagerContainers","otherEmbedIds","rendersInBrowser"],"description":"What the page showed. It is read as text and never run."},"program":{"type":"object","properties":{"status":{"type":"string","description":"Known values: draft, live, paused, archived."},"published":{"type":"boolean"},"widgetEnabled":{"type":"boolean"},"secretMade":{"type":"boolean","description":"An embed secret has been made. The secret itself is never returned."},"embedId":{"type":"string","nullable":true},"ready":{"type":"boolean"}},"required":["status","published","widgetEnabled","secretMade","embedId","ready"],"description":"Whether the program can be shown on a website at all."},"events":{"type":"object","properties":{"windowMinutes":{"type":"integer"},"received":{"type":"integer","description":"Awards scored in the last windowMinutes."},"playerEvents":{"type":"integer","description":"Player events accepted in the last windowMinutes, from browsers and servers, scored or not."},"fromThisSite":{"type":"integer","description":"Of those player events, the ones a browser sent from this website."},"lastAt":{"type":"string","format":"date-time","nullable":true,"description":"The newest scored award or accepted player event ever."},"note":{"type":"string"}},"required":["windowMinutes","received","playerEvents","fromThisSite","lastAt","note"],"description":"What reached the program: scored awards (manual adjustments are not counted) and accepted player events."},"checkedAt":{"type":"string","format":"date-time"},"checkedBy":{"type":"string","nullable":true}},"required":["id","programKey","platform","url","origin","verdict","headline","fixes","page","program","events","checkedAt","checkedBy"]},"description":"Newest first."},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["checks","total","limit","offset"]},"example":{"checks":[{"id":"00000000-0000-0000-0000-000000000000","programKey":"string","platform":"string","url":"string","origin":"string","verdict":"string","headline":"string","fixes":["string"],"page":{"reached":true,"status":0,"finalUrl":"string","error":"string","contentType":"string","redirectedElsewhere":true,"tagFound":true,"foundIn":"string","tagManagerContainers":["string"],"otherEmbedIds":["string"],"rendersInBrowser":true},"program":{"status":"string","published":true,"widgetEnabled":true,"secretMade":true,"embedId":"string","ready":true},"events":{"windowMinutes":0,"received":0,"playerEvents":0,"fromThisSite":0,"lastAt":"2026-01-01T00:00:00Z","note":"string"},"checkedAt":"2026-01-01T00:00:00Z","checkedBy":"string"}],"total":0,"limit":0,"offset":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/programs/{key}/level-destinations":{"put":{"operationId":"SetGamificationLevelDestinations","tags":["gamification"],"summary":"Set Gamification Level Destinations","security":[{"ApiKeyAuth":["gamification:write"]},{"BearerAuth":[]},{"OAuth2":["gamification:write"]}],"description":"Replaces the list (at most 10). A webhook is { \"type\": \"webhook\", \"webhookSubscriptionId\": <id> } (create one with POST /v1/webhooks/subscriptions). A connected system is { \"type\": \"connection\", \"connectionId\": <id>, \"entity\": <object api name>, \"on\": [\"level-reached\" | \"award\"], \"fields\": [{ \"target\": <field, dotted for nested>, \"from\": <player | program | metric | value | level | points | rule | outcome | at> | \"value\": <fixed text>, \"format\"?: \"unix-seconds\" }] }: one field must take the player id, and the object must be one Inferrex can write (it has a create or update endpoint and needs no record key in its address). Each outcome is written as one record through the same writer as a sync, sharing its rate budget and retry rules; a refused or failed write is reported as a pipeline event on that connection, not retried blindly.","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":63}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"destinations":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["destinations"]},"example":{"destinations":[{}]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"program":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string"},"name":{"type":"string"},"template":{"type":"string"},"stage":{"type":"string","nullable":true,"description":"The journey stage (open vocabulary). Known values: acquisition, purchase, retention, winback."},"status":{"type":"string","description":"Known values: draft, live, paused, archived."},"environmentId":{"type":"string","format":"uuid","nullable":true,"description":"null = the workspace default environment."},"playerKind":{"type":"string","nullable":true},"draft":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"]},"draftRevision":{"type":"integer"},"published":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"],"nullable":true,"description":"The definition last published; null until the first publish."},"publishedRevision":{"type":"integer","nullable":true},"publishedVersion":{"type":"integer"},"publishedAt":{"type":"string","format":"date-time","nullable":true},"publishedBy":{"type":"string","nullable":true},"hasUnpublishedChanges":{"type":"boolean","description":"A draft has been saved since the last publish."},"pausedAt":{"type":"string","format":"date-time","nullable":true},"archivedAt":{"type":"string","format":"date-time","nullable":true},"archivedBy":{"type":"string","nullable":true},"duplicatedFromProgramId":{"type":"string","format":"uuid","nullable":true},"promotedFromProgramId":{"type":"string","format":"uuid","nullable":true},"delivery":{"type":"object","properties":{"widget":{"type":"object","properties":{"enabled":{"type":"boolean"},"show":{"type":"array","items":{"type":"string"},"description":"Known values: progress, leaderboard, recent-awards."}},"required":["enabled","show"]},"look":{"type":"object","additionalProperties":{"type":"string"},"description":"Known keys: theme, corners, font, accent."},"allowedOrigins":{"type":"array","items":{"type":"string"}},"showOtherPlayerNames":{"type":"boolean"},"termsUrl":{"type":"string","nullable":true}},"required":["widget","look","allowedOrigins","showOtherPlayerNames","termsUrl"]},"levelDestinations":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Known values: webhook, connection."},"webhookSubscriptionId":{"type":"string","format":"uuid","description":"webhook: the subscription."},"connectionId":{"type":"string","format":"uuid","description":"connection: the connected system written to."},"entity":{"type":"string","description":"connection: the object (api name) each outcome is written as."},"on":{"type":"array","items":{"type":"string"},"description":"connection: which outcomes it receives. Known values: level-reached, award."},"fields":{"type":"array","items":{"type":"object","properties":{"target":{"type":"string","description":"The field written, dotted for a nested one."},"from":{"type":"string","description":"Known values: player, program, metric, value, level, points, rule, outcome, at."},"value":{"type":"string","description":"A fixed text, sent on every record."},"format":{"type":"string","description":"Known values: unix-seconds (for at)."}},"required":["target"]},"description":"connection: the record's fields, each filled from a value of the outcome or a fixed text."}},"required":["type"]},"description":"Where the program's outcomes go. A webhook receives level-ups; a connection receives the outcomes in `on` as records of one of its objects."},"embed":{"type":"object","properties":{"embedId":{"type":"string","nullable":true,"description":"The program's embed id, which the Play SDK and the paste-in snippet name. There is no hosted widget address: hosted Play is deferred (2026-11-09)."},"snippet":{"type":"string","nullable":true,"description":"A paste-in HTML + script widget for the program, calling the embed route (v1 read) with the player token from window.myobosAccount (playerToken, else token), else the div's data-player-token; on a 401 it asks window.myobosAccount.getToken() once for a fresh token. Null until the program has an embed id."},"secretRotatedAt":{"type":"string","format":"date-time","nullable":true}},"required":["embedId","snippet","secretRotatedAt"],"description":"The secret itself is never returned after the rotation that made it."},"players":{"type":"integer","description":"Distinct players it has scored."},"createdBy":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","key","name","template","stage","status","environmentId","playerKind","draft","draftRevision","published","publishedRevision","publishedVersion","publishedAt","publishedBy","hasUnpublishedChanges","pausedAt","archivedAt","archivedBy","duplicatedFromProgramId","promotedFromProgramId","delivery","levelDestinations","embed","players","createdBy","createdAt","updatedAt"]}},"required":["program"]},"example":{"program":{"id":"00000000-0000-0000-0000-000000000000","key":"string","name":"string","template":"string","stage":"string","status":"string","environmentId":"00000000-0000-0000-0000-000000000000","playerKind":"string","draft":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"draftRevision":0,"published":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"publishedRevision":0,"publishedVersion":0,"publishedAt":"2026-01-01T00:00:00Z","publishedBy":"string","hasUnpublishedChanges":true,"pausedAt":"2026-01-01T00:00:00Z","archivedAt":"2026-01-01T00:00:00Z","archivedBy":"string","duplicatedFromProgramId":"00000000-0000-0000-0000-000000000000","promotedFromProgramId":"00000000-0000-0000-0000-000000000000","delivery":{"widget":{"enabled":true,"show":["string"]},"look":{},"allowedOrigins":["string"],"showOtherPlayerNames":true,"termsUrl":"string"},"levelDestinations":[{"type":"string","webhookSubscriptionId":"00000000-0000-0000-0000-000000000000","connectionId":"00000000-0000-0000-0000-000000000000","entity":"string","on":["string"],"fields":[{"target":"string","from":"string","value":"string","format":"string"}]}],"embed":{"embedId":"string","snippet":"string","secretRotatedAt":"2026-01-01T00:00:00Z"},"players":0,"createdBy":"string","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/programs/{key}/pause":{"post":{"operationId":"PauseGamificationProgram","tags":["gamification"],"summary":"Pause Gamification Program","security":[{"ApiKeyAuth":["gamification:write"]},{"BearerAuth":[]},{"OAuth2":["gamification:write"]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":63}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"paused":{"type":"boolean","description":"true pauses, false resumes."}},"required":["paused"]},"example":{"paused":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"program":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string"},"name":{"type":"string"},"template":{"type":"string"},"stage":{"type":"string","nullable":true,"description":"The journey stage (open vocabulary). Known values: acquisition, purchase, retention, winback."},"status":{"type":"string","description":"Known values: draft, live, paused, archived."},"environmentId":{"type":"string","format":"uuid","nullable":true,"description":"null = the workspace default environment."},"playerKind":{"type":"string","nullable":true},"draft":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"]},"draftRevision":{"type":"integer"},"published":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"],"nullable":true,"description":"The definition last published; null until the first publish."},"publishedRevision":{"type":"integer","nullable":true},"publishedVersion":{"type":"integer"},"publishedAt":{"type":"string","format":"date-time","nullable":true},"publishedBy":{"type":"string","nullable":true},"hasUnpublishedChanges":{"type":"boolean","description":"A draft has been saved since the last publish."},"pausedAt":{"type":"string","format":"date-time","nullable":true},"archivedAt":{"type":"string","format":"date-time","nullable":true},"archivedBy":{"type":"string","nullable":true},"duplicatedFromProgramId":{"type":"string","format":"uuid","nullable":true},"promotedFromProgramId":{"type":"string","format":"uuid","nullable":true},"delivery":{"type":"object","properties":{"widget":{"type":"object","properties":{"enabled":{"type":"boolean"},"show":{"type":"array","items":{"type":"string"},"description":"Known values: progress, leaderboard, recent-awards."}},"required":["enabled","show"]},"look":{"type":"object","additionalProperties":{"type":"string"},"description":"Known keys: theme, corners, font, accent."},"allowedOrigins":{"type":"array","items":{"type":"string"}},"showOtherPlayerNames":{"type":"boolean"},"termsUrl":{"type":"string","nullable":true}},"required":["widget","look","allowedOrigins","showOtherPlayerNames","termsUrl"]},"levelDestinations":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Known values: webhook, connection."},"webhookSubscriptionId":{"type":"string","format":"uuid","description":"webhook: the subscription."},"connectionId":{"type":"string","format":"uuid","description":"connection: the connected system written to."},"entity":{"type":"string","description":"connection: the object (api name) each outcome is written as."},"on":{"type":"array","items":{"type":"string"},"description":"connection: which outcomes it receives. Known values: level-reached, award."},"fields":{"type":"array","items":{"type":"object","properties":{"target":{"type":"string","description":"The field written, dotted for a nested one."},"from":{"type":"string","description":"Known values: player, program, metric, value, level, points, rule, outcome, at."},"value":{"type":"string","description":"A fixed text, sent on every record."},"format":{"type":"string","description":"Known values: unix-seconds (for at)."}},"required":["target"]},"description":"connection: the record's fields, each filled from a value of the outcome or a fixed text."}},"required":["type"]},"description":"Where the program's outcomes go. A webhook receives level-ups; a connection receives the outcomes in `on` as records of one of its objects."},"embed":{"type":"object","properties":{"embedId":{"type":"string","nullable":true,"description":"The program's embed id, which the Play SDK and the paste-in snippet name. There is no hosted widget address: hosted Play is deferred (2026-11-09)."},"snippet":{"type":"string","nullable":true,"description":"A paste-in HTML + script widget for the program, calling the embed route (v1 read) with the player token from window.myobosAccount (playerToken, else token), else the div's data-player-token; on a 401 it asks window.myobosAccount.getToken() once for a fresh token. Null until the program has an embed id."},"secretRotatedAt":{"type":"string","format":"date-time","nullable":true}},"required":["embedId","snippet","secretRotatedAt"],"description":"The secret itself is never returned after the rotation that made it."},"players":{"type":"integer","description":"Distinct players it has scored."},"createdBy":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","key","name","template","stage","status","environmentId","playerKind","draft","draftRevision","published","publishedRevision","publishedVersion","publishedAt","publishedBy","hasUnpublishedChanges","pausedAt","archivedAt","archivedBy","duplicatedFromProgramId","promotedFromProgramId","delivery","levelDestinations","embed","players","createdBy","createdAt","updatedAt"]}},"required":["program"]},"example":{"program":{"id":"00000000-0000-0000-0000-000000000000","key":"string","name":"string","template":"string","stage":"string","status":"string","environmentId":"00000000-0000-0000-0000-000000000000","playerKind":"string","draft":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"draftRevision":0,"published":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"publishedRevision":0,"publishedVersion":0,"publishedAt":"2026-01-01T00:00:00Z","publishedBy":"string","hasUnpublishedChanges":true,"pausedAt":"2026-01-01T00:00:00Z","archivedAt":"2026-01-01T00:00:00Z","archivedBy":"string","duplicatedFromProgramId":"00000000-0000-0000-0000-000000000000","promotedFromProgramId":"00000000-0000-0000-0000-000000000000","delivery":{"widget":{"enabled":true,"show":["string"]},"look":{},"allowedOrigins":["string"],"showOtherPlayerNames":true,"termsUrl":"string"},"levelDestinations":[{"type":"string","webhookSubscriptionId":"00000000-0000-0000-0000-000000000000","connectionId":"00000000-0000-0000-0000-000000000000","entity":"string","on":["string"],"fields":[{"target":"string","from":"string","value":"string","format":"string"}]}],"embed":{"embedId":"string","snippet":"string","secretRotatedAt":"2026-01-01T00:00:00Z"},"players":0,"createdBy":"string","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/programs/{key}/player-events":{"get":{"operationId":"ListGamificationPlayerEvents","tags":["gamification"],"summary":"List Gamification Player Events","security":[{"ApiKeyAuth":["gamification:read"]},{"BearerAuth":[]},{"OAuth2":["gamification:read"]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":63}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"Events per page. Default 50."},"description":"Events per page. Default 50."},{"name":"before","in":"query","required":false,"schema":{"type":"string","maxLength":100,"description":"The previous page's nextBefore."},"description":"The previous page's nextBefore."},{"name":"name","in":"query","required":false,"schema":{"type":"string","maxLength":63,"description":"Only events with this name."},"description":"Only events with this name."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"eventId":{"type":"string","format":"uuid"},"name":{"type":"string"},"playerId":{"type":"string"},"trust":{"type":"string","description":"Known values: client (the player's browser), server (your server)."},"properties":{"type":"object","additionalProperties":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}},"pagePath":{"type":"string","nullable":true},"clientAt":{"type":"string","format":"date-time","nullable":true},"receivedAt":{"type":"string","format":"date-time"},"awards":{"type":"integer","description":"How many of the program's rules newly awarded on it."}},"required":["id","eventId","name","playerId","trust","properties","pagePath","clientAt","receivedAt","awards"]},"description":"Newest first. Kept for retention.gamificationPlayerEventsDays (90 days by default)."},"nextBefore":{"type":"string","nullable":true,"description":"Pass as before for the next page; null on the last."}},"required":["events","nextBefore"]},"example":{"events":[{"id":"00000000-0000-0000-0000-000000000000","eventId":"00000000-0000-0000-0000-000000000000","name":"string","playerId":"string","trust":"string","properties":{},"pagePath":"string","clientAt":"2026-01-01T00:00:00Z","receivedAt":"2026-01-01T00:00:00Z","awards":0}],"nextBefore":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/programs/{key}/promote":{"post":{"operationId":"PromoteGamificationProgram","tags":["gamification"],"summary":"Promote Gamification Program","security":[{"ApiKeyAuth":["gamification:write"]},{"BearerAuth":[]},{"OAuth2":["gamification:write"]}],"description":"Uses the environment and promotion model pipelines use: the target must belong to this workspace, its class must be within the plan (task 74), and the step must be in the workspace's promotion path (task 75). Nothing goes live in the target until someone publishes the counterpart there. A step with an approval policy is refused: program promotions cannot be held for approval yet.","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":63}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"toEnvironmentId":{"type":"string","format":"uuid"},"newKey":{"type":"string","maxLength":63,"description":"The counterpart's key on a first promotion. Derived from the program key and the environment name when absent."}},"required":["toEnvironmentId"]},"example":{"toEnvironmentId":"00000000-0000-0000-0000-000000000000","newKey":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"program":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string"},"name":{"type":"string"},"template":{"type":"string"},"stage":{"type":"string","nullable":true,"description":"The journey stage (open vocabulary). Known values: acquisition, purchase, retention, winback."},"status":{"type":"string","description":"Known values: draft, live, paused, archived."},"environmentId":{"type":"string","format":"uuid","nullable":true,"description":"null = the workspace default environment."},"playerKind":{"type":"string","nullable":true},"draft":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"]},"draftRevision":{"type":"integer"},"published":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"],"nullable":true,"description":"The definition last published; null until the first publish."},"publishedRevision":{"type":"integer","nullable":true},"publishedVersion":{"type":"integer"},"publishedAt":{"type":"string","format":"date-time","nullable":true},"publishedBy":{"type":"string","nullable":true},"hasUnpublishedChanges":{"type":"boolean","description":"A draft has been saved since the last publish."},"pausedAt":{"type":"string","format":"date-time","nullable":true},"archivedAt":{"type":"string","format":"date-time","nullable":true},"archivedBy":{"type":"string","nullable":true},"duplicatedFromProgramId":{"type":"string","format":"uuid","nullable":true},"promotedFromProgramId":{"type":"string","format":"uuid","nullable":true},"delivery":{"type":"object","properties":{"widget":{"type":"object","properties":{"enabled":{"type":"boolean"},"show":{"type":"array","items":{"type":"string"},"description":"Known values: progress, leaderboard, recent-awards."}},"required":["enabled","show"]},"look":{"type":"object","additionalProperties":{"type":"string"},"description":"Known keys: theme, corners, font, accent."},"allowedOrigins":{"type":"array","items":{"type":"string"}},"showOtherPlayerNames":{"type":"boolean"},"termsUrl":{"type":"string","nullable":true}},"required":["widget","look","allowedOrigins","showOtherPlayerNames","termsUrl"]},"levelDestinations":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Known values: webhook, connection."},"webhookSubscriptionId":{"type":"string","format":"uuid","description":"webhook: the subscription."},"connectionId":{"type":"string","format":"uuid","description":"connection: the connected system written to."},"entity":{"type":"string","description":"connection: the object (api name) each outcome is written as."},"on":{"type":"array","items":{"type":"string"},"description":"connection: which outcomes it receives. Known values: level-reached, award."},"fields":{"type":"array","items":{"type":"object","properties":{"target":{"type":"string","description":"The field written, dotted for a nested one."},"from":{"type":"string","description":"Known values: player, program, metric, value, level, points, rule, outcome, at."},"value":{"type":"string","description":"A fixed text, sent on every record."},"format":{"type":"string","description":"Known values: unix-seconds (for at)."}},"required":["target"]},"description":"connection: the record's fields, each filled from a value of the outcome or a fixed text."}},"required":["type"]},"description":"Where the program's outcomes go. A webhook receives level-ups; a connection receives the outcomes in `on` as records of one of its objects."},"embed":{"type":"object","properties":{"embedId":{"type":"string","nullable":true,"description":"The program's embed id, which the Play SDK and the paste-in snippet name. There is no hosted widget address: hosted Play is deferred (2026-11-09)."},"snippet":{"type":"string","nullable":true,"description":"A paste-in HTML + script widget for the program, calling the embed route (v1 read) with the player token from window.myobosAccount (playerToken, else token), else the div's data-player-token; on a 401 it asks window.myobosAccount.getToken() once for a fresh token. Null until the program has an embed id."},"secretRotatedAt":{"type":"string","format":"date-time","nullable":true}},"required":["embedId","snippet","secretRotatedAt"],"description":"The secret itself is never returned after the rotation that made it."},"players":{"type":"integer","description":"Distinct players it has scored."},"createdBy":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","key","name","template","stage","status","environmentId","playerKind","draft","draftRevision","published","publishedRevision","publishedVersion","publishedAt","publishedBy","hasUnpublishedChanges","pausedAt","archivedAt","archivedBy","duplicatedFromProgramId","promotedFromProgramId","delivery","levelDestinations","embed","players","createdBy","createdAt","updatedAt"],"description":"The counterpart program in the target environment."},"created":{"type":"boolean"},"fromEnvironmentId":{"type":"string","format":"uuid","nullable":true},"toEnvironmentId":{"type":"string","format":"uuid"}},"required":["program","created","toEnvironmentId"]},"example":{"program":{"id":"00000000-0000-0000-0000-000000000000","key":"string","name":"string","template":"string","stage":"string","status":"string","environmentId":"00000000-0000-0000-0000-000000000000","playerKind":"string","draft":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"draftRevision":0,"published":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"publishedRevision":0,"publishedVersion":0,"publishedAt":"2026-01-01T00:00:00Z","publishedBy":"string","hasUnpublishedChanges":true,"pausedAt":"2026-01-01T00:00:00Z","archivedAt":"2026-01-01T00:00:00Z","archivedBy":"string","duplicatedFromProgramId":"00000000-0000-0000-0000-000000000000","promotedFromProgramId":"00000000-0000-0000-0000-000000000000","delivery":{"widget":{"enabled":true,"show":["string"]},"look":{},"allowedOrigins":["string"],"showOtherPlayerNames":true,"termsUrl":"string"},"levelDestinations":[{"type":"string","webhookSubscriptionId":"00000000-0000-0000-0000-000000000000","connectionId":"00000000-0000-0000-0000-000000000000","entity":"string","on":["string"],"fields":[{"target":"string","from":"string","value":"string","format":"string"}]}],"embed":{"embedId":"string","snippet":"string","secretRotatedAt":"2026-01-01T00:00:00Z"},"players":0,"createdBy":"string","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z"},"created":true,"fromEnvironmentId":"00000000-0000-0000-0000-000000000000","toEnvironmentId":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/programs/{key}/publish":{"post":{"operationId":"PublishGamificationProgram","tags":["gamification"],"summary":"Publish Gamification Program","security":[{"ApiKeyAuth":["gamification:write"]},{"BearerAuth":[]},{"OAuth2":["gamification:write"]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":63}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"baseRevision":{"type":"integer","minimum":1,"description":"The draft revision being published. Refused if the draft has changed since, so what goes live is what was reviewed."}}},"example":{"baseRevision":0}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"program":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string"},"name":{"type":"string"},"template":{"type":"string"},"stage":{"type":"string","nullable":true,"description":"The journey stage (open vocabulary). Known values: acquisition, purchase, retention, winback."},"status":{"type":"string","description":"Known values: draft, live, paused, archived."},"environmentId":{"type":"string","format":"uuid","nullable":true,"description":"null = the workspace default environment."},"playerKind":{"type":"string","nullable":true},"draft":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"]},"draftRevision":{"type":"integer"},"published":{"type":"object","properties":{"players":{"type":"object","properties":{"kind":{"type":"string","description":"Any kind of golden record (account, person, driver, device). Open vocabulary."},"description":{"type":"string"},"followGoldenRecords":{"type":"boolean","description":"Off unless set. When on, and a person merges or splits golden records of `kind`, the players those records are become one player or two again, and their points move with them. Needs `kind`."}},"description":"What a player is."},"rules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","description":"Known values: points (scored); instant-win, prize-draw, collect-set (stored and checked, not drawn yet)."},"enabled":{"type":"boolean"},"metric":{"type":"string","description":"Points rules: the metric it accrues to, e.g. points."},"trigger":{"type":"object","properties":{"canonicalRole":{"type":"string","description":"The classification of the field whose value earns the award, e.g. monetary-amount. Absent only on a connection trigger, where each record counts once."},"canonicalFacet":{"type":"string","description":"Which part of it, e.g. total. Absent = any."},"eventType":{"type":"string","description":"What fires it. Known values: sync.completed (a synced record), player.event (a named event from the player's browser or the tenant's server, B4a)."},"source":{"type":"string","description":"player-event on a trigger fired by a named player event (eventType player.event). Absent on a synced-record trigger."},"name":{"type":"string","description":"A player-event trigger: the event name that fires it, e.g. deposit (`^[a-z][a-z0-9_.-]{0,62}$`)."},"trust":{"type":"string","description":"A player-event trigger: who must have reported the event. Known values: server (only the tenant's own server, POST /v1/gamification/player-events), client (the player's browser or the server; a player can forge a browser event)."},"amountFrom":{"type":"string","description":"A player-event trigger: the event property whose number the award tiers step on, e.g. amount. Absent = each event counts once (amount 1); an event without a finite number there earns nothing from this rule."},"connectionId":{"type":"string","format":"uuid","description":"A connection trigger: only records synced FROM this connected system (as its source), with entityType."},"entityType":{"type":"string","description":"A connection trigger: the object of that system whose records score (its api name)."},"playerField":{"type":"string","description":"The record field (dotted for a nested one) that names the player. Absent = the record's own id."}}},"award":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"minAmount":{"type":"number"},"points":{"type":"integer"}},"required":["points"]},"description":"Highest minimum first; exactly one tier has no minAmount — what every other matching record earns."}},"required":["tiers"],"description":"Points rules."},"chance":{"type":"object","properties":{"odds":{"type":"object","properties":{"chances":{"type":"integer"},"outOf":{"type":"integer"}},"required":["chances","outOf"],"description":"Instant win: chances in outOf per qualifying record."},"prizes":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"integer"}},"required":["name","quantity"]}},"limits":{"type":"object","properties":{"perPlayer":{"type":"object","properties":{"count":{"type":"integer"},"period":{"type":"string","description":"Known values: day, week, month, program."}},"required":["count","period"],"nullable":true,"description":"null = no limit, chosen explicitly."},"total":{"type":"integer","nullable":true}},"required":["perPlayer","total"]},"eligibleRegions":{"type":"array","items":{"type":"string"}},"termsUrl":{"type":"string"},"drawAt":{"type":"string"},"entriesPerAward":{"type":"integer"},"items":{"type":"array","items":{"type":"string"}}},"required":["prizes","limits","eligibleRegions","termsUrl"],"description":"Chance rules: every term is the tenant's own."}},"required":["key","name","kind","enabled","trigger"]},"description":"In the order they are checked. A points rule has `metric` and `award`; a chance rule has `chance`."},"levels":{"type":"object","properties":{"metric":{"type":"string"},"tiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"threshold":{"type":"integer"}},"required":["name","threshold"]}}},"required":["metric","tiers"],"description":"Levels reached on one metric as it accrues, lowest threshold first."}},"required":["rules"],"nullable":true,"description":"The definition last published; null until the first publish."},"publishedRevision":{"type":"integer","nullable":true},"publishedVersion":{"type":"integer"},"publishedAt":{"type":"string","format":"date-time","nullable":true},"publishedBy":{"type":"string","nullable":true},"hasUnpublishedChanges":{"type":"boolean","description":"A draft has been saved since the last publish."},"pausedAt":{"type":"string","format":"date-time","nullable":true},"archivedAt":{"type":"string","format":"date-time","nullable":true},"archivedBy":{"type":"string","nullable":true},"duplicatedFromProgramId":{"type":"string","format":"uuid","nullable":true},"promotedFromProgramId":{"type":"string","format":"uuid","nullable":true},"delivery":{"type":"object","properties":{"widget":{"type":"object","properties":{"enabled":{"type":"boolean"},"show":{"type":"array","items":{"type":"string"},"description":"Known values: progress, leaderboard, recent-awards."}},"required":["enabled","show"]},"look":{"type":"object","additionalProperties":{"type":"string"},"description":"Known keys: theme, corners, font, accent."},"allowedOrigins":{"type":"array","items":{"type":"string"}},"showOtherPlayerNames":{"type":"boolean"},"termsUrl":{"type":"string","nullable":true}},"required":["widget","look","allowedOrigins","showOtherPlayerNames","termsUrl"]},"levelDestinations":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Known values: webhook, connection."},"webhookSubscriptionId":{"type":"string","format":"uuid","description":"webhook: the subscription."},"connectionId":{"type":"string","format":"uuid","description":"connection: the connected system written to."},"entity":{"type":"string","description":"connection: the object (api name) each outcome is written as."},"on":{"type":"array","items":{"type":"string"},"description":"connection: which outcomes it receives. Known values: level-reached, award."},"fields":{"type":"array","items":{"type":"object","properties":{"target":{"type":"string","description":"The field written, dotted for a nested one."},"from":{"type":"string","description":"Known values: player, program, metric, value, level, points, rule, outcome, at."},"value":{"type":"string","description":"A fixed text, sent on every record."},"format":{"type":"string","description":"Known values: unix-seconds (for at)."}},"required":["target"]},"description":"connection: the record's fields, each filled from a value of the outcome or a fixed text."}},"required":["type"]},"description":"Where the program's outcomes go. A webhook receives level-ups; a connection receives the outcomes in `on` as records of one of its objects."},"embed":{"type":"object","properties":{"embedId":{"type":"string","nullable":true,"description":"The program's embed id, which the Play SDK and the paste-in snippet name. There is no hosted widget address: hosted Play is deferred (2026-11-09)."},"snippet":{"type":"string","nullable":true,"description":"A paste-in HTML + script widget for the program, calling the embed route (v1 read) with the player token from window.myobosAccount (playerToken, else token), else the div's data-player-token; on a 401 it asks window.myobosAccount.getToken() once for a fresh token. Null until the program has an embed id."},"secretRotatedAt":{"type":"string","format":"date-time","nullable":true}},"required":["embedId","snippet","secretRotatedAt"],"description":"The secret itself is never returned after the rotation that made it."},"players":{"type":"integer","description":"Distinct players it has scored."},"createdBy":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","key","name","template","stage","status","environmentId","playerKind","draft","draftRevision","published","publishedRevision","publishedVersion","publishedAt","publishedBy","hasUnpublishedChanges","pausedAt","archivedAt","archivedBy","duplicatedFromProgramId","promotedFromProgramId","delivery","levelDestinations","embed","players","createdBy","createdAt","updatedAt"]}},"required":["program"]},"example":{"program":{"id":"00000000-0000-0000-0000-000000000000","key":"string","name":"string","template":"string","stage":"string","status":"string","environmentId":"00000000-0000-0000-0000-000000000000","playerKind":"string","draft":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"draftRevision":0,"published":{"players":{"kind":"string","description":"string","followGoldenRecords":true},"rules":[{"key":"string","name":"string","kind":"string","enabled":true,"metric":"string","trigger":{"canonicalRole":"string","canonicalFacet":"string","eventType":"string","source":"string","name":"string","trust":"string","amountFrom":"string","connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","playerField":"string"},"award":{"tiers":[{"minAmount":0,"points":0}]},"chance":{"odds":{"chances":0,"outOf":0},"prizes":[{"name":"string","quantity":0}],"limits":{"perPlayer":{"count":0,"period":"string"},"total":0},"eligibleRegions":["string"],"termsUrl":"string","drawAt":"string","entriesPerAward":0,"items":["string"]}}],"levels":{"metric":"string","tiers":[{"name":"string","threshold":0}]}},"publishedRevision":0,"publishedVersion":0,"publishedAt":"2026-01-01T00:00:00Z","publishedBy":"string","hasUnpublishedChanges":true,"pausedAt":"2026-01-01T00:00:00Z","archivedAt":"2026-01-01T00:00:00Z","archivedBy":"string","duplicatedFromProgramId":"00000000-0000-0000-0000-000000000000","promotedFromProgramId":"00000000-0000-0000-0000-000000000000","delivery":{"widget":{"enabled":true,"show":["string"]},"look":{},"allowedOrigins":["string"],"showOtherPlayerNames":true,"termsUrl":"string"},"levelDestinations":[{"type":"string","webhookSubscriptionId":"00000000-0000-0000-0000-000000000000","connectionId":"00000000-0000-0000-0000-000000000000","entity":"string","on":["string"],"fields":[{"target":"string","from":"string","value":"string","format":"string"}]}],"embed":{"embedId":"string","snippet":"string","secretRotatedAt":"2026-01-01T00:00:00Z"},"players":0,"createdBy":"string","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/gamification/state":{"get":{"operationId":"ListGamificationState","tags":["gamification"],"summary":"List Gamification State","security":[{"ApiKeyAuth":["gamification:read"]},{"BearerAuth":[]},{"OAuth2":["gamification:read"]}],"description":"Scores and levels for your workspace’s players, highest first: use it for a leaderboard, or narrow it to one program with program, or to one player with player, to see their progress. A program’s entries carry its key in program_key, and their metric is named <program key>.<metric> (for example clinic-rewards.points), so two programs counting points for the same player never share an entry. Entries from Inferrex’s own schemes have no program key.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":1000,"description":"How many entries to return: 1 to 1,000, 100 if you leave it out.","default":100},"description":"How many entries to return: 1 to 1,000, 100 if you leave it out."},{"name":"program","in":"query","required":false,"schema":{"type":"string","maxLength":63,"description":"Only this program's players (its key)."},"description":"Only this program's players (its key)."},{"name":"player","in":"query","required":false,"schema":{"type":"string","maxLength":500,"description":"Only this player (the id they have in your systems)."},"description":"Only this player (the id they have in your systems)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"object","additionalProperties":true}},"required":["state"]},"example":{"state":{}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/golden-records/{entityClusterId}/edit-preview":{"post":{"operationId":"PreviewGoldenEdit","tags":["golden_record"],"summary":"Preview Golden Edit","security":[{"ApiKeyAuth":["golden-records:write"]},{"BearerAuth":[]},{"OAuth2":["golden-records:write"]}],"description":"Preview an edit of this golden record. `merge` joins `otherId` (a golden record of the same kind) into this one: this one keeps its id, the other is archived. `split` moves the `move` source records out into a golden record of their own. `restore` brings back this archived record. `archive` archives this record, only when none of its source records still exists. The answer is what the golden build would make with the edit in place, under your current source rules. When the edit cannot be done, `allowed` is false and `refusal.message` says why in words (for example, two records of one system with different ids can never share a golden record).","parameters":[{"name":"entityClusterId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["merge","split","restore","archive"]},"otherId":{"type":"string","format":"uuid","description":"merge: the golden record to merge into this one."},"move":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"sourceType":{"type":"string"},"externalId":{"type":"string"}},"required":["connectionId","sourceType","externalId"]},"description":"split: the source records to move out, as `sources` lists them."}},"required":["kind"]},"example":{"kind":"merge","otherId":"00000000-0000-0000-0000-000000000000","move":[{"connectionId":"00000000-0000-0000-0000-000000000000","sourceType":"string","externalId":"string"}]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string"},"entityType":{"type":"string"},"allowed":{"type":"boolean"},"refusal":{"type":"object","properties":{"code":{"type":"string","description":"same_connection, same_record, not_current, not_archived, split_choice, not_a_member, still_built, edit_pending, not_honoured. Open."},"message":{"type":"string","description":"Why, in words."},"pendingProposalId":{"type":"string","format":"uuid","nullable":true,"description":"edit_pending: the edit already waiting."}},"required":["code","message"],"nullable":true},"summary":{"type":"string","description":"What approving would do, in one or two sentences."},"riskLevel":{"type":"string"},"riskReasons":{"type":"array","items":{"type":"string"}},"records":{"type":"array","items":{"type":"object","properties":{"entityClusterId":{"type":"string","format":"uuid"},"role":{"type":"string"},"isNew":{"type":"boolean"},"members":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"provider":{"type":"string"},"sourceType":{"type":"string","nullable":true},"externalId":{"type":"string"}},"required":["connectionId","provider","sourceType","externalId"]}},"fields":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"value":{"description":"After the edit; null when hidden from your role (`redacted`)."},"oldValue":{"description":"Its value now, when it changes."},"change":{"type":"string","description":"same, added, changed or removed."},"redacted":{"type":"boolean"},"connectionId":{"type":"string","format":"uuid","nullable":true,"description":"The system whose value wins."},"provider":{"type":"string","nullable":true},"externalId":{"type":"string","nullable":true},"strategy":{"type":"string","nullable":true,"description":"The rule that picked it."},"ruleApplied":{"type":"boolean"},"contested":{"type":"boolean"}},"required":["field","change","redacted","connectionId","provider","externalId","strategy","ruleApplied","contested"]},"description":"Every field after the edit, and fields it loses."},"qualityScore":{"type":"number"},"fieldCount":{"type":"integer"},"sourceCount":{"type":"integer"}},"required":["entityClusterId","role","isNew","members","fields","qualityScore","fieldCount","sourceCount"]},"description":"Each golden record the edit writes, target first."},"retires":{"type":"array","items":{"type":"object","properties":{"entityClusterId":{"type":"string","format":"uuid"},"reason":{"type":"string"},"reasonText":{"type":"string"},"rebuiltAs":{"type":"array","items":{"type":"string","format":"uuid"}}},"required":["entityClusterId","reason","reasonText","rebuiltAs"]},"description":"Golden records it archives."},"restores":{"type":"array","items":{"type":"string","format":"uuid"}},"links":{"type":"object","properties":{"together":{"type":"integer"},"apart":{"type":"integer"},"revoked":{"type":"integer"}},"required":["together","apart","revoked"]}},"required":["kind","entityType","allowed","refusal","summary","riskLevel","riskReasons","records","retires","restores","links"]},"example":{"kind":"string","entityType":"string","allowed":true,"refusal":{"code":"string","message":"string","pendingProposalId":"00000000-0000-0000-0000-000000000000"},"summary":"string","riskLevel":"string","riskReasons":["string"],"records":[{"entityClusterId":"00000000-0000-0000-0000-000000000000","role":"string","isNew":true,"members":[{"connectionId":"00000000-0000-0000-0000-000000000000","provider":"string","sourceType":"string","externalId":"string"}],"fields":[{"field":"string","value":null,"oldValue":null,"change":"string","redacted":true,"connectionId":"00000000-0000-0000-0000-000000000000","provider":"string","externalId":"string","strategy":"string","ruleApplied":true,"contested":true}],"qualityScore":0,"fieldCount":0,"sourceCount":0}],"retires":[{"entityClusterId":"00000000-0000-0000-0000-000000000000","reason":"string","reasonText":"string","rebuiltAs":["00000000-0000-0000-0000-000000000000"]}],"restores":["00000000-0000-0000-0000-000000000000"],"links":{"together":0,"apart":0,"revoked":0}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/golden-records/{entityClusterId}/edits":{"post":{"operationId":"ProposeGoldenEdit","tags":["golden_record"],"summary":"Propose Golden Edit","security":[{"ApiKeyAuth":["golden-records:write"]},{"BearerAuth":[]},{"OAuth2":["golden-records:write"]}],"description":"Propose an edit of this golden record. Same body as the preview, plus an optional `note` kept with the proposal. Returns the proposal's id and status (`pending`, or `approved` when a policy approved it at once). Approve or reject it with POST /v1/canonical-proposals/:id/approve or /reject; a merge can be split back, a split merged back, and a restore archived again, each by another edit. 409 when the edit cannot be done (the message says why) or another edit of one of these golden records is already waiting.","parameters":[{"name":"entityClusterId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["merge","split","restore","archive"]},"otherId":{"type":"string","format":"uuid"},"move":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"sourceType":{"type":"string"},"externalId":{"type":"string"}},"required":["connectionId","sourceType","externalId"]}},"note":{"type":"string","maxLength":2000,"description":"Why, for whoever approves it."}},"required":["kind"]},"example":{"kind":"merge","otherId":"00000000-0000-0000-0000-000000000000","move":[{"connectionId":"00000000-0000-0000-0000-000000000000","sourceType":"string","externalId":"string"}],"note":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"proposalId":{"type":"string","format":"uuid"},"status":{"type":"string","description":"pending, or approved when an approval policy approved it at once."},"riskLevel":{"type":"string"},"riskReasons":{"type":"array","items":{"type":"string"}}},"required":["proposalId","status","riskLevel","riskReasons"]},"example":{"proposalId":"00000000-0000-0000-0000-000000000000","status":"string","riskLevel":"string","riskReasons":["string"]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/golden-records/{entityClusterId}/fields":{"get":{"operationId":"GetGoldenRecordFields","tags":["unified_api"],"summary":"Get Golden Record Fields","security":[{"ApiKeyAuth":["golden-records:read"]},{"BearerAuth":[]},{"OAuth2":["golden-records:read"]}],"description":"Every field of one golden record, one row per field: its value, which system it came from, why that value was chosen and how confident Inferrex is, whether your systems disagree about it, and what kind of data it is (including how sensitive). Values you are not allowed to see because of their sensitivity are hidden and marked as redacted.","parameters":[{"name":"entityClusterId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the golden record."},"description":"The id of the golden record."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"fields":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"value":{"description":"The field's value as the winning system holds it: any JSON value. Null when redacted."},"provider":{"type":"string"},"connectionId":{"type":"string"},"externalId":{"type":"string"},"sourceEntity":{"type":"string","description":"The object (entity) in the source system the value was read from — its API name there, e.g. `invoice`, `Contact`. A golden record is built from source records of one object, so this is the record's entity_type; absent when no system supplied the field."},"recordVersion":{"type":"number"},"observedAt":{"type":"string"},"strategy":{"type":"string"},"ruleApplied":{"type":"boolean"},"confidence":{"type":"number"},"contested":{"type":"boolean"},"l2Type":{"type":"string"},"role":{"type":"string"},"facet":{"type":"string"},"sensitivity":{"type":"string"},"category":{"type":"string"},"redacted":{"type":"boolean"}},"required":["field","value","l2Type","category"]}}},"required":["fields"]},"example":{"fields":[{"field":"string","value":null,"provider":"string","connectionId":"string","externalId":"string","sourceEntity":"string","recordVersion":0,"observedAt":"string","strategy":"string","ruleApplied":true,"confidence":0,"contested":true,"l2Type":"string","role":"string","facet":"string","sensitivity":"string","category":"string","redacted":true}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/golden-records/{entityClusterId}/lineage":{"get":{"operationId":"GetGoldenFieldLineage","tags":["golden_record"],"summary":"Get Golden Field Lineage","security":[{"ApiKeyAuth":["golden-records:read"]},{"BearerAuth":[]},{"OAuth2":["golden-records:read"]}],"description":"Where one value of a golden record came from and where it goes. `source` is the record it was read from and the value there; `decided` is the rule that chose it; `candidates` are the values every source record holds for it, the winner marked; `flows` are the flows reading that system that carry the field, each with the field it writes, its conversion, the value it writes, and this record's id in the destination when it has been written; `goldenDestinations` receive golden records with this field. A value your role may not see is empty and `redacted` everywhere.","parameters":[{"name":"entityClusterId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The golden record."},"description":"The golden record."},{"name":"field","in":"query","required":true,"schema":{"type":"string","description":"The golden field, by its name on the golden record (a part of an object as path.to.part)."},"description":"The golden field, by its name on the golden record (a part of an object as path.to.part)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"field":{"type":"string"},"value":{"description":"The golden value; null when redacted."},"redacted":{"type":"boolean"},"source":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"system":{"type":"string","nullable":true},"sourceEntity":{"type":"string","nullable":true},"externalId":{"type":"string","nullable":true},"field":{"type":"string","description":"The field's own name in that system."},"valueAsRead":{"description":"The value as that record holds it now; null when redacted or no longer held."},"recordVersion":{"type":"number","nullable":true}},"required":["connectionId","system","sourceEntity","externalId","field","valueAsRead","recordVersion"],"nullable":true,"description":"The record the value was read from; null when no system supplied it."},"decided":{"type":"object","properties":{"rule":{"type":"string","description":"The rule that chose the value, in words."},"strategy":{"type":"string","nullable":true},"ruleApplied":{"type":"boolean","description":"A rule set for this field chose it, not the default."},"confidence":{"type":"number","nullable":true},"contested":{"type":"boolean"},"observedAt":{"type":"string","nullable":true}},"required":["rule","strategy","ruleApplied","confidence","contested","observedAt"]},"candidates":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"system":{"type":"string","nullable":true},"sourceEntity":{"type":"string","nullable":true},"externalId":{"type":"string"},"value":{"description":"Null when redacted, missing, or the record is no longer held."},"held":{"type":"boolean","description":"Its system still holds the record."},"won":{"type":"boolean"}},"required":["connectionId","system","sourceEntity","externalId","value","held","won"]}},"flows":{"type":"array","items":{"type":"object","properties":{"flowId":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"destinationConnectionId":{"type":"string","format":"uuid","nullable":true},"destination":{"type":"string","nullable":true},"targetEntity":{"type":"string"},"targetField":{"type":"string"},"transform":{"type":"string"},"writes":{"description":"What the flow writes for this value, converted; null when redacted."},"written":{"type":"object","properties":{"targetExternalId":{"type":"string"},"at":{"type":"string","format":"date-time"}},"required":["targetExternalId","at"],"nullable":true,"description":"This record's id in the destination and when its link was last written; null when not yet written there."}},"required":["flowId","name","status","destinationConnectionId","destination","targetEntity","targetField","transform","writes","written"]}},"goldenDestinations":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"system":{"type":"string","nullable":true}},"required":["connectionId","system"]}}},"required":["field","value","redacted","source","decided","candidates","flows","goldenDestinations"]},"example":{"field":"string","value":null,"redacted":true,"source":{"connectionId":"00000000-0000-0000-0000-000000000000","system":"string","sourceEntity":"string","externalId":"string","field":"string","valueAsRead":null,"recordVersion":0},"decided":{"rule":"string","strategy":"string","ruleApplied":true,"confidence":0,"contested":true,"observedAt":"string"},"candidates":[{"connectionId":"00000000-0000-0000-0000-000000000000","system":"string","sourceEntity":"string","externalId":"string","value":null,"held":true,"won":true}],"flows":[{"flowId":"00000000-0000-0000-0000-000000000000","name":"string","status":"string","destinationConnectionId":"00000000-0000-0000-0000-000000000000","destination":"string","targetEntity":"string","targetField":"string","transform":"string","writes":null,"written":{"targetExternalId":"string","at":"2026-01-01T00:00:00Z"}}],"goldenDestinations":[{"connectionId":"00000000-0000-0000-0000-000000000000","system":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/golden-records/{entityClusterId}/sources":{"get":{"operationId":"ListGoldenRecordSources","tags":["golden_record"],"summary":"List Golden Record Sources","security":[{"ApiKeyAuth":["golden-records:read"]},{"BearerAuth":[]},{"OAuth2":["golden-records:read"]}],"description":"The source records that make up a golden record, as the golden build groups them now. Each names its system (connection), object and id there, its own name when it has one and your role may see it, whether its system still holds it, and the golden record it is part of now. `links` are the durable \"these belong together\" and \"keep these apart\" links from approved edits. `pendingEdit` is an edit of this record waiting for approval, or null.","parameters":[{"name":"entityClusterId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The golden record (current or archived)."},"description":"The golden record (current or archived)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"entityClusterId":{"type":"string","format":"uuid"},"entityType":{"type":"string"},"archived":{"type":"boolean"},"members":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"provider":{"type":"string"},"sourceType":{"type":"string","nullable":true,"description":"The object in that system."},"externalId":{"type":"string","description":"The record's id in that system."},"name":{"type":"string","nullable":true,"description":"Its own name; null when it has none or your role may not see it."},"exists":{"type":"boolean","description":"False when its system no longer holds it."},"nowIn":{"type":"string","format":"uuid","nullable":true,"description":"The golden record it is part of now."}},"required":["connectionId","provider","sourceType","externalId","name","exists","nowIn"]}},"links":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"link":{"type":"string","description":"together (kept in one golden record) or apart (never in one)."},"aConnectionId":{"type":"string","format":"uuid"},"aExternalId":{"type":"string"},"bConnectionId":{"type":"string","format":"uuid"},"bExternalId":{"type":"string"},"proposalId":{"type":"string","format":"uuid","description":"The approved edit that made it."},"createdAt":{"type":"string","format":"date-time"}},"required":["id","link","aConnectionId","aExternalId","bConnectionId","bExternalId","proposalId","createdAt"]}},"pendingEdit":{"type":"object","properties":{"proposalId":{"type":"string","format":"uuid"},"kind":{"type":"string","description":"merge, split, restore or archive."}},"required":["proposalId","kind"],"nullable":true}},"required":["entityClusterId","entityType","archived","members","links","pendingEdit"]},"example":{"entityClusterId":"00000000-0000-0000-0000-000000000000","entityType":"string","archived":true,"members":[{"connectionId":"00000000-0000-0000-0000-000000000000","provider":"string","sourceType":"string","externalId":"string","name":"string","exists":true,"nowIn":"00000000-0000-0000-0000-000000000000"}],"links":[{"id":"00000000-0000-0000-0000-000000000000","link":"string","aConnectionId":"00000000-0000-0000-0000-000000000000","aExternalId":"string","bConnectionId":"00000000-0000-0000-0000-000000000000","bExternalId":"string","proposalId":"00000000-0000-0000-0000-000000000000","createdAt":"2026-01-01T00:00:00Z"}],"pendingEdit":{"proposalId":"00000000-0000-0000-0000-000000000000","kind":"string"}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/golden-records/{entityClusterId}/sync":{"post":{"operationId":"SyncGoldenRecord","tags":["unified_api"],"summary":"Sync Golden Record","security":[{"ApiKeyAuth":["golden-records:write"]},{"BearerAuth":[]},{"OAuth2":["golden-records:write"]}],"description":"Send a golden record’s values back to the systems it was built from, so they all agree. You can limit it to particular fields. Fields you are not allowed to see because of their sensitivity are skipped. This runs in the background, one task per system; the response says how many systems and fields it is updating.","parameters":[{"name":"entityClusterId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the golden record."},"description":"The id of the golden record."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fields":{"type":"array","items":{"type":"string"},"description":"Only send these fields. Leave out to send every field you can see."}}},"example":{"fields":["string"]}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"targets":{"type":"integer"},"fields":{"type":"integer"}},"required":["status","targets","fields"]},"example":{"status":"string","targets":0,"fields":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/golden-records/archived":{"get":{"operationId":"ListArchivedGoldenRecords","tags":["golden_record"],"summary":"List Archived Golden Records","security":[{"ApiKeyAuth":["golden-records:read"]},{"BearerAuth":[]},{"OAuth2":["golden-records:read"]}],"description":"Archived golden records, newest first. `entity_type` narrows to one kind. Each carries its last version's values (`data`) with the values your role may not see answered as null and named in `redactedFields`, the reason in words, the members it was built from and what became of each, and the approval that archived it. A restored record (a later change was approved for it) is not listed.","parameters":[{"name":"entity_type","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"records":{"type":"array","items":{"type":"object","properties":{"entityClusterId":{"type":"string","format":"uuid"},"entityType":{"type":"string"},"reason":{"type":"string","description":"sources_deleted, rebuilt or no_longer_built. Open."},"reasonText":{"type":"string","description":"The reason in words."},"data":{"type":"object","additionalProperties":true,"description":"The values it held when archived (its last version)."},"redactedFields":{"type":"array","items":{"type":"string"},"description":"Fields of `data` your role may not see, answered as null."},"lastVersion":{"type":"integer","nullable":true},"members":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"provider":{"type":"string"},"externalId":{"type":"string","description":"The record's id in that system. Absent when the golden record predates source ids (2026-07-04)."},"state":{"type":"string","description":"deleted (no longer held for that system), moved (now part of another golden record, `nowIn`) or unknown."},"nowIn":{"type":"string","format":"uuid","description":"The golden record it now belongs to, when moved."}},"required":["connectionId","provider","state"]},"description":"The source records it was built from and what became of each."},"rebuiltAs":{"type":"array","items":{"type":"string","format":"uuid"}},"passesDeleteOn":{"type":"boolean"},"proposalId":{"type":"string","format":"uuid","description":"The approved change that archived it."},"retiredBy":{"type":"string"},"retiredAt":{"type":"string","format":"date-time"}},"required":["entityClusterId","entityType","reason","reasonText","data","redactedFields","members","rebuiltAs","passesDeleteOn","proposalId","retiredBy","retiredAt"]}}},"required":["total","records"]},"example":{"total":0,"records":[{"entityClusterId":"00000000-0000-0000-0000-000000000000","entityType":"string","reason":"string","reasonText":"string","data":{},"redactedFields":["string"],"lastVersion":0,"members":[{"connectionId":"00000000-0000-0000-0000-000000000000","provider":"string","externalId":"string","state":"string","nowIn":"00000000-0000-0000-0000-000000000000"}],"rebuiltAs":["00000000-0000-0000-0000-000000000000"],"passesDeleteOn":true,"proposalId":"00000000-0000-0000-0000-000000000000","retiredBy":"string","retiredAt":"2026-01-01T00:00:00Z"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/golden-records/delete-choices":{"get":{"operationId":"ListDestinationDeleteChoices","tags":["golden_record"],"summary":"List Destination Delete Choices","security":[{"ApiKeyAuth":["golden-records:read"]},{"BearerAuth":[]},{"OAuth2":["golden-records:read"]}],"description":"Every connection in the workspace that is not archived, with its delete choice (`action`, null when it follows the default), the choice in force (`effectiveAction`) and how many deletes it was passed, by status. `actions` lists the choices with their labels; `defaultAction` is the one a destination with no choice follows. Erasure (a data subject request) is separate and not affected.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"defaultAction":{"type":"string"},"actions":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}},"required":["value","label"]}},"destinations":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"name":{"type":"string"},"systemKey":{"type":"string","nullable":true},"action":{"type":"string","nullable":true,"description":"The destination's own choice; null when it follows the default."},"effectiveAction":{"type":"string"},"counts":{"type":"object","additionalProperties":true,"description":"Deletes passed to it, by status (kept, scheduled, pending, deleted, marked, not_supported, failed, cancelled)."}},"required":["connectionId","name","effectiveAction","counts"]}}},"required":["defaultAction","actions","destinations"]},"example":{"defaultAction":"string","actions":[{"value":"string","label":"string"}],"destinations":[{"connectionId":"00000000-0000-0000-0000-000000000000","name":"string","systemKey":"string","action":"string","effectiveAction":"string","counts":{}}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/golden-records/deletions":{"get":{"operationId":"ListDestinationDeletions","tags":["golden_record"],"summary":"List Destination Deletions","security":[{"ApiKeyAuth":["golden-records:read"]},{"BearerAuth":[]},{"OAuth2":["golden-records:read"]}],"description":"Deletes passed on to destinations, newest first. Filter by `status` or by `connection_id` (the destination). Each row names the origin (source_deleted: a pipeline had written the record there and its source deleted it; golden_retired: a golden record archived because its sources deleted it), the destination and its object, the choice as it stood, when it is due, and the outcome in words.","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"connection_id","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"deletions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"origin":{"type":"string"},"destinationConnectionId":{"type":"string","format":"uuid"},"pipelineId":{"type":"string","format":"uuid","nullable":true},"sourceConnectionId":{"type":"string","format":"uuid","nullable":true},"sourceEntityType":{"type":"string"},"sourceExternalId":{"type":"string"},"entityClusterId":{"type":"string","format":"uuid","nullable":true},"targetEntity":{"type":"string","nullable":true},"targetExternalId":{"type":"string","nullable":true},"action":{"type":"string"},"actionSource":{"type":"string","description":"chosen or default."},"status":{"type":"string"},"detail":{"type":"string","nullable":true},"deletedAt":{"type":"string","format":"date-time"},"dueAt":{"type":"string","format":"date-time","nullable":true},"attempts":{"type":"integer"},"completedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","origin","destinationConnectionId","sourceEntityType","sourceExternalId","action","actionSource","status","deletedAt","attempts","createdAt"]}}},"required":["deletions"]},"example":{"deletions":[{"id":"00000000-0000-0000-0000-000000000000","origin":"string","destinationConnectionId":"00000000-0000-0000-0000-000000000000","pipelineId":"00000000-0000-0000-0000-000000000000","sourceConnectionId":"00000000-0000-0000-0000-000000000000","sourceEntityType":"string","sourceExternalId":"string","entityClusterId":"00000000-0000-0000-0000-000000000000","targetEntity":"string","targetExternalId":"string","action":"string","actionSource":"string","status":"string","detail":"string","deletedAt":"2026-01-01T00:00:00Z","dueAt":"2026-01-01T00:00:00Z","attempts":0,"completedAt":"2026-01-01T00:00:00Z","createdAt":"2026-01-01T00:00:00Z"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/golden-records/retirement-check":{"post":{"operationId":"CheckGoldenRetirements","tags":["golden_record"],"summary":"Check Golden Retirements","security":[{"ApiKeyAuth":["golden-records:write"]},{"BearerAuth":[]},{"OAuth2":["golden-records:write"]}],"description":"Queue a golden-record rebuild for each kind of golden record in the workspace, or only `entityType`. The rebuild proposes changes as usual and proposes archiving each golden record it no longer produces: one whose source records were all deleted in their systems, or whose records now make up other golden records. A retirement is rated high risk, so it waits for a person in Changes. Returns the kinds queued.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"entityType":{"type":"string","maximum":200,"description":"One kind of golden record; leave it out for every kind."}}},"example":{"entityType":"string"}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"queued":{"type":"array","items":{"type":"string"},"description":"The kinds of golden record a rebuild was queued for."}},"required":["queued"]},"example":{"queued":["string"]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/golden-records/setup-suggestion":{"get":{"operationId":"GetGoldenSetupSuggestion","tags":["golden_record"],"summary":"Get Golden Setup Suggestion","security":[{"ApiKeyAuth":["golden-records:read"]},{"BearerAuth":[]},{"OAuth2":["golden-records:read"]}],"description":"Suggest a starting golden-record setup for your workspace, worked out from the golden records and proposed changes you already have. For each kind of golden record it lists the systems that supplied it; for each kind with no approval policy it suggests one that approves a change on its own when the risk is medium or lower and at most 5 fields change, whichever systems supplied it (high-risk changes and the rest wait for an admin); and for each system whose role for a kind nobody confirmed it suggests one (the source of truth is the system your rules already name, else the one supplying the most records). Every suggestion carries a reason and a key; nothing is created until you apply it.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"entityTypes":{"type":"array","items":{"type":"object","properties":{"entityType":{"type":"string","description":"The kind of golden record, e.g. customer."},"records":{"type":"integer","description":"Distinct golden records of this kind, counting proposed and current ones once each."},"providers":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","description":"The system: the connection the values came through."},"providerKey":{"type":"string","description":"The connection's system key, a label only: two connections to one vendor share it."},"systemName":{"type":"string","description":"The connection's display name."},"records":{"type":"integer","description":"Records of this kind it supplied at least one value of."}},"required":["connectionId","providerKey","systemName","records"]},"description":"The systems that supplied records of this kind, one per connection, most records first."},"reason":{"type":"string","description":"In plain English, e.g. \"Myobos Demo Site supplies all 164 customer records.\""}},"required":["entityType","records","providers","reason"]},"description":"Each kind of golden record in the workspace, most records first."},"policies":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Pass in `only` to apply this suggestion alone."},"entityType":{"type":"string"},"name":{"type":"string","description":"The policy name it would be created with, e.g. \"Customer – auto-approve lower-risk changes\"."},"autoApproveConditions":{"type":"object","properties":{"maxRiskLevel":{"type":"string","description":"Known values: low, medium."},"maxRiskScore":{"type":"integer","description":"Approved at or below this 0-100 risk score; the level decides for a change scored before scores existed."},"maxConflicts":{"type":"integer","nullable":true,"description":"The most conflicts a change may carry; null is no limit of its own (the risk already counts disagreement)."},"maxFieldsChanged":{"type":"integer"},"singleProviderOnly":{"type":"boolean","description":"Whether only a change one system supplied is approved. The suggestion does not ask for it."}},"required":["maxRiskLevel","maxRiskScore","maxConflicts","maxFieldsChanged","singleProviderOnly"],"description":"When a change is approved without a person."},"requiredApprovers":{"type":"array","items":{"type":"string"},"description":"Who approves the rest, one person per entry."},"enabled":{"type":"boolean"},"reason":{"type":"string"}},"required":["key","entityType","name","autoApproveConditions","requiredApprovers","enabled","reason"]},"description":"Suggested approval policies, one per kind that has none."},"roles":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Pass in `only` to apply this suggestion alone: role:<kind>:<connection id>."},"entityType":{"type":"string"},"connectionId":{"type":"string","format":"uuid"},"systemName":{"type":"string"},"role":{"type":"string","description":"The suggested role: system_of_record, contributor, reference or receiver."},"currentRole":{"type":"string","nullable":true,"description":"Inferrex's unconfirmed recommendation in force, or null when it has none."},"because":{"type":"array","items":{"type":"string"}},"convertsRules":{"type":"integer","description":"\"This system wins\" rules naming it that applying replaces."}},"required":["key","entityType","connectionId","systemName","role","currentRole","because","convertsRules"]},"description":"Suggested source roles: one per system whose role for a kind nobody confirmed, with no change waiting."},"pendingCount":{"type":"integer","description":"How many suggestions are not applied yet. 0 when the workspace's setup already covers everything suggested."}},"required":["entityTypes","policies","roles","pendingCount"]},"example":{"entityTypes":[{"entityType":"string","records":0,"providers":[{"connectionId":"00000000-0000-0000-0000-000000000000","providerKey":"string","systemName":"string","records":0}],"reason":"string"}],"policies":[{"key":"string","entityType":"string","name":"string","autoApproveConditions":{"maxRiskLevel":"string","maxRiskScore":0,"maxConflicts":0,"maxFieldsChanged":0,"singleProviderOnly":true},"requiredApprovers":["string"],"enabled":true,"reason":"string"}],"roles":[{"key":"string","entityType":"string","connectionId":"00000000-0000-0000-0000-000000000000","systemName":"string","role":"string","currentRole":"string","because":["string"],"convertsRules":0}],"pendingCount":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/golden-records/setup-suggestion/apply":{"post":{"operationId":"ApplyGoldenSetupSuggestion","tags":["golden_record"],"summary":"Apply Golden Setup Suggestion","security":[{"ApiKeyAuth":["golden-records:write"]},{"BearerAuth":[]},{"OAuth2":["golden-records:write"]}],"description":"Apply Inferrex's suggested golden-record setup: create the suggested approval policies that do not exist yet, and set the suggested source roles as confirmed by you. Making a system the source of truth replaces the \"this system wins\" rules naming it for that kind. Send `only` with suggestion keys to apply just those; leave it out to apply everything suggested. Anything already set up, or waiting for approval, is skipped and listed, so it is safe to run twice.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"only":{"type":"array","items":{"type":"string"},"description":"The keys of the suggestions to apply (e.g. \"policy:customer\" or \"role:customer:<connection id>\"), as GET /v1/golden-records/setup-suggestion lists them. Leave it out to apply every suggestion."}}},"example":{"only":["string"]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"created":{"type":"object","properties":{"policies":{"type":"integer"},"roles":{"type":"integer","description":"Roles now in force."},"convertedRules":{"type":"integer","description":"\"This system wins\" rules those roles replaced, and that were deleted."}},"required":["policies","roles","convertedRules"],"description":"How many this call created or set."},"createdKeys":{"type":"array","items":{"type":"string"},"description":"The keys of the suggestions this call created."},"skipped":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"reason":{"type":"string"}},"required":["key","reason"]},"description":"Asked-for suggestions that were not created, and why."},"remaining":{"type":"integer","description":"Suggestions still not applied after this call."}},"required":["created","createdKeys","skipped","remaining"]},"example":{"created":{"policies":0,"roles":0,"convertedRules":0},"createdKeys":["string"],"skipped":[{"key":"string","reason":"string"}],"remaining":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/golden-records/source-roles":{"get":{"operationId":"ListSourceRoles","tags":["golden_record"],"summary":"List Source Roles","security":[{"ApiKeyAuth":["golden-records:read"]},{"BearerAuth":[]},{"OAuth2":["golden-records:read"]}],"description":"Which system is the source of truth for each kind of golden record. For each kind (customer, product…) it lists the systems that supply it or receive it from Inferrex, each with its role in force and who set it, Inferrex's recommendation with the reasons from your own data, and any change to it waiting for approval. With no rule for a field, the source of truth's own value wins in the golden record. `unconfirmed` counts the systems whose role nobody has confirmed; `approvalRequired` says whether your workspace's approval policy governs these changes.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"goldenTypes":{"type":"array","items":{"type":"object","properties":{"entityType":{"type":"string"},"records":{"type":"integer"},"systems":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","description":"The system, by its connection id."},"systemName":{"type":"string"},"records":{"type":"integer","description":"Records of this kind it supplied a value of."},"role":{"type":"string","nullable":true,"description":"The role in force: system_of_record, contributor, reference or receiver; null when it has none."},"roleSource":{"type":"string","nullable":true,"description":"customer (a person set it) or inferrex (Inferrex's recommendation, not confirmed)."},"recommendedRole":{"type":"string","nullable":true},"because":{"type":"array","items":{"type":"string"},"description":"Why Inferrex recommends it, from your own data."},"pending":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Approve or reject it by this id."},"role":{"type":"string"},"kind":{"type":"string","description":"first_connection, confirm, change_system_of_record, rule_conversion or drift_suggestion."},"requestedAt":{"type":"string"},"riskScore":{"type":"integer","description":"0 to 100."},"riskReasons":{"type":"array","items":{"type":"string"}}},"required":["id","role","kind","requestedAt","riskScore","riskReasons"],"nullable":true,"description":"A change to this role waiting for approval."}},"required":["connectionId","systemName","records","role","roleSource","recommendedRole","because","pending"]}},"warnings":{"type":"array","items":{"type":"string"},"description":"What is inconsistent, e.g. two sources of truth for one kind."}},"required":["entityType","records","systems","warnings"]},"description":"Each kind of golden record, most records first."},"unconfirmed":{"type":"integer"},"approvalRequired":{"type":"boolean"}},"required":["goldenTypes","unconfirmed","approvalRequired"]},"example":{"goldenTypes":[{"entityType":"string","records":0,"systems":[{"connectionId":"00000000-0000-0000-0000-000000000000","systemName":"string","records":0,"role":"string","roleSource":"string","recommendedRole":"string","because":["string"],"pending":{"id":"00000000-0000-0000-0000-000000000000","role":"string","kind":"string","requestedAt":"string","riskScore":0,"riskReasons":["string"]}}],"warnings":["string"]}],"unconfirmed":0,"approvalRequired":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"SetSourceRole","tags":["golden_record"],"summary":"Set Source Role","security":[{"ApiKeyAuth":["golden-records:write"]},{"BearerAuth":[]},{"OAuth2":["golden-records:write"]}],"description":"Set which role a system plays for one kind of golden record. `choice`: confirm (the role you send, usually Inferrex's pick), choose (another role) or not_sure (Inferrex's recommendation, kept as unconfirmed). It applies at once unless your workspace has an approval policy for source-of-truth changes and this change's risk is above it; then it waits for approval, and the role in force keeps deciding. 409 while another change to the same system's roles waits for approval.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","description":"The system, by its connection id, as GET /v1/golden-records/source-roles lists it."},"entityType":{"type":"string","maximum":200,"description":"The kind of golden record, e.g. customer, as GET /v1/golden-records/source-roles lists it."},"role":{"type":"string","description":"system_of_record, contributor, reference or receiver. Not needed with choice not_sure."},"choice":{"type":"string","description":"confirm (Inferrex's pick, sent as role), choose (another role) or not_sure (Inferrex's recommendation, kept unconfirmed)."}},"required":["connectionId","entityType","choice"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","entityType":"string","role":"string","choice":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"applied":{"type":"boolean","description":"false when it waits for approval."},"id":{"type":"string","format":"uuid","description":"The roles version written; approve or reject a waiting one by this id."},"status":{"type":"string","description":"active or pending_approval."},"role":{"type":"string"},"roleSource":{"type":"string"},"riskScore":{"type":"integer"},"riskReasons":{"type":"array","items":{"type":"string"}},"reason":{"type":"string"},"convertedRules":{"type":"integer","description":"\"This system wins\" rules the role replaced, and that were deleted."}},"required":["applied","id","status","role","roleSource","riskScore","riskReasons","reason","convertedRules"]},"example":{"applied":true,"id":"00000000-0000-0000-0000-000000000000","status":"string","role":"string","roleSource":"string","riskScore":0,"riskReasons":["string"],"reason":"string","convertedRules":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/golden-records/source-roles/{id}/approve":{"post":{"operationId":"ApproveSourceRole","tags":["golden_record"],"summary":"Approve Source Role","security":[{"ApiKeyAuth":["golden-records:write"]},{"BearerAuth":[]},{"OAuth2":["golden-records:write"]}],"description":"Approve a change to a system's role that is waiting for approval. When its required approvers are all filled, each by a different member and not by whoever requested it, the new role is in force from the next golden build. 403 when you requested it or fill none of the places left; 409 when it is not waiting.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","maximum":2000}}},"example":{"notes":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"applied":{"type":"boolean"},"id":{"type":"string","format":"uuid"},"convertedRules":{"type":"integer"},"approvals":{"type":"object","properties":{"required":{"type":"array","items":{"type":"string"},"description":"The roles or teams that must each approve, one person per entry (an entry listed twice needs two people). Empty when no approval policy names approvers."},"received":{"type":"array","items":{"type":"object","properties":{"approver":{"type":"string","format":"uuid","nullable":true,"description":"The approving workspace member (workspace_users.id). Null when an API key or OAuth client approved a change that named no approvers."},"role":{"type":"string","nullable":true,"description":"The required entry this approval filled. Null when the change named no approvers."},"decidedAt":{"type":"string","format":"date-time"}},"required":["approver","role","decidedAt"]},"description":"The approvals recorded so far, oldest first."},"satisfied":{"type":"boolean","description":"True once the change has been approved (by people or automatically by a policy), or every required entry is filled."}},"required":["required","received","satisfied"],"description":"Who must approve this change and who has. Each `required` entry names a workspace role or a workspace team. A person fills an entry when it is their role, a role below theirs (owner fills admin), or a team they belong to. The change applies when every entry is filled by a different person, and the person who requested it cannot fill one. An empty `required` means one approval from anyone allowed to approve applies it."}},"required":["applied","id","convertedRules","approvals"]},"example":{"applied":true,"id":"00000000-0000-0000-0000-000000000000","convertedRules":0,"approvals":{"required":["string"],"received":[{"approver":"00000000-0000-0000-0000-000000000000","role":"string","decidedAt":"2026-01-01T00:00:00Z"}],"satisfied":true}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/golden-records/source-roles/{id}/reject":{"post":{"operationId":"RejectSourceRole","tags":["golden_record"],"summary":"Reject Source Role","security":[{"ApiKeyAuth":["golden-records:write"]},{"BearerAuth":[]},{"OAuth2":["golden-records:write"]}],"description":"Reject a change to a system's role that is waiting for approval. The role in force stays; the change is kept as rejected.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maximum":2000}}},"example":{"reason":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"},"approvals":{"type":"object","properties":{"required":{"type":"array","items":{"type":"string"},"description":"The roles or teams that must each approve, one person per entry (an entry listed twice needs two people). Empty when no approval policy names approvers."},"received":{"type":"array","items":{"type":"object","properties":{"approver":{"type":"string","format":"uuid","nullable":true,"description":"The approving workspace member (workspace_users.id). Null when an API key or OAuth client approved a change that named no approvers."},"role":{"type":"string","nullable":true,"description":"The required entry this approval filled. Null when the change named no approvers."},"decidedAt":{"type":"string","format":"date-time"}},"required":["approver","role","decidedAt"]},"description":"The approvals recorded so far, oldest first."},"satisfied":{"type":"boolean","description":"True once the change has been approved (by people or automatically by a policy), or every required entry is filled."}},"required":["required","received","satisfied"],"description":"Who must approve this change and who has. Each `required` entry names a workspace role or a workspace team. A person fills an entry when it is their role, a role below theirs (owner fills admin), or a team they belong to. The change applies when every entry is filled by a different person, and the person who requested it cannot fill one. An empty `required` means one approval from anyone allowed to approve applies it."}},"required":["id","status","approvals"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string","approvals":{"required":["string"],"received":[{"approver":"00000000-0000-0000-0000-000000000000","role":"string","decidedAt":"2026-01-01T00:00:00Z"}],"satisfied":true}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/golden-records/sync-batch":{"post":{"operationId":"SyncGoldenRecordsBatch","tags":["unified_api"],"summary":"Sync Golden Records Batch","security":[{"ApiKeyAuth":["golden-records:write"]},{"BearerAuth":[]},{"OAuth2":["golden-records:write"]}],"description":"Send several golden records’ values back to the systems they were built from, in one call (up to 100). Fields you are not allowed to see are skipped. A record that cannot be found is reported as skipped rather than failing the whole batch.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"entityClusterIds":{"type":"array","items":{"type":"string"},"description":"The ids of the golden records to send back, up to 100."}},"required":["entityClusterIds"]},"example":{"entityClusterIds":["string"]}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"dispatched":{"type":"integer"},"results":{"type":"array","items":{"type":"object","properties":{"entityClusterId":{"type":"string"},"status":{"type":"string"},"targets":{"type":"integer"},"fields":{"type":"integer"}},"required":["entityClusterId","status","targets","fields"]}}},"required":["dispatched","results"]},"example":{"dispatched":0,"results":[{"entityClusterId":"string","status":"string","targets":0,"fields":0}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/governance/sensitivity-map":{"get":{"operationId":"GetTenantSensitivityMap","tags":["governance"],"summary":"Get Tenant Sensitivity Map","security":[{"ApiKeyAuth":["governance:read"]},{"BearerAuth":[]},{"OAuth2":["governance:read"]}],"description":"Your sensitive data map: every field in your connected systems that holds personal, financial, health or credential data.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":1000,"description":"How many fields to return: 1 to 1,000, 200 if you leave it out.","default":200},"description":"How many fields to return: 1 to 1,000, 200 if you leave it out."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"fields":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"tenant":{"type":"string"},"connection":{"type":"string"},"entity":{"type":"string"},"field":{"type":"string"},"role":{"type":"string"},"sensitivity":{"type":"string","enum":["pii","financial","health","credential"]}},"required":["id","tenant","connection","entity","field","role","sensitivity"]}},"totals":{"type":"object","properties":{"pii":{"type":"integer"},"financial":{"type":"integer"},"health":{"type":"integer"},"credential":{"type":"integer"}},"required":["pii","financial","health","credential"]},"fieldCount":{"type":"integer"}},"required":["fields","totals","fieldCount"]},"example":{"fields":[{"id":"string","tenant":"string","connection":"string","entity":"string","field":"string","role":"string","sensitivity":"pii"}],"totals":{"pii":0,"financial":0,"health":0,"credential":0},"fieldCount":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/heals":{"get":{"operationId":"ListHeals","tags":["heals"],"summary":"List Heals","security":[{"ApiKeyAuth":["heals:read"]},{"BearerAuth":[]},{"OAuth2":["heals:read"]}],"description":"Problems Inferrex has found and fixed, or needs your help with: questions waiting for your answer, and fixes. Newest first. With no options it returns the latest 40. For the next page, pass the nextCursor from the previous page as cursor; status (open or resolved), tier (1, 2 or 3), pipeline_id (one flow) and connection_id (one system) narrow the list.","parameters":[{"name":"cursor","in":"query","required":false,"schema":{"type":"string","description":"nextCursor from the previous page. Omit for the first page."},"description":"nextCursor from the previous page. Omit for the first page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"description":"Heals per page. Default 40.","default":40},"description":"Heals per page. Default 40."},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["open","resolved"],"description":"open: a Tier 3 question still waiting for your answer. resolved: everything else — fixed automatically (Tier 1), fixed and told you (Tier 2), or answered (see resolution for what became of the answer)."},"description":"open: a Tier 3 question still waiting for your answer. resolved: everything else — fixed automatically (Tier 1), fixed and told you (Tier 2), or answered (see resolution for what became of the answer)."},{"name":"tier","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":3,"description":"1: fixed automatically. 2: fixed and told you. 3: needed your decision."},"description":"1: fixed automatically. 2: fixed and told you. 3: needed your decision."},{"name":"pipeline_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only this flow's repairs."},"description":"Only this flow's repairs."},{"name":"connection_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only this system's repairs: those that name it, and those of every flow that reads from it, writes to it or has it as an extra destination."},"description":"Only this system's repairs: those that name it, and those of every flow that reads from it, writes to it or has it as an extra destination."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"failureType":{"type":"string"},"tier":{"type":"integer"},"resolution":{"type":"string","nullable":true,"description":"How the heal stands, an open set of words. Tier 1 and 2: resolved or notified. Tier 3: escalated (waiting for your answer); answer_received or continuing (answered, Inferrex is applying it); resolved (applied); needs_operator (answer recorded, Inferrex cannot act on it by itself); continuation_failed (applying it failed — see continuationNote)."},"pipelineId":{"type":"string","format":"uuid","nullable":true},"resolved":{"type":"boolean","description":"True only once the heal is closed. An answered Tier 3 question stays false until Inferrex has applied the answer."},"createdAt":{"type":"string"},"resolvedAt":{"type":"string","nullable":true},"message":{"type":"string","description":"The failure's errorMessage, when the reporting service sent one."},"question":{"type":"string","description":"Tier 3 only: the one question the customer has to answer."},"options":{"type":"array","items":{"type":"string"},"description":"Tier 3 only: the suggested answers."},"answer":{"type":"string","description":"The customer's recorded answer to a Tier 3 question."},"continuationNote":{"type":"string","description":"Tier 3, once answered: what Inferrex did with the answer, or why it could not carry on."},"connectionId":{"type":"string","format":"uuid"}},"required":["id","failureType","tier","resolved","createdAt"]}},"nextCursor":{"type":"string","nullable":true,"description":"Pass as cursor for the next page; null on the last page."},"hasMore":{"type":"boolean"}},"required":["items","nextCursor","hasMore"]},"example":{"items":[{"id":"00000000-0000-0000-0000-000000000000","failureType":"string","tier":0,"resolution":"string","pipelineId":"00000000-0000-0000-0000-000000000000","resolved":true,"createdAt":"string","resolvedAt":"string","message":"string","question":"string","options":["string"],"answer":"string","continuationNote":"string","connectionId":"00000000-0000-0000-0000-000000000000"}],"nextCursor":"string","hasMore":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/heals/{id}":{"get":{"operationId":"GetHeal","tags":["heals"],"summary":"Get Heal","security":[{"ApiKeyAuth":["heals:read"]},{"BearerAuth":[]},{"OAuth2":["heals:read"]}],"description":"One repair retained in your workspace. A repair id from another workspace is indistinguishable from an unknown id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The repair id."},"description":"The repair id."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"failureType":{"type":"string"},"tier":{"type":"integer"},"resolution":{"type":"string","nullable":true},"pipelineId":{"type":"string","format":"uuid","nullable":true},"resolved":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"resolvedAt":{"type":"string","format":"date-time","nullable":true},"message":{"type":"string"},"question":{"type":"string"},"options":{"type":"array","items":{"type":"string"}},"answer":{"type":"string"},"continuationNote":{"type":"string"},"connectionId":{"type":"string","format":"uuid"}},"required":["id","failureType","tier","resolution","pipelineId","resolved","createdAt","resolvedAt"]},"example":{"id":"00000000-0000-0000-0000-000000000000","failureType":"string","tier":0,"resolution":"string","pipelineId":"00000000-0000-0000-0000-000000000000","resolved":true,"createdAt":"2026-01-01T00:00:00Z","resolvedAt":"2026-01-01T00:00:00Z","message":"string","question":"string","options":["string"],"answer":"string","continuationNote":"string","connectionId":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/heals/{id}/answer":{"post":{"operationId":"AnswerHeal","tags":["heals"],"summary":"Answer Heal","security":[{"ApiKeyAuth":["heals:write"]},{"BearerAuth":[]},{"OAuth2":["heals:write"]}],"description":"Answer a question Inferrex asked about a problem it could not fix on its own. The answer is recorded and Inferrex carries on with it: the problem is closed once the answer has been applied, and the list of problems shows if Inferrex could not act on it. Sending the same answer again is safe and returns the same result; if Inferrex could not carry on with it (continuation_failed), sending the same answer again tries once more.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the question."},"description":"The id of the question."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"answer":{"type":"string","maxLength":2000,"description":"Your answer to the question: one of its suggested answers, or your own words."}},"required":["answer"]},"example":{"answer":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","description":"Where the heal stands now, an open set of words: continuing (answer recorded, Inferrex is applying it), resolved, needs_operator, or continuation_failed. The first answer, and a resend that retries a continuation_failed answer, return continuing."},"resolved":{"type":"boolean","description":"True only once the answer has been applied and the heal closed."},"answer":{"type":"string"}},"required":["id","status","resolved","answer"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string","resolved":true,"answer":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/hooks/messages/{customerId}/{deliveryKey}":{"post":{"operationId":"ReceiveBloomreachMessageDelivery","tags":["bloomreach"],"summary":"Receive Bloomreach Message Delivery","security":[],"description":"Authenticated by the workspace's receive secret in X-Inferrex-Webhook-Secret, Authorization: Bearer or as the Basic password (the replaced secret too, for 24 hours), or, when turned on, by an Inferrex access token from POST /v1/oauth/token for the same workspace holding hooks:receive. 404 unknown address or a workspace without the Bloomreach module; 401 wrong or missing secret or token; 400 a body that is not one of the two shapes; 409 an unknown campaign, one Bloomreach sends itself, one not approved, or an approval that lapsed or no longer matches the messages; otherwise 200 with how many were accepted, already asked for, or not in the campaign. Renders and sends nothing in the request.","parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"deliveryKey","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"campaignId":{"type":"string","format":"uuid","description":"The campaign's id as Inferrex shows it. Required unless the body is empty (an integration test)."},"registered":{"type":"string","maxLength":300,"description":"One person's registered id."},"customers":{"type":"array","items":{"type":"object","properties":{"registered":{"type":"string","maxLength":300}},"required":["registered"]},"description":"Up to 200 { registered }."},"trigger":{"type":"string","maxLength":200,"description":"What triggered it, stored with each message (an API trigger's name, say)."}}},"example":{"campaignId":"00000000-0000-0000-0000-000000000000","registered":"string","customers":[{"registered":"string"}],"trigger":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"received":{"type":"boolean"},"accepted":{"type":"integer"},"duplicates":{"type":"integer"},"notFound":{"type":"integer"}},"required":["received","accepted","duplicates","notFound"]},"example":{"received":true,"accepted":0,"duplicates":0,"notFound":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/initial-loads":{"get":{"operationId":"InitialLoadsList","tags":["operations"],"summary":"Initial Loads List","security":[{"ApiKeyAuth":["initial-loads:read"]},{"BearerAuth":[]},{"OAuth2":["initial-loads:read"]}],"description":"List your initial loads, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"connection_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only initial loads for this connection. Pass its id."},"description":"Only initial loads for this connection. Pass its id."},{"name":"approved_by","in":"query","required":false,"schema":{"type":"string","description":"Only initial loads whose approved by is exactly this."},"description":"Only initial loads whose approved by is exactly this."},{"name":"approved_by_contains","in":"query","required":false,"schema":{"type":"string","description":"Only initial loads whose approved by contains this text (upper and lower case are treated the same)."},"description":"Only initial loads whose approved by contains this text (upper and lower case are treated the same)."},{"name":"approved_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only initial loads whose approved time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only initial loads whose approved time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"approved_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only initial loads whose approved time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only initial loads whose approved time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Only initial loads whose status is exactly this."},"description":"Only initial loads whose status is exactly this."},{"name":"status_contains","in":"query","required":false,"schema":{"type":"string","description":"Only initial loads whose status contains this text (upper and lower case are treated the same)."},"description":"Only initial loads whose status contains this text (upper and lower case are treated the same)."},{"name":"records_loaded_gte","in":"query","required":false,"schema":{"type":"number","description":"Only initial loads whose records loaded is this number or more."},"description":"Only initial loads whose records loaded is this number or more."},{"name":"records_loaded_lte","in":"query","required":false,"schema":{"type":"number","description":"Only initial loads whose records loaded is this number or less."},"description":"Only initial loads whose records loaded is this number or less."},{"name":"records_total_gte","in":"query","required":false,"schema":{"type":"number","description":"Only initial loads whose records total is this number or more."},"description":"Only initial loads whose records total is this number or more."},{"name":"records_total_lte","in":"query","required":false,"schema":{"type":"number","description":"Only initial loads whose records total is this number or less."},"description":"Only initial loads whose records total is this number or less."},{"name":"storage_consumed_gb_gte","in":"query","required":false,"schema":{"type":"number","description":"Only initial loads whose storage consumed gb is this number or more."},"description":"Only initial loads whose storage consumed gb is this number or more."},{"name":"storage_consumed_gb_lte","in":"query","required":false,"schema":{"type":"number","description":"Only initial loads whose storage consumed gb is this number or less."},"description":"Only initial loads whose storage consumed gb is this number or less."},{"name":"load_started_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only initial loads whose load started time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only initial loads whose load started time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"load_started_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only initial loads whose load started time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only initial loads whose load started time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"load_completed_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only initial loads whose load completed time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only initial loads whose load completed time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"load_completed_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only initial loads whose load completed time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only initial loads whose load completed time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"load_duration_ms_gte","in":"query","required":false,"schema":{"type":"number","description":"Only initial loads whose load duration ms is this number or more."},"description":"Only initial loads whose load duration ms is this number or more."},{"name":"load_duration_ms_lte","in":"query","required":false,"schema":{"type":"number","description":"Only initial loads whose load duration ms is this number or less."},"description":"Only initial loads whose load duration ms is this number or less."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many initial loads to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many initial loads to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many initial loads to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many initial loads to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","connection_id","approved_by","approved_at","status","records_loaded","records_total","storage_consumed_gb","load_started_at","load_completed_at","load_duration_ms","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns initial loads where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns initial loads where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid"},"scope_assessment":{"type":"object","additionalProperties":true},"approved_by":{"type":"string","nullable":true},"approved_at":{"type":"string","nullable":true},"status":{"type":"string"},"records_loaded":{"type":"integer"},"records_total":{"type":"integer","nullable":true},"storage_consumed_gb":{"type":"number"},"load_started_at":{"type":"string","nullable":true},"load_completed_at":{"type":"string","nullable":true},"load_duration_ms":{"type":"integer","nullable":true},"progress_log":{"type":"object","additionalProperties":true},"error_log":{"type":"object","additionalProperties":true,"nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","connection_id","scope_assessment"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","scope_assessment":{},"approved_by":"string","approved_at":"string","status":"string","records_loaded":0,"records_total":0,"storage_consumed_gb":0,"load_started_at":"string","load_completed_at":"string","load_duration_ms":0,"progress_log":{},"error_log":{},"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"InitialLoadsCreate","tags":["operations"],"summary":"Initial Loads Create","security":[{"ApiKeyAuth":["initial-loads:write"]},{"BearerAuth":[]},{"OAuth2":["initial-loads:write"]}],"description":"Create an initial load. Returns the new initial load, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connection_id":{"type":"string","format":"uuid"},"scope_assessment":{"type":"object","additionalProperties":true},"records_total":{"type":"integer","nullable":true},"storage_consumed_gb":{"type":"number"},"progress_log":{"type":"object","additionalProperties":true}},"required":["connection_id","scope_assessment"]},"example":{"connection_id":"00000000-0000-0000-0000-000000000000","scope_assessment":{},"records_total":0,"storage_consumed_gb":0,"progress_log":{}}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid"},"scope_assessment":{"type":"object","additionalProperties":true},"approved_by":{"type":"string","nullable":true},"approved_at":{"type":"string","nullable":true},"status":{"type":"string"},"records_loaded":{"type":"integer"},"records_total":{"type":"integer","nullable":true},"storage_consumed_gb":{"type":"number"},"load_started_at":{"type":"string","nullable":true},"load_completed_at":{"type":"string","nullable":true},"load_duration_ms":{"type":"integer","nullable":true},"progress_log":{"type":"object","additionalProperties":true},"error_log":{"type":"object","additionalProperties":true,"nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","connection_id","scope_assessment"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","scope_assessment":{},"approved_by":"string","approved_at":"string","status":"string","records_loaded":0,"records_total":0,"storage_consumed_gb":0,"load_started_at":"string","load_completed_at":"string","load_duration_ms":0,"progress_log":{},"error_log":{},"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/initial-loads/{id}":{"get":{"operationId":"InitialLoadsGet","tags":["operations"],"summary":"Initial Loads Get","security":[{"ApiKeyAuth":["initial-loads:read"]},{"BearerAuth":[]},{"OAuth2":["initial-loads:read"]}],"description":"Get one of your initial loads by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the initial load."},"description":"The id of the initial load."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid"},"scope_assessment":{"type":"object","additionalProperties":true},"approved_by":{"type":"string","nullable":true},"approved_at":{"type":"string","nullable":true},"status":{"type":"string"},"records_loaded":{"type":"integer"},"records_total":{"type":"integer","nullable":true},"storage_consumed_gb":{"type":"number"},"load_started_at":{"type":"string","nullable":true},"load_completed_at":{"type":"string","nullable":true},"load_duration_ms":{"type":"integer","nullable":true},"progress_log":{"type":"object","additionalProperties":true},"error_log":{"type":"object","additionalProperties":true,"nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","connection_id","scope_assessment"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","scope_assessment":{},"approved_by":"string","approved_at":"string","status":"string","records_loaded":0,"records_total":0,"storage_consumed_gb":0,"load_started_at":"string","load_completed_at":"string","load_duration_ms":0,"progress_log":{},"error_log":{},"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"InitialLoadsUpdate","tags":["operations"],"summary":"Initial Loads Update","security":[{"ApiKeyAuth":["initial-loads:write"]},{"BearerAuth":[]},{"OAuth2":["initial-loads:write"]}],"description":"Change an initial load. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the initial load."},"description":"The id of the initial load."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connection_id":{"type":"string","format":"uuid"},"scope_assessment":{"type":"object","additionalProperties":true},"records_total":{"type":"integer","nullable":true},"storage_consumed_gb":{"type":"number"},"progress_log":{"type":"object","additionalProperties":true}}},"example":{"connection_id":"00000000-0000-0000-0000-000000000000","scope_assessment":{},"records_total":0,"storage_consumed_gb":0,"progress_log":{}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid"},"scope_assessment":{"type":"object","additionalProperties":true},"approved_by":{"type":"string","nullable":true},"approved_at":{"type":"string","nullable":true},"status":{"type":"string"},"records_loaded":{"type":"integer"},"records_total":{"type":"integer","nullable":true},"storage_consumed_gb":{"type":"number"},"load_started_at":{"type":"string","nullable":true},"load_completed_at":{"type":"string","nullable":true},"load_duration_ms":{"type":"integer","nullable":true},"progress_log":{"type":"object","additionalProperties":true},"error_log":{"type":"object","additionalProperties":true,"nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","connection_id","scope_assessment"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","scope_assessment":{},"approved_by":"string","approved_at":"string","status":"string","records_loaded":0,"records_total":0,"storage_consumed_gb":0,"load_started_at":"string","load_completed_at":"string","load_duration_ms":0,"progress_log":{},"error_log":{},"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/initial-loads/{id}/approve":{"post":{"operationId":"ApproveInitialLoad","tags":["operations"],"summary":"Approve Initial Load","security":[{"ApiKeyAuth":["initial-loads:write"]},{"BearerAuth":[]},{"OAuth2":["initial-loads:write"]}],"description":"Approve an initial load, the first full copy of a connected system’s existing records. Within about a minute Inferrex runs a full first sync for every active pipeline that reads from that system, and the load shows how many records arrived once they finish. If no active pipeline reads from the system, the load fails with that reason.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the initial load."},"description":"The id of the initial load."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","description":"The status the load moved to. Known values: approved, paused, cancelled."},"approved_by":{"type":"string","nullable":true,"description":"The approving member (workspace user id); null until approved, and null when approved by an API key or a platform admin."},"approved_at":{"type":"string","nullable":true}},"required":["id","status"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string","approved_by":"string","approved_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/initial-loads/{id}/cancel":{"post":{"operationId":"CancelInitialLoad","tags":["operations"],"summary":"Cancel Initial Load","security":[{"ApiKeyAuth":["initial-loads:write"]},{"BearerAuth":[]},{"OAuth2":["initial-loads:write"]}],"description":"Cancel an initial load. This is final: a cancelled load cannot be resumed. Syncs it has already started are not stopped.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the initial load."},"description":"The id of the initial load."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","description":"The status the load moved to. Known values: approved, paused, cancelled."},"approved_by":{"type":"string","nullable":true,"description":"The approving member (workspace user id); null until approved, and null when approved by an API key or a platform admin."},"approved_at":{"type":"string","nullable":true}},"required":["id","status"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string","approved_by":"string","approved_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/initial-loads/{id}/pause":{"post":{"operationId":"PauseInitialLoad","tags":["operations"],"summary":"Pause Initial Load","security":[{"ApiKeyAuth":["initial-loads:write"]},{"BearerAuth":[]},{"OAuth2":["initial-loads:write"]}],"description":"Pause an initial load. Syncs it has already started are not stopped.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the initial load."},"description":"The id of the initial load."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","description":"The status the load moved to. Known values: approved, paused, cancelled."},"approved_by":{"type":"string","nullable":true,"description":"The approving member (workspace user id); null until approved, and null when approved by an API key or a platform admin."},"approved_at":{"type":"string","nullable":true}},"required":["id","status"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string","approved_by":"string","approved_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/consolidation":{"get":{"operationId":"GetConsolidation","tags":["intelligence"],"summary":"Get Consolidation","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"Systems that overlap enough that you might be able to combine them, based on the latest comparison of your systems. Run the stack map first to bring the comparison up to date.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"customerId":{"type":"string"},"recommendations":{"type":"array","items":{"type":"object","properties":{"entityType":{"type":"string"},"affectedProviders":{"type":"array","items":{"type":"string"}},"recommendedAction":{"type":"string"},"priority":{"type":"string","enum":["high","medium","low"]},"actionSteps":{"type":"array","items":{"type":"string"}}},"required":["entityType","affectedProviders","recommendedAction","priority","actionSteps"]}},"generatedAt":{"type":"string","format":"date-time"}},"required":["customerId","recommendations","generatedAt"]},"example":{"customerId":"string","recommendations":[{"entityType":"string","affectedProviders":["string"],"recommendedAction":"string","priority":"high","actionSteps":["string"]}],"generatedAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/dark-data-report":{"get":{"operationId":"GetDarkDataReport","tags":["intelligence"],"summary":"Get Dark Data Report","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"Recommendations for data that is not being used: records that nothing has touched for a long time, or that no pipeline uses. For each group, Inferrex suggests whether to archive it, delete it or start using it again.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"customerId":{"type":"string"},"recommendations":{"type":"array","items":{"type":"object","properties":{"recordId":{"type":"string"},"providerKey":{"type":"string"},"entityType":{"type":"string"},"bucket":{"type":"string","enum":["dark","orphaned"]},"recommendedAction":{"type":"string","enum":["archive","delete","re-activate"]},"daysSinceModified":{"type":"integer"}},"required":["recordId","providerKey","entityType","bucket","recommendedAction","daysSinceModified"]}},"generatedAt":{"type":"string","format":"date-time"}},"required":["customerId","recommendations","generatedAt"]},"example":{"customerId":"string","recommendations":[{"recordId":"string","providerKey":"string","entityType":"string","bucket":"dark","recommendedAction":"archive","daysSinceModified":0}],"generatedAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/dashboard":{"get":{"operationId":"GetIntelligenceDashboard","tags":["intelligence"],"summary":"Get Intelligence Dashboard","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"Everything on the insights dashboard in one call: how valuable and complete the data in each pipeline is (including how much looks wasted and what it may cost to keep), partner services that could fill gaps in your data, and your daily usage. You can narrow it to one pipeline.","parameters":[{"name":"pipelineId","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only show figures for this pipeline."},"description":"Only show figures for this pipeline."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"description":"How many days of usage to include: 1 to 100, 30 if you leave it out.","default":30},"description":"How many days of usage to include: 1 to 100, 30 if you leave it out."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"entityValueProfiles":{"type":"array","items":{"type":"object","properties":{"entity_type":{"type":"string"},"pipeline_id":{"type":"string"},"total_records":{"type":"number"},"high_value_count":{"type":"number"},"low_value_count":{"type":"number"},"duplicate_count":{"type":"number"},"incomplete_count":{"type":"number"},"waste_count":{"type":"number"},"completeness_score":{"type":"number","nullable":true},"freshness_score":{"type":"number","nullable":true},"estimated_waste_gb":{"type":"number","nullable":true},"estimated_waste_cost_gbp":{"type":"number","nullable":true},"analysed_at":{"type":"string"}},"required":["entity_type","pipeline_id","total_records","high_value_count","low_value_count","duplicate_count","incomplete_count","waste_count","completeness_score","freshness_score","estimated_waste_gb","estimated_waste_cost_gbp","analysed_at"]}},"partnerSuggestionsEnabled":{"type":"boolean","description":"Whether partner suggestions are offered to this workspace. When false, partnerOpportunities is empty and no partner section should be shown."},"partnerOpportunities":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"gap_type":{"type":"string"},"coverage_score":{"type":"number"},"affected_record_count":{"type":"number","nullable":true},"gap_description":{"type":"string"},"status":{"type":"string","enum":["surfaced","viewed","accepted","dismissed"]},"surfaced_at":{"type":"string"},"actioned_at":{"type":"string","nullable":true},"referral_id":{"type":"string","nullable":true},"partner_name":{"type":"string"},"partner_key":{"type":"string"},"capability":{"type":"string"},"referral_model":{"type":"string"}},"required":["id","gap_type","coverage_score","affected_record_count","gap_description","status","surfaced_at","actioned_at","referral_id","partner_name","partner_key","capability","referral_model"]}},"usageMeters":{"type":"array","items":{"type":"object","properties":{"meter_date":{"type":"string"},"record_count":{"type":"number"},"storage_gb":{"type":"number"},"sync_operations":{"type":"number"},"inference_count":{"type":"number"},"archival_compliance_gb":{"type":"number"},"archival_elective_gb":{"type":"number"},"archival_warm_gb":{"type":"number"}},"required":["meter_date","record_count","storage_gb","sync_operations","inference_count","archival_compliance_gb","archival_elective_gb","archival_warm_gb"]}}},"required":["entityValueProfiles","partnerSuggestionsEnabled","partnerOpportunities","usageMeters"]},"example":{"entityValueProfiles":[{"entity_type":"string","pipeline_id":"string","total_records":0,"high_value_count":0,"low_value_count":0,"duplicate_count":0,"incomplete_count":0,"waste_count":0,"completeness_score":0,"freshness_score":0,"estimated_waste_gb":0,"estimated_waste_cost_gbp":0,"analysed_at":"string"}],"partnerSuggestionsEnabled":true,"partnerOpportunities":[{"id":"string","gap_type":"string","coverage_score":0,"affected_record_count":0,"gap_description":"string","status":"surfaced","surfaced_at":"string","actioned_at":"string","referral_id":"string","partner_name":"string","partner_key":"string","capability":"string","referral_model":"string"}],"usageMeters":[{"meter_date":"string","record_count":0,"storage_gb":0,"sync_operations":0,"inference_count":0,"archival_compliance_gb":0,"archival_elective_gb":0,"archival_warm_gb":0}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/data-model":{"get":{"operationId":"GetDataModel","tags":["intelligence"],"summary":"Get Data Model","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"One combined picture of your data across every connected system: the kinds of record, their fields and how they relate, built from what Inferrex learned about each system and how they map to each other.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"entities":{"type":"array","items":{"type":"object","properties":{"entityName":{"type":"string"},"providerKey":{"type":"string"},"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"dataType":{"type":"string"}},"required":["name","dataType"]}}},"required":["entityName","providerKey","fields"]}},"relationships":{"type":"array","items":{"type":"object","properties":{"sourceEntity":{"type":"string"},"targetEntity":{"type":"string"},"relationshipType":{"type":"string","enum":["one-to-one","one-to-many","many-to-many"]},"cardinality":{"type":"string"}},"required":["sourceEntity","targetEntity","relationshipType","cardinality"]}},"crossProviderMappings":{"type":"array","items":{"type":"object","properties":{"sourceProvider":{"type":"string"},"sourceField":{"type":"string"},"targetProvider":{"type":"string"},"targetField":{"type":"string"},"confidence":{"type":"number"}},"required":["sourceProvider","sourceField","targetProvider","targetField","confidence"]}},"partialFailures":{"type":"array","items":{"type":"object","properties":{"providerKey":{"type":"string"},"reason":{"type":"string"}},"required":["providerKey","reason"]}}},"required":["entities","relationships","crossProviderMappings","partialFailures"]},"example":{"entities":[{"entityName":"string","providerKey":"string","fields":[{"name":"string","dataType":"string"}]}],"relationships":[{"sourceEntity":"string","targetEntity":"string","relationshipType":"one-to-one","cardinality":"string"}],"crossProviderMappings":[{"sourceProvider":"string","sourceField":"string","targetProvider":"string","targetField":"string","confidence":0}],"partialFailures":[{"providerKey":"string","reason":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/data-utilisation":{"get":{"operationId":"DataUtilisationAnalysisList","tags":["intelligence"],"summary":"Data Utilisation Analysis List","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"List your data utilisation analyses, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"provider_key","in":"query","required":false,"schema":{"type":"string","description":"Only data utilisation analyses whose provider key is exactly this."},"description":"Only data utilisation analyses whose provider key is exactly this."},{"name":"provider_key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only data utilisation analyses whose provider key contains this text (upper and lower case are treated the same)."},"description":"Only data utilisation analyses whose provider key contains this text (upper and lower case are treated the same)."},{"name":"vendor_key","in":"query","required":false,"schema":{"type":"string","description":"Only data utilisation analyses whose vendor key is exactly this."},"description":"Only data utilisation analyses whose vendor key is exactly this."},{"name":"vendor_key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only data utilisation analyses whose vendor key contains this text (upper and lower case are treated the same)."},"description":"Only data utilisation analyses whose vendor key contains this text (upper and lower case are treated the same)."},{"name":"service_key","in":"query","required":false,"schema":{"type":"string","description":"Only data utilisation analyses whose service key is exactly this."},"description":"Only data utilisation analyses whose service key is exactly this."},{"name":"service_key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only data utilisation analyses whose service key contains this text (upper and lower case are treated the same)."},"description":"Only data utilisation analyses whose service key contains this text (upper and lower case are treated the same)."},{"name":"entity_type","in":"query","required":false,"schema":{"type":"string","description":"Only data utilisation analyses whose entity type is exactly this."},"description":"Only data utilisation analyses whose entity type is exactly this."},{"name":"entity_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only data utilisation analyses whose entity type contains this text (upper and lower case are treated the same)."},"description":"Only data utilisation analyses whose entity type contains this text (upper and lower case are treated the same)."},{"name":"bucket","in":"query","required":false,"schema":{"type":"string","description":"Only data utilisation analyses whose bucket is exactly this."},"description":"Only data utilisation analyses whose bucket is exactly this."},{"name":"bucket_contains","in":"query","required":false,"schema":{"type":"string","description":"Only data utilisation analyses whose bucket contains this text (upper and lower case are treated the same)."},"description":"Only data utilisation analyses whose bucket contains this text (upper and lower case are treated the same)."},{"name":"record_count_gte","in":"query","required":false,"schema":{"type":"number","description":"Only data utilisation analyses whose record count is this number or more."},"description":"Only data utilisation analyses whose record count is this number or more."},{"name":"record_count_lte","in":"query","required":false,"schema":{"type":"number","description":"Only data utilisation analyses whose record count is this number or less."},"description":"Only data utilisation analyses whose record count is this number or less."},{"name":"percentage_gte","in":"query","required":false,"schema":{"type":"number","description":"Only data utilisation analyses whose percentage is this number or more."},"description":"Only data utilisation analyses whose percentage is this number or more."},{"name":"percentage_lte","in":"query","required":false,"schema":{"type":"number","description":"Only data utilisation analyses whose percentage is this number or less."},"description":"Only data utilisation analyses whose percentage is this number or less."},{"name":"computed_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only data utilisation analyses whose computed time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only data utilisation analyses whose computed time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"computed_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only data utilisation analyses whose computed time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only data utilisation analyses whose computed time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many data utilisation analyses to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many data utilisation analyses to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many data utilisation analyses to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many data utilisation analyses to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","provider_key","vendor_key","service_key","entity_type","bucket","record_count","percentage","computed_at"],"description":"The field to sort the list by.","default":"computed_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns data utilisation analyses where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns data utilisation analyses where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"provider_key":{"type":"string"},"vendor_key":{"type":"string","nullable":true},"service_key":{"type":"string","nullable":true},"entity_type":{"type":"string"},"bucket":{"type":"string","description":"How actively these records are used. Active: changed in the last 30 days and mostly filled in. Dormant: unchanged for 90 days. Dark: unchanged for 180 days and used by no pipeline. Orphaned: no active pipeline uses them. Stale: everything else."},"record_count":{"type":"integer"},"percentage":{"type":"number","description":"The share of this system’s records of this kind that fall in this group."},"computed_at":{"type":"string"}},"required":["customer_id","provider_key","entity_type","bucket"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","provider_key":"string","vendor_key":"string","service_key":"string","entity_type":"string","bucket":"string","record_count":0,"percentage":0,"computed_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/data-utilisation/{id}":{"get":{"operationId":"DataUtilisationAnalysisGet","tags":["intelligence"],"summary":"Data Utilisation Analysis Get","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"Get one of your data utilisation analyses by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the data utilisation analysis."},"description":"The id of the data utilisation analysis."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"provider_key":{"type":"string"},"vendor_key":{"type":"string","nullable":true},"service_key":{"type":"string","nullable":true},"entity_type":{"type":"string"},"bucket":{"type":"string","description":"How actively these records are used. Active: changed in the last 30 days and mostly filled in. Dormant: unchanged for 90 days. Dark: unchanged for 180 days and used by no pipeline. Orphaned: no active pipeline uses them. Stale: everything else."},"record_count":{"type":"integer"},"percentage":{"type":"number","description":"The share of this system’s records of this kind that fall in this group."},"computed_at":{"type":"string"}},"required":["customer_id","provider_key","entity_type","bucket"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","provider_key":"string","vendor_key":"string","service_key":"string","entity_type":"string","bucket":"string","record_count":0,"percentage":0,"computed_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/enrichment-opportunities":{"get":{"operationId":"GetEnrichmentOpportunities","tags":["intelligence"],"summary":"Get Enrichment Opportunities","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"For one kind of record, the fields that are often empty and the other connected systems that could fill them in.","parameters":[{"name":"entityType","in":"query","required":true,"schema":{"type":"string","description":"The kind of record to check, such as contact."},"description":"The kind of record to check, such as contact."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"customerId":{"type":"string"},"entityType":{"type":"string"},"opportunities":{"type":"array","items":{"type":"object","properties":{"fieldName":{"type":"string"},"recordsAffected":{"type":"integer"},"sourceProvider":{"type":"string"},"confidence":{"type":"number"},"classification":{"type":"string","enum":["auto-enrichable","review-required","low-confidence"]}},"required":["fieldName","recordsAffected","sourceProvider","confidence","classification"]}}},"required":["customerId","entityType","opportunities"]},"example":{"customerId":"string","entityType":"string","opportunities":[{"fieldName":"string","recordsAffected":0,"sourceProvider":"string","confidence":0,"classification":"auto-enrichable"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/insights":{"get":{"operationId":"ListStackInsights","tags":["intelligence"],"summary":"List Stack Insights","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"Insights from how your data actually flows: systems that receive only a subset of what another already gets from the same source (so one may be redundant), and tools whose job Inferrex already does for you. Each insight names the fields, destinations and mapping that show it. Systems that are not yet receiving data are compared on their data shapes instead. A system is also said to duplicate another when your golden records show that nearly everything it holds is a copy of the other, that it adds no record or field, and that both are the same kind of system; each such finding gives its counts and how sure it is (certain, high or possible). Nothing is ever acted on automatically: a system with little traffic is only flagged, since it may be an archive or a disaster-recovery copy. Insights are private to your workspace, and one you dismiss stays dismissed. The list gives the insights still to decide first, then the ones you marked to act on or dismissed, each with its status and, when dismissed, the reason you gave.","parameters":[{"name":"windowDays","in":"query","required":false,"schema":{"type":"integer","description":"How many past days of data flow to look at: 30 if you leave it out, at most 365."},"description":"How many past days of data flow to look at: 30 if you leave it out, at most 365."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"customerId":{"type":"string"},"insights":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"family":{"type":"string"},"basis":{"type":"string"},"fingerprint":{"type":"string"},"title":{"type":"string"},"rationale":{"type":"string"},"impact":{"type":"string","nullable":true},"low_traffic":{"type":"boolean"},"evidence":{"type":"object","additionalProperties":true},"status":{"type":"string"},"dismissed_reason":{"type":"string","nullable":true},"window_days":{"type":"integer"},"first_seen_at":{"type":"string","format":"date-time"},"computed_at":{"type":"string","format":"date-time"},"actioned_at":{"type":"string","format":"date-time","nullable":true}},"required":["id","family","basis","fingerprint","title","rationale","low_traffic","evidence","status","window_days","first_seen_at","computed_at"]}},"candidateCount":{"type":"integer"},"windowDays":{"type":"integer"},"computedAt":{"type":"string","format":"date-time"}},"required":["customerId","insights","candidateCount","windowDays","computedAt"]},"example":{"customerId":"string","insights":[{"id":"00000000-0000-0000-0000-000000000000","family":"string","basis":"string","fingerprint":"string","title":"string","rationale":"string","impact":"string","low_traffic":true,"evidence":{},"status":"string","dismissed_reason":"string","window_days":0,"first_seen_at":"2026-01-01T00:00:00Z","computed_at":"2026-01-01T00:00:00Z","actioned_at":"2026-01-01T00:00:00Z"}],"candidateCount":0,"windowDays":0,"computedAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/insights/{insightId}/accept":{"post":{"operationId":"AcceptStackInsight","tags":["intelligence"],"summary":"Accept Stack Insight","security":[{"ApiKeyAuth":["intelligence:write"]},{"BearerAuth":[]},{"OAuth2":["intelligence:write"]}],"description":"Accept an insight, to say “yes, this is worth acting on”. It is marked accepted and helps Inferrex make better suggestions for you. Accepting does not change anything itself: retiring a system or cancelling a tool is still your decision to carry out.","parameters":[{"name":"insightId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the insight."},"description":"The id of the insight."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"}},"required":["id","status"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/insights/{insightId}/dismiss":{"post":{"operationId":"DismissStackInsight","tags":["intelligence"],"summary":"Dismiss Stack Insight","security":[{"ApiKeyAuth":["intelligence:write"]},{"BearerAuth":[]},{"OAuth2":["intelligence:write"]}],"description":"Dismiss an insight, with a reason (for example “this is our disaster-recovery copy” or “the overlap is intended”). It stays dismissed when insights are recalculated, and your reason helps Inferrex make better suggestions. Your reason stays private to your workspace.","parameters":[{"name":"insightId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the insight."},"description":"The id of the insight."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maximum":2000,"description":"Why this does not apply to you. Required."}},"required":["reason"]},"example":{"reason":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"}},"required":["id","status"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/migrations":{"get":{"operationId":"MigrationsList","tags":["migration"],"summary":"Migrations List","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"List your migrations, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"source_provider_key","in":"query","required":false,"schema":{"type":"string","description":"Only migrations whose source provider key is exactly this."},"description":"Only migrations whose source provider key is exactly this."},{"name":"source_provider_key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only migrations whose source provider key contains this text (upper and lower case are treated the same)."},"description":"Only migrations whose source provider key contains this text (upper and lower case are treated the same)."},{"name":"destination_provider_key","in":"query","required":false,"schema":{"type":"string","description":"Only migrations whose destination provider key is exactly this."},"description":"Only migrations whose destination provider key is exactly this."},{"name":"destination_provider_key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only migrations whose destination provider key contains this text (upper and lower case are treated the same)."},"description":"Only migrations whose destination provider key contains this text (upper and lower case are treated the same)."},{"name":"source_connection_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only migrations for this source connection. Pass its id."},"description":"Only migrations for this source connection. Pass its id."},{"name":"destination_connection_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only migrations for this destination connection. Pass its id."},"description":"Only migrations for this destination connection. Pass its id."},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Only migrations whose status is exactly this."},"description":"Only migrations whose status is exactly this."},{"name":"status_contains","in":"query","required":false,"schema":{"type":"string","description":"Only migrations whose status contains this text (upper and lower case are treated the same)."},"description":"Only migrations whose status contains this text (upper and lower case are treated the same)."},{"name":"migration_completeness_score_gte","in":"query","required":false,"schema":{"type":"number","description":"Only migrations whose migration completeness score is this number or more."},"description":"Only migrations whose migration completeness score is this number or more."},{"name":"migration_completeness_score_lte","in":"query","required":false,"schema":{"type":"number","description":"Only migrations whose migration completeness score is this number or less."},"description":"Only migrations whose migration completeness score is this number or less."},{"name":"estimated_record_count_gte","in":"query","required":false,"schema":{"type":"number","description":"Only migrations whose estimated record count is this number or more."},"description":"Only migrations whose estimated record count is this number or more."},{"name":"estimated_record_count_lte","in":"query","required":false,"schema":{"type":"number","description":"Only migrations whose estimated record count is this number or less."},"description":"Only migrations whose estimated record count is this number or less."},{"name":"estimated_duration_seconds_gte","in":"query","required":false,"schema":{"type":"number","description":"Only migrations whose estimated duration seconds is this number or more."},"description":"Only migrations whose estimated duration seconds is this number or more."},{"name":"estimated_duration_seconds_lte","in":"query","required":false,"schema":{"type":"number","description":"Only migrations whose estimated duration seconds is this number or less."},"description":"Only migrations whose estimated duration seconds is this number or less."},{"name":"rollback_feasibility","in":"query","required":false,"schema":{"type":"string","description":"Only migrations whose rollback feasibility is exactly this."},"description":"Only migrations whose rollback feasibility is exactly this."},{"name":"rollback_feasibility_contains","in":"query","required":false,"schema":{"type":"string","description":"Only migrations whose rollback feasibility contains this text (upper and lower case are treated the same)."},"description":"Only migrations whose rollback feasibility contains this text (upper and lower case are treated the same)."},{"name":"records_processed_gte","in":"query","required":false,"schema":{"type":"number","description":"Only migrations whose records processed is this number or more."},"description":"Only migrations whose records processed is this number or more."},{"name":"records_processed_lte","in":"query","required":false,"schema":{"type":"number","description":"Only migrations whose records processed is this number or less."},"description":"Only migrations whose records processed is this number or less."},{"name":"records_failed_gte","in":"query","required":false,"schema":{"type":"number","description":"Only migrations whose records failed is this number or more."},"description":"Only migrations whose records failed is this number or more."},{"name":"records_failed_lte","in":"query","required":false,"schema":{"type":"number","description":"Only migrations whose records failed is this number or less."},"description":"Only migrations whose records failed is this number or less."},{"name":"started_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only migrations whose started time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only migrations whose started time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"started_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only migrations whose started time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only migrations whose started time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"completed_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only migrations whose completed time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only migrations whose completed time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"completed_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only migrations whose completed time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only migrations whose completed time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"cancelled_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only migrations whose cancelled time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only migrations whose cancelled time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"cancelled_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only migrations whose cancelled time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only migrations whose cancelled time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"failure_reason","in":"query","required":false,"schema":{"type":"string","description":"Only migrations whose failure reason is exactly this."},"description":"Only migrations whose failure reason is exactly this."},{"name":"failure_reason_contains","in":"query","required":false,"schema":{"type":"string","description":"Only migrations whose failure reason contains this text (upper and lower case are treated the same)."},"description":"Only migrations whose failure reason contains this text (upper and lower case are treated the same)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many migrations to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many migrations to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many migrations to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many migrations to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","source_provider_key","destination_provider_key","source_connection_id","destination_connection_id","status","migration_completeness_score","estimated_record_count","estimated_duration_seconds","rollback_feasibility","records_processed","records_failed","started_at","completed_at","cancelled_at","failure_reason","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns migrations where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns migrations where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"source_provider_key":{"type":"string","nullable":true},"destination_provider_key":{"type":"string","nullable":true},"source_connection_id":{"type":"string","format":"uuid","nullable":true},"destination_connection_id":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string"},"field_mappings":{"type":"object","additionalProperties":true},"migration_completeness_score":{"type":"number","nullable":true},"estimated_record_count":{"type":"integer","nullable":true},"estimated_duration_seconds":{"type":"integer","nullable":true},"rollback_feasibility":{"type":"string","nullable":true},"records_processed":{"type":"integer"},"records_failed":{"type":"integer"},"verification_report":{"type":"object","additionalProperties":true,"nullable":true},"started_at":{"type":"string","nullable":true},"completed_at":{"type":"string","nullable":true},"cancelled_at":{"type":"string","nullable":true},"failure_reason":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","source_provider_key":"string","destination_provider_key":"string","source_connection_id":"00000000-0000-0000-0000-000000000000","destination_connection_id":"00000000-0000-0000-0000-000000000000","status":"string","field_mappings":{},"migration_completeness_score":0,"estimated_record_count":0,"estimated_duration_seconds":0,"rollback_feasibility":"string","records_processed":0,"records_failed":0,"verification_report":{},"started_at":"string","completed_at":"string","cancelled_at":"string","failure_reason":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/intelligence/migrations/{id}":{"get":{"operationId":"MigrationsGet","tags":["migration"],"summary":"Migrations Get","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"Get one of your migrations by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the migration."},"description":"The id of the migration."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"source_provider_key":{"type":"string","nullable":true},"destination_provider_key":{"type":"string","nullable":true},"source_connection_id":{"type":"string","format":"uuid","nullable":true},"destination_connection_id":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string"},"field_mappings":{"type":"object","additionalProperties":true},"migration_completeness_score":{"type":"number","nullable":true},"estimated_record_count":{"type":"integer","nullable":true},"estimated_duration_seconds":{"type":"integer","nullable":true},"rollback_feasibility":{"type":"string","nullable":true},"records_processed":{"type":"integer"},"records_failed":{"type":"integer"},"verification_report":{"type":"object","additionalProperties":true,"nullable":true},"started_at":{"type":"string","nullable":true},"completed_at":{"type":"string","nullable":true},"cancelled_at":{"type":"string","nullable":true},"failure_reason":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","source_provider_key":"string","destination_provider_key":"string","source_connection_id":"00000000-0000-0000-0000-000000000000","destination_connection_id":"00000000-0000-0000-0000-000000000000","status":"string","field_mappings":{},"migration_completeness_score":0,"estimated_record_count":0,"estimated_duration_seconds":0,"rollback_feasibility":"string","records_processed":0,"records_failed":0,"verification_report":{},"started_at":"string","completed_at":"string","cancelled_at":"string","failure_reason":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/intelligence/migrations/{id}/cancel":{"post":{"operationId":"CancelMigration","tags":["migration"],"summary":"Cancel Migration","security":[{"ApiKeyAuth":["intelligence:write"]},{"BearerAuth":[]},{"OAuth2":["intelligence:write"]}],"description":"Stop a migration that is still running (while it is pending, backing up, copying or checking). It stops within about ten seconds.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the migration."},"description":"The id of the migration."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"cancelled":{"type":"boolean"},"migrationId":{"type":"string","format":"uuid"}},"required":["cancelled","migrationId"]},"example":{"cancelled":true,"migrationId":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/intelligence/migrations/execute":{"post":{"operationId":"ExecuteMigration","tags":["migration"],"summary":"Execute Migration","security":[{"ApiKeyAuth":["intelligence:write"]},{"BearerAuth":[]},{"OAuth2":["intelligence:write"]}],"description":"Start moving data from one of your connected systems to another, each named by its connection id. Both are checked as for a migration preview, with the same refusals. Inferrex backs up the data, copies the records across in batches, then checks them. This runs in the background: the response gives the migration’s id, so you can follow its progress or cancel it.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sourceConnectionId":{"type":"string","format":"uuid","description":"The connected system records move FROM (a connection id)."},"destinationConnectionId":{"type":"string","format":"uuid","description":"The connected system records move INTO (a connection id)."}},"required":["sourceConnectionId","destinationConnectionId"]},"example":{"sourceConnectionId":"00000000-0000-0000-0000-000000000000","destinationConnectionId":"00000000-0000-0000-0000-000000000000"}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"migrationId":{"type":"string","format":"uuid"},"status":{"type":"string"}},"required":["migrationId","status"]},"example":{"migrationId":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/intelligence/migrations/preview":{"post":{"operationId":"PreviewMigration","tags":["migration"],"summary":"Preview Migration","security":[{"ApiKeyAuth":["intelligence:write"]},{"BearerAuth":[]},{"OAuth2":["intelligence:write"]}],"description":"Preview moving data from one of your connected systems to another before you do it: how the fields would map, what has no match, how complete the result would be, how risky the move is, and whether it could be rolled back. Name each system by its connection id (the id GET /v1/connections lists). A connection that is unknown or in another workspace (404), the same on both sides (400) or not approved yet (409) is refused with a message saying why.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sourceConnectionId":{"type":"string","format":"uuid","description":"The connected system records move FROM (a connection id)."},"destinationConnectionId":{"type":"string","format":"uuid","description":"The connected system records move INTO (a connection id)."}},"required":["sourceConnectionId","destinationConnectionId"]},"example":{"sourceConnectionId":"00000000-0000-0000-0000-000000000000","destinationConnectionId":"00000000-0000-0000-0000-000000000000"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"sourceConnectionId":{"type":"string","format":"uuid"},"destinationConnectionId":{"type":"string","format":"uuid"},"sourceName":{"type":"string"},"destinationName":{"type":"string"},"sourceProvider":{"type":"string","nullable":true},"destinationProvider":{"type":"string","nullable":true},"fieldMappings":{"type":"array","items":{"type":"object","properties":{"sourceField":{"type":"string"},"destinationField":{"type":"string","nullable":true},"category":{"type":"string","enum":["mapped","unmapped_source","unmapped_destination","type_mismatch"]},"confidence":{"type":"number"},"sourceType":{"type":"string"},"destinationType":{"type":"string","nullable":true}},"required":["sourceField","category","confidence","sourceType"]}},"migrationCompletenessScore":{"type":"number"},"riskLevel":{"type":"string","enum":["low","medium","high"]},"estimatedRecordCount":{"type":"integer"},"estimatedDurationSeconds":{"type":"integer"},"rollbackFeasibility":{"type":"string","enum":["full","partial","none"]}},"required":["sourceConnectionId","destinationConnectionId","sourceName","destinationName","sourceProvider","destinationProvider","fieldMappings","migrationCompletenessScore","riskLevel","estimatedRecordCount","estimatedDurationSeconds","rollbackFeasibility"]},"example":{"sourceConnectionId":"00000000-0000-0000-0000-000000000000","destinationConnectionId":"00000000-0000-0000-0000-000000000000","sourceName":"string","destinationName":"string","sourceProvider":"string","destinationProvider":"string","fieldMappings":[{"sourceField":"string","destinationField":"string","category":"mapped","confidence":0,"sourceType":"string","destinationType":"string"}],"migrationCompletenessScore":0,"riskLevel":"low","estimatedRecordCount":0,"estimatedDurationSeconds":0,"rollbackFeasibility":"full"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/intelligence/partners":{"get":{"operationId":"ListPartnerOpportunities","tags":["intelligence"],"summary":"List Partner Opportunities","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"Partner services that could fill gaps Inferrex has found in your data, best fit first: what is missing, how many records it affects, and which partner could help. `enabled` says whether partner suggestions are offered to your workspace; when it is false the list is empty.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether partner suggestions are offered to this workspace. When false the list is always empty and no partner section should be shown."},"partnerOpportunities":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"gap_type":{"type":"string"},"coverage_score":{"type":"number"},"affected_record_count":{"type":"number","nullable":true},"gap_description":{"type":"string"},"status":{"type":"string","enum":["surfaced","viewed","accepted","dismissed"]},"surfaced_at":{"type":"string"},"actioned_at":{"type":"string","nullable":true},"referral_id":{"type":"string","nullable":true},"partner_name":{"type":"string"},"partner_key":{"type":"string"},"capability":{"type":"string"},"referral_model":{"type":"string"}},"required":["id","gap_type","coverage_score","affected_record_count","gap_description","status","surfaced_at","actioned_at","referral_id","partner_name","partner_key","capability","referral_model"]}}},"required":["enabled","partnerOpportunities"]},"example":{"enabled":true,"partnerOpportunities":[{"id":"string","gap_type":"string","coverage_score":0,"affected_record_count":0,"gap_description":"string","status":"surfaced","surfaced_at":"string","actioned_at":"string","referral_id":"string","partner_name":"string","partner_key":"string","capability":"string","referral_model":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/partners/{opportunityId}/connect":{"post":{"operationId":"ConnectPartner","tags":["intelligence"],"summary":"Connect Partner","security":[{"ApiKeyAuth":["intelligence:write"]},{"BearerAuth":[]},{"OAuth2":["intelligence:write"]}],"description":"Say yes to a partner suggestion, to show you want to use that partner to fill the gap. Only a suggestion that has not been acted on yet can be accepted, and only while partner suggestions are offered to your workspace.","parameters":[{"name":"opportunityId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the partner suggestion."},"description":"The id of the partner suggestion."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"opportunity":{"type":"object","additionalProperties":true}},"required":["opportunity"]},"example":{"opportunity":{}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/schema-contracts":{"get":{"operationId":"SchemaContractsList","tags":["intelligence"],"summary":"Schema Contracts List","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"List your schema contracts, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"provider_key","in":"query","required":false,"schema":{"type":"string","description":"Only schema contracts whose provider key is exactly this."},"description":"Only schema contracts whose provider key is exactly this."},{"name":"provider_key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only schema contracts whose provider key contains this text (upper and lower case are treated the same)."},"description":"Only schema contracts whose provider key contains this text (upper and lower case are treated the same)."},{"name":"vendor_key","in":"query","required":false,"schema":{"type":"string","description":"Only schema contracts whose vendor key is exactly this."},"description":"Only schema contracts whose vendor key is exactly this."},{"name":"vendor_key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only schema contracts whose vendor key contains this text (upper and lower case are treated the same)."},"description":"Only schema contracts whose vendor key contains this text (upper and lower case are treated the same)."},{"name":"service_key","in":"query","required":false,"schema":{"type":"string","description":"Only schema contracts whose service key is exactly this."},"description":"Only schema contracts whose service key is exactly this."},{"name":"service_key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only schema contracts whose service key contains this text (upper and lower case are treated the same)."},"description":"Only schema contracts whose service key contains this text (upper and lower case are treated the same)."},{"name":"entity_type","in":"query","required":false,"schema":{"type":"string","description":"Only schema contracts whose entity type is exactly this."},"description":"Only schema contracts whose entity type is exactly this."},{"name":"entity_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only schema contracts whose entity type contains this text (upper and lower case are treated the same)."},"description":"Only schema contracts whose entity type contains this text (upper and lower case are treated the same)."},{"name":"drift_detected","in":"query","required":false,"schema":{"type":"boolean","description":"Only schema contracts where drift detected is true, or false for only those where it is false."},"description":"Only schema contracts where drift detected is true, or false for only those where it is false."},{"name":"detected_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only schema contracts whose detected time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only schema contracts whose detected time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"detected_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only schema contracts whose detected time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only schema contracts whose detected time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"acknowledged_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only schema contracts whose acknowledged time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only schema contracts whose acknowledged time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"acknowledged_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only schema contracts whose acknowledged time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only schema contracts whose acknowledged time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many schema contracts to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many schema contracts to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many schema contracts to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many schema contracts to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","provider_key","vendor_key","service_key","entity_type","drift_detected","detected_at","acknowledged_at","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns schema contracts where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns schema contracts where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"provider_key":{"type":"string"},"vendor_key":{"type":"string","nullable":true},"service_key":{"type":"string","nullable":true},"entity_type":{"type":"string"},"expected_schema":{"type":"object","additionalProperties":true},"actual_schema":{"type":"object","additionalProperties":true,"nullable":true},"drift_detected":{"type":"boolean"},"drift_details":{"type":"array","items":{"type":"object","properties":{"fieldName":{"type":"string"},"driftType":{"type":"string","enum":["field_added","field_removed","type_changed"]},"contractedType":{"type":"string","description":"The type the expected structure names; absent for an added field."},"observedType":{"type":"string","description":"The type seen in synced records; absent for a removed field."}},"required":["fieldName","driftType"]},"nullable":true,"description":"One entry per field that differs between the expected structure and the records synced. Null when nothing has drifted."},"detected_at":{"type":"string","nullable":true},"acknowledged_at":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","provider_key","entity_type","expected_schema"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","provider_key":"string","vendor_key":"string","service_key":"string","entity_type":"string","expected_schema":{},"actual_schema":{},"drift_detected":true,"drift_details":[{"fieldName":"string","driftType":"field_added","contractedType":"string","observedType":"string"}],"detected_at":"string","acknowledged_at":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"SchemaContractsCreate","tags":["intelligence"],"summary":"Schema Contracts Create","security":[{"ApiKeyAuth":["intelligence:write"]},{"BearerAuth":[]},{"OAuth2":["intelligence:write"]}],"description":"Create a schema contract. Returns the new schema contract, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"provider_key":{"type":"string"},"vendor_key":{"type":"string","nullable":true},"service_key":{"type":"string","nullable":true},"entity_type":{"type":"string"},"expected_schema":{"type":"object","additionalProperties":true},"actual_schema":{"type":"object","additionalProperties":true,"nullable":true},"drift_detected":{"type":"boolean"},"drift_details":{"type":"object","additionalProperties":true,"nullable":true},"detected_at":{"type":"string","nullable":true},"acknowledged_at":{"type":"string","nullable":true}},"required":["provider_key","entity_type","expected_schema"]},"example":{"provider_key":"string","vendor_key":"string","service_key":"string","entity_type":"string","expected_schema":{},"actual_schema":{},"drift_detected":true,"drift_details":{},"detected_at":"string","acknowledged_at":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"provider_key":{"type":"string"},"vendor_key":{"type":"string","nullable":true},"service_key":{"type":"string","nullable":true},"entity_type":{"type":"string"},"expected_schema":{"type":"object","additionalProperties":true},"actual_schema":{"type":"object","additionalProperties":true,"nullable":true},"drift_detected":{"type":"boolean"},"drift_details":{"type":"array","items":{"type":"object","properties":{"fieldName":{"type":"string"},"driftType":{"type":"string","enum":["field_added","field_removed","type_changed"]},"contractedType":{"type":"string","description":"The type the expected structure names; absent for an added field."},"observedType":{"type":"string","description":"The type seen in synced records; absent for a removed field."}},"required":["fieldName","driftType"]},"nullable":true,"description":"One entry per field that differs between the expected structure and the records synced. Null when nothing has drifted."},"detected_at":{"type":"string","nullable":true},"acknowledged_at":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","provider_key","entity_type","expected_schema"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","provider_key":"string","vendor_key":"string","service_key":"string","entity_type":"string","expected_schema":{},"actual_schema":{},"drift_detected":true,"drift_details":[{"fieldName":"string","driftType":"field_added","contractedType":"string","observedType":"string"}],"detected_at":"string","acknowledged_at":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/schema-contracts/{id}":{"delete":{"operationId":"SchemaContractsDelete","tags":["intelligence"],"summary":"Schema Contracts Delete","security":[{"ApiKeyAuth":["intelligence:delete"]},{"BearerAuth":[]},{"OAuth2":["intelligence:delete"]}],"description":"Delete a schema contract permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the schema contract."},"description":"The id of the schema contract."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"SchemaContractsGet","tags":["intelligence"],"summary":"Schema Contracts Get","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"Get one of your schema contracts by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the schema contract."},"description":"The id of the schema contract."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"provider_key":{"type":"string"},"vendor_key":{"type":"string","nullable":true},"service_key":{"type":"string","nullable":true},"entity_type":{"type":"string"},"expected_schema":{"type":"object","additionalProperties":true},"actual_schema":{"type":"object","additionalProperties":true,"nullable":true},"drift_detected":{"type":"boolean"},"drift_details":{"type":"array","items":{"type":"object","properties":{"fieldName":{"type":"string"},"driftType":{"type":"string","enum":["field_added","field_removed","type_changed"]},"contractedType":{"type":"string","description":"The type the expected structure names; absent for an added field."},"observedType":{"type":"string","description":"The type seen in synced records; absent for a removed field."}},"required":["fieldName","driftType"]},"nullable":true,"description":"One entry per field that differs between the expected structure and the records synced. Null when nothing has drifted."},"detected_at":{"type":"string","nullable":true},"acknowledged_at":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","provider_key","entity_type","expected_schema"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","provider_key":"string","vendor_key":"string","service_key":"string","entity_type":"string","expected_schema":{},"actual_schema":{},"drift_detected":true,"drift_details":[{"fieldName":"string","driftType":"field_added","contractedType":"string","observedType":"string"}],"detected_at":"string","acknowledged_at":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"SchemaContractsUpdate","tags":["intelligence"],"summary":"Schema Contracts Update","security":[{"ApiKeyAuth":["intelligence:write"]},{"BearerAuth":[]},{"OAuth2":["intelligence:write"]}],"description":"Change a schema contract. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the schema contract."},"description":"The id of the schema contract."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"provider_key":{"type":"string"},"vendor_key":{"type":"string","nullable":true},"service_key":{"type":"string","nullable":true},"entity_type":{"type":"string"},"expected_schema":{"type":"object","additionalProperties":true},"actual_schema":{"type":"object","additionalProperties":true,"nullable":true},"drift_detected":{"type":"boolean"},"drift_details":{"type":"object","additionalProperties":true,"nullable":true},"detected_at":{"type":"string","nullable":true},"acknowledged_at":{"type":"string","nullable":true}}},"example":{"provider_key":"string","vendor_key":"string","service_key":"string","entity_type":"string","expected_schema":{},"actual_schema":{},"drift_detected":true,"drift_details":{},"detected_at":"string","acknowledged_at":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"provider_key":{"type":"string"},"vendor_key":{"type":"string","nullable":true},"service_key":{"type":"string","nullable":true},"entity_type":{"type":"string"},"expected_schema":{"type":"object","additionalProperties":true},"actual_schema":{"type":"object","additionalProperties":true,"nullable":true},"drift_detected":{"type":"boolean"},"drift_details":{"type":"array","items":{"type":"object","properties":{"fieldName":{"type":"string"},"driftType":{"type":"string","enum":["field_added","field_removed","type_changed"]},"contractedType":{"type":"string","description":"The type the expected structure names; absent for an added field."},"observedType":{"type":"string","description":"The type seen in synced records; absent for a removed field."}},"required":["fieldName","driftType"]},"nullable":true,"description":"One entry per field that differs between the expected structure and the records synced. Null when nothing has drifted."},"detected_at":{"type":"string","nullable":true},"acknowledged_at":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","provider_key","entity_type","expected_schema"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","provider_key":"string","vendor_key":"string","service_key":"string","entity_type":"string","expected_schema":{},"actual_schema":{},"drift_detected":true,"drift_details":[{"fieldName":"string","driftType":"field_added","contractedType":"string","observedType":"string"}],"detected_at":"string","acknowledged_at":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/schema-contracts/{id}/acknowledge-drift":{"post":{"operationId":"AcknowledgeDrift","tags":["intelligence"],"summary":"Acknowledge Drift","security":[{"ApiKeyAuth":["intelligence:write"]},{"BearerAuth":[]},{"OAuth2":["intelligence:write"]}],"description":"Accept a change in a connected system’s data shape. The shape Inferrex now sees becomes the expected one, the drift warning is cleared, and the time you accepted it is recorded.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the schema contract."},"description":"The id of the schema contract."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"acknowledged":{"type":"boolean"},"contractId":{"type":"string","format":"uuid"}},"required":["acknowledged","contractId"]},"example":{"acknowledged":true,"contractId":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/stack-analysis":{"get":{"operationId":"StackAnalysisList","tags":["intelligence"],"summary":"Stack Analysis List","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"List your stack analyses, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"provider_a","in":"query","required":false,"schema":{"type":"string","description":"Only stack analyses whose provider a is exactly this."},"description":"Only stack analyses whose provider a is exactly this."},{"name":"provider_a_contains","in":"query","required":false,"schema":{"type":"string","description":"Only stack analyses whose provider a contains this text (upper and lower case are treated the same)."},"description":"Only stack analyses whose provider a contains this text (upper and lower case are treated the same)."},{"name":"provider_b","in":"query","required":false,"schema":{"type":"string","description":"Only stack analyses whose provider b is exactly this."},"description":"Only stack analyses whose provider b is exactly this."},{"name":"provider_b_contains","in":"query","required":false,"schema":{"type":"string","description":"Only stack analyses whose provider b contains this text (upper and lower case are treated the same)."},"description":"Only stack analyses whose provider b contains this text (upper and lower case are treated the same)."},{"name":"total_entity_types_gte","in":"query","required":false,"schema":{"type":"number","description":"Only stack analyses whose total entity types is this number or more."},"description":"Only stack analyses whose total entity types is this number or more."},{"name":"total_entity_types_lte","in":"query","required":false,"schema":{"type":"number","description":"Only stack analyses whose total entity types is this number or less."},"description":"Only stack analyses whose total entity types is this number or less."},{"name":"overlap_score_gte","in":"query","required":false,"schema":{"type":"number","description":"Only stack analyses whose overlap score is this number or more."},"description":"Only stack analyses whose overlap score is this number or more."},{"name":"overlap_score_lte","in":"query","required":false,"schema":{"type":"number","description":"Only stack analyses whose overlap score is this number or less."},"description":"Only stack analyses whose overlap score is this number or less."},{"name":"computed_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only stack analyses whose computed time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only stack analyses whose computed time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"computed_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only stack analyses whose computed time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only stack analyses whose computed time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many stack analyses to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many stack analyses to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many stack analyses to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many stack analyses to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","provider_a","provider_b","total_entity_types","overlap_score","computed_at"],"description":"The field to sort the list by.","default":"computed_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns stack analyses where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns stack analyses where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"provider_a":{"type":"string","description":"First provider in the compared pair."},"provider_b":{"type":"string","description":"Second provider in the compared pair."},"shared_entity_types":{"type":"object","additionalProperties":true},"total_entity_types":{"type":"integer"},"overlap_score":{"type":"number","description":"How much the kinds of record the two systems hold overlap: 0 means nothing in common, 1 means exactly the same."},"computed_at":{"type":"string"}},"required":["customer_id","provider_a","provider_b"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","provider_a":"string","provider_b":"string","shared_entity_types":{},"total_entity_types":0,"overlap_score":0,"computed_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/stack-analysis/{id}":{"get":{"operationId":"StackAnalysisGet","tags":["intelligence"],"summary":"Stack Analysis Get","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"Get one of your stack analyses by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the stack analysis."},"description":"The id of the stack analysis."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"provider_a":{"type":"string","description":"First provider in the compared pair."},"provider_b":{"type":"string","description":"Second provider in the compared pair."},"shared_entity_types":{"type":"object","additionalProperties":true},"total_entity_types":{"type":"integer"},"overlap_score":{"type":"number","description":"How much the kinds of record the two systems hold overlap: 0 means nothing in common, 1 means exactly the same."},"computed_at":{"type":"string"}},"required":["customer_id","provider_a","provider_b"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","provider_a":"string","provider_b":"string","shared_entity_types":{},"total_entity_types":0,"overlap_score":0,"computed_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/stack-bloat-report":{"get":{"operationId":"GetStackBloatReport","tags":["intelligence"],"summary":"Get Stack Bloat Report","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"Pairs of systems that overlap heavily (an overlap score above 0.7), with a suggestion for each: merge them, retire one, or review them. Retiring one is suggested only when your golden records show one of the pair only duplicates the other; overlap alone is a pair to review.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"customerId":{"type":"string"},"recommendations":{"type":"array","items":{"type":"object","properties":{"providerA":{"type":"string"},"providerB":{"type":"string"},"sharedEntityTypes":{"type":"array","items":{"type":"string"}},"overlapScore":{"type":"number"},"suggestedAction":{"type":"string","enum":["merge","decommission_one","review"]}},"required":["providerA","providerB","sharedEntityTypes","overlapScore","suggestedAction"]}},"message":{"type":"string","nullable":true},"generatedAt":{"type":"string","format":"date-time"}},"required":["customerId","recommendations","generatedAt"]},"example":{"customerId":"string","recommendations":[{"providerA":"string","providerB":"string","sharedEntityTypes":["string"],"overlapScore":0,"suggestedAction":"merge"}],"message":"string","generatedAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/stack-map":{"get":{"operationId":"GetStackMap","tags":["intelligence"],"summary":"Get Stack Map","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"Compare your connected systems in pairs and score how much of the same kind of data each pair holds, from 0 (nothing in common) to 1 (the same). Also lists the kinds of record each pair shares. The results are saved, so the stack analysis list and the consolidation report use them.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"customerId":{"type":"string"},"providerPairs":{"type":"array","items":{"type":"object","properties":{"providerA":{"type":"string"},"providerB":{"type":"string"},"sharedEntityTypes":{"type":"array","items":{"type":"string"}},"totalEntityTypes":{"type":"integer"},"overlapScore":{"type":"number"}},"required":["providerA","providerB","sharedEntityTypes","totalEntityTypes","overlapScore"]}},"computedAt":{"type":"string","format":"date-time"}},"required":["customerId","providerPairs","computedAt"]},"example":{"customerId":"string","providerPairs":[{"providerA":"string","providerB":"string","sharedEntityTypes":["string"],"totalEntityTypes":0,"overlapScore":0}],"computedAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/usage":{"get":{"operationId":"GetUsageMeters","tags":["intelligence"],"summary":"Get Usage Meters","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"Your daily usage, newest day first: records, storage, sync operations, AI operations and archive storage.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":365,"description":"How many days to return: 1 to 365, 30 if you leave it out.","default":30},"description":"How many days to return: 1 to 365, 30 if you leave it out."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"usage":{"type":"object","additionalProperties":true}},"required":["usage"]},"example":{"usage":{}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/intelligence/value-profiles":{"get":{"operationId":"ListEntityValueProfiles","tags":["intelligence"],"summary":"List Entity Value Profiles","security":[{"ApiKeyAuth":["intelligence:read"]},{"BearerAuth":[]},{"OAuth2":["intelligence:read"]}],"description":"How valuable the data in each pipeline is, one entry per kind of record: how many records are high or low value, duplicated, incomplete or wasted, how complete and up to date they are, and an estimate of the storage and cost of the waste. Biggest waste first.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"profiles":{"type":"object","additionalProperties":true}},"required":["profiles"]},"example":{"profiles":{}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/internal/marketing-sync":{"post":{"operationId":"MarketingSyncIngest","tags":["marketing"],"summary":"Marketing Sync Ingest","security":[],"description":"Apply a batch of marketing-site D1 changes idempotently (newest seq wins per row; deletes keep a tombstone) and acknowledge the cursor. Internal hostname only; Authorization: Bearer <INFERREX_MARKETING_SYNC_TOKEN>.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"changes":{"type":"array","items":{"type":"object","properties":{"seq":{"type":"integer","minimum":1,"description":"Outbox sequence number; newest wins per row."},"table_name":{"type":"string","enum":["visitors","events","progress","passports","consents","beta_requests","leaderboard","experiment_exposures"]},"row_key":{"type":"string","minLength":2,"maxLength":1024,"description":"JSON array of the primary-key values, e.g. [\"v_1\",\"n_9\"]."},"op":{"type":"string","enum":["insert","update","delete"]},"row":{"type":"object","additionalProperties":true,"nullable":true,"description":"The current row, or null for a delete or a row the source no longer has."}},"required":["seq","table_name","row_key","op"]},"maxItems":500},"through_seq":{"type":"integer","minimum":0,"description":"The cursor this batch completes; at least every seq in it."}},"required":["changes","through_seq"]},"example":{"changes":[{"seq":0,"table_name":"visitors","row_key":"string","op":"insert","row":{}}],"through_seq":0}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"acked_seq":{"type":"integer"}},"required":["acked_seq"]},"example":{"acked_seq":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/jobs":{"get":{"operationId":"ListJobs","tags":["jobs"],"summary":"List Jobs","security":[{"ApiKeyAuth":["jobs:read"]},{"BearerAuth":[]},{"OAuth2":["jobs:read"]}],"description":"The newest rows of the pollable-job table for this workspace, each overlaid with its live execution record exactly as GET /v1/jobs/:id does. Syncs a pipeline's schedule starts (including the weekly deletion listing) have a job row too, with triggeredBy schedule. Finished jobs are kept for the platform retention.jobsDays window; the run itself stays on the pipeline's sync history.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50,"description":"How many jobs, newest first. Default 20, at most 50."},"description":"How many jobs, newest first. Default 20, at most 50."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"jobs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","description":"e.g. pipeline.sync, pipeline.dryrun, connection.match"},"status":{"type":"string","enum":["queued","running","succeeded","failed","cancelled"]},"progress":{"type":"integer","nullable":true},"result":{"type":"object","properties":{"mappingId":{"type":"string","format":"uuid","nullable":true},"recordsRead":{"type":"integer"},"recordsWritten":{"type":"integer"},"recordsWouldWrite":{"type":"integer"},"recordsFailed":{"type":"integer"},"recordsSkipped":{"type":"integer"},"durationMs":{"type":"integer","nullable":true}},"nullable":true,"description":"As on GET /v1/jobs/:id."},"error":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"cancelRequestedAt":{"type":"string","format":"date-time","nullable":true},"pipelineId":{"type":"string","format":"uuid","nullable":true,"description":"pipeline.* jobs: the pipeline the run belongs to, once the sync worker has opened its run; null before that and for other kinds."},"connectionId":{"type":"string","format":"uuid","nullable":true,"description":"connection.* jobs: the system being matched, once the match run exists; null before that and for other kinds."},"subject":{"type":"object","properties":{"type":{"type":"string","description":"Open vocabulary: pipeline (syncs, dry runs), connection (matches), …"},"id":{"type":"string","format":"uuid"}},"required":["type","id"],"nullable":true,"description":"What the job is about, stamped when it was started, so it is known before the run exists. Null on jobs started before this was recorded."},"triggeredBy":{"type":"string","nullable":true,"description":"Who started it. Open vocabulary: user (an API call, from the app or a key), schedule (the pipeline's schedule), system. Null on jobs started before this was recorded."}},"required":["id","kind","status","createdAt"]},"description":"Newest first. Each has the GET /v1/jobs/:id shape."}},"required":["jobs"]},"example":{"jobs":[{"id":"00000000-0000-0000-0000-000000000000","kind":"string","status":"queued","progress":0,"result":{"mappingId":"00000000-0000-0000-0000-000000000000","recordsRead":0,"recordsWritten":0,"recordsWouldWrite":0,"recordsFailed":0,"recordsSkipped":0,"durationMs":0},"error":"string","createdAt":"2026-01-01T00:00:00Z","cancelRequestedAt":"2026-01-01T00:00:00Z","pipelineId":"00000000-0000-0000-0000-000000000000","connectionId":"00000000-0000-0000-0000-000000000000","subject":{"type":"string","id":"00000000-0000-0000-0000-000000000000"},"triggeredBy":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/jobs/{id}":{"get":{"operationId":"GetJob","tags":["jobs"],"summary":"Get Job","security":[{"ApiKeyAuth":["jobs:read"]},{"BearerAuth":[]},{"OAuth2":["jobs:read"]}],"description":"Check on a long-running task, such as a sync, using the job id it returned. Shows whether it is queued, running, succeeded or failed, how far it has got, and its result.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the job (the jobId a call returned)."},"description":"The id of the job (the jobId a call returned)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","description":"e.g. pipeline.sync"},"status":{"type":"string","enum":["queued","running","succeeded","failed","cancelled"]},"progress":{"type":"integer","nullable":true,"description":"Null while the job is queued or running; 100 once it has finished. There is no per-object breakdown."},"result":{"type":"object","properties":{"mappingId":{"type":"string","format":"uuid","nullable":true,"description":"connection.match: the stored mapping, once the match has produced one."},"engine":{"type":"string","nullable":true,"description":"connection.match: the match engine that ran."},"arm":{"type":"string","nullable":true,"description":"connection.match: how the engine was chosen."},"engineFallbackReason":{"type":"string","nullable":true,"description":"connection.match: why the chosen engine fell back, when it did."},"recordsRead":{"type":"integer","description":"pipeline.*: records read from the source so far."},"recordsWritten":{"type":"integer","description":"pipeline.*: records written. Always 0 on a dry run, which writes nothing."},"recordsWouldWrite":{"type":"integer","description":"pipeline.dryrun only: records it would have written."},"recordsFailed":{"type":"integer","description":"pipeline.*: records that failed to write."},"recordsSkipped":{"type":"integer","description":"pipeline.*: records skipped."},"durationMs":{"type":"integer","nullable":true,"description":"How long the run took. Null until it finishes."},"preview":{"type":"object","properties":{"recordsRead":{"type":"integer"},"destinations":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","nullable":true,"description":"The destination system; empty for a flow whose only destination is the golden record."},"wouldWrite":{"type":"integer"},"held":{"type":"integer","description":"Records that would not be sent: held for a missing value, or refused for this destination."},"samples":{"type":"array","items":{"type":"object","properties":{"targetEntity":{"type":"string"},"recordId":{"type":"string"},"source":{"type":"object","additionalProperties":true,"nullable":true,"description":"The record as read, bounded: its first 30 fields and of each nested object (three levels; deeper is cut text), lists to five items, long text cut. Empty when it was not in the batch."},"converted":{"type":"object","additionalProperties":true,"description":"What would be sent, bounded the same way."}},"required":["targetEntity","recordId","source","converted"]}}},"required":["connectionId","wouldWrite","held","samples"]}}},"required":["recordsRead","destinations"],"description":"pipeline.dryrun, once it has finished: what it would have written. recordsRead, and destinations: for each, connectionId (empty for the golden record), wouldWrite, held, and up to three samples, each with targetEntity, recordId, source (the record as read) and converted (what would be sent)."}},"nullable":true,"description":"Null until the job's execution record exists. connection.match jobs: mappingId, engine, arm, engineFallbackReason, durationMs. pipeline.sync and pipeline.dryrun jobs: recordsRead, recordsWritten, recordsFailed, recordsSkipped, durationMs; a dry run also recordsWouldWrite and, once finished, preview."},"error":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"cancelRequestedAt":{"type":"string","format":"date-time","nullable":true,"description":"When someone asked to stop this job (POST /v1/jobs/:id/cancel); null if nobody has."},"pipelineId":{"type":"string","format":"uuid","nullable":true,"description":"pipeline.* jobs: the pipeline the run belongs to, once the sync worker has opened its run; null before that and for other kinds."},"connectionId":{"type":"string","format":"uuid","nullable":true,"description":"connection.* jobs: the system being matched, once the match run exists; null before that and for other kinds."},"subject":{"type":"object","properties":{"type":{"type":"string","description":"Open vocabulary: pipeline (syncs, dry runs), connection (matches), …"},"id":{"type":"string","format":"uuid"}},"required":["type","id"],"nullable":true,"description":"What the job is about, stamped when it was started, so it is known before the run exists. Null on jobs started before this was recorded."},"triggeredBy":{"type":"string","nullable":true,"description":"Who started it. Open vocabulary: user (an API call, from the app or a key), schedule (the pipeline's schedule), system. Null on jobs started before this was recorded."}},"required":["id","kind","status","createdAt"]},"example":{"id":"00000000-0000-0000-0000-000000000000","kind":"string","status":"queued","progress":0,"result":{"mappingId":"00000000-0000-0000-0000-000000000000","engine":"string","arm":"string","engineFallbackReason":"string","recordsRead":0,"recordsWritten":0,"recordsWouldWrite":0,"recordsFailed":0,"recordsSkipped":0,"durationMs":0,"preview":{"recordsRead":0,"destinations":[{"connectionId":"00000000-0000-0000-0000-000000000000","wouldWrite":0,"held":0,"samples":[{"targetEntity":"string","recordId":"string","source":{},"converted":{}}]}]}},"error":"string","createdAt":"2026-01-01T00:00:00Z","cancelRequestedAt":"2026-01-01T00:00:00Z","pipelineId":"00000000-0000-0000-0000-000000000000","connectionId":"00000000-0000-0000-0000-000000000000","subject":{"type":"string","id":"00000000-0000-0000-0000-000000000000"},"triggeredBy":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/jobs/{id}/cancel":{"post":{"operationId":"CancelJob","tags":["jobs"],"summary":"Cancel Job","security":[{"ApiKeyAuth":["jobs:write"]},{"BearerAuth":[]},{"OAuth2":["jobs:write"]}],"description":"Request that a pipeline sync or dry-run job stop. Queued (not yet picked up): cancelled at once. Running: the sync worker stops at its next safe point (before it starts, between source pages, or just before it stores versions and writes) and marks the job cancelled. A run already storing and writing records finishes, because stopping between writes would leave records the next sync treats as unchanged; GET /v1/jobs/:id then reports succeeded or failed with cancelRequestedAt set. Asking again is harmless. Refused (409) for a job that has already finished and for kinds that cannot be stopped.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","running","succeeded","failed","cancelled"],"description":"The job's status right after the request: cancelled when it had not started, otherwise running until the worker reaches a safe point."},"cancelRequestedAt":{"type":"string","format":"date-time"}},"required":["id","status","cancelRequestedAt"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"queued","cancelRequestedAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/library/connectors/upload":{"post":{"operationId":"Upload","tags":["library"],"summary":"Upload","security":[{"ApiKeyAuth":["library:write"]},{"BearerAuth":[]},{"OAuth2":["library:write"]}],"description":"Upload a file that describes an API (an OpenAPI, GraphQL or other schema file), and Inferrex works out the API’s kinds of record and fields from it. If you are setting up a connection whose API could not be read automatically, pass its id to complete that connection.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"string","description":"The file’s contents, Base64-encoded."},"fileName":{"type":"string","description":"The file’s name, including its extension."},"schemaTitle":{"type":"string","description":"A name for the API, if the file does not give one."},"connectionId":{"type":"string","format":"uuid","description":"The connection this file completes, if you are setting one up. Leave out for a separate upload."}},"required":["content","fileName"]},"example":{"content":"string","fileName":"string","schemaTitle":"string","connectionId":"00000000-0000-0000-0000-000000000000"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"manifestId":{"type":"string","format":"uuid"},"providerKey":{"type":"string"},"detectedFormat":{"type":"string"},"fieldsRequiringReview":{"type":"array","items":{"type":"string"}},"error":{"type":"object","properties":{"reason":{"type":"string"},"statusCode":{"type":"integer"},"formatsAttempted":{"type":"array","items":{"type":"string"}}},"required":["reason"]}},"required":["success"]},"example":{"success":true,"manifestId":"00000000-0000-0000-0000-000000000000","providerKey":"string","detectedFormat":"string","fieldsRequiringReview":["string"],"error":{"reason":"string","statusCode":0,"formatsAttempted":["string"]}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/library/contributions":{"get":{"operationId":"ListContributions","tags":["library"],"summary":"List Contributions","security":[{"ApiKeyAuth":["library:read"]},{"BearerAuth":[]},{"OAuth2":["library:read"]}],"description":"This workspace's own contributions (connector_library.promotion_staging rows it submitted), newest first. Paged by `limit` / `offset`; there is no total, so a page shorter than `limit` is the last one.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}},{"name":"connectionId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"contributions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"connectionId":{"type":"string","format":"uuid","nullable":true},"source":{"type":"string","nullable":true},"approvalState":{"type":"string","enum":["requested","approved","declined"],"nullable":true},"providerKey":{"type":"string"},"displayName":{"type":"string"},"category":{"type":"string"},"status":{"type":"string","description":"Known values: staged (queued for review), released, rejected."},"reviewNotes":{"type":"string","nullable":true,"description":"The reviewer's notes, on a rejected contribution."},"releaseVersion":{"type":"string","nullable":true,"description":"The library release that published it, once released."},"stagedAt":{"type":"string","format":"date-time"},"reviewedAt":{"type":"string","format":"date-time","nullable":true}},"required":["id","connectionId","source","approvalState","providerKey","displayName","category","status","reviewNotes","releaseVersion","stagedAt","reviewedAt"]}},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["contributions","limit","offset"]},"example":{"contributions":[{"id":"00000000-0000-0000-0000-000000000000","connectionId":"00000000-0000-0000-0000-000000000000","source":"string","approvalState":"requested","providerKey":"string","displayName":"string","category":"string","status":"string","reviewNotes":"string","releaseVersion":"string","stagedAt":"2026-01-01T00:00:00Z","reviewedAt":"2026-01-01T00:00:00Z"}],"limit":0,"offset":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"SubmitConnectorContribution","tags":["library"],"summary":"Submit Connector Contribution","security":[{"ApiKeyAuth":["library:write"]},{"BearerAuth":[]},{"OAuth2":["library:write"]}],"description":"With connectionId, the server builds the contribution from the stored connection: the vendor's standard structure only. A member requests it and a workspace admin or owner approves it before Inferrex reviews it. Client manifests are refused. Without connectionId this is a written suggestion, never a schema or automatic publication.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","description":"The workspace connection whose standard schema is requested."},"version":{"type":"string","maxLength":500,"description":"A confirmed vendor apiVersionId; defaults to the current catalogue selection."},"providerKey":{"type":"string","minLength":1,"maxLength":200,"description":"Required for a written suggestion; a connection contributes under its server-resolved key."},"displayName":{"type":"string","minLength":1,"maxLength":255,"description":"The system’s name."},"category":{"type":"string","maxLength":100,"description":"The category it belongs in, such as CRM."},"documentationUrl":{"type":"string","maxLength":2048,"description":"Where the system’s API documentation is published."},"notes":{"type":"string","maxLength":2000,"description":"Anything the reviewers should know."}}},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","version":"string","providerKey":"string","displayName":"string","category":"string","documentationUrl":"string","notes":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"contributionId":{"type":"string","format":"uuid"},"status":{"type":"string"},"message":{"type":"string"}},"required":["success","contributionId","status","message"]},"example":{"success":true,"contributionId":"00000000-0000-0000-0000-000000000000","status":"string","message":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/library/contributions/{id}":{"get":{"operationId":"GetContributionStatus","tags":["library"],"summary":"Get Contribution Status","security":[{"ApiKeyAuth":["library:read"]},{"BearerAuth":[]},{"OAuth2":["library:read"]}],"description":"Check on a catalogue suggestion you made: whether it is still waiting for review, was published (and in which release) or was turned down, with the reviewer’s notes.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the catalogue suggestion."},"description":"The id of the catalogue suggestion."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"providerKey":{"type":"string"},"status":{"type":"string"},"reviewNotes":{"type":"string","nullable":true},"releaseVersion":{"type":"string","nullable":true},"stagedAt":{"type":"string"},"reviewedAt":{"type":"string","nullable":true}},"required":["id","providerKey","status","stagedAt"]},"example":{"id":"00000000-0000-0000-0000-000000000000","providerKey":"string","status":"string","reviewNotes":"string","releaseVersion":"string","stagedAt":"string","reviewedAt":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/licence/upload":{"post":{"operationId":"UploadLicence","tags":["licence"],"summary":"Upload Licence","security":[{"ApiKeyAuth":["licence:write"]},{"BearerAuth":[]},{"OAuth2":["licence:write"]}],"description":"Install a signed licence file on your self-hosted Inferrex. Only the workspace owner can do this.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"licenceJson":{"type":"string","description":"The licence file’s contents."},"signature":{"type":"string","description":"The signature that came with the licence file."}},"required":["licenceJson","signature"]},"example":{"licenceJson":"string","signature":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"string"},"expiresAt":{"type":"string"}}},"example":{"state":"string","expiresAt":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/licence/validate":{"post":{"operationId":"ValidateLicence","tags":["licence"],"summary":"Validate Licence","security":[{"ApiKeyAuth":["licence:write"]},{"BearerAuth":[]},{"OAuth2":["licence:write"]}],"description":"Check a signed licence file without installing it. Only the workspace owner can do this.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"licenceJson":{"type":"string","description":"The licence file’s contents."},"signature":{"type":"string","description":"The signature that came with the licence file."}},"required":["licenceJson","signature"]},"example":{"licenceJson":"string","signature":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"valid":{"type":"boolean"},"reason":{"type":"string"},"wouldExpire":{"type":"string"},"wouldState":{"type":"string"}}},"example":{"valid":true,"reason":"string","wouldExpire":"string","wouldState":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/licences/validate-deployment":{"post":{"operationId":"ValidateDeployment","tags":["licence"],"summary":"Validate Deployment","security":[],"description":"Lets a connected self-hosted Inferrex check that its licence is still valid: active, in its grace period, expired or revoked (with the reason). The answer is signed by Inferrex and includes the one-time value the request sent, so it cannot be faked or replayed. Deployments with no internet connection never call this; they check their licence offline.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"customer_id":{"type":"string","description":"The workspace the licence was issued to."},"licence_hash":{"type":"string","description":"The fingerprint of the installed licence."},"nonce":{"type":"string","description":"A new random value for each check. It is included in the signed answer, which proves the answer is fresh."}},"required":["customer_id","licence_hash","nonce"]},"example":{"customer_id":"string","licence_hash":"string","nonce":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"valid":{"type":"boolean"},"status":{"type":"string"},"nonce":{"type":"string","description":"Echo of the request nonce (inside the signed payload)."},"issuedAt":{"type":"string","description":"Server sign time (inside the signed payload)."},"signature":{"type":"string","description":"Base64 Ed25519 signature over {customerId,status,valid,nonce,issuedAt}."},"expiresAt":{"type":"string"},"gracePeriodEnd":{"type":"string"},"revokedReason":{"type":"string"}},"required":["valid","status","nonce","issuedAt","signature"]},"example":{"valid":true,"status":"string","nonce":"string","issuedAt":"string","signature":"string","expiresAt":"string","gracePeriodEnd":"string","revokedReason":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings":{"get":{"operationId":"ListMappings","tags":["mappings"],"summary":"List Mappings","security":[{"ApiKeyAuth":["mappings:read"]},{"BearerAuth":[]},{"OAuth2":["mappings:read"]}],"description":"List your mappings, newest first. A mapping says how the data in one connected system lines up with another: which kinds of record correspond and which fields feed which. Each entry shows the two systems, how many records and fields are mapped, how far the review has got, and how confident Inferrex is. Archived mappings, and mappings between archived connections, are left out. Each entry has a label that tells it apart from other mappings between the same two systems: show people the label, never the id.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"description":"How many mappings to return: 1 to 500, 100 if you leave it out.","default":100},"description":"How many mappings to return: 1 to 500, 100 if you leave it out."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"mappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The latest version of the mapping."},"label":{"type":"string","description":"The mapping's name for people, e.g. `Salesforce Sandbox → Bloomreach mock · 10 Oct 20:20 UTC · awaiting review · 20/22 approved`. Mappings have no name of their own and the same two systems can be matched more than once, so the label adds when it was matched, its review state and progress."},"source":{"type":"string","description":"Source connection's name, or its id when the connection is not found."},"target":{"type":"string","description":"Target connection's name, or its id when the connection is not found."},"source_connection_id":{"type":"string","description":"The source connection's id."},"target_connection_id":{"type":"string","description":"The target connection's id."},"entities":{"type":"integer","description":"Object pairings in the mapping."},"fields":{"type":"integer","description":"Field mappings across all pairings."},"approved":{"type":"integer","description":"Field mappings a person approved."},"rejected":{"type":"integer","description":"Field mappings a person rejected as wrong."},"omitted":{"type":"integer","description":"Field mappings a person left out of the sync."},"confidence":{"type":"number","description":"Overall match confidence, 0 to 1."},"status":{"type":"string","description":"Review state of this version, e.g. draft, awaiting-review, approved, active."},"matched_at":{"type":"string","format":"date-time","description":"When the match that produced the mapping ran."}},"required":["id","label","source","target","source_connection_id","target_connection_id","entities","fields","approved","rejected","omitted","confidence","status","matched_at"]}},"mappingCount":{"type":"integer","description":"Rows returned (after the limit)."}},"required":["mappings","mappingCount"]},"example":{"mappings":[{"id":"00000000-0000-0000-0000-000000000000","label":"string","source":"string","target":"string","source_connection_id":"string","target_connection_id":"string","entities":0,"fields":0,"approved":0,"rejected":0,"omitted":0,"confidence":0,"status":"string","matched_at":"2026-01-01T00:00:00Z"}],"mappingCount":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/{id}":{"get":{"operationId":"GetMapping","tags":["mappings"],"summary":"Get Mapping","security":[{"ApiKeyAuth":["mappings:read"]},{"BearerAuth":[]},{"OAuth2":["mappings:read"]}],"description":"Get one mapping in full: each pair of matching record kinds, how they relate (for example one-to-one), and each field-to-field link with the conversion Inferrex suggests and how confident it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The id written inside the mapping document. Use the id in the path (or `id` from GET /v1/mappings) to address the mapping."},"version":{"type":"number"},"customerId":{"type":"string"},"sourceConnectionId":{"type":"string"},"targetConnectionId":{"type":"string"},"entityMappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sourceEntityId":{"type":"string"},"targetEntityId":{"type":"string"},"confidence":{"type":"number"},"entityRelationship":{"type":"string","description":"L15 relationship-inferrer's cross-provider equivalence verdict (equivalent / parent_child / related / unrelated) — refines whether the two entities should map at all. Open by design: a novel relationship label still flows through."},"fieldMappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sourceEntityId":{"type":"string"},"sourceFieldId":{"type":"string"},"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"authority":{"type":"string","description":"Known values: provider-wins, native-only, native-override, latest-wins, merge."},"conflictStrategy":{"type":"string","description":"Known values: latest-timestamp, highest-authority, flag-for-review."},"transform":{"type":"string","description":"Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"suggestedTransform":{"type":"string","description":"L17 transform-inferrer's raw OPEN suggestion (identity / unit_conversion / format_conversion / enum_mapping / …) — what the AI proposed before the customer confirmed the executable `transform`. Open by design: a novel transform label still flows through. Drives the transform-override control in the mapping review."},"transformConfig":{"type":"object","additionalProperties":true},"syncTier":{"type":"string","description":"Per-FIELD sync cadence (functionality.md: \"per-field sync tiers\"; VISUAL-MAPPING-SPEC §0.1) — seeded from the tenant's per-entity onboarding selection at pipeline activation, overridable per field in the mapping review. Absent = the pipeline's default cadence. Known values: realtime, near-realtime, periodic, archival."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-link predicate (§7: \"only when type = business\") evaluated against the SOURCE record by the shared field-evaluator — the field syncs only when it holds. Absent = always syncs. A malformed condition evaluates FALSE (fail closed)."},"direction":{"type":"string","description":"Per-FIELD flow direction (VISUAL-MAPPING-SPEC item 11): source-to-target, target-to-source, or bidirectional — any field can flow either way, both ways, or (via omitted) not at all. Absent = inherit the mapping's syncConfig.direction. Enforced by the shared evaluator's pass filter; on the reverse pass a non-invertible transform skips the field (visible in preview) rather than writing a wrongly-transformed value. Known values: source-to-target, target-to-source, bidirectional."},"confidence":{"type":"number"},"matchRationale":{"type":"string","description":"why Layer 5 proposed this pairing"},"customerApproved":{"type":"boolean"},"customerRejected":{"type":"boolean","description":"Customer explicitly marked this match WRONG (audit §2.3) — distinct from customerApproved:false, which also covers never-reviewed. Same optional-for-back-compat pattern as `omitted`. A rejected field is excluded from sync by the shared evaluator (a wrong match must not move data) and is the negative training signal's home. Cleared by a later approve."},"customerModified":{"type":"boolean","description":"customer changed the AI proposal"},"autoApplied":{"type":"boolean","description":"Applied automatically because confidence cleared the tenant's auto-apply threshold (mapping.autoApplyThreshold tunable, §11b) — deliberately NOT customerApproved, which stays a genuine customer signal; an auto-applied field the customer later approves or rejects converts to a real signal. Auto-applied fields skip the review queue but sync like approved ones; the manifest-level approval gate still applies."},"omitted":{"type":"boolean","description":"Customer chose not to sync this field — a business decision, NOT a correctness verdict (reject ≠ omit, VISUAL-MAPPING-SPEC §11a). Never touches customerApproved, feeds no training signal, and is sticky: re-matching carries it forward instead of re-proposing the field. Absent = syncs normally."},"omittedProposalChanged":{"type":"boolean","description":"Set by re-matching when a NEW proposal arrived for a field the customer omitted — surfaced as a note (\"a new proposal exists\"), never auto-restored. Cleared when the customer restores the field."},"manualAuthored":{"type":"boolean","description":"A human authored this link FROM NOTHING — the AI never proposed it (audit §2.4). Distinct from customerModified, which is AI-proposed-then-edited: different provenance, different training signal, and only this one is a durable TENANT FACT. Sticky exactly as `omitted` is: re-matching and healing carry it forward instead of dropping it, because a re-inference must never silently undo a decision a person made. Stays in the tenant's override layer and is NEVER promoted into the shared corpus without explicit vetting — a tenant's anomaly is not the platform's knowledge."},"manualProposalConflict":{"type":"boolean","description":"Set by re-matching when the AI proposed a DIFFERENT target for a source field the customer hand-mapped — surfaced as a note (\"the AI now proposes something else\"), never an auto-overwrite. The manual mapping wins and keeps running. Mirrors omittedProposalChanged; cleared when the customer resolves it."},"matchSource":{"type":"string","description":"Provenance of the proposal this mapping came from (see FieldMatchProposal.matchSource). Lets the review page and the engine comparison say whether a rule, the golden layer, the lake or a model proposed the pair. The API answers a model-proposed pair as plain `l95`: the provider and deployment stay in the stored record and never reach a tenant (DEBT-202)."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within the mapping — the key `dependsOn` and the dispatch ledger reference."},"kind":{"type":"string","description":"OPEN destination kind. 'record' = write into a connected system; 'action' = invoke a capability. Unknown kinds fail loudly at dispatch rather than being silently skipped — a destination nobody delivers is the shipped-but-inert shape."},"label":{"type":"string","description":"Human name shown wherever the destination appears — what the tenant called it, not a generated id."},"connectionId":{"type":"string","description":"For kind=record: which connected system receives it. Absent = the mapping's own target connection."},"targetEntityId":{"type":"string","description":"For kind=record: entity written into. Absent = the field mapping's own targetEntityId."},"targetFieldId":{"type":"string","description":"For kind=record: field written. Absent = the field mapping's own targetFieldId."},"channelType":{"type":"string","description":"For kind=action: HOW to deliver — an OPEN channel type resolved by the notification engine (email / sms / webhook / in_app / …). The same vocabulary alert rules use, so actions ride the ONE hardened delivery path rather than a second transport."},"channelTarget":{"type":"string","description":"For kind=action: WHO receives it (address, number, URL, or a channel id)."},"channelId":{"type":"string","description":"For kind=action: pin a specific notification_channels row instead of resolving the tenant's first verified channel of that type."},"order":{"type":"number","description":"Explicit sequence within the field's destination set. Ordering is REQUIRED, not cosmetic: \"save, and IF that committed, send\" is only expressible when the order is declared rather than inferred from array position."},"dependsOn":{"type":"string","description":"Destination id that must have COMMITTED for THIS record before this one runs. A failed or skipped dependency skips the dependant — the \"if that committed\" half of the ordering guarantee."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-destination predicate over the SOURCE record, evaluated by the shared field-evaluator — the same type and the same semantics as the per-field condition. Absent = always. A malformed condition evaluates FALSE (fail closed)."},"transform":{"type":"string","description":"Per-destination transform. Absent = inherit the field mapping's transform, so a destination only declares what DIFFERS. Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"transformConfig":{"type":"object","additionalProperties":true},"direction":{"type":"string","description":"Per-destination flow direction; absent = inherit the field mapping's. A destination only participates in a pass its direction allows. Known values: source-to-target, target-to-source, bidirectional."},"dedupeKeyFields":{"type":"array","items":{"type":"string"},"description":"Source-record fields forming the idempotency key. Absent, the key is the record's identity plus the value being delivered — so a re-sync of UNCHANGED data dispatches nothing while a genuine change still does. This is not optional decoration: a backfill over an action destination is how a tenant discovers 40,000 text messages."},"maxPerMinute":{"type":"number","description":"Per-tenant ceiling on dispatches to THIS destination. When the trailing minute is already at the ceiling, dispatch to this destination halts for the rest of the run and the skipped count is recorded and surfaced — a safety valve that is visible rather than silent."},"enabled":{"type":"boolean","description":"Absent = enabled. Turning a destination off must not require deleting it, or the only way to pause an action is to lose its configuration."}},"required":["id","kind","label","order"]},"description":"ADDITIONAL destinations this field reaches beyond its primary target — the end of the one-field-one-destination model (§2.3/§3.3). Absent = the field behaves exactly as before, which is why adding fan-out changes nothing for an existing mapping. Dispatched in `order` after the primary sink write, so a record destination and an action destination can be sequenced (\"save, and if that committed, send\")."},"alternatives":{"type":"array","items":{"type":"object","properties":{"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"score":{"type":"number","description":"The number that ranked this candidate, in the units scoreKind names."},"scoreKind":{"type":"string","description":"OPEN vocabulary naming what `score` is: `lexical` (token-overlap rank from explainCandidates, unbounded), `embedding` (cosine similarity, -1..1), `model` (the matching model's own 0..1 confidence for this pair). A novel kind flows through as a string; a UI that does not know it shows no number."},"matchSource":{"type":"string","description":"Which stage ranked it (`embedding-candidate`, `lexical-candidate`, or `l95:<provider>:<deployment>` for a model answer — the API strips the provider and deployment, DEBT-202)."}},"required":["targetEntityId","targetFieldId","score","scoreKind","matchSource"]},"description":"The runners-up the matcher ranked for this source field, best first, never including this mapping's own target (OPEN-WORK 128 d). Read only by the review UI — nothing in sync or resolution reads it. Absent = the matcher ranked nothing else (a rule decided the pair) or the mapping predates the field. Re-matching carries it forward onto an unchanged pair that came back without any."}},"required":["id","sourceEntityId","sourceFieldId","targetEntityId","targetFieldId","authority","conflictStrategy","transform","confidence","matchRationale","customerApproved","customerModified"]}},"matchOn":{"type":"array","items":{"type":"string"},"description":"Target field api names that identify the same real-world record (target-id memory, 2026-10-08), e.g. ['billing_email'] or ['invoice_number']. Before creating a record it has no link for, the sync reads the target entity and links to an existing row whose values on every matchOn field equal the outgoing record's, then updates it instead of creating a duplicate. Empty or absent = no matching. Set with PATCH /v1/mappings/:id/entity-match."},"goldenId":{"type":"object","properties":{"targetField":{"type":"string","description":"Dotted target field the golden record id is written to (`customer_ids.inferrex_id`)."},"matchTargetField":{"type":"string","description":"Dotted target field holding the shared id after projection (`customer_ids.registered`)."},"goldenEntityType":{"type":"string","description":"The golden records searched: their entity type."},"goldenField":{"type":"string","description":"The golden field compared with the shared id, exactly (no case folding: an id is an id)."}},"required":["targetField","matchTargetField","goldenEntityType","goldenField"],"description":"Stamp each outgoing record with the id of the golden record it belongs to (2026-10-27, Bloomreach Engagement phase 1, D13: every command carries the tenant's own id AND the golden id). After the fields are projected, the sync finds the ONE golden record of `goldenEntityType` whose `goldenField` equals the value the record carries at `matchTargetField`, and writes its id at `targetField`. None or several: nothing is written there, and the count is logged. Absent = no stamp. Set by an approved destination setup plan."},"each":{"type":"object","properties":{"field":{"type":"string","description":"Dotted path of the list in the source record (`items`). A value that is not a list sends nothing; an element that is not an object is skipped."},"parentAs":{"type":"string","description":"The key the whole source record is read under while one element is projected (`$parent`): a field mapping reading `$parent.customer_email` reads the source record's own field."},"idField":{"type":"string","description":"The element's own field that identifies it (a line id), so an element keeps its record id (`<record>#<list>[<field>=<value>]`) when lines are inserted or reordered and is sent once (2026-10-28, Sentry on #847). Absent, or an element without a value there: the element is known by its position (`<record>#<list>[<n>]`), and a line inserted or reordered after the record was sent may be sent twice or not at all."}},"required":["field","parentAs"],"description":"One outgoing record per element of a list in the source record (2026-10-28, generic; Bloomreach Engagement: one `purchase_item` event per order line beside the order's `purchase`). The field mappings are projected once per element that is an object, reading the element's own fields by name and the source record's under `parentAs` (`$parent.id`); each result is written to `targetEntityId` as a record of its own, after the source record's own write and only when that write went out (a source record held back, refused or left out by a send rule takes its elements with it). Forward pass only. Absent = one record per source record, as before. Set by an approved destination setup plan."}},"required":["id","sourceEntityId","targetEntityId","confidence","fieldMappings"]},"description":"Each object pairing, with its field mappings: transform, authority, confidence, direction, condition, destinations and review state (customerApproved, customerRejected, omitted, manualAuthored). A field mapping may carry `alternatives`: the target fields the matcher ranked for that source field but did not choose, best first, each { targetEntityId, targetFieldId, score, scoreKind, matchSource }. `score` is a confidence only when scoreKind is `model`; `lexical` is a token-overlap rank and `embedding` a cosine similarity, so never show those as percentages. GET /v1/mappings/:id/field-candidates ranks more, with reasons."},"groupDestinations":{"type":"array","items":{"type":"object","properties":{"group":{"type":"string","description":"The open group label these destinations apply to — matched against InferredField.group."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within the mapping — the key `dependsOn` and the dispatch ledger reference."},"kind":{"type":"string","description":"OPEN destination kind. 'record' = write into a connected system; 'action' = invoke a capability. Unknown kinds fail loudly at dispatch rather than being silently skipped — a destination nobody delivers is the shipped-but-inert shape."},"label":{"type":"string","description":"Human name shown wherever the destination appears — what the tenant called it, not a generated id."},"connectionId":{"type":"string","description":"For kind=record: which connected system receives it. Absent = the mapping's own target connection."},"targetEntityId":{"type":"string","description":"For kind=record: entity written into. Absent = the field mapping's own targetEntityId."},"targetFieldId":{"type":"string","description":"For kind=record: field written. Absent = the field mapping's own targetFieldId."},"channelType":{"type":"string","description":"For kind=action: HOW to deliver — an OPEN channel type resolved by the notification engine (email / sms / webhook / in_app / …). The same vocabulary alert rules use, so actions ride the ONE hardened delivery path rather than a second transport."},"channelTarget":{"type":"string","description":"For kind=action: WHO receives it (address, number, URL, or a channel id)."},"channelId":{"type":"string","description":"For kind=action: pin a specific notification_channels row instead of resolving the tenant's first verified channel of that type."},"order":{"type":"number","description":"Explicit sequence within the field's destination set. Ordering is REQUIRED, not cosmetic: \"save, and IF that committed, send\" is only expressible when the order is declared rather than inferred from array position."},"dependsOn":{"type":"string","description":"Destination id that must have COMMITTED for THIS record before this one runs. A failed or skipped dependency skips the dependant — the \"if that committed\" half of the ordering guarantee."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-destination predicate over the SOURCE record, evaluated by the shared field-evaluator — the same type and the same semantics as the per-field condition. Absent = always. A malformed condition evaluates FALSE (fail closed)."},"transform":{"type":"string","description":"Per-destination transform. Absent = inherit the field mapping's transform, so a destination only declares what DIFFERS. Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"transformConfig":{"type":"object","additionalProperties":true},"direction":{"type":"string","description":"Per-destination flow direction; absent = inherit the field mapping's. A destination only participates in a pass its direction allows. Known values: source-to-target, target-to-source, bidirectional."},"dedupeKeyFields":{"type":"array","items":{"type":"string"},"description":"Source-record fields forming the idempotency key. Absent, the key is the record's identity plus the value being delivered — so a re-sync of UNCHANGED data dispatches nothing while a genuine change still does. This is not optional decoration: a backfill over an action destination is how a tenant discovers 40,000 text messages."},"maxPerMinute":{"type":"number","description":"Per-tenant ceiling on dispatches to THIS destination. When the trailing minute is already at the ceiling, dispatch to this destination halts for the rest of the run and the skipped count is recorded and surfaced — a safety valve that is visible rather than silent."},"enabled":{"type":"boolean","description":"Absent = enabled. Turning a destination off must not require deleting it, or the only way to pause an action is to lose its configuration."}},"required":["id","kind","label","order"]},"description":"The same destination shape a field declares, so there is one vocabulary and one executor rather than a parallel group path."}},"required":["group","destinations"]},"description":"Destinations declared for a whole field group. Absent when every destination is declared per field."},"syncConfig":{"type":"object","properties":{"mode":{"type":"string","description":"Known values: realtime, near-realtime, periodic, archival."},"direction":{"type":"string","description":"Known values: source-to-target, target-to-source, bidirectional."},"schedule":{"type":"string","description":"cron expression for periodic"},"intervalMinutes":{"type":"number","description":"for near-realtime"},"realtimeChannel":{"type":"string","description":"webhook/CDC channel for realtime"},"sourceType":{"type":"string","description":"How the source delivers data — drives the sync dispatch branch. Default (absent) is periodic = the batch job path; realtime subscribes to streamConfig via the QueueClient. Known values: realtime, near-realtime, periodic."},"streamConfig":{"type":"object","properties":{"broker":{"type":"string","description":"Known values: pubsub, nats, kafka, amqp, kinesis."},"topic":{"type":"string"},"offset":{"type":"string","description":"Known values: earliest, latest."}},"required":["broker"],"description":"Per-source stream binding for realtime sources. pubsub/nats resolve via the QueueClient today; kafka/amqp/kinesis are broker clients landing in unit A.5. Open by design — the broker set tracks the QueueClient providers + planned brokers."},"targetType":{"type":"string","description":"Where the synced records land — drives the sync WRITE branch (Phase 2 B.10). Default (absent) is api = the existing HTTP write to the target ConnectionManifest. warehouse → getWarehouseClient().upsert (analytical sink, schema ensured from the mapping); lake → getLakeClient().write (partitioned object-store landing tier). Both the batch and realtime paths flow through the SAME sink. Known values: api, warehouse, lake."},"targetTable":{"type":"string","description":"Explicit warehouse table / lake dataset name override (B.11). When absent the sink derives one table per target entity from the mapping (the targetEntityId apiName, sanitised). Set this to land every entity into one named table."},"batchSize":{"type":"number"},"retryPolicy":{"type":"object","properties":{"maxAttempts":{"type":"number"},"backoffMs":{"type":"number"},"backoffMultiplier":{"type":"number"}},"required":["maxAttempts","backoffMs","backoffMultiplier"]}},"required":["mode","direction","batchSize","retryPolicy"]},"matchedAt":{"type":"string"},"matchedBy":{"type":"string"},"overallConfidence":{"type":"number","description":"0 to 1."},"status":{"type":"string","description":"The status written inside the mapping document. Approving a mapping changes the stored version's status, not this one, so read approval from `status` on GET /v1/mappings. Known values: draft, awaiting-review, approved, active, paused."},"customerApprovedAt":{"type":"string"},"customerApprovedBy":{"type":"string"},"engine":{"type":"string","description":"Which match engine produced the mapping, e.g. v1, v2."},"engineArm":{"type":"string"},"engineFallbackReason":{"type":"string"},"archived":{"type":"boolean","description":"True when the mapping was archived (POST /v1/mappings/:id/archive). An archived mapping is left out of the lists and search but can still be read by id."}},"required":["id","version","customerId","sourceConnectionId","targetConnectionId","entityMappings","syncConfig","matchedAt","matchedBy","overallConfidence","status","archived"]},"example":{"id":"string","version":0,"customerId":"string","sourceConnectionId":"string","targetConnectionId":"string","entityMappings":[{"id":"string","sourceEntityId":"string","targetEntityId":"string","confidence":0,"entityRelationship":"string","fieldMappings":[{"id":"string","sourceEntityId":"string","sourceFieldId":"string","targetEntityId":"string","targetFieldId":"string","authority":"string","conflictStrategy":"string","transform":"string","suggestedTransform":"string","transformConfig":{},"syncTier":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"direction":"string","confidence":0,"matchRationale":"string","customerApproved":true,"customerRejected":true,"customerModified":true,"autoApplied":true,"omitted":true,"omittedProposalChanged":true,"manualAuthored":true,"manualProposalConflict":true,"matchSource":"string","destinations":[{"id":"string","kind":"string","label":"string","connectionId":"string","targetEntityId":"string","targetFieldId":"string","channelType":"string","channelTarget":"string","channelId":"string","order":0,"dependsOn":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"transform":"string","transformConfig":{},"direction":"string","dedupeKeyFields":["string"],"maxPerMinute":0,"enabled":true}],"alternatives":[{"targetEntityId":"string","targetFieldId":"string","score":0,"scoreKind":"string","matchSource":"string"}]}],"matchOn":["string"],"goldenId":{"targetField":"string","matchTargetField":"string","goldenEntityType":"string","goldenField":"string"},"each":{"field":"string","parentAs":"string","idField":"string"}}],"groupDestinations":[{"group":"string","destinations":[{"id":"string","kind":"string","label":"string","connectionId":"string","targetEntityId":"string","targetFieldId":"string","channelType":"string","channelTarget":"string","channelId":"string","order":0,"dependsOn":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"transform":"string","transformConfig":{},"direction":"string","dedupeKeyFields":["string"],"maxPerMinute":0,"enabled":true}]}],"syncConfig":{"mode":"string","direction":"string","schedule":"string","intervalMinutes":0,"realtimeChannel":"string","sourceType":"string","streamConfig":{"broker":"string","topic":"string","offset":"string"},"targetType":"string","targetTable":"string","batchSize":0,"retryPolicy":{"maxAttempts":0,"backoffMs":0,"backoffMultiplier":0}},"matchedAt":"string","matchedBy":"string","overallConfidence":0,"status":"string","customerApprovedAt":"string","customerApprovedBy":"string","engine":"string","engineArm":"string","engineFallbackReason":"string","archived":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/{id}/approve":{"post":{"operationId":"ApproveMapping","tags":["mappings"],"summary":"Approve Mapping","security":[{"ApiKeyAuth":["mappings:write"]},{"BearerAuth":[]},{"OAuth2":["mappings:write"]}],"description":"Approve a mapping once you have reviewed it, so pipelines that use it can be activated and sync. Approving an already approved mapping does nothing. Inferrex learns from the links you kept, to make better suggestions next time.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"mappingId":{"type":"string","format":"uuid"},"status":{"type":"string","description":"approved"},"alreadyApproved":{"type":"boolean"}},"required":["mappingId","status","alreadyApproved"]},"example":{"mappingId":"00000000-0000-0000-0000-000000000000","status":"string","alreadyApproved":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/{id}/archive":{"post":{"operationId":"ArchiveMapping","tags":["mappings"],"summary":"Archive Mapping","security":[{"ApiKeyAuth":["mappings:write"]},{"BearerAuth":[]},{"OAuth2":["mappings:write"]}],"description":"Archive a cross-system mapping (soft delete: the current version's stored status becomes `archived`). It leaves GET /v1/mappings, GET /v1/mappings/targets and search; GET /v1/mappings/:id still returns it with `archived: true`, and every version is kept. Rejected 409 mapping_in_use, naming the pipelines, while a pipeline that is not archived pins any version of the mapping (as GET /v1/mappings/:id/pipelines lists them): archive that pipeline first. Idempotent: an archived mapping returns its current state.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"mappingId":{"type":"string","format":"uuid","description":"The current version's id."},"status":{"type":"string","description":"archived"},"alreadyArchived":{"type":"boolean"}},"required":["mappingId","status","alreadyArchived"]},"example":{"mappingId":"00000000-0000-0000-0000-000000000000","status":"string","alreadyArchived":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/{id}/compare":{"get":{"operationId":"CompareMappingVersions","tags":["mappings"],"summary":"Compare Mapping Versions","security":[{"ApiKeyAuth":["mappings:read"]},{"BearerAuth":[]},{"OAuth2":["mappings:read"]}],"description":"What changes between two versions of a mapping: from (a version number) to to (a version number, the latest when left out). A link is the same link in both when it joins the same source field to the same target field of the same object pair. Use it before moving a flow with POST /v1/pipelines/:id/apply-mapping.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},{"name":"from","in":"query","required":true,"schema":{"type":"integer","minimum":1,"description":"The version compared from, for example the one a flow runs."},"description":"The version compared from, for example the one a flow runs."},{"name":"to","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"The version compared to. The latest when left out."},"description":"The version compared to. The latest when left out."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"from":{"type":"object","properties":{"mappingId":{"type":"string","format":"uuid"},"version":{"type":"integer"}},"required":["mappingId","version"]},"to":{"type":"object","properties":{"mappingId":{"type":"string","format":"uuid"},"version":{"type":"integer"}},"required":["mappingId","version"]},"added":{"type":"array","items":{"type":"object","properties":{"sourceEntityId":{"type":"string"},"sourceFieldId":{"type":"string"},"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"sourceEntity":{"type":"string","description":"The source object's API name."},"sourceField":{"type":"string","description":"The source field's API name."},"targetEntity":{"type":"string"},"targetField":{"type":"string"}},"required":["sourceEntityId","sourceFieldId","targetEntityId","targetFieldId","sourceEntity","sourceField","targetEntity","targetField"]},"description":"Links in to and not in from."},"removed":{"type":"array","items":{"type":"object","properties":{"sourceEntityId":{"type":"string"},"sourceFieldId":{"type":"string"},"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"sourceEntity":{"type":"string","description":"The source object's API name."},"sourceField":{"type":"string","description":"The source field's API name."},"targetEntity":{"type":"string"},"targetField":{"type":"string"}},"required":["sourceEntityId","sourceFieldId","targetEntityId","targetFieldId","sourceEntity","sourceField","targetEntity","targetField"]},"description":"Links in from and not in to."},"changed":{"type":"array","items":{"type":"object","properties":{"sourceEntityId":{"type":"string"},"sourceFieldId":{"type":"string"},"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"sourceEntity":{"type":"string","description":"The source object's API name."},"sourceField":{"type":"string","description":"The source field's API name."},"targetEntity":{"type":"string"},"targetField":{"type":"string"},"changes":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"transform, settings, authority, direction, condition, review, omitted or destinations."},"from":{"type":"string"},"to":{"type":"string"}},"required":["kind","from","to"]}}},"required":["sourceEntityId","sourceFieldId","targetEntityId","targetFieldId","sourceEntity","sourceField","targetEntity","targetField","changes"]},"description":"Links in both that differ."},"matchKeys":{"type":"array","items":{"type":"object","properties":{"sourceEntityId":{"type":"string"},"targetEntityId":{"type":"string"},"sourceEntity":{"type":"string"},"targetEntity":{"type":"string"},"from":{"type":"array","items":{"type":"string"}},"to":{"type":"array","items":{"type":"string"}}},"required":["sourceEntityId","targetEntityId","sourceEntity","targetEntity","from","to"]},"description":"Object pairs whose match key (\"Find existing records by\") changed."},"unchanged":{"type":"integer","description":"Links in both with nothing different."}},"required":["from","to","added","removed","changed","matchKeys","unchanged"]},"example":{"from":{"mappingId":"00000000-0000-0000-0000-000000000000","version":0},"to":{"mappingId":"00000000-0000-0000-0000-000000000000","version":0},"added":[{"sourceEntityId":"string","sourceFieldId":"string","targetEntityId":"string","targetFieldId":"string","sourceEntity":"string","sourceField":"string","targetEntity":"string","targetField":"string"}],"removed":[{"sourceEntityId":"string","sourceFieldId":"string","targetEntityId":"string","targetFieldId":"string","sourceEntity":"string","sourceField":"string","targetEntity":"string","targetField":"string"}],"changed":[{"sourceEntityId":"string","sourceFieldId":"string","targetEntityId":"string","targetFieldId":"string","sourceEntity":"string","sourceField":"string","targetEntity":"string","targetField":"string","changes":[{"kind":"string","from":"string","to":"string"}]}],"matchKeys":[{"sourceEntityId":"string","targetEntityId":"string","sourceEntity":"string","targetEntity":"string","from":["string"],"to":["string"]}],"unchanged":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/{id}/entity-match":{"patch":{"operationId":"SetEntityMatch","tags":["mappings"],"summary":"Set Entity Match","security":[{"ApiKeyAuth":["mappings:write"]},{"BearerAuth":[]},{"OAuth2":["mappings:write"]}],"description":"Choose the fields that identify the same real-world record in the target system, such as an email address or invoice number. Before creating a record, the sync looks for a target record with the same values in these fields and updates it instead, so you do not get duplicates. A value shared by more than one target record is ignored. Send an empty list to clear it. Saved as a new version: the answer lists in flowsBehind the flows still running an older version, which keep it until each is moved to the new one.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetEntityId":{"type":"string","description":"The kind of record in the target system."},"matchOn":{"type":"array","items":{"type":"string"},"maximum":10,"description":"The target fields that identify a record, for example [\"billing_email\"] or [\"invoice_number\"]. Up to 10."}},"required":["targetEntityId","matchOn"]},"example":{"targetEntityId":"string","matchOn":["string"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The id written inside the mapping document. Use the id in the path (or `id` from GET /v1/mappings) to address the mapping."},"version":{"type":"number"},"customerId":{"type":"string"},"sourceConnectionId":{"type":"string"},"targetConnectionId":{"type":"string"},"entityMappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sourceEntityId":{"type":"string"},"targetEntityId":{"type":"string"},"confidence":{"type":"number"},"entityRelationship":{"type":"string","description":"L15 relationship-inferrer's cross-provider equivalence verdict (equivalent / parent_child / related / unrelated) — refines whether the two entities should map at all. Open by design: a novel relationship label still flows through."},"fieldMappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sourceEntityId":{"type":"string"},"sourceFieldId":{"type":"string"},"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"authority":{"type":"string","description":"Known values: provider-wins, native-only, native-override, latest-wins, merge."},"conflictStrategy":{"type":"string","description":"Known values: latest-timestamp, highest-authority, flag-for-review."},"transform":{"type":"string","description":"Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"suggestedTransform":{"type":"string","description":"L17 transform-inferrer's raw OPEN suggestion (identity / unit_conversion / format_conversion / enum_mapping / …) — what the AI proposed before the customer confirmed the executable `transform`. Open by design: a novel transform label still flows through. Drives the transform-override control in the mapping review."},"transformConfig":{"type":"object","additionalProperties":true},"syncTier":{"type":"string","description":"Per-FIELD sync cadence (functionality.md: \"per-field sync tiers\"; VISUAL-MAPPING-SPEC §0.1) — seeded from the tenant's per-entity onboarding selection at pipeline activation, overridable per field in the mapping review. Absent = the pipeline's default cadence. Known values: realtime, near-realtime, periodic, archival."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-link predicate (§7: \"only when type = business\") evaluated against the SOURCE record by the shared field-evaluator — the field syncs only when it holds. Absent = always syncs. A malformed condition evaluates FALSE (fail closed)."},"direction":{"type":"string","description":"Per-FIELD flow direction (VISUAL-MAPPING-SPEC item 11): source-to-target, target-to-source, or bidirectional — any field can flow either way, both ways, or (via omitted) not at all. Absent = inherit the mapping's syncConfig.direction. Enforced by the shared evaluator's pass filter; on the reverse pass a non-invertible transform skips the field (visible in preview) rather than writing a wrongly-transformed value. Known values: source-to-target, target-to-source, bidirectional."},"confidence":{"type":"number"},"matchRationale":{"type":"string","description":"why Layer 5 proposed this pairing"},"customerApproved":{"type":"boolean"},"customerRejected":{"type":"boolean","description":"Customer explicitly marked this match WRONG (audit §2.3) — distinct from customerApproved:false, which also covers never-reviewed. Same optional-for-back-compat pattern as `omitted`. A rejected field is excluded from sync by the shared evaluator (a wrong match must not move data) and is the negative training signal's home. Cleared by a later approve."},"customerModified":{"type":"boolean","description":"customer changed the AI proposal"},"autoApplied":{"type":"boolean","description":"Applied automatically because confidence cleared the tenant's auto-apply threshold (mapping.autoApplyThreshold tunable, §11b) — deliberately NOT customerApproved, which stays a genuine customer signal; an auto-applied field the customer later approves or rejects converts to a real signal. Auto-applied fields skip the review queue but sync like approved ones; the manifest-level approval gate still applies."},"omitted":{"type":"boolean","description":"Customer chose not to sync this field — a business decision, NOT a correctness verdict (reject ≠ omit, VISUAL-MAPPING-SPEC §11a). Never touches customerApproved, feeds no training signal, and is sticky: re-matching carries it forward instead of re-proposing the field. Absent = syncs normally."},"omittedProposalChanged":{"type":"boolean","description":"Set by re-matching when a NEW proposal arrived for a field the customer omitted — surfaced as a note (\"a new proposal exists\"), never auto-restored. Cleared when the customer restores the field."},"manualAuthored":{"type":"boolean","description":"A human authored this link FROM NOTHING — the AI never proposed it (audit §2.4). Distinct from customerModified, which is AI-proposed-then-edited: different provenance, different training signal, and only this one is a durable TENANT FACT. Sticky exactly as `omitted` is: re-matching and healing carry it forward instead of dropping it, because a re-inference must never silently undo a decision a person made. Stays in the tenant's override layer and is NEVER promoted into the shared corpus without explicit vetting — a tenant's anomaly is not the platform's knowledge."},"manualProposalConflict":{"type":"boolean","description":"Set by re-matching when the AI proposed a DIFFERENT target for a source field the customer hand-mapped — surfaced as a note (\"the AI now proposes something else\"), never an auto-overwrite. The manual mapping wins and keeps running. Mirrors omittedProposalChanged; cleared when the customer resolves it."},"matchSource":{"type":"string","description":"Provenance of the proposal this mapping came from (see FieldMatchProposal.matchSource). Lets the review page and the engine comparison say whether a rule, the golden layer, the lake or a model proposed the pair. The API answers a model-proposed pair as plain `l95`: the provider and deployment stay in the stored record and never reach a tenant (DEBT-202)."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within the mapping — the key `dependsOn` and the dispatch ledger reference."},"kind":{"type":"string","description":"OPEN destination kind. 'record' = write into a connected system; 'action' = invoke a capability. Unknown kinds fail loudly at dispatch rather than being silently skipped — a destination nobody delivers is the shipped-but-inert shape."},"label":{"type":"string","description":"Human name shown wherever the destination appears — what the tenant called it, not a generated id."},"connectionId":{"type":"string","description":"For kind=record: which connected system receives it. Absent = the mapping's own target connection."},"targetEntityId":{"type":"string","description":"For kind=record: entity written into. Absent = the field mapping's own targetEntityId."},"targetFieldId":{"type":"string","description":"For kind=record: field written. Absent = the field mapping's own targetFieldId."},"channelType":{"type":"string","description":"For kind=action: HOW to deliver — an OPEN channel type resolved by the notification engine (email / sms / webhook / in_app / …). The same vocabulary alert rules use, so actions ride the ONE hardened delivery path rather than a second transport."},"channelTarget":{"type":"string","description":"For kind=action: WHO receives it (address, number, URL, or a channel id)."},"channelId":{"type":"string","description":"For kind=action: pin a specific notification_channels row instead of resolving the tenant's first verified channel of that type."},"order":{"type":"number","description":"Explicit sequence within the field's destination set. Ordering is REQUIRED, not cosmetic: \"save, and IF that committed, send\" is only expressible when the order is declared rather than inferred from array position."},"dependsOn":{"type":"string","description":"Destination id that must have COMMITTED for THIS record before this one runs. A failed or skipped dependency skips the dependant — the \"if that committed\" half of the ordering guarantee."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-destination predicate over the SOURCE record, evaluated by the shared field-evaluator — the same type and the same semantics as the per-field condition. Absent = always. A malformed condition evaluates FALSE (fail closed)."},"transform":{"type":"string","description":"Per-destination transform. Absent = inherit the field mapping's transform, so a destination only declares what DIFFERS. Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"transformConfig":{"type":"object","additionalProperties":true},"direction":{"type":"string","description":"Per-destination flow direction; absent = inherit the field mapping's. A destination only participates in a pass its direction allows. Known values: source-to-target, target-to-source, bidirectional."},"dedupeKeyFields":{"type":"array","items":{"type":"string"},"description":"Source-record fields forming the idempotency key. Absent, the key is the record's identity plus the value being delivered — so a re-sync of UNCHANGED data dispatches nothing while a genuine change still does. This is not optional decoration: a backfill over an action destination is how a tenant discovers 40,000 text messages."},"maxPerMinute":{"type":"number","description":"Per-tenant ceiling on dispatches to THIS destination. When the trailing minute is already at the ceiling, dispatch to this destination halts for the rest of the run and the skipped count is recorded and surfaced — a safety valve that is visible rather than silent."},"enabled":{"type":"boolean","description":"Absent = enabled. Turning a destination off must not require deleting it, or the only way to pause an action is to lose its configuration."}},"required":["id","kind","label","order"]},"description":"ADDITIONAL destinations this field reaches beyond its primary target — the end of the one-field-one-destination model (§2.3/§3.3). Absent = the field behaves exactly as before, which is why adding fan-out changes nothing for an existing mapping. Dispatched in `order` after the primary sink write, so a record destination and an action destination can be sequenced (\"save, and if that committed, send\")."},"alternatives":{"type":"array","items":{"type":"object","properties":{"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"score":{"type":"number","description":"The number that ranked this candidate, in the units scoreKind names."},"scoreKind":{"type":"string","description":"OPEN vocabulary naming what `score` is: `lexical` (token-overlap rank from explainCandidates, unbounded), `embedding` (cosine similarity, -1..1), `model` (the matching model's own 0..1 confidence for this pair). A novel kind flows through as a string; a UI that does not know it shows no number."},"matchSource":{"type":"string","description":"Which stage ranked it (`embedding-candidate`, `lexical-candidate`, or `l95:<provider>:<deployment>` for a model answer — the API strips the provider and deployment, DEBT-202)."}},"required":["targetEntityId","targetFieldId","score","scoreKind","matchSource"]},"description":"The runners-up the matcher ranked for this source field, best first, never including this mapping's own target (OPEN-WORK 128 d). Read only by the review UI — nothing in sync or resolution reads it. Absent = the matcher ranked nothing else (a rule decided the pair) or the mapping predates the field. Re-matching carries it forward onto an unchanged pair that came back without any."}},"required":["id","sourceEntityId","sourceFieldId","targetEntityId","targetFieldId","authority","conflictStrategy","transform","confidence","matchRationale","customerApproved","customerModified"]}},"matchOn":{"type":"array","items":{"type":"string"},"description":"Target field api names that identify the same real-world record (target-id memory, 2026-10-08), e.g. ['billing_email'] or ['invoice_number']. Before creating a record it has no link for, the sync reads the target entity and links to an existing row whose values on every matchOn field equal the outgoing record's, then updates it instead of creating a duplicate. Empty or absent = no matching. Set with PATCH /v1/mappings/:id/entity-match."},"goldenId":{"type":"object","properties":{"targetField":{"type":"string","description":"Dotted target field the golden record id is written to (`customer_ids.inferrex_id`)."},"matchTargetField":{"type":"string","description":"Dotted target field holding the shared id after projection (`customer_ids.registered`)."},"goldenEntityType":{"type":"string","description":"The golden records searched: their entity type."},"goldenField":{"type":"string","description":"The golden field compared with the shared id, exactly (no case folding: an id is an id)."}},"required":["targetField","matchTargetField","goldenEntityType","goldenField"],"description":"Stamp each outgoing record with the id of the golden record it belongs to (2026-10-27, Bloomreach Engagement phase 1, D13: every command carries the tenant's own id AND the golden id). After the fields are projected, the sync finds the ONE golden record of `goldenEntityType` whose `goldenField` equals the value the record carries at `matchTargetField`, and writes its id at `targetField`. None or several: nothing is written there, and the count is logged. Absent = no stamp. Set by an approved destination setup plan."},"each":{"type":"object","properties":{"field":{"type":"string","description":"Dotted path of the list in the source record (`items`). A value that is not a list sends nothing; an element that is not an object is skipped."},"parentAs":{"type":"string","description":"The key the whole source record is read under while one element is projected (`$parent`): a field mapping reading `$parent.customer_email` reads the source record's own field."},"idField":{"type":"string","description":"The element's own field that identifies it (a line id), so an element keeps its record id (`<record>#<list>[<field>=<value>]`) when lines are inserted or reordered and is sent once (2026-10-28, Sentry on #847). Absent, or an element without a value there: the element is known by its position (`<record>#<list>[<n>]`), and a line inserted or reordered after the record was sent may be sent twice or not at all."}},"required":["field","parentAs"],"description":"One outgoing record per element of a list in the source record (2026-10-28, generic; Bloomreach Engagement: one `purchase_item` event per order line beside the order's `purchase`). The field mappings are projected once per element that is an object, reading the element's own fields by name and the source record's under `parentAs` (`$parent.id`); each result is written to `targetEntityId` as a record of its own, after the source record's own write and only when that write went out (a source record held back, refused or left out by a send rule takes its elements with it). Forward pass only. Absent = one record per source record, as before. Set by an approved destination setup plan."}},"required":["id","sourceEntityId","targetEntityId","confidence","fieldMappings"]},"description":"Each object pairing, with its field mappings: transform, authority, confidence, direction, condition, destinations and review state (customerApproved, customerRejected, omitted, manualAuthored). A field mapping may carry `alternatives`: the target fields the matcher ranked for that source field but did not choose, best first, each { targetEntityId, targetFieldId, score, scoreKind, matchSource }. `score` is a confidence only when scoreKind is `model`; `lexical` is a token-overlap rank and `embedding` a cosine similarity, so never show those as percentages. GET /v1/mappings/:id/field-candidates ranks more, with reasons."},"groupDestinations":{"type":"array","items":{"type":"object","properties":{"group":{"type":"string","description":"The open group label these destinations apply to — matched against InferredField.group."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within the mapping — the key `dependsOn` and the dispatch ledger reference."},"kind":{"type":"string","description":"OPEN destination kind. 'record' = write into a connected system; 'action' = invoke a capability. Unknown kinds fail loudly at dispatch rather than being silently skipped — a destination nobody delivers is the shipped-but-inert shape."},"label":{"type":"string","description":"Human name shown wherever the destination appears — what the tenant called it, not a generated id."},"connectionId":{"type":"string","description":"For kind=record: which connected system receives it. Absent = the mapping's own target connection."},"targetEntityId":{"type":"string","description":"For kind=record: entity written into. Absent = the field mapping's own targetEntityId."},"targetFieldId":{"type":"string","description":"For kind=record: field written. Absent = the field mapping's own targetFieldId."},"channelType":{"type":"string","description":"For kind=action: HOW to deliver — an OPEN channel type resolved by the notification engine (email / sms / webhook / in_app / …). The same vocabulary alert rules use, so actions ride the ONE hardened delivery path rather than a second transport."},"channelTarget":{"type":"string","description":"For kind=action: WHO receives it (address, number, URL, or a channel id)."},"channelId":{"type":"string","description":"For kind=action: pin a specific notification_channels row instead of resolving the tenant's first verified channel of that type."},"order":{"type":"number","description":"Explicit sequence within the field's destination set. Ordering is REQUIRED, not cosmetic: \"save, and IF that committed, send\" is only expressible when the order is declared rather than inferred from array position."},"dependsOn":{"type":"string","description":"Destination id that must have COMMITTED for THIS record before this one runs. A failed or skipped dependency skips the dependant — the \"if that committed\" half of the ordering guarantee."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-destination predicate over the SOURCE record, evaluated by the shared field-evaluator — the same type and the same semantics as the per-field condition. Absent = always. A malformed condition evaluates FALSE (fail closed)."},"transform":{"type":"string","description":"Per-destination transform. Absent = inherit the field mapping's transform, so a destination only declares what DIFFERS. Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"transformConfig":{"type":"object","additionalProperties":true},"direction":{"type":"string","description":"Per-destination flow direction; absent = inherit the field mapping's. A destination only participates in a pass its direction allows. Known values: source-to-target, target-to-source, bidirectional."},"dedupeKeyFields":{"type":"array","items":{"type":"string"},"description":"Source-record fields forming the idempotency key. Absent, the key is the record's identity plus the value being delivered — so a re-sync of UNCHANGED data dispatches nothing while a genuine change still does. This is not optional decoration: a backfill over an action destination is how a tenant discovers 40,000 text messages."},"maxPerMinute":{"type":"number","description":"Per-tenant ceiling on dispatches to THIS destination. When the trailing minute is already at the ceiling, dispatch to this destination halts for the rest of the run and the skipped count is recorded and surfaced — a safety valve that is visible rather than silent."},"enabled":{"type":"boolean","description":"Absent = enabled. Turning a destination off must not require deleting it, or the only way to pause an action is to lose its configuration."}},"required":["id","kind","label","order"]},"description":"The same destination shape a field declares, so there is one vocabulary and one executor rather than a parallel group path."}},"required":["group","destinations"]},"description":"Destinations declared for a whole field group. Absent when every destination is declared per field."},"syncConfig":{"type":"object","properties":{"mode":{"type":"string","description":"Known values: realtime, near-realtime, periodic, archival."},"direction":{"type":"string","description":"Known values: source-to-target, target-to-source, bidirectional."},"schedule":{"type":"string","description":"cron expression for periodic"},"intervalMinutes":{"type":"number","description":"for near-realtime"},"realtimeChannel":{"type":"string","description":"webhook/CDC channel for realtime"},"sourceType":{"type":"string","description":"How the source delivers data — drives the sync dispatch branch. Default (absent) is periodic = the batch job path; realtime subscribes to streamConfig via the QueueClient. Known values: realtime, near-realtime, periodic."},"streamConfig":{"type":"object","properties":{"broker":{"type":"string","description":"Known values: pubsub, nats, kafka, amqp, kinesis."},"topic":{"type":"string"},"offset":{"type":"string","description":"Known values: earliest, latest."}},"required":["broker"],"description":"Per-source stream binding for realtime sources. pubsub/nats resolve via the QueueClient today; kafka/amqp/kinesis are broker clients landing in unit A.5. Open by design — the broker set tracks the QueueClient providers + planned brokers."},"targetType":{"type":"string","description":"Where the synced records land — drives the sync WRITE branch (Phase 2 B.10). Default (absent) is api = the existing HTTP write to the target ConnectionManifest. warehouse → getWarehouseClient().upsert (analytical sink, schema ensured from the mapping); lake → getLakeClient().write (partitioned object-store landing tier). Both the batch and realtime paths flow through the SAME sink. Known values: api, warehouse, lake."},"targetTable":{"type":"string","description":"Explicit warehouse table / lake dataset name override (B.11). When absent the sink derives one table per target entity from the mapping (the targetEntityId apiName, sanitised). Set this to land every entity into one named table."},"batchSize":{"type":"number"},"retryPolicy":{"type":"object","properties":{"maxAttempts":{"type":"number"},"backoffMs":{"type":"number"},"backoffMultiplier":{"type":"number"}},"required":["maxAttempts","backoffMs","backoffMultiplier"]}},"required":["mode","direction","batchSize","retryPolicy"]},"matchedAt":{"type":"string"},"matchedBy":{"type":"string"},"overallConfidence":{"type":"number","description":"0 to 1."},"status":{"type":"string","description":"The status written inside the mapping document. Approving a mapping changes the stored version's status, not this one, so read approval from `status` on GET /v1/mappings. Known values: draft, awaiting-review, approved, active, paused."},"customerApprovedAt":{"type":"string"},"customerApprovedBy":{"type":"string"},"engine":{"type":"string","description":"Which match engine produced the mapping, e.g. v1, v2."},"engineArm":{"type":"string"},"engineFallbackReason":{"type":"string"},"archived":{"type":"boolean","description":"True when the mapping was archived (POST /v1/mappings/:id/archive). An archived mapping is left out of the lists and search but can still be read by id."},"flowsBehind":{"type":"array","items":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"pinnedMappingId":{"type":"string","format":"uuid","description":"The version the flow runs."},"headMappingId":{"type":"string","format":"uuid","description":"The version this edit saved."}},"required":["pipelineId","name","status","pinnedMappingId","headMappingId"]},"description":"The flows (pipelines) still running an older version of this mapping after the edit: each keeps its version until it is moved with POST /v1/pipelines/:id/apply-mapping, naming headMappingId. Empty when no flow is behind. Archived flows are left out."}},"required":["id","version","customerId","sourceConnectionId","targetConnectionId","entityMappings","syncConfig","matchedAt","matchedBy","overallConfidence","status","archived","flowsBehind"]},"example":{"id":"string","version":0,"customerId":"string","sourceConnectionId":"string","targetConnectionId":"string","entityMappings":[{"id":"string","sourceEntityId":"string","targetEntityId":"string","confidence":0,"entityRelationship":"string","fieldMappings":[{"id":"string","sourceEntityId":"string","sourceFieldId":"string","targetEntityId":"string","targetFieldId":"string","authority":"string","conflictStrategy":"string","transform":"string","suggestedTransform":"string","transformConfig":{},"syncTier":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"direction":"string","confidence":0,"matchRationale":"string","customerApproved":true,"customerRejected":true,"customerModified":true,"autoApplied":true,"omitted":true,"omittedProposalChanged":true,"manualAuthored":true,"manualProposalConflict":true,"matchSource":"string","destinations":[{"id":"string","kind":"string","label":"string","connectionId":"string","targetEntityId":"string","targetFieldId":"string","channelType":"string","channelTarget":"string","channelId":"string","order":0,"dependsOn":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"transform":"string","transformConfig":{},"direction":"string","dedupeKeyFields":["string"],"maxPerMinute":0,"enabled":true}],"alternatives":[{"targetEntityId":"string","targetFieldId":"string","score":0,"scoreKind":"string","matchSource":"string"}]}],"matchOn":["string"],"goldenId":{"targetField":"string","matchTargetField":"string","goldenEntityType":"string","goldenField":"string"},"each":{"field":"string","parentAs":"string","idField":"string"}}],"groupDestinations":[{"group":"string","destinations":[{"id":"string","kind":"string","label":"string","connectionId":"string","targetEntityId":"string","targetFieldId":"string","channelType":"string","channelTarget":"string","channelId":"string","order":0,"dependsOn":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"transform":"string","transformConfig":{},"direction":"string","dedupeKeyFields":["string"],"maxPerMinute":0,"enabled":true}]}],"syncConfig":{"mode":"string","direction":"string","schedule":"string","intervalMinutes":0,"realtimeChannel":"string","sourceType":"string","streamConfig":{"broker":"string","topic":"string","offset":"string"},"targetType":"string","targetTable":"string","batchSize":0,"retryPolicy":{"maxAttempts":0,"backoffMs":0,"backoffMultiplier":0}},"matchedAt":"string","matchedBy":"string","overallConfidence":0,"status":"string","customerApprovedAt":"string","customerApprovedBy":"string","engine":"string","engineArm":"string","engineFallbackReason":"string","archived":true,"flowsBehind":[{"pipelineId":"00000000-0000-0000-0000-000000000000","name":"string","status":"string","pinnedMappingId":"00000000-0000-0000-0000-000000000000","headMappingId":"00000000-0000-0000-0000-000000000000"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/{id}/estate":{"get":{"operationId":"GetMappingEstate","tags":["mappings"],"summary":"Get Mapping Estate","security":[{"ApiKeyAuth":["mappings:read"]},{"BearerAuth":[]},{"OAuth2":["mappings:read"]}],"description":"Show one real record from the source system beside the matching record in the target, with a line joining each pair of fields that is approved and written. Fields you have held back, left out or rejected are not joined, and a target record that is not the same real-world record is not shown. Read only. Looks at up to the first 300 records.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":299,"description":"Which source record to show, counting from 0, within the first 300.","default":0},"description":"Which source record to show, counting from 0, within the first 300."},{"name":"entity","in":"query","required":false,"schema":{"type":"string","description":"Which kind of source record to show. Defaults to the one with the most approved fields."},"description":"Which kind of source record to show. Defaults to the one with the most approved fields."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"sourceSystem":{"type":"string"},"targetSystem":{"type":"string"},"sourceEntity":{"type":"string"},"targetEntity":{"type":"string"},"sourceEntityLabel":{"type":"string"},"targetEntityLabel":{"type":"string"},"offset":{"type":"integer"},"total":{"type":"integer"},"matched":{"type":"boolean"},"label":{"type":"string","description":"A short name for this source record. Empty when there is no record at this position."},"note":{"type":"string","nullable":true,"description":"Why nothing lines up, or that the list was capped. Null when there is nothing to say."},"join":{"type":"object","properties":{"sourceField":{"type":"string"},"targetField":{"type":"string"},"sourceLabel":{"type":"string"},"targetLabel":{"type":"string"},"sourceValue":{"type":"string"},"targetValue":{"type":"string","nullable":true,"description":"Null when no target record shares the value."}},"required":["sourceField","targetField","sourceLabel","targetLabel","sourceValue","targetValue"],"nullable":true,"description":"The shared value that makes the target row the same record (an email by preference). Null when no field on this record can line the two systems up."},"written":{"type":"array","items":{"type":"object","properties":{"sourceField":{"type":"string","description":"Source field api name."},"targetField":{"type":"string","description":"Target field api name."},"sourceLabel":{"type":"string"},"targetLabel":{"type":"string"},"sourceValue":{"type":"string","nullable":true,"description":"The value on this source record, as display text (long values are cut)."},"targetValue":{"type":"string","nullable":true,"description":"The value on the matching target record. Null when no target record matched."},"verdict":{"type":"object","properties":{"agreement":{"type":"string","description":"Known values: match, equivalent, different, one-sided."},"agreementLabel":{"type":"string"},"goldenValue":{"type":"string","nullable":true},"winner":{"type":"string","description":"Which side the golden record keeps. Known values: source, target, either, unresolved."},"goldenLabel":{"type":"string","description":"One sentence saying why."}},"required":["agreement","agreementLabel","goldenValue","winner","goldenLabel"],"description":"Whether the two values agree and which one the golden record would keep. Read only."}},"required":["sourceField","targetField","sourceLabel","targetLabel","sourceValue","targetValue","verdict"]},"description":"Fields that are approved and would be written into the target, one line each."},"held":{"type":"array","items":{"type":"object","properties":{"sourceField":{"type":"string","description":"Source field api name."},"targetField":{"type":"string","description":"Target field api name."},"sourceLabel":{"type":"string"},"targetLabel":{"type":"string"},"sourceValue":{"type":"string","nullable":true,"description":"The value on this source record, as display text (long values are cut)."},"targetValue":{"type":"string","nullable":true,"description":"The value on the matching target record. Null when no target record matched."},"verdict":{"type":"object","properties":{"agreement":{"type":"string","description":"Known values: match, equivalent, different, one-sided."},"agreementLabel":{"type":"string"},"goldenValue":{"type":"string","nullable":true},"winner":{"type":"string","description":"Which side the golden record keeps. Known values: source, target, either, unresolved."},"goldenLabel":{"type":"string","description":"One sentence saying why."}},"required":["agreement","agreementLabel","goldenValue","winner","goldenLabel"],"description":"Whether the two values agree and which one the golden record would keep. Read only."},"reason":{"type":"string","description":"Why the field stays off, e.g. not approved, rejected, left off the sync, flows the other way, its condition does not hold, or no value."}},"required":["sourceField","targetField","sourceLabel","targetLabel","sourceValue","targetValue","verdict","reason"]},"description":"Fields that would not be written for this record, each with the reason."},"otherPairs":{"type":"integer","description":"Other object pairings in this mapping, viewable with `entity`."},"relation":{"type":"object","properties":{"kind":{"type":"string","description":"Known values: none, one-to-one, one-to-many, many-to-one, many-to-many."},"sourceCount":{"type":"integer"},"targetCount":{"type":"integer"},"label":{"type":"string"}},"required":["kind","sourceCount","targetCount","label"],"description":"How many rows in each system share the join value: one-to-one, one-to-many, many-to-one, or many-to-many."},"places":{"type":"array","items":{"type":"object","properties":{"system":{"type":"string"},"entity":{"type":"string","description":"Empty when the system could not be read or has no object with an email."},"count":{"type":"integer","description":"Rows there that share the email. On the last \"Other systems\" row: how many systems were not read."},"note":{"type":"string"},"rows":{"type":"integer","nullable":true,"description":"Rows in the list that was read. Null when it could not be read."},"unique":{"type":"integer","nullable":true,"description":"Distinct records in that list. Copies of one email or phone count once."}},"required":["system","entity","count","note","rows","unique"]},"nullable":true,"description":"Other connected systems lined up on this email, with a count of copies. Read only. Null when the record has no email."},"census":{"type":"array","items":{"type":"object","properties":{"system":{"type":"string"},"entity":{"type":"string"},"rows":{"type":"integer","nullable":true},"unique":{"type":"integer","nullable":true},"note":{"type":"string","nullable":true}},"required":["system","entity","rows","unique","note"]},"description":"Each system on this record: row count and unique record count. Copies of one email or phone count once. Absent when no source record was shown."}},"required":["sourceSystem","targetSystem","sourceEntity","targetEntity","sourceEntityLabel","targetEntityLabel","offset","total","matched","label","note","join","written","held","otherPairs","relation","places"]},"example":{"sourceSystem":"string","targetSystem":"string","sourceEntity":"string","targetEntity":"string","sourceEntityLabel":"string","targetEntityLabel":"string","offset":0,"total":0,"matched":true,"label":"string","note":"string","join":{"sourceField":"string","targetField":"string","sourceLabel":"string","targetLabel":"string","sourceValue":"string","targetValue":"string"},"written":[{"sourceField":"string","targetField":"string","sourceLabel":"string","targetLabel":"string","sourceValue":"string","targetValue":"string","verdict":{"agreement":"string","agreementLabel":"string","goldenValue":"string","winner":"string","goldenLabel":"string"}}],"held":[{"sourceField":"string","targetField":"string","sourceLabel":"string","targetLabel":"string","sourceValue":"string","targetValue":"string","verdict":{"agreement":"string","agreementLabel":"string","goldenValue":"string","winner":"string","goldenLabel":"string"},"reason":"string"}],"otherPairs":0,"relation":{"kind":"string","sourceCount":0,"targetCount":0,"label":"string"},"places":[{"system":"string","entity":"string","count":0,"note":"string","rows":0,"unique":0}],"census":[{"system":"string","entity":"string","rows":0,"unique":0,"note":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/{id}/field-candidates":{"get":{"operationId":"GetMappingFieldCandidates","tags":["mappings"],"summary":"Get Mapping Field Candidates","security":[{"ApiKeyAuth":["mappings:read"]},{"BearerAuth":[]},{"OAuth2":["mappings:read"]}],"description":"Ranks the fields of this mapping's target system for one source field, using the same lexical rule the matcher uses to choose candidates: same field name, shared words, same meaning (role) and same type. Each candidate lists the reasons that held. `score` is that rule's rank (it can be above 1) and is NOT a confidence — scoreKind is always `lexical` here; never show it as a percentage. linkedHere marks a target this mapping already links the source field to. Fields excluded from either connection are left out. No AI model is called.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},{"name":"sourceEntityId","in":"query","required":true,"schema":{"type":"string","maxLength":300,"description":"The source field's entity id (or API name) in the source connection."},"description":"The source field's entity id (or API name) in the source connection."},{"name":"sourceFieldId","in":"query","required":true,"schema":{"type":"string","maxLength":500,"description":"The source field's id (or API name)."},"description":"The source field's id (or API name)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"sourceEntityId":{"type":"string"},"sourceFieldId":{"type":"string"},"sourceEntity":{"type":"string","description":"Entity API name."},"sourceField":{"type":"string","description":"Field API name."},"scoreKind":{"type":"string","description":"What every `score` below is: `lexical` (a token-overlap rank, not a confidence)."},"candidates":{"type":"array","items":{"type":"object","properties":{"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"targetEntity":{"type":"string","description":"Entity API name."},"targetField":{"type":"string","description":"Field API name."},"targetType":{"type":"string"},"score":{"type":"number","description":"The lexical rank. Not a confidence."},"reasons":{"type":"array","items":{"type":"string"},"description":"Why it ranks, in plain words — only the rules that held."},"linkedHere":{"type":"boolean","description":"This mapping already has a live link from the source field to this target field."}},"required":["targetEntityId","targetFieldId","targetEntity","targetField","targetType","score","reasons","linkedHere"]},"description":"Best first, at most mapping.fieldCandidatesLimit."}},"required":["sourceEntityId","sourceFieldId","sourceEntity","sourceField","scoreKind","candidates"]},"example":{"sourceEntityId":"string","sourceFieldId":"string","sourceEntity":"string","sourceField":"string","scoreKind":"string","candidates":[{"targetEntityId":"string","targetFieldId":"string","targetEntity":"string","targetField":"string","targetType":"string","score":0,"reasons":["string"],"linkedHere":true}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/{id}/field-mapping":{"patch":{"operationId":"UpdateFieldMapping","tags":["mappings"],"summary":"Update Field Mapping","security":[{"ApiKeyAuth":["mappings:write"]},{"BearerAuth":[]},{"OAuth2":["mappings:write"]}],"description":"Change one field-to-field link: how values are converted, which system wins when they disagree, whether it is approved or rejected, or whether it is left out. Leaving a link out means “do not sync this field”; rejecting it means “this link is wrong”. Leaving out does not change whether the link is approved. Saved as a new version: the answer lists in flowsBehind the flows still running an older version, which keep it until each is moved to the new one.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fieldMappingId":{"type":"string","format":"uuid","description":"The id of the field-to-field link to change."},"transform":{"type":"string","description":"How to convert the value on the way: direct, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, or golden-lookup (read the value from a related golden record; needs transformConfig)."},"transformConfig":{"type":"object","additionalProperties":true,"nullable":true,"description":"Settings for the conversion. map-values or lookup: {mappings, default?}. concatenate: {fields, separator?}. split: {separator?, index?}. type-cast: {targetType}. default-value: {defaultValue}. format: {format}. formula: {expression}. golden-lookup (required, sent with the transform): {goldenEntityType, sourceIdKey, returnField, sourceField?, fallbackVia?: {viaField, goldenEntityType, sourceIdKey, returnField}, format?, optional?} — the value is read from the golden record of goldenEntityType whose source_ids.<sourceIdKey> equals the source field (sourceField, else the link's own source field) (a Stripe charge's metadata.myobos_order_id → the golden order's email); with fallbackVia, a golden record with no returnField is followed by its viaField to a second golden record. A record whose lookup finds nothing is held back for review, never sent without the value, unless optional is true. Send null to clear it."},"authority":{"type":"string","description":"Which system wins when the two disagree."},"syncTier":{"type":"string","description":"How promptly this field syncs: realtime, near-realtime, periodic or archival."},"direction":{"type":"string","description":"Which way this field flows: source-to-target, target-to-source or bidirectional. Leave out to use the mapping’s direction."},"condition":{"type":"object","additionalProperties":true,"nullable":true,"description":"Only sync this field when a condition holds, as {field, op, value}, with more checks in also (each {field, op, value}) combined by match: all (the default) or any. Send null to clear it."},"approved":{"type":"boolean","description":"true to approve the link, false to reject it."},"omitted":{"type":"boolean","description":"true to leave this field out of syncs, false to put it back."}},"required":["fieldMappingId"]},"example":{"fieldMappingId":"00000000-0000-0000-0000-000000000000","transform":"string","transformConfig":{},"authority":"string","syncTier":"string","direction":"string","condition":{},"approved":true,"omitted":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The id written inside the mapping document. Use the id in the path (or `id` from GET /v1/mappings) to address the mapping."},"version":{"type":"number"},"customerId":{"type":"string"},"sourceConnectionId":{"type":"string"},"targetConnectionId":{"type":"string"},"entityMappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sourceEntityId":{"type":"string"},"targetEntityId":{"type":"string"},"confidence":{"type":"number"},"entityRelationship":{"type":"string","description":"L15 relationship-inferrer's cross-provider equivalence verdict (equivalent / parent_child / related / unrelated) — refines whether the two entities should map at all. Open by design: a novel relationship label still flows through."},"fieldMappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sourceEntityId":{"type":"string"},"sourceFieldId":{"type":"string"},"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"authority":{"type":"string","description":"Known values: provider-wins, native-only, native-override, latest-wins, merge."},"conflictStrategy":{"type":"string","description":"Known values: latest-timestamp, highest-authority, flag-for-review."},"transform":{"type":"string","description":"Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"suggestedTransform":{"type":"string","description":"L17 transform-inferrer's raw OPEN suggestion (identity / unit_conversion / format_conversion / enum_mapping / …) — what the AI proposed before the customer confirmed the executable `transform`. Open by design: a novel transform label still flows through. Drives the transform-override control in the mapping review."},"transformConfig":{"type":"object","additionalProperties":true},"syncTier":{"type":"string","description":"Per-FIELD sync cadence (functionality.md: \"per-field sync tiers\"; VISUAL-MAPPING-SPEC §0.1) — seeded from the tenant's per-entity onboarding selection at pipeline activation, overridable per field in the mapping review. Absent = the pipeline's default cadence. Known values: realtime, near-realtime, periodic, archival."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-link predicate (§7: \"only when type = business\") evaluated against the SOURCE record by the shared field-evaluator — the field syncs only when it holds. Absent = always syncs. A malformed condition evaluates FALSE (fail closed)."},"direction":{"type":"string","description":"Per-FIELD flow direction (VISUAL-MAPPING-SPEC item 11): source-to-target, target-to-source, or bidirectional — any field can flow either way, both ways, or (via omitted) not at all. Absent = inherit the mapping's syncConfig.direction. Enforced by the shared evaluator's pass filter; on the reverse pass a non-invertible transform skips the field (visible in preview) rather than writing a wrongly-transformed value. Known values: source-to-target, target-to-source, bidirectional."},"confidence":{"type":"number"},"matchRationale":{"type":"string","description":"why Layer 5 proposed this pairing"},"customerApproved":{"type":"boolean"},"customerRejected":{"type":"boolean","description":"Customer explicitly marked this match WRONG (audit §2.3) — distinct from customerApproved:false, which also covers never-reviewed. Same optional-for-back-compat pattern as `omitted`. A rejected field is excluded from sync by the shared evaluator (a wrong match must not move data) and is the negative training signal's home. Cleared by a later approve."},"customerModified":{"type":"boolean","description":"customer changed the AI proposal"},"autoApplied":{"type":"boolean","description":"Applied automatically because confidence cleared the tenant's auto-apply threshold (mapping.autoApplyThreshold tunable, §11b) — deliberately NOT customerApproved, which stays a genuine customer signal; an auto-applied field the customer later approves or rejects converts to a real signal. Auto-applied fields skip the review queue but sync like approved ones; the manifest-level approval gate still applies."},"omitted":{"type":"boolean","description":"Customer chose not to sync this field — a business decision, NOT a correctness verdict (reject ≠ omit, VISUAL-MAPPING-SPEC §11a). Never touches customerApproved, feeds no training signal, and is sticky: re-matching carries it forward instead of re-proposing the field. Absent = syncs normally."},"omittedProposalChanged":{"type":"boolean","description":"Set by re-matching when a NEW proposal arrived for a field the customer omitted — surfaced as a note (\"a new proposal exists\"), never auto-restored. Cleared when the customer restores the field."},"manualAuthored":{"type":"boolean","description":"A human authored this link FROM NOTHING — the AI never proposed it (audit §2.4). Distinct from customerModified, which is AI-proposed-then-edited: different provenance, different training signal, and only this one is a durable TENANT FACT. Sticky exactly as `omitted` is: re-matching and healing carry it forward instead of dropping it, because a re-inference must never silently undo a decision a person made. Stays in the tenant's override layer and is NEVER promoted into the shared corpus without explicit vetting — a tenant's anomaly is not the platform's knowledge."},"manualProposalConflict":{"type":"boolean","description":"Set by re-matching when the AI proposed a DIFFERENT target for a source field the customer hand-mapped — surfaced as a note (\"the AI now proposes something else\"), never an auto-overwrite. The manual mapping wins and keeps running. Mirrors omittedProposalChanged; cleared when the customer resolves it."},"matchSource":{"type":"string","description":"Provenance of the proposal this mapping came from (see FieldMatchProposal.matchSource). Lets the review page and the engine comparison say whether a rule, the golden layer, the lake or a model proposed the pair. The API answers a model-proposed pair as plain `l95`: the provider and deployment stay in the stored record and never reach a tenant (DEBT-202)."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within the mapping — the key `dependsOn` and the dispatch ledger reference."},"kind":{"type":"string","description":"OPEN destination kind. 'record' = write into a connected system; 'action' = invoke a capability. Unknown kinds fail loudly at dispatch rather than being silently skipped — a destination nobody delivers is the shipped-but-inert shape."},"label":{"type":"string","description":"Human name shown wherever the destination appears — what the tenant called it, not a generated id."},"connectionId":{"type":"string","description":"For kind=record: which connected system receives it. Absent = the mapping's own target connection."},"targetEntityId":{"type":"string","description":"For kind=record: entity written into. Absent = the field mapping's own targetEntityId."},"targetFieldId":{"type":"string","description":"For kind=record: field written. Absent = the field mapping's own targetFieldId."},"channelType":{"type":"string","description":"For kind=action: HOW to deliver — an OPEN channel type resolved by the notification engine (email / sms / webhook / in_app / …). The same vocabulary alert rules use, so actions ride the ONE hardened delivery path rather than a second transport."},"channelTarget":{"type":"string","description":"For kind=action: WHO receives it (address, number, URL, or a channel id)."},"channelId":{"type":"string","description":"For kind=action: pin a specific notification_channels row instead of resolving the tenant's first verified channel of that type."},"order":{"type":"number","description":"Explicit sequence within the field's destination set. Ordering is REQUIRED, not cosmetic: \"save, and IF that committed, send\" is only expressible when the order is declared rather than inferred from array position."},"dependsOn":{"type":"string","description":"Destination id that must have COMMITTED for THIS record before this one runs. A failed or skipped dependency skips the dependant — the \"if that committed\" half of the ordering guarantee."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-destination predicate over the SOURCE record, evaluated by the shared field-evaluator — the same type and the same semantics as the per-field condition. Absent = always. A malformed condition evaluates FALSE (fail closed)."},"transform":{"type":"string","description":"Per-destination transform. Absent = inherit the field mapping's transform, so a destination only declares what DIFFERS. Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"transformConfig":{"type":"object","additionalProperties":true},"direction":{"type":"string","description":"Per-destination flow direction; absent = inherit the field mapping's. A destination only participates in a pass its direction allows. Known values: source-to-target, target-to-source, bidirectional."},"dedupeKeyFields":{"type":"array","items":{"type":"string"},"description":"Source-record fields forming the idempotency key. Absent, the key is the record's identity plus the value being delivered — so a re-sync of UNCHANGED data dispatches nothing while a genuine change still does. This is not optional decoration: a backfill over an action destination is how a tenant discovers 40,000 text messages."},"maxPerMinute":{"type":"number","description":"Per-tenant ceiling on dispatches to THIS destination. When the trailing minute is already at the ceiling, dispatch to this destination halts for the rest of the run and the skipped count is recorded and surfaced — a safety valve that is visible rather than silent."},"enabled":{"type":"boolean","description":"Absent = enabled. Turning a destination off must not require deleting it, or the only way to pause an action is to lose its configuration."}},"required":["id","kind","label","order"]},"description":"ADDITIONAL destinations this field reaches beyond its primary target — the end of the one-field-one-destination model (§2.3/§3.3). Absent = the field behaves exactly as before, which is why adding fan-out changes nothing for an existing mapping. Dispatched in `order` after the primary sink write, so a record destination and an action destination can be sequenced (\"save, and if that committed, send\")."},"alternatives":{"type":"array","items":{"type":"object","properties":{"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"score":{"type":"number","description":"The number that ranked this candidate, in the units scoreKind names."},"scoreKind":{"type":"string","description":"OPEN vocabulary naming what `score` is: `lexical` (token-overlap rank from explainCandidates, unbounded), `embedding` (cosine similarity, -1..1), `model` (the matching model's own 0..1 confidence for this pair). A novel kind flows through as a string; a UI that does not know it shows no number."},"matchSource":{"type":"string","description":"Which stage ranked it (`embedding-candidate`, `lexical-candidate`, or `l95:<provider>:<deployment>` for a model answer — the API strips the provider and deployment, DEBT-202)."}},"required":["targetEntityId","targetFieldId","score","scoreKind","matchSource"]},"description":"The runners-up the matcher ranked for this source field, best first, never including this mapping's own target (OPEN-WORK 128 d). Read only by the review UI — nothing in sync or resolution reads it. Absent = the matcher ranked nothing else (a rule decided the pair) or the mapping predates the field. Re-matching carries it forward onto an unchanged pair that came back without any."}},"required":["id","sourceEntityId","sourceFieldId","targetEntityId","targetFieldId","authority","conflictStrategy","transform","confidence","matchRationale","customerApproved","customerModified"]}},"matchOn":{"type":"array","items":{"type":"string"},"description":"Target field api names that identify the same real-world record (target-id memory, 2026-10-08), e.g. ['billing_email'] or ['invoice_number']. Before creating a record it has no link for, the sync reads the target entity and links to an existing row whose values on every matchOn field equal the outgoing record's, then updates it instead of creating a duplicate. Empty or absent = no matching. Set with PATCH /v1/mappings/:id/entity-match."},"goldenId":{"type":"object","properties":{"targetField":{"type":"string","description":"Dotted target field the golden record id is written to (`customer_ids.inferrex_id`)."},"matchTargetField":{"type":"string","description":"Dotted target field holding the shared id after projection (`customer_ids.registered`)."},"goldenEntityType":{"type":"string","description":"The golden records searched: their entity type."},"goldenField":{"type":"string","description":"The golden field compared with the shared id, exactly (no case folding: an id is an id)."}},"required":["targetField","matchTargetField","goldenEntityType","goldenField"],"description":"Stamp each outgoing record with the id of the golden record it belongs to (2026-10-27, Bloomreach Engagement phase 1, D13: every command carries the tenant's own id AND the golden id). After the fields are projected, the sync finds the ONE golden record of `goldenEntityType` whose `goldenField` equals the value the record carries at `matchTargetField`, and writes its id at `targetField`. None or several: nothing is written there, and the count is logged. Absent = no stamp. Set by an approved destination setup plan."},"each":{"type":"object","properties":{"field":{"type":"string","description":"Dotted path of the list in the source record (`items`). A value that is not a list sends nothing; an element that is not an object is skipped."},"parentAs":{"type":"string","description":"The key the whole source record is read under while one element is projected (`$parent`): a field mapping reading `$parent.customer_email` reads the source record's own field."},"idField":{"type":"string","description":"The element's own field that identifies it (a line id), so an element keeps its record id (`<record>#<list>[<field>=<value>]`) when lines are inserted or reordered and is sent once (2026-10-28, Sentry on #847). Absent, or an element without a value there: the element is known by its position (`<record>#<list>[<n>]`), and a line inserted or reordered after the record was sent may be sent twice or not at all."}},"required":["field","parentAs"],"description":"One outgoing record per element of a list in the source record (2026-10-28, generic; Bloomreach Engagement: one `purchase_item` event per order line beside the order's `purchase`). The field mappings are projected once per element that is an object, reading the element's own fields by name and the source record's under `parentAs` (`$parent.id`); each result is written to `targetEntityId` as a record of its own, after the source record's own write and only when that write went out (a source record held back, refused or left out by a send rule takes its elements with it). Forward pass only. Absent = one record per source record, as before. Set by an approved destination setup plan."}},"required":["id","sourceEntityId","targetEntityId","confidence","fieldMappings"]},"description":"Each object pairing, with its field mappings: transform, authority, confidence, direction, condition, destinations and review state (customerApproved, customerRejected, omitted, manualAuthored). A field mapping may carry `alternatives`: the target fields the matcher ranked for that source field but did not choose, best first, each { targetEntityId, targetFieldId, score, scoreKind, matchSource }. `score` is a confidence only when scoreKind is `model`; `lexical` is a token-overlap rank and `embedding` a cosine similarity, so never show those as percentages. GET /v1/mappings/:id/field-candidates ranks more, with reasons."},"groupDestinations":{"type":"array","items":{"type":"object","properties":{"group":{"type":"string","description":"The open group label these destinations apply to — matched against InferredField.group."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within the mapping — the key `dependsOn` and the dispatch ledger reference."},"kind":{"type":"string","description":"OPEN destination kind. 'record' = write into a connected system; 'action' = invoke a capability. Unknown kinds fail loudly at dispatch rather than being silently skipped — a destination nobody delivers is the shipped-but-inert shape."},"label":{"type":"string","description":"Human name shown wherever the destination appears — what the tenant called it, not a generated id."},"connectionId":{"type":"string","description":"For kind=record: which connected system receives it. Absent = the mapping's own target connection."},"targetEntityId":{"type":"string","description":"For kind=record: entity written into. Absent = the field mapping's own targetEntityId."},"targetFieldId":{"type":"string","description":"For kind=record: field written. Absent = the field mapping's own targetFieldId."},"channelType":{"type":"string","description":"For kind=action: HOW to deliver — an OPEN channel type resolved by the notification engine (email / sms / webhook / in_app / …). The same vocabulary alert rules use, so actions ride the ONE hardened delivery path rather than a second transport."},"channelTarget":{"type":"string","description":"For kind=action: WHO receives it (address, number, URL, or a channel id)."},"channelId":{"type":"string","description":"For kind=action: pin a specific notification_channels row instead of resolving the tenant's first verified channel of that type."},"order":{"type":"number","description":"Explicit sequence within the field's destination set. Ordering is REQUIRED, not cosmetic: \"save, and IF that committed, send\" is only expressible when the order is declared rather than inferred from array position."},"dependsOn":{"type":"string","description":"Destination id that must have COMMITTED for THIS record before this one runs. A failed or skipped dependency skips the dependant — the \"if that committed\" half of the ordering guarantee."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-destination predicate over the SOURCE record, evaluated by the shared field-evaluator — the same type and the same semantics as the per-field condition. Absent = always. A malformed condition evaluates FALSE (fail closed)."},"transform":{"type":"string","description":"Per-destination transform. Absent = inherit the field mapping's transform, so a destination only declares what DIFFERS. Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"transformConfig":{"type":"object","additionalProperties":true},"direction":{"type":"string","description":"Per-destination flow direction; absent = inherit the field mapping's. A destination only participates in a pass its direction allows. Known values: source-to-target, target-to-source, bidirectional."},"dedupeKeyFields":{"type":"array","items":{"type":"string"},"description":"Source-record fields forming the idempotency key. Absent, the key is the record's identity plus the value being delivered — so a re-sync of UNCHANGED data dispatches nothing while a genuine change still does. This is not optional decoration: a backfill over an action destination is how a tenant discovers 40,000 text messages."},"maxPerMinute":{"type":"number","description":"Per-tenant ceiling on dispatches to THIS destination. When the trailing minute is already at the ceiling, dispatch to this destination halts for the rest of the run and the skipped count is recorded and surfaced — a safety valve that is visible rather than silent."},"enabled":{"type":"boolean","description":"Absent = enabled. Turning a destination off must not require deleting it, or the only way to pause an action is to lose its configuration."}},"required":["id","kind","label","order"]},"description":"The same destination shape a field declares, so there is one vocabulary and one executor rather than a parallel group path."}},"required":["group","destinations"]},"description":"Destinations declared for a whole field group. Absent when every destination is declared per field."},"syncConfig":{"type":"object","properties":{"mode":{"type":"string","description":"Known values: realtime, near-realtime, periodic, archival."},"direction":{"type":"string","description":"Known values: source-to-target, target-to-source, bidirectional."},"schedule":{"type":"string","description":"cron expression for periodic"},"intervalMinutes":{"type":"number","description":"for near-realtime"},"realtimeChannel":{"type":"string","description":"webhook/CDC channel for realtime"},"sourceType":{"type":"string","description":"How the source delivers data — drives the sync dispatch branch. Default (absent) is periodic = the batch job path; realtime subscribes to streamConfig via the QueueClient. Known values: realtime, near-realtime, periodic."},"streamConfig":{"type":"object","properties":{"broker":{"type":"string","description":"Known values: pubsub, nats, kafka, amqp, kinesis."},"topic":{"type":"string"},"offset":{"type":"string","description":"Known values: earliest, latest."}},"required":["broker"],"description":"Per-source stream binding for realtime sources. pubsub/nats resolve via the QueueClient today; kafka/amqp/kinesis are broker clients landing in unit A.5. Open by design — the broker set tracks the QueueClient providers + planned brokers."},"targetType":{"type":"string","description":"Where the synced records land — drives the sync WRITE branch (Phase 2 B.10). Default (absent) is api = the existing HTTP write to the target ConnectionManifest. warehouse → getWarehouseClient().upsert (analytical sink, schema ensured from the mapping); lake → getLakeClient().write (partitioned object-store landing tier). Both the batch and realtime paths flow through the SAME sink. Known values: api, warehouse, lake."},"targetTable":{"type":"string","description":"Explicit warehouse table / lake dataset name override (B.11). When absent the sink derives one table per target entity from the mapping (the targetEntityId apiName, sanitised). Set this to land every entity into one named table."},"batchSize":{"type":"number"},"retryPolicy":{"type":"object","properties":{"maxAttempts":{"type":"number"},"backoffMs":{"type":"number"},"backoffMultiplier":{"type":"number"}},"required":["maxAttempts","backoffMs","backoffMultiplier"]}},"required":["mode","direction","batchSize","retryPolicy"]},"matchedAt":{"type":"string"},"matchedBy":{"type":"string"},"overallConfidence":{"type":"number","description":"0 to 1."},"status":{"type":"string","description":"The status written inside the mapping document. Approving a mapping changes the stored version's status, not this one, so read approval from `status` on GET /v1/mappings. Known values: draft, awaiting-review, approved, active, paused."},"customerApprovedAt":{"type":"string"},"customerApprovedBy":{"type":"string"},"engine":{"type":"string","description":"Which match engine produced the mapping, e.g. v1, v2."},"engineArm":{"type":"string"},"engineFallbackReason":{"type":"string"},"archived":{"type":"boolean","description":"True when the mapping was archived (POST /v1/mappings/:id/archive). An archived mapping is left out of the lists and search but can still be read by id."},"flowsBehind":{"type":"array","items":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"pinnedMappingId":{"type":"string","format":"uuid","description":"The version the flow runs."},"headMappingId":{"type":"string","format":"uuid","description":"The version this edit saved."}},"required":["pipelineId","name","status","pinnedMappingId","headMappingId"]},"description":"The flows (pipelines) still running an older version of this mapping after the edit: each keeps its version until it is moved with POST /v1/pipelines/:id/apply-mapping, naming headMappingId. Empty when no flow is behind. Archived flows are left out."}},"required":["id","version","customerId","sourceConnectionId","targetConnectionId","entityMappings","syncConfig","matchedAt","matchedBy","overallConfidence","status","archived","flowsBehind"]},"example":{"id":"string","version":0,"customerId":"string","sourceConnectionId":"string","targetConnectionId":"string","entityMappings":[{"id":"string","sourceEntityId":"string","targetEntityId":"string","confidence":0,"entityRelationship":"string","fieldMappings":[{"id":"string","sourceEntityId":"string","sourceFieldId":"string","targetEntityId":"string","targetFieldId":"string","authority":"string","conflictStrategy":"string","transform":"string","suggestedTransform":"string","transformConfig":{},"syncTier":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"direction":"string","confidence":0,"matchRationale":"string","customerApproved":true,"customerRejected":true,"customerModified":true,"autoApplied":true,"omitted":true,"omittedProposalChanged":true,"manualAuthored":true,"manualProposalConflict":true,"matchSource":"string","destinations":[{"id":"string","kind":"string","label":"string","connectionId":"string","targetEntityId":"string","targetFieldId":"string","channelType":"string","channelTarget":"string","channelId":"string","order":0,"dependsOn":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"transform":"string","transformConfig":{},"direction":"string","dedupeKeyFields":["string"],"maxPerMinute":0,"enabled":true}],"alternatives":[{"targetEntityId":"string","targetFieldId":"string","score":0,"scoreKind":"string","matchSource":"string"}]}],"matchOn":["string"],"goldenId":{"targetField":"string","matchTargetField":"string","goldenEntityType":"string","goldenField":"string"},"each":{"field":"string","parentAs":"string","idField":"string"}}],"groupDestinations":[{"group":"string","destinations":[{"id":"string","kind":"string","label":"string","connectionId":"string","targetEntityId":"string","targetFieldId":"string","channelType":"string","channelTarget":"string","channelId":"string","order":0,"dependsOn":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"transform":"string","transformConfig":{},"direction":"string","dedupeKeyFields":["string"],"maxPerMinute":0,"enabled":true}]}],"syncConfig":{"mode":"string","direction":"string","schedule":"string","intervalMinutes":0,"realtimeChannel":"string","sourceType":"string","streamConfig":{"broker":"string","topic":"string","offset":"string"},"targetType":"string","targetTable":"string","batchSize":0,"retryPolicy":{"maxAttempts":0,"backoffMs":0,"backoffMultiplier":0}},"matchedAt":"string","matchedBy":"string","overallConfidence":0,"status":"string","customerApprovedAt":"string","customerApprovedBy":"string","engine":"string","engineArm":"string","engineFallbackReason":"string","archived":true,"flowsBehind":[{"pipelineId":"00000000-0000-0000-0000-000000000000","name":"string","status":"string","pinnedMappingId":"00000000-0000-0000-0000-000000000000","headMappingId":"00000000-0000-0000-0000-000000000000"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"CreateFieldMapping","tags":["mappings"],"summary":"Create Field Mapping","security":[{"ApiKeyAuth":["mappings:write"]},{"BearerAuth":[]},{"OAuth2":["mappings:write"]}],"description":"Add a field-to-field link yourself, for a pair of fields Inferrex did not suggest. Both fields must be ones Inferrex found in the two systems (and not excluded). A link you add counts as approved. It is kept when the systems are read again or repaired, Inferrex will never replace it with a suggestion of its own, and it is never shared outside your workspace. Saved as a new version: the answer lists in flowsBehind the flows still running an older version, which keep it until each is moved to the new one.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sourceEntityId":{"type":"string","description":"The kind of record in the source system, as Inferrex found it."},"sourceFieldId":{"type":"string","description":"The field in the source system."},"targetEntityId":{"type":"string","description":"The kind of record in the target system."},"targetFieldId":{"type":"string","description":"The field in the target system."},"transform":{"type":"string","description":"How to convert the value on the way. direct (copy it as it is) if you leave it out."},"transformConfig":{"type":"object","additionalProperties":true,"description":"Settings for the conversion, where it needs any. See transformConfig on the update call."},"authority":{"type":"string","description":"Which system wins when the two disagree. provider-wins if you leave it out."},"conflictStrategy":{"type":"string","description":"What to do when both systems changed the value. flag-for-review (ask you) if you leave it out."},"syncTier":{"type":"string","description":"How promptly this field syncs: realtime, near-realtime, periodic or archival."},"direction":{"type":"string","description":"Which way this field flows: source-to-target, target-to-source or bidirectional. Defaults to the mapping’s direction."},"condition":{"type":"object","additionalProperties":true,"description":"Only sync this field when a condition holds, as {field, op, value}, with more checks in also (each {field, op, value}) combined by match: all (the default) or any."}},"required":["sourceEntityId","sourceFieldId","targetEntityId","targetFieldId"]},"example":{"sourceEntityId":"string","sourceFieldId":"string","targetEntityId":"string","targetFieldId":"string","transform":"string","transformConfig":{},"authority":"string","conflictStrategy":"string","syncTier":"string","direction":"string","condition":{}}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The id written inside the mapping document. Use the id in the path (or `id` from GET /v1/mappings) to address the mapping."},"version":{"type":"number"},"customerId":{"type":"string"},"sourceConnectionId":{"type":"string"},"targetConnectionId":{"type":"string"},"entityMappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sourceEntityId":{"type":"string"},"targetEntityId":{"type":"string"},"confidence":{"type":"number"},"entityRelationship":{"type":"string","description":"L15 relationship-inferrer's cross-provider equivalence verdict (equivalent / parent_child / related / unrelated) — refines whether the two entities should map at all. Open by design: a novel relationship label still flows through."},"fieldMappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sourceEntityId":{"type":"string"},"sourceFieldId":{"type":"string"},"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"authority":{"type":"string","description":"Known values: provider-wins, native-only, native-override, latest-wins, merge."},"conflictStrategy":{"type":"string","description":"Known values: latest-timestamp, highest-authority, flag-for-review."},"transform":{"type":"string","description":"Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"suggestedTransform":{"type":"string","description":"L17 transform-inferrer's raw OPEN suggestion (identity / unit_conversion / format_conversion / enum_mapping / …) — what the AI proposed before the customer confirmed the executable `transform`. Open by design: a novel transform label still flows through. Drives the transform-override control in the mapping review."},"transformConfig":{"type":"object","additionalProperties":true},"syncTier":{"type":"string","description":"Per-FIELD sync cadence (functionality.md: \"per-field sync tiers\"; VISUAL-MAPPING-SPEC §0.1) — seeded from the tenant's per-entity onboarding selection at pipeline activation, overridable per field in the mapping review. Absent = the pipeline's default cadence. Known values: realtime, near-realtime, periodic, archival."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-link predicate (§7: \"only when type = business\") evaluated against the SOURCE record by the shared field-evaluator — the field syncs only when it holds. Absent = always syncs. A malformed condition evaluates FALSE (fail closed)."},"direction":{"type":"string","description":"Per-FIELD flow direction (VISUAL-MAPPING-SPEC item 11): source-to-target, target-to-source, or bidirectional — any field can flow either way, both ways, or (via omitted) not at all. Absent = inherit the mapping's syncConfig.direction. Enforced by the shared evaluator's pass filter; on the reverse pass a non-invertible transform skips the field (visible in preview) rather than writing a wrongly-transformed value. Known values: source-to-target, target-to-source, bidirectional."},"confidence":{"type":"number"},"matchRationale":{"type":"string","description":"why Layer 5 proposed this pairing"},"customerApproved":{"type":"boolean"},"customerRejected":{"type":"boolean","description":"Customer explicitly marked this match WRONG (audit §2.3) — distinct from customerApproved:false, which also covers never-reviewed. Same optional-for-back-compat pattern as `omitted`. A rejected field is excluded from sync by the shared evaluator (a wrong match must not move data) and is the negative training signal's home. Cleared by a later approve."},"customerModified":{"type":"boolean","description":"customer changed the AI proposal"},"autoApplied":{"type":"boolean","description":"Applied automatically because confidence cleared the tenant's auto-apply threshold (mapping.autoApplyThreshold tunable, §11b) — deliberately NOT customerApproved, which stays a genuine customer signal; an auto-applied field the customer later approves or rejects converts to a real signal. Auto-applied fields skip the review queue but sync like approved ones; the manifest-level approval gate still applies."},"omitted":{"type":"boolean","description":"Customer chose not to sync this field — a business decision, NOT a correctness verdict (reject ≠ omit, VISUAL-MAPPING-SPEC §11a). Never touches customerApproved, feeds no training signal, and is sticky: re-matching carries it forward instead of re-proposing the field. Absent = syncs normally."},"omittedProposalChanged":{"type":"boolean","description":"Set by re-matching when a NEW proposal arrived for a field the customer omitted — surfaced as a note (\"a new proposal exists\"), never auto-restored. Cleared when the customer restores the field."},"manualAuthored":{"type":"boolean","description":"A human authored this link FROM NOTHING — the AI never proposed it (audit §2.4). Distinct from customerModified, which is AI-proposed-then-edited: different provenance, different training signal, and only this one is a durable TENANT FACT. Sticky exactly as `omitted` is: re-matching and healing carry it forward instead of dropping it, because a re-inference must never silently undo a decision a person made. Stays in the tenant's override layer and is NEVER promoted into the shared corpus without explicit vetting — a tenant's anomaly is not the platform's knowledge."},"manualProposalConflict":{"type":"boolean","description":"Set by re-matching when the AI proposed a DIFFERENT target for a source field the customer hand-mapped — surfaced as a note (\"the AI now proposes something else\"), never an auto-overwrite. The manual mapping wins and keeps running. Mirrors omittedProposalChanged; cleared when the customer resolves it."},"matchSource":{"type":"string","description":"Provenance of the proposal this mapping came from (see FieldMatchProposal.matchSource). Lets the review page and the engine comparison say whether a rule, the golden layer, the lake or a model proposed the pair. The API answers a model-proposed pair as plain `l95`: the provider and deployment stay in the stored record and never reach a tenant (DEBT-202)."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within the mapping — the key `dependsOn` and the dispatch ledger reference."},"kind":{"type":"string","description":"OPEN destination kind. 'record' = write into a connected system; 'action' = invoke a capability. Unknown kinds fail loudly at dispatch rather than being silently skipped — a destination nobody delivers is the shipped-but-inert shape."},"label":{"type":"string","description":"Human name shown wherever the destination appears — what the tenant called it, not a generated id."},"connectionId":{"type":"string","description":"For kind=record: which connected system receives it. Absent = the mapping's own target connection."},"targetEntityId":{"type":"string","description":"For kind=record: entity written into. Absent = the field mapping's own targetEntityId."},"targetFieldId":{"type":"string","description":"For kind=record: field written. Absent = the field mapping's own targetFieldId."},"channelType":{"type":"string","description":"For kind=action: HOW to deliver — an OPEN channel type resolved by the notification engine (email / sms / webhook / in_app / …). The same vocabulary alert rules use, so actions ride the ONE hardened delivery path rather than a second transport."},"channelTarget":{"type":"string","description":"For kind=action: WHO receives it (address, number, URL, or a channel id)."},"channelId":{"type":"string","description":"For kind=action: pin a specific notification_channels row instead of resolving the tenant's first verified channel of that type."},"order":{"type":"number","description":"Explicit sequence within the field's destination set. Ordering is REQUIRED, not cosmetic: \"save, and IF that committed, send\" is only expressible when the order is declared rather than inferred from array position."},"dependsOn":{"type":"string","description":"Destination id that must have COMMITTED for THIS record before this one runs. A failed or skipped dependency skips the dependant — the \"if that committed\" half of the ordering guarantee."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-destination predicate over the SOURCE record, evaluated by the shared field-evaluator — the same type and the same semantics as the per-field condition. Absent = always. A malformed condition evaluates FALSE (fail closed)."},"transform":{"type":"string","description":"Per-destination transform. Absent = inherit the field mapping's transform, so a destination only declares what DIFFERS. Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"transformConfig":{"type":"object","additionalProperties":true},"direction":{"type":"string","description":"Per-destination flow direction; absent = inherit the field mapping's. A destination only participates in a pass its direction allows. Known values: source-to-target, target-to-source, bidirectional."},"dedupeKeyFields":{"type":"array","items":{"type":"string"},"description":"Source-record fields forming the idempotency key. Absent, the key is the record's identity plus the value being delivered — so a re-sync of UNCHANGED data dispatches nothing while a genuine change still does. This is not optional decoration: a backfill over an action destination is how a tenant discovers 40,000 text messages."},"maxPerMinute":{"type":"number","description":"Per-tenant ceiling on dispatches to THIS destination. When the trailing minute is already at the ceiling, dispatch to this destination halts for the rest of the run and the skipped count is recorded and surfaced — a safety valve that is visible rather than silent."},"enabled":{"type":"boolean","description":"Absent = enabled. Turning a destination off must not require deleting it, or the only way to pause an action is to lose its configuration."}},"required":["id","kind","label","order"]},"description":"ADDITIONAL destinations this field reaches beyond its primary target — the end of the one-field-one-destination model (§2.3/§3.3). Absent = the field behaves exactly as before, which is why adding fan-out changes nothing for an existing mapping. Dispatched in `order` after the primary sink write, so a record destination and an action destination can be sequenced (\"save, and if that committed, send\")."},"alternatives":{"type":"array","items":{"type":"object","properties":{"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"score":{"type":"number","description":"The number that ranked this candidate, in the units scoreKind names."},"scoreKind":{"type":"string","description":"OPEN vocabulary naming what `score` is: `lexical` (token-overlap rank from explainCandidates, unbounded), `embedding` (cosine similarity, -1..1), `model` (the matching model's own 0..1 confidence for this pair). A novel kind flows through as a string; a UI that does not know it shows no number."},"matchSource":{"type":"string","description":"Which stage ranked it (`embedding-candidate`, `lexical-candidate`, or `l95:<provider>:<deployment>` for a model answer — the API strips the provider and deployment, DEBT-202)."}},"required":["targetEntityId","targetFieldId","score","scoreKind","matchSource"]},"description":"The runners-up the matcher ranked for this source field, best first, never including this mapping's own target (OPEN-WORK 128 d). Read only by the review UI — nothing in sync or resolution reads it. Absent = the matcher ranked nothing else (a rule decided the pair) or the mapping predates the field. Re-matching carries it forward onto an unchanged pair that came back without any."}},"required":["id","sourceEntityId","sourceFieldId","targetEntityId","targetFieldId","authority","conflictStrategy","transform","confidence","matchRationale","customerApproved","customerModified"]}},"matchOn":{"type":"array","items":{"type":"string"},"description":"Target field api names that identify the same real-world record (target-id memory, 2026-10-08), e.g. ['billing_email'] or ['invoice_number']. Before creating a record it has no link for, the sync reads the target entity and links to an existing row whose values on every matchOn field equal the outgoing record's, then updates it instead of creating a duplicate. Empty or absent = no matching. Set with PATCH /v1/mappings/:id/entity-match."},"goldenId":{"type":"object","properties":{"targetField":{"type":"string","description":"Dotted target field the golden record id is written to (`customer_ids.inferrex_id`)."},"matchTargetField":{"type":"string","description":"Dotted target field holding the shared id after projection (`customer_ids.registered`)."},"goldenEntityType":{"type":"string","description":"The golden records searched: their entity type."},"goldenField":{"type":"string","description":"The golden field compared with the shared id, exactly (no case folding: an id is an id)."}},"required":["targetField","matchTargetField","goldenEntityType","goldenField"],"description":"Stamp each outgoing record with the id of the golden record it belongs to (2026-10-27, Bloomreach Engagement phase 1, D13: every command carries the tenant's own id AND the golden id). After the fields are projected, the sync finds the ONE golden record of `goldenEntityType` whose `goldenField` equals the value the record carries at `matchTargetField`, and writes its id at `targetField`. None or several: nothing is written there, and the count is logged. Absent = no stamp. Set by an approved destination setup plan."},"each":{"type":"object","properties":{"field":{"type":"string","description":"Dotted path of the list in the source record (`items`). A value that is not a list sends nothing; an element that is not an object is skipped."},"parentAs":{"type":"string","description":"The key the whole source record is read under while one element is projected (`$parent`): a field mapping reading `$parent.customer_email` reads the source record's own field."},"idField":{"type":"string","description":"The element's own field that identifies it (a line id), so an element keeps its record id (`<record>#<list>[<field>=<value>]`) when lines are inserted or reordered and is sent once (2026-10-28, Sentry on #847). Absent, or an element without a value there: the element is known by its position (`<record>#<list>[<n>]`), and a line inserted or reordered after the record was sent may be sent twice or not at all."}},"required":["field","parentAs"],"description":"One outgoing record per element of a list in the source record (2026-10-28, generic; Bloomreach Engagement: one `purchase_item` event per order line beside the order's `purchase`). The field mappings are projected once per element that is an object, reading the element's own fields by name and the source record's under `parentAs` (`$parent.id`); each result is written to `targetEntityId` as a record of its own, after the source record's own write and only when that write went out (a source record held back, refused or left out by a send rule takes its elements with it). Forward pass only. Absent = one record per source record, as before. Set by an approved destination setup plan."}},"required":["id","sourceEntityId","targetEntityId","confidence","fieldMappings"]},"description":"Each object pairing, with its field mappings: transform, authority, confidence, direction, condition, destinations and review state (customerApproved, customerRejected, omitted, manualAuthored). A field mapping may carry `alternatives`: the target fields the matcher ranked for that source field but did not choose, best first, each { targetEntityId, targetFieldId, score, scoreKind, matchSource }. `score` is a confidence only when scoreKind is `model`; `lexical` is a token-overlap rank and `embedding` a cosine similarity, so never show those as percentages. GET /v1/mappings/:id/field-candidates ranks more, with reasons."},"groupDestinations":{"type":"array","items":{"type":"object","properties":{"group":{"type":"string","description":"The open group label these destinations apply to — matched against InferredField.group."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within the mapping — the key `dependsOn` and the dispatch ledger reference."},"kind":{"type":"string","description":"OPEN destination kind. 'record' = write into a connected system; 'action' = invoke a capability. Unknown kinds fail loudly at dispatch rather than being silently skipped — a destination nobody delivers is the shipped-but-inert shape."},"label":{"type":"string","description":"Human name shown wherever the destination appears — what the tenant called it, not a generated id."},"connectionId":{"type":"string","description":"For kind=record: which connected system receives it. Absent = the mapping's own target connection."},"targetEntityId":{"type":"string","description":"For kind=record: entity written into. Absent = the field mapping's own targetEntityId."},"targetFieldId":{"type":"string","description":"For kind=record: field written. Absent = the field mapping's own targetFieldId."},"channelType":{"type":"string","description":"For kind=action: HOW to deliver — an OPEN channel type resolved by the notification engine (email / sms / webhook / in_app / …). The same vocabulary alert rules use, so actions ride the ONE hardened delivery path rather than a second transport."},"channelTarget":{"type":"string","description":"For kind=action: WHO receives it (address, number, URL, or a channel id)."},"channelId":{"type":"string","description":"For kind=action: pin a specific notification_channels row instead of resolving the tenant's first verified channel of that type."},"order":{"type":"number","description":"Explicit sequence within the field's destination set. Ordering is REQUIRED, not cosmetic: \"save, and IF that committed, send\" is only expressible when the order is declared rather than inferred from array position."},"dependsOn":{"type":"string","description":"Destination id that must have COMMITTED for THIS record before this one runs. A failed or skipped dependency skips the dependant — the \"if that committed\" half of the ordering guarantee."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-destination predicate over the SOURCE record, evaluated by the shared field-evaluator — the same type and the same semantics as the per-field condition. Absent = always. A malformed condition evaluates FALSE (fail closed)."},"transform":{"type":"string","description":"Per-destination transform. Absent = inherit the field mapping's transform, so a destination only declares what DIFFERS. Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"transformConfig":{"type":"object","additionalProperties":true},"direction":{"type":"string","description":"Per-destination flow direction; absent = inherit the field mapping's. A destination only participates in a pass its direction allows. Known values: source-to-target, target-to-source, bidirectional."},"dedupeKeyFields":{"type":"array","items":{"type":"string"},"description":"Source-record fields forming the idempotency key. Absent, the key is the record's identity plus the value being delivered — so a re-sync of UNCHANGED data dispatches nothing while a genuine change still does. This is not optional decoration: a backfill over an action destination is how a tenant discovers 40,000 text messages."},"maxPerMinute":{"type":"number","description":"Per-tenant ceiling on dispatches to THIS destination. When the trailing minute is already at the ceiling, dispatch to this destination halts for the rest of the run and the skipped count is recorded and surfaced — a safety valve that is visible rather than silent."},"enabled":{"type":"boolean","description":"Absent = enabled. Turning a destination off must not require deleting it, or the only way to pause an action is to lose its configuration."}},"required":["id","kind","label","order"]},"description":"The same destination shape a field declares, so there is one vocabulary and one executor rather than a parallel group path."}},"required":["group","destinations"]},"description":"Destinations declared for a whole field group. Absent when every destination is declared per field."},"syncConfig":{"type":"object","properties":{"mode":{"type":"string","description":"Known values: realtime, near-realtime, periodic, archival."},"direction":{"type":"string","description":"Known values: source-to-target, target-to-source, bidirectional."},"schedule":{"type":"string","description":"cron expression for periodic"},"intervalMinutes":{"type":"number","description":"for near-realtime"},"realtimeChannel":{"type":"string","description":"webhook/CDC channel for realtime"},"sourceType":{"type":"string","description":"How the source delivers data — drives the sync dispatch branch. Default (absent) is periodic = the batch job path; realtime subscribes to streamConfig via the QueueClient. Known values: realtime, near-realtime, periodic."},"streamConfig":{"type":"object","properties":{"broker":{"type":"string","description":"Known values: pubsub, nats, kafka, amqp, kinesis."},"topic":{"type":"string"},"offset":{"type":"string","description":"Known values: earliest, latest."}},"required":["broker"],"description":"Per-source stream binding for realtime sources. pubsub/nats resolve via the QueueClient today; kafka/amqp/kinesis are broker clients landing in unit A.5. Open by design — the broker set tracks the QueueClient providers + planned brokers."},"targetType":{"type":"string","description":"Where the synced records land — drives the sync WRITE branch (Phase 2 B.10). Default (absent) is api = the existing HTTP write to the target ConnectionManifest. warehouse → getWarehouseClient().upsert (analytical sink, schema ensured from the mapping); lake → getLakeClient().write (partitioned object-store landing tier). Both the batch and realtime paths flow through the SAME sink. Known values: api, warehouse, lake."},"targetTable":{"type":"string","description":"Explicit warehouse table / lake dataset name override (B.11). When absent the sink derives one table per target entity from the mapping (the targetEntityId apiName, sanitised). Set this to land every entity into one named table."},"batchSize":{"type":"number"},"retryPolicy":{"type":"object","properties":{"maxAttempts":{"type":"number"},"backoffMs":{"type":"number"},"backoffMultiplier":{"type":"number"}},"required":["maxAttempts","backoffMs","backoffMultiplier"]}},"required":["mode","direction","batchSize","retryPolicy"]},"matchedAt":{"type":"string"},"matchedBy":{"type":"string"},"overallConfidence":{"type":"number","description":"0 to 1."},"status":{"type":"string","description":"The status written inside the mapping document. Approving a mapping changes the stored version's status, not this one, so read approval from `status` on GET /v1/mappings. Known values: draft, awaiting-review, approved, active, paused."},"customerApprovedAt":{"type":"string"},"customerApprovedBy":{"type":"string"},"engine":{"type":"string","description":"Which match engine produced the mapping, e.g. v1, v2."},"engineArm":{"type":"string"},"engineFallbackReason":{"type":"string"},"archived":{"type":"boolean","description":"True when the mapping was archived (POST /v1/mappings/:id/archive). An archived mapping is left out of the lists and search but can still be read by id."},"flowsBehind":{"type":"array","items":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"pinnedMappingId":{"type":"string","format":"uuid","description":"The version the flow runs."},"headMappingId":{"type":"string","format":"uuid","description":"The version this edit saved."}},"required":["pipelineId","name","status","pinnedMappingId","headMappingId"]},"description":"The flows (pipelines) still running an older version of this mapping after the edit: each keeps its version until it is moved with POST /v1/pipelines/:id/apply-mapping, naming headMappingId. Empty when no flow is behind. Archived flows are left out."}},"required":["id","version","customerId","sourceConnectionId","targetConnectionId","entityMappings","syncConfig","matchedAt","matchedBy","overallConfidence","status","archived","flowsBehind"]},"example":{"id":"string","version":0,"customerId":"string","sourceConnectionId":"string","targetConnectionId":"string","entityMappings":[{"id":"string","sourceEntityId":"string","targetEntityId":"string","confidence":0,"entityRelationship":"string","fieldMappings":[{"id":"string","sourceEntityId":"string","sourceFieldId":"string","targetEntityId":"string","targetFieldId":"string","authority":"string","conflictStrategy":"string","transform":"string","suggestedTransform":"string","transformConfig":{},"syncTier":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"direction":"string","confidence":0,"matchRationale":"string","customerApproved":true,"customerRejected":true,"customerModified":true,"autoApplied":true,"omitted":true,"omittedProposalChanged":true,"manualAuthored":true,"manualProposalConflict":true,"matchSource":"string","destinations":[{"id":"string","kind":"string","label":"string","connectionId":"string","targetEntityId":"string","targetFieldId":"string","channelType":"string","channelTarget":"string","channelId":"string","order":0,"dependsOn":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"transform":"string","transformConfig":{},"direction":"string","dedupeKeyFields":["string"],"maxPerMinute":0,"enabled":true}],"alternatives":[{"targetEntityId":"string","targetFieldId":"string","score":0,"scoreKind":"string","matchSource":"string"}]}],"matchOn":["string"],"goldenId":{"targetField":"string","matchTargetField":"string","goldenEntityType":"string","goldenField":"string"},"each":{"field":"string","parentAs":"string","idField":"string"}}],"groupDestinations":[{"group":"string","destinations":[{"id":"string","kind":"string","label":"string","connectionId":"string","targetEntityId":"string","targetFieldId":"string","channelType":"string","channelTarget":"string","channelId":"string","order":0,"dependsOn":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"transform":"string","transformConfig":{},"direction":"string","dedupeKeyFields":["string"],"maxPerMinute":0,"enabled":true}]}],"syncConfig":{"mode":"string","direction":"string","schedule":"string","intervalMinutes":0,"realtimeChannel":"string","sourceType":"string","streamConfig":{"broker":"string","topic":"string","offset":"string"},"targetType":"string","targetTable":"string","batchSize":0,"retryPolicy":{"maxAttempts":0,"backoffMs":0,"backoffMultiplier":0}},"matchedAt":"string","matchedBy":"string","overallConfidence":0,"status":"string","customerApprovedAt":"string","customerApprovedBy":"string","engine":"string","engineArm":"string","engineFallbackReason":"string","archived":true,"flowsBehind":[{"pipelineId":"00000000-0000-0000-0000-000000000000","name":"string","status":"string","pinnedMappingId":"00000000-0000-0000-0000-000000000000","headMappingId":"00000000-0000-0000-0000-000000000000"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/{id}/field-mapping/destinations":{"put":{"operationId":"SetFieldMappingDestinations","tags":["mappings"],"summary":"Set Field Mapping Destinations","security":[{"ApiKeyAuth":["mappings:write"]},{"BearerAuth":[]},{"OAuth2":["mappings:write"]}],"description":"Choose every place one field is sent, beyond its main target: another connected system, or an action such as sending a text message. Send the complete list each time: anything not in it is removed, and an empty list removes them all. Each destination is checked when you save it (the connection must be yours and the field must exist; an action must say how and where to deliver; anything it depends on must come earlier in the list), so a bad destination is caught now rather than failing later. Saved as a new version: the answer lists in flowsBehind the flows still running an older version, which keep it until each is moved to the new one.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fieldMappingId":{"type":"string","format":"uuid","description":"The id of the field-to-field link."},"destinations":{"type":"array","items":{"type":"object","additionalProperties":true},"maximum":25,"description":"The complete list, up to 25. Each entry is {id, kind, label, order, …}. An empty list removes every destination from this field."}},"required":["fieldMappingId","destinations"]},"example":{"fieldMappingId":"00000000-0000-0000-0000-000000000000","destinations":[{}]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The id written inside the mapping document. Use the id in the path (or `id` from GET /v1/mappings) to address the mapping."},"version":{"type":"number"},"customerId":{"type":"string"},"sourceConnectionId":{"type":"string"},"targetConnectionId":{"type":"string"},"entityMappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sourceEntityId":{"type":"string"},"targetEntityId":{"type":"string"},"confidence":{"type":"number"},"entityRelationship":{"type":"string","description":"L15 relationship-inferrer's cross-provider equivalence verdict (equivalent / parent_child / related / unrelated) — refines whether the two entities should map at all. Open by design: a novel relationship label still flows through."},"fieldMappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sourceEntityId":{"type":"string"},"sourceFieldId":{"type":"string"},"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"authority":{"type":"string","description":"Known values: provider-wins, native-only, native-override, latest-wins, merge."},"conflictStrategy":{"type":"string","description":"Known values: latest-timestamp, highest-authority, flag-for-review."},"transform":{"type":"string","description":"Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"suggestedTransform":{"type":"string","description":"L17 transform-inferrer's raw OPEN suggestion (identity / unit_conversion / format_conversion / enum_mapping / …) — what the AI proposed before the customer confirmed the executable `transform`. Open by design: a novel transform label still flows through. Drives the transform-override control in the mapping review."},"transformConfig":{"type":"object","additionalProperties":true},"syncTier":{"type":"string","description":"Per-FIELD sync cadence (functionality.md: \"per-field sync tiers\"; VISUAL-MAPPING-SPEC §0.1) — seeded from the tenant's per-entity onboarding selection at pipeline activation, overridable per field in the mapping review. Absent = the pipeline's default cadence. Known values: realtime, near-realtime, periodic, archival."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-link predicate (§7: \"only when type = business\") evaluated against the SOURCE record by the shared field-evaluator — the field syncs only when it holds. Absent = always syncs. A malformed condition evaluates FALSE (fail closed)."},"direction":{"type":"string","description":"Per-FIELD flow direction (VISUAL-MAPPING-SPEC item 11): source-to-target, target-to-source, or bidirectional — any field can flow either way, both ways, or (via omitted) not at all. Absent = inherit the mapping's syncConfig.direction. Enforced by the shared evaluator's pass filter; on the reverse pass a non-invertible transform skips the field (visible in preview) rather than writing a wrongly-transformed value. Known values: source-to-target, target-to-source, bidirectional."},"confidence":{"type":"number"},"matchRationale":{"type":"string","description":"why Layer 5 proposed this pairing"},"customerApproved":{"type":"boolean"},"customerRejected":{"type":"boolean","description":"Customer explicitly marked this match WRONG (audit §2.3) — distinct from customerApproved:false, which also covers never-reviewed. Same optional-for-back-compat pattern as `omitted`. A rejected field is excluded from sync by the shared evaluator (a wrong match must not move data) and is the negative training signal's home. Cleared by a later approve."},"customerModified":{"type":"boolean","description":"customer changed the AI proposal"},"autoApplied":{"type":"boolean","description":"Applied automatically because confidence cleared the tenant's auto-apply threshold (mapping.autoApplyThreshold tunable, §11b) — deliberately NOT customerApproved, which stays a genuine customer signal; an auto-applied field the customer later approves or rejects converts to a real signal. Auto-applied fields skip the review queue but sync like approved ones; the manifest-level approval gate still applies."},"omitted":{"type":"boolean","description":"Customer chose not to sync this field — a business decision, NOT a correctness verdict (reject ≠ omit, VISUAL-MAPPING-SPEC §11a). Never touches customerApproved, feeds no training signal, and is sticky: re-matching carries it forward instead of re-proposing the field. Absent = syncs normally."},"omittedProposalChanged":{"type":"boolean","description":"Set by re-matching when a NEW proposal arrived for a field the customer omitted — surfaced as a note (\"a new proposal exists\"), never auto-restored. Cleared when the customer restores the field."},"manualAuthored":{"type":"boolean","description":"A human authored this link FROM NOTHING — the AI never proposed it (audit §2.4). Distinct from customerModified, which is AI-proposed-then-edited: different provenance, different training signal, and only this one is a durable TENANT FACT. Sticky exactly as `omitted` is: re-matching and healing carry it forward instead of dropping it, because a re-inference must never silently undo a decision a person made. Stays in the tenant's override layer and is NEVER promoted into the shared corpus without explicit vetting — a tenant's anomaly is not the platform's knowledge."},"manualProposalConflict":{"type":"boolean","description":"Set by re-matching when the AI proposed a DIFFERENT target for a source field the customer hand-mapped — surfaced as a note (\"the AI now proposes something else\"), never an auto-overwrite. The manual mapping wins and keeps running. Mirrors omittedProposalChanged; cleared when the customer resolves it."},"matchSource":{"type":"string","description":"Provenance of the proposal this mapping came from (see FieldMatchProposal.matchSource). Lets the review page and the engine comparison say whether a rule, the golden layer, the lake or a model proposed the pair. The API answers a model-proposed pair as plain `l95`: the provider and deployment stay in the stored record and never reach a tenant (DEBT-202)."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within the mapping — the key `dependsOn` and the dispatch ledger reference."},"kind":{"type":"string","description":"OPEN destination kind. 'record' = write into a connected system; 'action' = invoke a capability. Unknown kinds fail loudly at dispatch rather than being silently skipped — a destination nobody delivers is the shipped-but-inert shape."},"label":{"type":"string","description":"Human name shown wherever the destination appears — what the tenant called it, not a generated id."},"connectionId":{"type":"string","description":"For kind=record: which connected system receives it. Absent = the mapping's own target connection."},"targetEntityId":{"type":"string","description":"For kind=record: entity written into. Absent = the field mapping's own targetEntityId."},"targetFieldId":{"type":"string","description":"For kind=record: field written. Absent = the field mapping's own targetFieldId."},"channelType":{"type":"string","description":"For kind=action: HOW to deliver — an OPEN channel type resolved by the notification engine (email / sms / webhook / in_app / …). The same vocabulary alert rules use, so actions ride the ONE hardened delivery path rather than a second transport."},"channelTarget":{"type":"string","description":"For kind=action: WHO receives it (address, number, URL, or a channel id)."},"channelId":{"type":"string","description":"For kind=action: pin a specific notification_channels row instead of resolving the tenant's first verified channel of that type."},"order":{"type":"number","description":"Explicit sequence within the field's destination set. Ordering is REQUIRED, not cosmetic: \"save, and IF that committed, send\" is only expressible when the order is declared rather than inferred from array position."},"dependsOn":{"type":"string","description":"Destination id that must have COMMITTED for THIS record before this one runs. A failed or skipped dependency skips the dependant — the \"if that committed\" half of the ordering guarantee."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-destination predicate over the SOURCE record, evaluated by the shared field-evaluator — the same type and the same semantics as the per-field condition. Absent = always. A malformed condition evaluates FALSE (fail closed)."},"transform":{"type":"string","description":"Per-destination transform. Absent = inherit the field mapping's transform, so a destination only declares what DIFFERS. Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"transformConfig":{"type":"object","additionalProperties":true},"direction":{"type":"string","description":"Per-destination flow direction; absent = inherit the field mapping's. A destination only participates in a pass its direction allows. Known values: source-to-target, target-to-source, bidirectional."},"dedupeKeyFields":{"type":"array","items":{"type":"string"},"description":"Source-record fields forming the idempotency key. Absent, the key is the record's identity plus the value being delivered — so a re-sync of UNCHANGED data dispatches nothing while a genuine change still does. This is not optional decoration: a backfill over an action destination is how a tenant discovers 40,000 text messages."},"maxPerMinute":{"type":"number","description":"Per-tenant ceiling on dispatches to THIS destination. When the trailing minute is already at the ceiling, dispatch to this destination halts for the rest of the run and the skipped count is recorded and surfaced — a safety valve that is visible rather than silent."},"enabled":{"type":"boolean","description":"Absent = enabled. Turning a destination off must not require deleting it, or the only way to pause an action is to lose its configuration."}},"required":["id","kind","label","order"]},"description":"ADDITIONAL destinations this field reaches beyond its primary target — the end of the one-field-one-destination model (§2.3/§3.3). Absent = the field behaves exactly as before, which is why adding fan-out changes nothing for an existing mapping. Dispatched in `order` after the primary sink write, so a record destination and an action destination can be sequenced (\"save, and if that committed, send\")."},"alternatives":{"type":"array","items":{"type":"object","properties":{"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"score":{"type":"number","description":"The number that ranked this candidate, in the units scoreKind names."},"scoreKind":{"type":"string","description":"OPEN vocabulary naming what `score` is: `lexical` (token-overlap rank from explainCandidates, unbounded), `embedding` (cosine similarity, -1..1), `model` (the matching model's own 0..1 confidence for this pair). A novel kind flows through as a string; a UI that does not know it shows no number."},"matchSource":{"type":"string","description":"Which stage ranked it (`embedding-candidate`, `lexical-candidate`, or `l95:<provider>:<deployment>` for a model answer — the API strips the provider and deployment, DEBT-202)."}},"required":["targetEntityId","targetFieldId","score","scoreKind","matchSource"]},"description":"The runners-up the matcher ranked for this source field, best first, never including this mapping's own target (OPEN-WORK 128 d). Read only by the review UI — nothing in sync or resolution reads it. Absent = the matcher ranked nothing else (a rule decided the pair) or the mapping predates the field. Re-matching carries it forward onto an unchanged pair that came back without any."}},"required":["id","sourceEntityId","sourceFieldId","targetEntityId","targetFieldId","authority","conflictStrategy","transform","confidence","matchRationale","customerApproved","customerModified"]}},"matchOn":{"type":"array","items":{"type":"string"},"description":"Target field api names that identify the same real-world record (target-id memory, 2026-10-08), e.g. ['billing_email'] or ['invoice_number']. Before creating a record it has no link for, the sync reads the target entity and links to an existing row whose values on every matchOn field equal the outgoing record's, then updates it instead of creating a duplicate. Empty or absent = no matching. Set with PATCH /v1/mappings/:id/entity-match."},"goldenId":{"type":"object","properties":{"targetField":{"type":"string","description":"Dotted target field the golden record id is written to (`customer_ids.inferrex_id`)."},"matchTargetField":{"type":"string","description":"Dotted target field holding the shared id after projection (`customer_ids.registered`)."},"goldenEntityType":{"type":"string","description":"The golden records searched: their entity type."},"goldenField":{"type":"string","description":"The golden field compared with the shared id, exactly (no case folding: an id is an id)."}},"required":["targetField","matchTargetField","goldenEntityType","goldenField"],"description":"Stamp each outgoing record with the id of the golden record it belongs to (2026-10-27, Bloomreach Engagement phase 1, D13: every command carries the tenant's own id AND the golden id). After the fields are projected, the sync finds the ONE golden record of `goldenEntityType` whose `goldenField` equals the value the record carries at `matchTargetField`, and writes its id at `targetField`. None or several: nothing is written there, and the count is logged. Absent = no stamp. Set by an approved destination setup plan."},"each":{"type":"object","properties":{"field":{"type":"string","description":"Dotted path of the list in the source record (`items`). A value that is not a list sends nothing; an element that is not an object is skipped."},"parentAs":{"type":"string","description":"The key the whole source record is read under while one element is projected (`$parent`): a field mapping reading `$parent.customer_email` reads the source record's own field."},"idField":{"type":"string","description":"The element's own field that identifies it (a line id), so an element keeps its record id (`<record>#<list>[<field>=<value>]`) when lines are inserted or reordered and is sent once (2026-10-28, Sentry on #847). Absent, or an element without a value there: the element is known by its position (`<record>#<list>[<n>]`), and a line inserted or reordered after the record was sent may be sent twice or not at all."}},"required":["field","parentAs"],"description":"One outgoing record per element of a list in the source record (2026-10-28, generic; Bloomreach Engagement: one `purchase_item` event per order line beside the order's `purchase`). The field mappings are projected once per element that is an object, reading the element's own fields by name and the source record's under `parentAs` (`$parent.id`); each result is written to `targetEntityId` as a record of its own, after the source record's own write and only when that write went out (a source record held back, refused or left out by a send rule takes its elements with it). Forward pass only. Absent = one record per source record, as before. Set by an approved destination setup plan."}},"required":["id","sourceEntityId","targetEntityId","confidence","fieldMappings"]},"description":"Each object pairing, with its field mappings: transform, authority, confidence, direction, condition, destinations and review state (customerApproved, customerRejected, omitted, manualAuthored). A field mapping may carry `alternatives`: the target fields the matcher ranked for that source field but did not choose, best first, each { targetEntityId, targetFieldId, score, scoreKind, matchSource }. `score` is a confidence only when scoreKind is `model`; `lexical` is a token-overlap rank and `embedding` a cosine similarity, so never show those as percentages. GET /v1/mappings/:id/field-candidates ranks more, with reasons."},"groupDestinations":{"type":"array","items":{"type":"object","properties":{"group":{"type":"string","description":"The open group label these destinations apply to — matched against InferredField.group."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within the mapping — the key `dependsOn` and the dispatch ledger reference."},"kind":{"type":"string","description":"OPEN destination kind. 'record' = write into a connected system; 'action' = invoke a capability. Unknown kinds fail loudly at dispatch rather than being silently skipped — a destination nobody delivers is the shipped-but-inert shape."},"label":{"type":"string","description":"Human name shown wherever the destination appears — what the tenant called it, not a generated id."},"connectionId":{"type":"string","description":"For kind=record: which connected system receives it. Absent = the mapping's own target connection."},"targetEntityId":{"type":"string","description":"For kind=record: entity written into. Absent = the field mapping's own targetEntityId."},"targetFieldId":{"type":"string","description":"For kind=record: field written. Absent = the field mapping's own targetFieldId."},"channelType":{"type":"string","description":"For kind=action: HOW to deliver — an OPEN channel type resolved by the notification engine (email / sms / webhook / in_app / …). The same vocabulary alert rules use, so actions ride the ONE hardened delivery path rather than a second transport."},"channelTarget":{"type":"string","description":"For kind=action: WHO receives it (address, number, URL, or a channel id)."},"channelId":{"type":"string","description":"For kind=action: pin a specific notification_channels row instead of resolving the tenant's first verified channel of that type."},"order":{"type":"number","description":"Explicit sequence within the field's destination set. Ordering is REQUIRED, not cosmetic: \"save, and IF that committed, send\" is only expressible when the order is declared rather than inferred from array position."},"dependsOn":{"type":"string","description":"Destination id that must have COMMITTED for THIS record before this one runs. A failed or skipped dependency skips the dependant — the \"if that committed\" half of the ordering guarantee."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-destination predicate over the SOURCE record, evaluated by the shared field-evaluator — the same type and the same semantics as the per-field condition. Absent = always. A malformed condition evaluates FALSE (fail closed)."},"transform":{"type":"string","description":"Per-destination transform. Absent = inherit the field mapping's transform, so a destination only declares what DIFFERS. Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"transformConfig":{"type":"object","additionalProperties":true},"direction":{"type":"string","description":"Per-destination flow direction; absent = inherit the field mapping's. A destination only participates in a pass its direction allows. Known values: source-to-target, target-to-source, bidirectional."},"dedupeKeyFields":{"type":"array","items":{"type":"string"},"description":"Source-record fields forming the idempotency key. Absent, the key is the record's identity plus the value being delivered — so a re-sync of UNCHANGED data dispatches nothing while a genuine change still does. This is not optional decoration: a backfill over an action destination is how a tenant discovers 40,000 text messages."},"maxPerMinute":{"type":"number","description":"Per-tenant ceiling on dispatches to THIS destination. When the trailing minute is already at the ceiling, dispatch to this destination halts for the rest of the run and the skipped count is recorded and surfaced — a safety valve that is visible rather than silent."},"enabled":{"type":"boolean","description":"Absent = enabled. Turning a destination off must not require deleting it, or the only way to pause an action is to lose its configuration."}},"required":["id","kind","label","order"]},"description":"The same destination shape a field declares, so there is one vocabulary and one executor rather than a parallel group path."}},"required":["group","destinations"]},"description":"Destinations declared for a whole field group. Absent when every destination is declared per field."},"syncConfig":{"type":"object","properties":{"mode":{"type":"string","description":"Known values: realtime, near-realtime, periodic, archival."},"direction":{"type":"string","description":"Known values: source-to-target, target-to-source, bidirectional."},"schedule":{"type":"string","description":"cron expression for periodic"},"intervalMinutes":{"type":"number","description":"for near-realtime"},"realtimeChannel":{"type":"string","description":"webhook/CDC channel for realtime"},"sourceType":{"type":"string","description":"How the source delivers data — drives the sync dispatch branch. Default (absent) is periodic = the batch job path; realtime subscribes to streamConfig via the QueueClient. Known values: realtime, near-realtime, periodic."},"streamConfig":{"type":"object","properties":{"broker":{"type":"string","description":"Known values: pubsub, nats, kafka, amqp, kinesis."},"topic":{"type":"string"},"offset":{"type":"string","description":"Known values: earliest, latest."}},"required":["broker"],"description":"Per-source stream binding for realtime sources. pubsub/nats resolve via the QueueClient today; kafka/amqp/kinesis are broker clients landing in unit A.5. Open by design — the broker set tracks the QueueClient providers + planned brokers."},"targetType":{"type":"string","description":"Where the synced records land — drives the sync WRITE branch (Phase 2 B.10). Default (absent) is api = the existing HTTP write to the target ConnectionManifest. warehouse → getWarehouseClient().upsert (analytical sink, schema ensured from the mapping); lake → getLakeClient().write (partitioned object-store landing tier). Both the batch and realtime paths flow through the SAME sink. Known values: api, warehouse, lake."},"targetTable":{"type":"string","description":"Explicit warehouse table / lake dataset name override (B.11). When absent the sink derives one table per target entity from the mapping (the targetEntityId apiName, sanitised). Set this to land every entity into one named table."},"batchSize":{"type":"number"},"retryPolicy":{"type":"object","properties":{"maxAttempts":{"type":"number"},"backoffMs":{"type":"number"},"backoffMultiplier":{"type":"number"}},"required":["maxAttempts","backoffMs","backoffMultiplier"]}},"required":["mode","direction","batchSize","retryPolicy"]},"matchedAt":{"type":"string"},"matchedBy":{"type":"string"},"overallConfidence":{"type":"number","description":"0 to 1."},"status":{"type":"string","description":"The status written inside the mapping document. Approving a mapping changes the stored version's status, not this one, so read approval from `status` on GET /v1/mappings. Known values: draft, awaiting-review, approved, active, paused."},"customerApprovedAt":{"type":"string"},"customerApprovedBy":{"type":"string"},"engine":{"type":"string","description":"Which match engine produced the mapping, e.g. v1, v2."},"engineArm":{"type":"string"},"engineFallbackReason":{"type":"string"},"archived":{"type":"boolean","description":"True when the mapping was archived (POST /v1/mappings/:id/archive). An archived mapping is left out of the lists and search but can still be read by id."},"flowsBehind":{"type":"array","items":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"pinnedMappingId":{"type":"string","format":"uuid","description":"The version the flow runs."},"headMappingId":{"type":"string","format":"uuid","description":"The version this edit saved."}},"required":["pipelineId","name","status","pinnedMappingId","headMappingId"]},"description":"The flows (pipelines) still running an older version of this mapping after the edit: each keeps its version until it is moved with POST /v1/pipelines/:id/apply-mapping, naming headMappingId. Empty when no flow is behind. Archived flows are left out."}},"required":["id","version","customerId","sourceConnectionId","targetConnectionId","entityMappings","syncConfig","matchedAt","matchedBy","overallConfidence","status","archived","flowsBehind"]},"example":{"id":"string","version":0,"customerId":"string","sourceConnectionId":"string","targetConnectionId":"string","entityMappings":[{"id":"string","sourceEntityId":"string","targetEntityId":"string","confidence":0,"entityRelationship":"string","fieldMappings":[{"id":"string","sourceEntityId":"string","sourceFieldId":"string","targetEntityId":"string","targetFieldId":"string","authority":"string","conflictStrategy":"string","transform":"string","suggestedTransform":"string","transformConfig":{},"syncTier":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"direction":"string","confidence":0,"matchRationale":"string","customerApproved":true,"customerRejected":true,"customerModified":true,"autoApplied":true,"omitted":true,"omittedProposalChanged":true,"manualAuthored":true,"manualProposalConflict":true,"matchSource":"string","destinations":[{"id":"string","kind":"string","label":"string","connectionId":"string","targetEntityId":"string","targetFieldId":"string","channelType":"string","channelTarget":"string","channelId":"string","order":0,"dependsOn":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"transform":"string","transformConfig":{},"direction":"string","dedupeKeyFields":["string"],"maxPerMinute":0,"enabled":true}],"alternatives":[{"targetEntityId":"string","targetFieldId":"string","score":0,"scoreKind":"string","matchSource":"string"}]}],"matchOn":["string"],"goldenId":{"targetField":"string","matchTargetField":"string","goldenEntityType":"string","goldenField":"string"},"each":{"field":"string","parentAs":"string","idField":"string"}}],"groupDestinations":[{"group":"string","destinations":[{"id":"string","kind":"string","label":"string","connectionId":"string","targetEntityId":"string","targetFieldId":"string","channelType":"string","channelTarget":"string","channelId":"string","order":0,"dependsOn":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"transform":"string","transformConfig":{},"direction":"string","dedupeKeyFields":["string"],"maxPerMinute":0,"enabled":true}]}],"syncConfig":{"mode":"string","direction":"string","schedule":"string","intervalMinutes":0,"realtimeChannel":"string","sourceType":"string","streamConfig":{"broker":"string","topic":"string","offset":"string"},"targetType":"string","targetTable":"string","batchSize":0,"retryPolicy":{"maxAttempts":0,"backoffMs":0,"backoffMultiplier":0}},"matchedAt":"string","matchedBy":"string","overallConfidence":0,"status":"string","customerApprovedAt":"string","customerApprovedBy":"string","engine":"string","engineArm":"string","engineFallbackReason":"string","archived":true,"flowsBehind":[{"pipelineId":"00000000-0000-0000-0000-000000000000","name":"string","status":"string","pinnedMappingId":"00000000-0000-0000-0000-000000000000","headMappingId":"00000000-0000-0000-0000-000000000000"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/{id}/field-mappings":{"patch":{"operationId":"BulkUpdateFieldMappings","tags":["mappings"],"summary":"Bulk Update Field Mappings","security":[{"ApiKeyAuth":["mappings:write"]},{"BearerAuth":[]},{"OAuth2":["mappings:write"]}],"description":"Apply one review action (approve, reject, leave out, restore or amend) to many field-to-field links at once. It is saved as a single new version, so it shows as one change in the history and can be undone in one step. Amending applies the same conversion and settings to every link you selected. Saved as a new version: the answer lists in flowsBehind the flows still running an older version, which keep it until each is moved to the new one.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fieldMappingIds":{"type":"array","items":{"type":"string"},"description":"The ids of the field-to-field links to change."},"action":{"type":"string","description":"approve, reject, omit (leave out), restore or amend."},"transform":{"type":"string","description":"For amend: how to convert values. Not golden-lookup, which has settings per link: set it with PATCH /v1/mappings/:id/field-mapping."},"authority":{"type":"string","description":"For amend: which system wins when they disagree."},"syncTier":{"type":"string","description":"For amend: how promptly these fields sync: realtime, near-realtime, periodic or archival."},"direction":{"type":"string","description":"For amend: which way these fields flow."}},"required":["fieldMappingIds","action"]},"example":{"fieldMappingIds":["string"],"action":"string","transform":"string","authority":"string","syncTier":"string","direction":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The id written inside the mapping document. Use the id in the path (or `id` from GET /v1/mappings) to address the mapping."},"version":{"type":"number"},"customerId":{"type":"string"},"sourceConnectionId":{"type":"string"},"targetConnectionId":{"type":"string"},"entityMappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sourceEntityId":{"type":"string"},"targetEntityId":{"type":"string"},"confidence":{"type":"number"},"entityRelationship":{"type":"string","description":"L15 relationship-inferrer's cross-provider equivalence verdict (equivalent / parent_child / related / unrelated) — refines whether the two entities should map at all. Open by design: a novel relationship label still flows through."},"fieldMappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sourceEntityId":{"type":"string"},"sourceFieldId":{"type":"string"},"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"authority":{"type":"string","description":"Known values: provider-wins, native-only, native-override, latest-wins, merge."},"conflictStrategy":{"type":"string","description":"Known values: latest-timestamp, highest-authority, flag-for-review."},"transform":{"type":"string","description":"Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"suggestedTransform":{"type":"string","description":"L17 transform-inferrer's raw OPEN suggestion (identity / unit_conversion / format_conversion / enum_mapping / …) — what the AI proposed before the customer confirmed the executable `transform`. Open by design: a novel transform label still flows through. Drives the transform-override control in the mapping review."},"transformConfig":{"type":"object","additionalProperties":true},"syncTier":{"type":"string","description":"Per-FIELD sync cadence (functionality.md: \"per-field sync tiers\"; VISUAL-MAPPING-SPEC §0.1) — seeded from the tenant's per-entity onboarding selection at pipeline activation, overridable per field in the mapping review. Absent = the pipeline's default cadence. Known values: realtime, near-realtime, periodic, archival."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-link predicate (§7: \"only when type = business\") evaluated against the SOURCE record by the shared field-evaluator — the field syncs only when it holds. Absent = always syncs. A malformed condition evaluates FALSE (fail closed)."},"direction":{"type":"string","description":"Per-FIELD flow direction (VISUAL-MAPPING-SPEC item 11): source-to-target, target-to-source, or bidirectional — any field can flow either way, both ways, or (via omitted) not at all. Absent = inherit the mapping's syncConfig.direction. Enforced by the shared evaluator's pass filter; on the reverse pass a non-invertible transform skips the field (visible in preview) rather than writing a wrongly-transformed value. Known values: source-to-target, target-to-source, bidirectional."},"confidence":{"type":"number"},"matchRationale":{"type":"string","description":"why Layer 5 proposed this pairing"},"customerApproved":{"type":"boolean"},"customerRejected":{"type":"boolean","description":"Customer explicitly marked this match WRONG (audit §2.3) — distinct from customerApproved:false, which also covers never-reviewed. Same optional-for-back-compat pattern as `omitted`. A rejected field is excluded from sync by the shared evaluator (a wrong match must not move data) and is the negative training signal's home. Cleared by a later approve."},"customerModified":{"type":"boolean","description":"customer changed the AI proposal"},"autoApplied":{"type":"boolean","description":"Applied automatically because confidence cleared the tenant's auto-apply threshold (mapping.autoApplyThreshold tunable, §11b) — deliberately NOT customerApproved, which stays a genuine customer signal; an auto-applied field the customer later approves or rejects converts to a real signal. Auto-applied fields skip the review queue but sync like approved ones; the manifest-level approval gate still applies."},"omitted":{"type":"boolean","description":"Customer chose not to sync this field — a business decision, NOT a correctness verdict (reject ≠ omit, VISUAL-MAPPING-SPEC §11a). Never touches customerApproved, feeds no training signal, and is sticky: re-matching carries it forward instead of re-proposing the field. Absent = syncs normally."},"omittedProposalChanged":{"type":"boolean","description":"Set by re-matching when a NEW proposal arrived for a field the customer omitted — surfaced as a note (\"a new proposal exists\"), never auto-restored. Cleared when the customer restores the field."},"manualAuthored":{"type":"boolean","description":"A human authored this link FROM NOTHING — the AI never proposed it (audit §2.4). Distinct from customerModified, which is AI-proposed-then-edited: different provenance, different training signal, and only this one is a durable TENANT FACT. Sticky exactly as `omitted` is: re-matching and healing carry it forward instead of dropping it, because a re-inference must never silently undo a decision a person made. Stays in the tenant's override layer and is NEVER promoted into the shared corpus without explicit vetting — a tenant's anomaly is not the platform's knowledge."},"manualProposalConflict":{"type":"boolean","description":"Set by re-matching when the AI proposed a DIFFERENT target for a source field the customer hand-mapped — surfaced as a note (\"the AI now proposes something else\"), never an auto-overwrite. The manual mapping wins and keeps running. Mirrors omittedProposalChanged; cleared when the customer resolves it."},"matchSource":{"type":"string","description":"Provenance of the proposal this mapping came from (see FieldMatchProposal.matchSource). Lets the review page and the engine comparison say whether a rule, the golden layer, the lake or a model proposed the pair. The API answers a model-proposed pair as plain `l95`: the provider and deployment stay in the stored record and never reach a tenant (DEBT-202)."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within the mapping — the key `dependsOn` and the dispatch ledger reference."},"kind":{"type":"string","description":"OPEN destination kind. 'record' = write into a connected system; 'action' = invoke a capability. Unknown kinds fail loudly at dispatch rather than being silently skipped — a destination nobody delivers is the shipped-but-inert shape."},"label":{"type":"string","description":"Human name shown wherever the destination appears — what the tenant called it, not a generated id."},"connectionId":{"type":"string","description":"For kind=record: which connected system receives it. Absent = the mapping's own target connection."},"targetEntityId":{"type":"string","description":"For kind=record: entity written into. Absent = the field mapping's own targetEntityId."},"targetFieldId":{"type":"string","description":"For kind=record: field written. Absent = the field mapping's own targetFieldId."},"channelType":{"type":"string","description":"For kind=action: HOW to deliver — an OPEN channel type resolved by the notification engine (email / sms / webhook / in_app / …). The same vocabulary alert rules use, so actions ride the ONE hardened delivery path rather than a second transport."},"channelTarget":{"type":"string","description":"For kind=action: WHO receives it (address, number, URL, or a channel id)."},"channelId":{"type":"string","description":"For kind=action: pin a specific notification_channels row instead of resolving the tenant's first verified channel of that type."},"order":{"type":"number","description":"Explicit sequence within the field's destination set. Ordering is REQUIRED, not cosmetic: \"save, and IF that committed, send\" is only expressible when the order is declared rather than inferred from array position."},"dependsOn":{"type":"string","description":"Destination id that must have COMMITTED for THIS record before this one runs. A failed or skipped dependency skips the dependant — the \"if that committed\" half of the ordering guarantee."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-destination predicate over the SOURCE record, evaluated by the shared field-evaluator — the same type and the same semantics as the per-field condition. Absent = always. A malformed condition evaluates FALSE (fail closed)."},"transform":{"type":"string","description":"Per-destination transform. Absent = inherit the field mapping's transform, so a destination only declares what DIFFERS. Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"transformConfig":{"type":"object","additionalProperties":true},"direction":{"type":"string","description":"Per-destination flow direction; absent = inherit the field mapping's. A destination only participates in a pass its direction allows. Known values: source-to-target, target-to-source, bidirectional."},"dedupeKeyFields":{"type":"array","items":{"type":"string"},"description":"Source-record fields forming the idempotency key. Absent, the key is the record's identity plus the value being delivered — so a re-sync of UNCHANGED data dispatches nothing while a genuine change still does. This is not optional decoration: a backfill over an action destination is how a tenant discovers 40,000 text messages."},"maxPerMinute":{"type":"number","description":"Per-tenant ceiling on dispatches to THIS destination. When the trailing minute is already at the ceiling, dispatch to this destination halts for the rest of the run and the skipped count is recorded and surfaced — a safety valve that is visible rather than silent."},"enabled":{"type":"boolean","description":"Absent = enabled. Turning a destination off must not require deleting it, or the only way to pause an action is to lose its configuration."}},"required":["id","kind","label","order"]},"description":"ADDITIONAL destinations this field reaches beyond its primary target — the end of the one-field-one-destination model (§2.3/§3.3). Absent = the field behaves exactly as before, which is why adding fan-out changes nothing for an existing mapping. Dispatched in `order` after the primary sink write, so a record destination and an action destination can be sequenced (\"save, and if that committed, send\")."},"alternatives":{"type":"array","items":{"type":"object","properties":{"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"score":{"type":"number","description":"The number that ranked this candidate, in the units scoreKind names."},"scoreKind":{"type":"string","description":"OPEN vocabulary naming what `score` is: `lexical` (token-overlap rank from explainCandidates, unbounded), `embedding` (cosine similarity, -1..1), `model` (the matching model's own 0..1 confidence for this pair). A novel kind flows through as a string; a UI that does not know it shows no number."},"matchSource":{"type":"string","description":"Which stage ranked it (`embedding-candidate`, `lexical-candidate`, or `l95:<provider>:<deployment>` for a model answer — the API strips the provider and deployment, DEBT-202)."}},"required":["targetEntityId","targetFieldId","score","scoreKind","matchSource"]},"description":"The runners-up the matcher ranked for this source field, best first, never including this mapping's own target (OPEN-WORK 128 d). Read only by the review UI — nothing in sync or resolution reads it. Absent = the matcher ranked nothing else (a rule decided the pair) or the mapping predates the field. Re-matching carries it forward onto an unchanged pair that came back without any."}},"required":["id","sourceEntityId","sourceFieldId","targetEntityId","targetFieldId","authority","conflictStrategy","transform","confidence","matchRationale","customerApproved","customerModified"]}},"matchOn":{"type":"array","items":{"type":"string"},"description":"Target field api names that identify the same real-world record (target-id memory, 2026-10-08), e.g. ['billing_email'] or ['invoice_number']. Before creating a record it has no link for, the sync reads the target entity and links to an existing row whose values on every matchOn field equal the outgoing record's, then updates it instead of creating a duplicate. Empty or absent = no matching. Set with PATCH /v1/mappings/:id/entity-match."},"goldenId":{"type":"object","properties":{"targetField":{"type":"string","description":"Dotted target field the golden record id is written to (`customer_ids.inferrex_id`)."},"matchTargetField":{"type":"string","description":"Dotted target field holding the shared id after projection (`customer_ids.registered`)."},"goldenEntityType":{"type":"string","description":"The golden records searched: their entity type."},"goldenField":{"type":"string","description":"The golden field compared with the shared id, exactly (no case folding: an id is an id)."}},"required":["targetField","matchTargetField","goldenEntityType","goldenField"],"description":"Stamp each outgoing record with the id of the golden record it belongs to (2026-10-27, Bloomreach Engagement phase 1, D13: every command carries the tenant's own id AND the golden id). After the fields are projected, the sync finds the ONE golden record of `goldenEntityType` whose `goldenField` equals the value the record carries at `matchTargetField`, and writes its id at `targetField`. None or several: nothing is written there, and the count is logged. Absent = no stamp. Set by an approved destination setup plan."},"each":{"type":"object","properties":{"field":{"type":"string","description":"Dotted path of the list in the source record (`items`). A value that is not a list sends nothing; an element that is not an object is skipped."},"parentAs":{"type":"string","description":"The key the whole source record is read under while one element is projected (`$parent`): a field mapping reading `$parent.customer_email` reads the source record's own field."},"idField":{"type":"string","description":"The element's own field that identifies it (a line id), so an element keeps its record id (`<record>#<list>[<field>=<value>]`) when lines are inserted or reordered and is sent once (2026-10-28, Sentry on #847). Absent, or an element without a value there: the element is known by its position (`<record>#<list>[<n>]`), and a line inserted or reordered after the record was sent may be sent twice or not at all."}},"required":["field","parentAs"],"description":"One outgoing record per element of a list in the source record (2026-10-28, generic; Bloomreach Engagement: one `purchase_item` event per order line beside the order's `purchase`). The field mappings are projected once per element that is an object, reading the element's own fields by name and the source record's under `parentAs` (`$parent.id`); each result is written to `targetEntityId` as a record of its own, after the source record's own write and only when that write went out (a source record held back, refused or left out by a send rule takes its elements with it). Forward pass only. Absent = one record per source record, as before. Set by an approved destination setup plan."}},"required":["id","sourceEntityId","targetEntityId","confidence","fieldMappings"]},"description":"Each object pairing, with its field mappings: transform, authority, confidence, direction, condition, destinations and review state (customerApproved, customerRejected, omitted, manualAuthored). A field mapping may carry `alternatives`: the target fields the matcher ranked for that source field but did not choose, best first, each { targetEntityId, targetFieldId, score, scoreKind, matchSource }. `score` is a confidence only when scoreKind is `model`; `lexical` is a token-overlap rank and `embedding` a cosine similarity, so never show those as percentages. GET /v1/mappings/:id/field-candidates ranks more, with reasons."},"groupDestinations":{"type":"array","items":{"type":"object","properties":{"group":{"type":"string","description":"The open group label these destinations apply to — matched against InferredField.group."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within the mapping — the key `dependsOn` and the dispatch ledger reference."},"kind":{"type":"string","description":"OPEN destination kind. 'record' = write into a connected system; 'action' = invoke a capability. Unknown kinds fail loudly at dispatch rather than being silently skipped — a destination nobody delivers is the shipped-but-inert shape."},"label":{"type":"string","description":"Human name shown wherever the destination appears — what the tenant called it, not a generated id."},"connectionId":{"type":"string","description":"For kind=record: which connected system receives it. Absent = the mapping's own target connection."},"targetEntityId":{"type":"string","description":"For kind=record: entity written into. Absent = the field mapping's own targetEntityId."},"targetFieldId":{"type":"string","description":"For kind=record: field written. Absent = the field mapping's own targetFieldId."},"channelType":{"type":"string","description":"For kind=action: HOW to deliver — an OPEN channel type resolved by the notification engine (email / sms / webhook / in_app / …). The same vocabulary alert rules use, so actions ride the ONE hardened delivery path rather than a second transport."},"channelTarget":{"type":"string","description":"For kind=action: WHO receives it (address, number, URL, or a channel id)."},"channelId":{"type":"string","description":"For kind=action: pin a specific notification_channels row instead of resolving the tenant's first verified channel of that type."},"order":{"type":"number","description":"Explicit sequence within the field's destination set. Ordering is REQUIRED, not cosmetic: \"save, and IF that committed, send\" is only expressible when the order is declared rather than inferred from array position."},"dependsOn":{"type":"string","description":"Destination id that must have COMMITTED for THIS record before this one runs. A failed or skipped dependency skips the dependant — the \"if that committed\" half of the ordering guarantee."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-destination predicate over the SOURCE record, evaluated by the shared field-evaluator — the same type and the same semantics as the per-field condition. Absent = always. A malformed condition evaluates FALSE (fail closed)."},"transform":{"type":"string","description":"Per-destination transform. Absent = inherit the field mapping's transform, so a destination only declares what DIFFERS. Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"transformConfig":{"type":"object","additionalProperties":true},"direction":{"type":"string","description":"Per-destination flow direction; absent = inherit the field mapping's. A destination only participates in a pass its direction allows. Known values: source-to-target, target-to-source, bidirectional."},"dedupeKeyFields":{"type":"array","items":{"type":"string"},"description":"Source-record fields forming the idempotency key. Absent, the key is the record's identity plus the value being delivered — so a re-sync of UNCHANGED data dispatches nothing while a genuine change still does. This is not optional decoration: a backfill over an action destination is how a tenant discovers 40,000 text messages."},"maxPerMinute":{"type":"number","description":"Per-tenant ceiling on dispatches to THIS destination. When the trailing minute is already at the ceiling, dispatch to this destination halts for the rest of the run and the skipped count is recorded and surfaced — a safety valve that is visible rather than silent."},"enabled":{"type":"boolean","description":"Absent = enabled. Turning a destination off must not require deleting it, or the only way to pause an action is to lose its configuration."}},"required":["id","kind","label","order"]},"description":"The same destination shape a field declares, so there is one vocabulary and one executor rather than a parallel group path."}},"required":["group","destinations"]},"description":"Destinations declared for a whole field group. Absent when every destination is declared per field."},"syncConfig":{"type":"object","properties":{"mode":{"type":"string","description":"Known values: realtime, near-realtime, periodic, archival."},"direction":{"type":"string","description":"Known values: source-to-target, target-to-source, bidirectional."},"schedule":{"type":"string","description":"cron expression for periodic"},"intervalMinutes":{"type":"number","description":"for near-realtime"},"realtimeChannel":{"type":"string","description":"webhook/CDC channel for realtime"},"sourceType":{"type":"string","description":"How the source delivers data — drives the sync dispatch branch. Default (absent) is periodic = the batch job path; realtime subscribes to streamConfig via the QueueClient. Known values: realtime, near-realtime, periodic."},"streamConfig":{"type":"object","properties":{"broker":{"type":"string","description":"Known values: pubsub, nats, kafka, amqp, kinesis."},"topic":{"type":"string"},"offset":{"type":"string","description":"Known values: earliest, latest."}},"required":["broker"],"description":"Per-source stream binding for realtime sources. pubsub/nats resolve via the QueueClient today; kafka/amqp/kinesis are broker clients landing in unit A.5. Open by design — the broker set tracks the QueueClient providers + planned brokers."},"targetType":{"type":"string","description":"Where the synced records land — drives the sync WRITE branch (Phase 2 B.10). Default (absent) is api = the existing HTTP write to the target ConnectionManifest. warehouse → getWarehouseClient().upsert (analytical sink, schema ensured from the mapping); lake → getLakeClient().write (partitioned object-store landing tier). Both the batch and realtime paths flow through the SAME sink. Known values: api, warehouse, lake."},"targetTable":{"type":"string","description":"Explicit warehouse table / lake dataset name override (B.11). When absent the sink derives one table per target entity from the mapping (the targetEntityId apiName, sanitised). Set this to land every entity into one named table."},"batchSize":{"type":"number"},"retryPolicy":{"type":"object","properties":{"maxAttempts":{"type":"number"},"backoffMs":{"type":"number"},"backoffMultiplier":{"type":"number"}},"required":["maxAttempts","backoffMs","backoffMultiplier"]}},"required":["mode","direction","batchSize","retryPolicy"]},"matchedAt":{"type":"string"},"matchedBy":{"type":"string"},"overallConfidence":{"type":"number","description":"0 to 1."},"status":{"type":"string","description":"The status written inside the mapping document. Approving a mapping changes the stored version's status, not this one, so read approval from `status` on GET /v1/mappings. Known values: draft, awaiting-review, approved, active, paused."},"customerApprovedAt":{"type":"string"},"customerApprovedBy":{"type":"string"},"engine":{"type":"string","description":"Which match engine produced the mapping, e.g. v1, v2."},"engineArm":{"type":"string"},"engineFallbackReason":{"type":"string"},"archived":{"type":"boolean","description":"True when the mapping was archived (POST /v1/mappings/:id/archive). An archived mapping is left out of the lists and search but can still be read by id."},"flowsBehind":{"type":"array","items":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"pinnedMappingId":{"type":"string","format":"uuid","description":"The version the flow runs."},"headMappingId":{"type":"string","format":"uuid","description":"The version this edit saved."}},"required":["pipelineId","name","status","pinnedMappingId","headMappingId"]},"description":"The flows (pipelines) still running an older version of this mapping after the edit: each keeps its version until it is moved with POST /v1/pipelines/:id/apply-mapping, naming headMappingId. Empty when no flow is behind. Archived flows are left out."}},"required":["id","version","customerId","sourceConnectionId","targetConnectionId","entityMappings","syncConfig","matchedAt","matchedBy","overallConfidence","status","archived","flowsBehind"]},"example":{"id":"string","version":0,"customerId":"string","sourceConnectionId":"string","targetConnectionId":"string","entityMappings":[{"id":"string","sourceEntityId":"string","targetEntityId":"string","confidence":0,"entityRelationship":"string","fieldMappings":[{"id":"string","sourceEntityId":"string","sourceFieldId":"string","targetEntityId":"string","targetFieldId":"string","authority":"string","conflictStrategy":"string","transform":"string","suggestedTransform":"string","transformConfig":{},"syncTier":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"direction":"string","confidence":0,"matchRationale":"string","customerApproved":true,"customerRejected":true,"customerModified":true,"autoApplied":true,"omitted":true,"omittedProposalChanged":true,"manualAuthored":true,"manualProposalConflict":true,"matchSource":"string","destinations":[{"id":"string","kind":"string","label":"string","connectionId":"string","targetEntityId":"string","targetFieldId":"string","channelType":"string","channelTarget":"string","channelId":"string","order":0,"dependsOn":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"transform":"string","transformConfig":{},"direction":"string","dedupeKeyFields":["string"],"maxPerMinute":0,"enabled":true}],"alternatives":[{"targetEntityId":"string","targetFieldId":"string","score":0,"scoreKind":"string","matchSource":"string"}]}],"matchOn":["string"],"goldenId":{"targetField":"string","matchTargetField":"string","goldenEntityType":"string","goldenField":"string"},"each":{"field":"string","parentAs":"string","idField":"string"}}],"groupDestinations":[{"group":"string","destinations":[{"id":"string","kind":"string","label":"string","connectionId":"string","targetEntityId":"string","targetFieldId":"string","channelType":"string","channelTarget":"string","channelId":"string","order":0,"dependsOn":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"transform":"string","transformConfig":{},"direction":"string","dedupeKeyFields":["string"],"maxPerMinute":0,"enabled":true}]}],"syncConfig":{"mode":"string","direction":"string","schedule":"string","intervalMinutes":0,"realtimeChannel":"string","sourceType":"string","streamConfig":{"broker":"string","topic":"string","offset":"string"},"targetType":"string","targetTable":"string","batchSize":0,"retryPolicy":{"maxAttempts":0,"backoffMs":0,"backoffMultiplier":0}},"matchedAt":"string","matchedBy":"string","overallConfidence":0,"status":"string","customerApprovedAt":"string","customerApprovedBy":"string","engine":"string","engineArm":"string","engineFallbackReason":"string","archived":true,"flowsBehind":[{"pipelineId":"00000000-0000-0000-0000-000000000000","name":"string","status":"string","pinnedMappingId":"00000000-0000-0000-0000-000000000000","headMappingId":"00000000-0000-0000-0000-000000000000"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/{id}/field-priors":{"get":{"operationId":"GetMappingFieldPriors","tags":["mappings"],"summary":"Get Mapping Field Priors","security":[{"ApiKeyAuth":["mappings:read"]},{"BearerAuth":[]},{"OAuth2":["mappings:read"]}],"description":"What other workspaces linked between the same two kinds of system as THIS mapping: per source field, the target fields that at least learning.priors.minWorkspaces contributing workspaces confirmed, ordered by how many did. Counts are rounded down to a multiple of that floor (workspacesAtLeast = 5 means \"5 or more\"); share is the field's portion among the suggestions shown. Each suggestion says whether the target field exists in this mapping's target connection and whether this mapping already links it. Shown only while the platform-admin switch match.crossWorkspaceHints is on (D30, off by default), and only when both systems can be compared; neither is named in the answer. available:false with a reason when there is nothing to consult: disabled (the switch is off), unknown-provider, references-unavailable, or not-in-this-deployment (sovereign).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"available":{"type":"boolean"},"reason":{"type":"string","description":"Why available is false: disabled, unknown-provider, references-unavailable or not-in-this-deployment."},"floor":{"type":"integer","description":"The fewest workspaces a suggestion stands for; every count is a multiple of it."},"fields":{"type":"array","items":{"type":"object","properties":{"sourceEntityId":{"type":"string"},"sourceFieldId":{"type":"string"},"sourceEntity":{"type":"string","description":"Entity API name."},"sourceField":{"type":"string","description":"Field API name."},"suggestions":{"type":"array","items":{"type":"object","properties":{"targetEntity":{"type":"string"},"targetField":{"type":"string"},"targetEntityId":{"type":"string","description":"Set when the target field exists in this mapping's target connection."},"targetFieldId":{"type":"string"},"workspacesAtLeast":{"type":"integer"},"rejectionsAtLeast":{"type":"integer","description":"0 unless at least `floor` workspaces rejected this pair."},"share":{"type":"number","description":"This suggestion's portion (0–1) of the workspace counts shown for the source field."},"linkedHere":{"type":"boolean","description":"This mapping already has a live link from the source field to this target field."}},"required":["targetEntity","targetField","workspacesAtLeast","rejectionsAtLeast","share","linkedHere"]}}},"required":["sourceEntityId","sourceFieldId","sourceEntity","sourceField","suggestions"]},"description":"One row per source field that has at least one suggestion."},"entityLinks":{"type":"array","items":{"type":"object","properties":{"sourceEntity":{"type":"string"},"targetEntity":{"type":"string"},"workspacesAtLeast":{"type":"integer"}},"required":["sourceEntity","targetEntity","workspacesAtLeast"]},"description":"Objects other workspaces link between these two systems in active pipelines."}},"required":["available","floor","fields","entityLinks"]},"example":{"available":true,"reason":"string","floor":0,"fields":[{"sourceEntityId":"string","sourceFieldId":"string","sourceEntity":"string","sourceField":"string","suggestions":[{"targetEntity":"string","targetField":"string","targetEntityId":"string","targetFieldId":"string","workspacesAtLeast":0,"rejectionsAtLeast":0,"share":0,"linkedHere":true}]}],"entityLinks":[{"sourceEntity":"string","targetEntity":"string","workspacesAtLeast":0}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/{id}/fields":{"get":{"operationId":"ListMappableFields","tags":["mappings"],"summary":"List Mappable Fields","security":[{"ApiKeyAuth":["mappings:read"]},{"BearerAuth":[]},{"OAuth2":["mappings:read"]}],"description":"Every field Inferrex found in both connected systems, each marked with whether a link in this mapping already uses it. Use it to find fields that still need a link, or to choose fields when you add a link yourself. Links you rejected or left out do not count, so their fields show as unlinked again. Fields you excluded from a connection are not listed, and example values are hidden for sensitive fields.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"source":{"type":"object","properties":{"connectionId":{"type":"string","description":"The `id` inside the connection's inferred manifest (ConnectionManifest.id). Despite the name it is not the connection's id: inference gives the manifest document its own id."},"displayName":{"type":"string","description":"The system's name as inferred."},"entities":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"apiName":{"type":"string"},"displayName":{"type":"string"},"archetype":{"type":"string","description":"The cross-system kind of object (e.g. customer, invoice), when inferred."},"fields":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"apiName":{"type":"string"},"displayName":{"type":"string"},"type":{"type":"string","description":"The inferred field type (a label from the L2 taxonomy)."},"required":{"type":"boolean"},"role":{"type":"string","description":"What the field means (e.g. email, amount), when known."},"description":{"type":"string"},"group":{"type":"string","description":"The field group label, when the field has one."},"exampleValues":{"type":"array","items":{},"description":"Up to 3 example values. Empty for a sensitive field."},"mapped":{"type":"boolean","description":"A live field mapping already uses this field. Omitted and rejected links do not count."}},"required":["id","apiName","displayName","type","required","exampleValues","mapped"]},"description":"Included fields only; fields excluded from the schema are not listed."}},"required":["id","apiName","displayName","fields"]}}},"required":["connectionId","displayName","entities"],"description":"The source connection's objects and fields."},"target":{"type":"object","properties":{"connectionId":{"type":"string","description":"The `id` inside the connection's inferred manifest (ConnectionManifest.id). Despite the name it is not the connection's id: inference gives the manifest document its own id."},"displayName":{"type":"string","description":"The system's name as inferred."},"entities":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"apiName":{"type":"string"},"displayName":{"type":"string"},"archetype":{"type":"string","description":"The cross-system kind of object (e.g. customer, invoice), when inferred."},"fields":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"apiName":{"type":"string"},"displayName":{"type":"string"},"type":{"type":"string","description":"The inferred field type (a label from the L2 taxonomy)."},"required":{"type":"boolean"},"role":{"type":"string","description":"What the field means (e.g. email, amount), when known."},"description":{"type":"string"},"group":{"type":"string","description":"The field group label, when the field has one."},"exampleValues":{"type":"array","items":{},"description":"Up to 3 example values. Empty for a sensitive field."},"mapped":{"type":"boolean","description":"A live field mapping already uses this field. Omitted and rejected links do not count."}},"required":["id","apiName","displayName","type","required","exampleValues","mapped"]},"description":"Included fields only; fields excluded from the schema are not listed."}},"required":["id","apiName","displayName","fields"]}}},"required":["connectionId","displayName","entities"],"description":"The target connection's objects and fields."},"unmappedSourceCount":{"type":"integer","description":"Source fields no live mapping uses."},"unmappedTargetCount":{"type":"integer","description":"Target fields no live mapping uses."}},"required":["source","target","unmappedSourceCount","unmappedTargetCount"]},"example":{"source":{"connectionId":"string","displayName":"string","entities":[{"id":"string","apiName":"string","displayName":"string","archetype":"string","fields":[{"id":"string","apiName":"string","displayName":"string","type":"string","required":true,"role":"string","description":"string","group":"string","exampleValues":[],"mapped":true}]}]},"target":{"connectionId":"string","displayName":"string","entities":[{"id":"string","apiName":"string","displayName":"string","archetype":"string","fields":[{"id":"string","apiName":"string","displayName":"string","type":"string","required":true,"role":"string","description":"string","group":"string","exampleValues":[],"mapped":true}]}]},"unmappedSourceCount":0,"unmappedTargetCount":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/{id}/group-destinations":{"put":{"operationId":"SetGroupDestinations","tags":["mappings"],"summary":"Set Group Destinations","security":[{"ApiKeyAuth":["mappings:write"]},{"BearerAuth":[]},{"OAuth2":["mappings:write"]}],"description":"Choose where every field in a group is sent, in one go, such as sending everything in the financial group to your data warehouse. A field added to the group later is sent too. Destinations are checked the same way as for a single field, and a destination set on a field itself overrides the group’s. Send an empty list for a group to remove its destinations. Saved as a new version: the answer lists in flowsBehind the flows still running an older version, which keep it until each is moved to the new one.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"groupDestinations":{"type":"array","items":{"type":"object","additionalProperties":true},"maximum":50,"description":"The complete list: [{group, destinations}]. An empty list removes all group destinations."}},"required":["groupDestinations"]},"example":{"groupDestinations":[{}]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The id written inside the mapping document. Use the id in the path (or `id` from GET /v1/mappings) to address the mapping."},"version":{"type":"number"},"customerId":{"type":"string"},"sourceConnectionId":{"type":"string"},"targetConnectionId":{"type":"string"},"entityMappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sourceEntityId":{"type":"string"},"targetEntityId":{"type":"string"},"confidence":{"type":"number"},"entityRelationship":{"type":"string","description":"L15 relationship-inferrer's cross-provider equivalence verdict (equivalent / parent_child / related / unrelated) — refines whether the two entities should map at all. Open by design: a novel relationship label still flows through."},"fieldMappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sourceEntityId":{"type":"string"},"sourceFieldId":{"type":"string"},"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"authority":{"type":"string","description":"Known values: provider-wins, native-only, native-override, latest-wins, merge."},"conflictStrategy":{"type":"string","description":"Known values: latest-timestamp, highest-authority, flag-for-review."},"transform":{"type":"string","description":"Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"suggestedTransform":{"type":"string","description":"L17 transform-inferrer's raw OPEN suggestion (identity / unit_conversion / format_conversion / enum_mapping / …) — what the AI proposed before the customer confirmed the executable `transform`. Open by design: a novel transform label still flows through. Drives the transform-override control in the mapping review."},"transformConfig":{"type":"object","additionalProperties":true},"syncTier":{"type":"string","description":"Per-FIELD sync cadence (functionality.md: \"per-field sync tiers\"; VISUAL-MAPPING-SPEC §0.1) — seeded from the tenant's per-entity onboarding selection at pipeline activation, overridable per field in the mapping review. Absent = the pipeline's default cadence. Known values: realtime, near-realtime, periodic, archival."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-link predicate (§7: \"only when type = business\") evaluated against the SOURCE record by the shared field-evaluator — the field syncs only when it holds. Absent = always syncs. A malformed condition evaluates FALSE (fail closed)."},"direction":{"type":"string","description":"Per-FIELD flow direction (VISUAL-MAPPING-SPEC item 11): source-to-target, target-to-source, or bidirectional — any field can flow either way, both ways, or (via omitted) not at all. Absent = inherit the mapping's syncConfig.direction. Enforced by the shared evaluator's pass filter; on the reverse pass a non-invertible transform skips the field (visible in preview) rather than writing a wrongly-transformed value. Known values: source-to-target, target-to-source, bidirectional."},"confidence":{"type":"number"},"matchRationale":{"type":"string","description":"why Layer 5 proposed this pairing"},"customerApproved":{"type":"boolean"},"customerRejected":{"type":"boolean","description":"Customer explicitly marked this match WRONG (audit §2.3) — distinct from customerApproved:false, which also covers never-reviewed. Same optional-for-back-compat pattern as `omitted`. A rejected field is excluded from sync by the shared evaluator (a wrong match must not move data) and is the negative training signal's home. Cleared by a later approve."},"customerModified":{"type":"boolean","description":"customer changed the AI proposal"},"autoApplied":{"type":"boolean","description":"Applied automatically because confidence cleared the tenant's auto-apply threshold (mapping.autoApplyThreshold tunable, §11b) — deliberately NOT customerApproved, which stays a genuine customer signal; an auto-applied field the customer later approves or rejects converts to a real signal. Auto-applied fields skip the review queue but sync like approved ones; the manifest-level approval gate still applies."},"omitted":{"type":"boolean","description":"Customer chose not to sync this field — a business decision, NOT a correctness verdict (reject ≠ omit, VISUAL-MAPPING-SPEC §11a). Never touches customerApproved, feeds no training signal, and is sticky: re-matching carries it forward instead of re-proposing the field. Absent = syncs normally."},"omittedProposalChanged":{"type":"boolean","description":"Set by re-matching when a NEW proposal arrived for a field the customer omitted — surfaced as a note (\"a new proposal exists\"), never auto-restored. Cleared when the customer restores the field."},"manualAuthored":{"type":"boolean","description":"A human authored this link FROM NOTHING — the AI never proposed it (audit §2.4). Distinct from customerModified, which is AI-proposed-then-edited: different provenance, different training signal, and only this one is a durable TENANT FACT. Sticky exactly as `omitted` is: re-matching and healing carry it forward instead of dropping it, because a re-inference must never silently undo a decision a person made. Stays in the tenant's override layer and is NEVER promoted into the shared corpus without explicit vetting — a tenant's anomaly is not the platform's knowledge."},"manualProposalConflict":{"type":"boolean","description":"Set by re-matching when the AI proposed a DIFFERENT target for a source field the customer hand-mapped — surfaced as a note (\"the AI now proposes something else\"), never an auto-overwrite. The manual mapping wins and keeps running. Mirrors omittedProposalChanged; cleared when the customer resolves it."},"matchSource":{"type":"string","description":"Provenance of the proposal this mapping came from (see FieldMatchProposal.matchSource). Lets the review page and the engine comparison say whether a rule, the golden layer, the lake or a model proposed the pair. The API answers a model-proposed pair as plain `l95`: the provider and deployment stay in the stored record and never reach a tenant (DEBT-202)."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within the mapping — the key `dependsOn` and the dispatch ledger reference."},"kind":{"type":"string","description":"OPEN destination kind. 'record' = write into a connected system; 'action' = invoke a capability. Unknown kinds fail loudly at dispatch rather than being silently skipped — a destination nobody delivers is the shipped-but-inert shape."},"label":{"type":"string","description":"Human name shown wherever the destination appears — what the tenant called it, not a generated id."},"connectionId":{"type":"string","description":"For kind=record: which connected system receives it. Absent = the mapping's own target connection."},"targetEntityId":{"type":"string","description":"For kind=record: entity written into. Absent = the field mapping's own targetEntityId."},"targetFieldId":{"type":"string","description":"For kind=record: field written. Absent = the field mapping's own targetFieldId."},"channelType":{"type":"string","description":"For kind=action: HOW to deliver — an OPEN channel type resolved by the notification engine (email / sms / webhook / in_app / …). The same vocabulary alert rules use, so actions ride the ONE hardened delivery path rather than a second transport."},"channelTarget":{"type":"string","description":"For kind=action: WHO receives it (address, number, URL, or a channel id)."},"channelId":{"type":"string","description":"For kind=action: pin a specific notification_channels row instead of resolving the tenant's first verified channel of that type."},"order":{"type":"number","description":"Explicit sequence within the field's destination set. Ordering is REQUIRED, not cosmetic: \"save, and IF that committed, send\" is only expressible when the order is declared rather than inferred from array position."},"dependsOn":{"type":"string","description":"Destination id that must have COMMITTED for THIS record before this one runs. A failed or skipped dependency skips the dependant — the \"if that committed\" half of the ordering guarantee."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-destination predicate over the SOURCE record, evaluated by the shared field-evaluator — the same type and the same semantics as the per-field condition. Absent = always. A malformed condition evaluates FALSE (fail closed)."},"transform":{"type":"string","description":"Per-destination transform. Absent = inherit the field mapping's transform, so a destination only declares what DIFFERS. Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"transformConfig":{"type":"object","additionalProperties":true},"direction":{"type":"string","description":"Per-destination flow direction; absent = inherit the field mapping's. A destination only participates in a pass its direction allows. Known values: source-to-target, target-to-source, bidirectional."},"dedupeKeyFields":{"type":"array","items":{"type":"string"},"description":"Source-record fields forming the idempotency key. Absent, the key is the record's identity plus the value being delivered — so a re-sync of UNCHANGED data dispatches nothing while a genuine change still does. This is not optional decoration: a backfill over an action destination is how a tenant discovers 40,000 text messages."},"maxPerMinute":{"type":"number","description":"Per-tenant ceiling on dispatches to THIS destination. When the trailing minute is already at the ceiling, dispatch to this destination halts for the rest of the run and the skipped count is recorded and surfaced — a safety valve that is visible rather than silent."},"enabled":{"type":"boolean","description":"Absent = enabled. Turning a destination off must not require deleting it, or the only way to pause an action is to lose its configuration."}},"required":["id","kind","label","order"]},"description":"ADDITIONAL destinations this field reaches beyond its primary target — the end of the one-field-one-destination model (§2.3/§3.3). Absent = the field behaves exactly as before, which is why adding fan-out changes nothing for an existing mapping. Dispatched in `order` after the primary sink write, so a record destination and an action destination can be sequenced (\"save, and if that committed, send\")."},"alternatives":{"type":"array","items":{"type":"object","properties":{"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"score":{"type":"number","description":"The number that ranked this candidate, in the units scoreKind names."},"scoreKind":{"type":"string","description":"OPEN vocabulary naming what `score` is: `lexical` (token-overlap rank from explainCandidates, unbounded), `embedding` (cosine similarity, -1..1), `model` (the matching model's own 0..1 confidence for this pair). A novel kind flows through as a string; a UI that does not know it shows no number."},"matchSource":{"type":"string","description":"Which stage ranked it (`embedding-candidate`, `lexical-candidate`, or `l95:<provider>:<deployment>` for a model answer — the API strips the provider and deployment, DEBT-202)."}},"required":["targetEntityId","targetFieldId","score","scoreKind","matchSource"]},"description":"The runners-up the matcher ranked for this source field, best first, never including this mapping's own target (OPEN-WORK 128 d). Read only by the review UI — nothing in sync or resolution reads it. Absent = the matcher ranked nothing else (a rule decided the pair) or the mapping predates the field. Re-matching carries it forward onto an unchanged pair that came back without any."}},"required":["id","sourceEntityId","sourceFieldId","targetEntityId","targetFieldId","authority","conflictStrategy","transform","confidence","matchRationale","customerApproved","customerModified"]}},"matchOn":{"type":"array","items":{"type":"string"},"description":"Target field api names that identify the same real-world record (target-id memory, 2026-10-08), e.g. ['billing_email'] or ['invoice_number']. Before creating a record it has no link for, the sync reads the target entity and links to an existing row whose values on every matchOn field equal the outgoing record's, then updates it instead of creating a duplicate. Empty or absent = no matching. Set with PATCH /v1/mappings/:id/entity-match."},"goldenId":{"type":"object","properties":{"targetField":{"type":"string","description":"Dotted target field the golden record id is written to (`customer_ids.inferrex_id`)."},"matchTargetField":{"type":"string","description":"Dotted target field holding the shared id after projection (`customer_ids.registered`)."},"goldenEntityType":{"type":"string","description":"The golden records searched: their entity type."},"goldenField":{"type":"string","description":"The golden field compared with the shared id, exactly (no case folding: an id is an id)."}},"required":["targetField","matchTargetField","goldenEntityType","goldenField"],"description":"Stamp each outgoing record with the id of the golden record it belongs to (2026-10-27, Bloomreach Engagement phase 1, D13: every command carries the tenant's own id AND the golden id). After the fields are projected, the sync finds the ONE golden record of `goldenEntityType` whose `goldenField` equals the value the record carries at `matchTargetField`, and writes its id at `targetField`. None or several: nothing is written there, and the count is logged. Absent = no stamp. Set by an approved destination setup plan."},"each":{"type":"object","properties":{"field":{"type":"string","description":"Dotted path of the list in the source record (`items`). A value that is not a list sends nothing; an element that is not an object is skipped."},"parentAs":{"type":"string","description":"The key the whole source record is read under while one element is projected (`$parent`): a field mapping reading `$parent.customer_email` reads the source record's own field."},"idField":{"type":"string","description":"The element's own field that identifies it (a line id), so an element keeps its record id (`<record>#<list>[<field>=<value>]`) when lines are inserted or reordered and is sent once (2026-10-28, Sentry on #847). Absent, or an element without a value there: the element is known by its position (`<record>#<list>[<n>]`), and a line inserted or reordered after the record was sent may be sent twice or not at all."}},"required":["field","parentAs"],"description":"One outgoing record per element of a list in the source record (2026-10-28, generic; Bloomreach Engagement: one `purchase_item` event per order line beside the order's `purchase`). The field mappings are projected once per element that is an object, reading the element's own fields by name and the source record's under `parentAs` (`$parent.id`); each result is written to `targetEntityId` as a record of its own, after the source record's own write and only when that write went out (a source record held back, refused or left out by a send rule takes its elements with it). Forward pass only. Absent = one record per source record, as before. Set by an approved destination setup plan."}},"required":["id","sourceEntityId","targetEntityId","confidence","fieldMappings"]},"description":"Each object pairing, with its field mappings: transform, authority, confidence, direction, condition, destinations and review state (customerApproved, customerRejected, omitted, manualAuthored). A field mapping may carry `alternatives`: the target fields the matcher ranked for that source field but did not choose, best first, each { targetEntityId, targetFieldId, score, scoreKind, matchSource }. `score` is a confidence only when scoreKind is `model`; `lexical` is a token-overlap rank and `embedding` a cosine similarity, so never show those as percentages. GET /v1/mappings/:id/field-candidates ranks more, with reasons."},"groupDestinations":{"type":"array","items":{"type":"object","properties":{"group":{"type":"string","description":"The open group label these destinations apply to — matched against InferredField.group."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within the mapping — the key `dependsOn` and the dispatch ledger reference."},"kind":{"type":"string","description":"OPEN destination kind. 'record' = write into a connected system; 'action' = invoke a capability. Unknown kinds fail loudly at dispatch rather than being silently skipped — a destination nobody delivers is the shipped-but-inert shape."},"label":{"type":"string","description":"Human name shown wherever the destination appears — what the tenant called it, not a generated id."},"connectionId":{"type":"string","description":"For kind=record: which connected system receives it. Absent = the mapping's own target connection."},"targetEntityId":{"type":"string","description":"For kind=record: entity written into. Absent = the field mapping's own targetEntityId."},"targetFieldId":{"type":"string","description":"For kind=record: field written. Absent = the field mapping's own targetFieldId."},"channelType":{"type":"string","description":"For kind=action: HOW to deliver — an OPEN channel type resolved by the notification engine (email / sms / webhook / in_app / …). The same vocabulary alert rules use, so actions ride the ONE hardened delivery path rather than a second transport."},"channelTarget":{"type":"string","description":"For kind=action: WHO receives it (address, number, URL, or a channel id)."},"channelId":{"type":"string","description":"For kind=action: pin a specific notification_channels row instead of resolving the tenant's first verified channel of that type."},"order":{"type":"number","description":"Explicit sequence within the field's destination set. Ordering is REQUIRED, not cosmetic: \"save, and IF that committed, send\" is only expressible when the order is declared rather than inferred from array position."},"dependsOn":{"type":"string","description":"Destination id that must have COMMITTED for THIS record before this one runs. A failed or skipped dependency skips the dependant — the \"if that committed\" half of the ordering guarantee."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-destination predicate over the SOURCE record, evaluated by the shared field-evaluator — the same type and the same semantics as the per-field condition. Absent = always. A malformed condition evaluates FALSE (fail closed)."},"transform":{"type":"string","description":"Per-destination transform. Absent = inherit the field mapping's transform, so a destination only declares what DIFFERS. Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"transformConfig":{"type":"object","additionalProperties":true},"direction":{"type":"string","description":"Per-destination flow direction; absent = inherit the field mapping's. A destination only participates in a pass its direction allows. Known values: source-to-target, target-to-source, bidirectional."},"dedupeKeyFields":{"type":"array","items":{"type":"string"},"description":"Source-record fields forming the idempotency key. Absent, the key is the record's identity plus the value being delivered — so a re-sync of UNCHANGED data dispatches nothing while a genuine change still does. This is not optional decoration: a backfill over an action destination is how a tenant discovers 40,000 text messages."},"maxPerMinute":{"type":"number","description":"Per-tenant ceiling on dispatches to THIS destination. When the trailing minute is already at the ceiling, dispatch to this destination halts for the rest of the run and the skipped count is recorded and surfaced — a safety valve that is visible rather than silent."},"enabled":{"type":"boolean","description":"Absent = enabled. Turning a destination off must not require deleting it, or the only way to pause an action is to lose its configuration."}},"required":["id","kind","label","order"]},"description":"The same destination shape a field declares, so there is one vocabulary and one executor rather than a parallel group path."}},"required":["group","destinations"]},"description":"Destinations declared for a whole field group. Absent when every destination is declared per field."},"syncConfig":{"type":"object","properties":{"mode":{"type":"string","description":"Known values: realtime, near-realtime, periodic, archival."},"direction":{"type":"string","description":"Known values: source-to-target, target-to-source, bidirectional."},"schedule":{"type":"string","description":"cron expression for periodic"},"intervalMinutes":{"type":"number","description":"for near-realtime"},"realtimeChannel":{"type":"string","description":"webhook/CDC channel for realtime"},"sourceType":{"type":"string","description":"How the source delivers data — drives the sync dispatch branch. Default (absent) is periodic = the batch job path; realtime subscribes to streamConfig via the QueueClient. Known values: realtime, near-realtime, periodic."},"streamConfig":{"type":"object","properties":{"broker":{"type":"string","description":"Known values: pubsub, nats, kafka, amqp, kinesis."},"topic":{"type":"string"},"offset":{"type":"string","description":"Known values: earliest, latest."}},"required":["broker"],"description":"Per-source stream binding for realtime sources. pubsub/nats resolve via the QueueClient today; kafka/amqp/kinesis are broker clients landing in unit A.5. Open by design — the broker set tracks the QueueClient providers + planned brokers."},"targetType":{"type":"string","description":"Where the synced records land — drives the sync WRITE branch (Phase 2 B.10). Default (absent) is api = the existing HTTP write to the target ConnectionManifest. warehouse → getWarehouseClient().upsert (analytical sink, schema ensured from the mapping); lake → getLakeClient().write (partitioned object-store landing tier). Both the batch and realtime paths flow through the SAME sink. Known values: api, warehouse, lake."},"targetTable":{"type":"string","description":"Explicit warehouse table / lake dataset name override (B.11). When absent the sink derives one table per target entity from the mapping (the targetEntityId apiName, sanitised). Set this to land every entity into one named table."},"batchSize":{"type":"number"},"retryPolicy":{"type":"object","properties":{"maxAttempts":{"type":"number"},"backoffMs":{"type":"number"},"backoffMultiplier":{"type":"number"}},"required":["maxAttempts","backoffMs","backoffMultiplier"]}},"required":["mode","direction","batchSize","retryPolicy"]},"matchedAt":{"type":"string"},"matchedBy":{"type":"string"},"overallConfidence":{"type":"number","description":"0 to 1."},"status":{"type":"string","description":"The status written inside the mapping document. Approving a mapping changes the stored version's status, not this one, so read approval from `status` on GET /v1/mappings. Known values: draft, awaiting-review, approved, active, paused."},"customerApprovedAt":{"type":"string"},"customerApprovedBy":{"type":"string"},"engine":{"type":"string","description":"Which match engine produced the mapping, e.g. v1, v2."},"engineArm":{"type":"string"},"engineFallbackReason":{"type":"string"},"archived":{"type":"boolean","description":"True when the mapping was archived (POST /v1/mappings/:id/archive). An archived mapping is left out of the lists and search but can still be read by id."},"flowsBehind":{"type":"array","items":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"pinnedMappingId":{"type":"string","format":"uuid","description":"The version the flow runs."},"headMappingId":{"type":"string","format":"uuid","description":"The version this edit saved."}},"required":["pipelineId","name","status","pinnedMappingId","headMappingId"]},"description":"The flows (pipelines) still running an older version of this mapping after the edit: each keeps its version until it is moved with POST /v1/pipelines/:id/apply-mapping, naming headMappingId. Empty when no flow is behind. Archived flows are left out."}},"required":["id","version","customerId","sourceConnectionId","targetConnectionId","entityMappings","syncConfig","matchedAt","matchedBy","overallConfidence","status","archived","flowsBehind"]},"example":{"id":"string","version":0,"customerId":"string","sourceConnectionId":"string","targetConnectionId":"string","entityMappings":[{"id":"string","sourceEntityId":"string","targetEntityId":"string","confidence":0,"entityRelationship":"string","fieldMappings":[{"id":"string","sourceEntityId":"string","sourceFieldId":"string","targetEntityId":"string","targetFieldId":"string","authority":"string","conflictStrategy":"string","transform":"string","suggestedTransform":"string","transformConfig":{},"syncTier":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"direction":"string","confidence":0,"matchRationale":"string","customerApproved":true,"customerRejected":true,"customerModified":true,"autoApplied":true,"omitted":true,"omittedProposalChanged":true,"manualAuthored":true,"manualProposalConflict":true,"matchSource":"string","destinations":[{"id":"string","kind":"string","label":"string","connectionId":"string","targetEntityId":"string","targetFieldId":"string","channelType":"string","channelTarget":"string","channelId":"string","order":0,"dependsOn":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"transform":"string","transformConfig":{},"direction":"string","dedupeKeyFields":["string"],"maxPerMinute":0,"enabled":true}],"alternatives":[{"targetEntityId":"string","targetFieldId":"string","score":0,"scoreKind":"string","matchSource":"string"}]}],"matchOn":["string"],"goldenId":{"targetField":"string","matchTargetField":"string","goldenEntityType":"string","goldenField":"string"},"each":{"field":"string","parentAs":"string","idField":"string"}}],"groupDestinations":[{"group":"string","destinations":[{"id":"string","kind":"string","label":"string","connectionId":"string","targetEntityId":"string","targetFieldId":"string","channelType":"string","channelTarget":"string","channelId":"string","order":0,"dependsOn":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"transform":"string","transformConfig":{},"direction":"string","dedupeKeyFields":["string"],"maxPerMinute":0,"enabled":true}]}],"syncConfig":{"mode":"string","direction":"string","schedule":"string","intervalMinutes":0,"realtimeChannel":"string","sourceType":"string","streamConfig":{"broker":"string","topic":"string","offset":"string"},"targetType":"string","targetTable":"string","batchSize":0,"retryPolicy":{"maxAttempts":0,"backoffMs":0,"backoffMultiplier":0}},"matchedAt":"string","matchedBy":"string","overallConfidence":0,"status":"string","customerApprovedAt":"string","customerApprovedBy":"string","engine":"string","engineArm":"string","engineFallbackReason":"string","archived":true,"flowsBehind":[{"pipelineId":"00000000-0000-0000-0000-000000000000","name":"string","status":"string","pinnedMappingId":"00000000-0000-0000-0000-000000000000","headMappingId":"00000000-0000-0000-0000-000000000000"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/{id}/pipelines":{"get":{"operationId":"ListMappingPipelines","tags":["mappings"],"summary":"List Mapping Pipelines","security":[{"ApiKeyAuth":["mappings:read"]},{"BearerAuth":[]},{"OAuth2":["mappings:read"]}],"description":"The pipelines that use any version of this mapping, with the version each one is running, the newest version, and whether they match. A pipeline keeps the mapping version it was activated with, so changes you make later only reach it once you apply them to the pipeline.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"pipelines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"pinnedMappingId":{"type":"string","format":"uuid","description":"The mapping version the pipeline runs."},"headMappingId":{"type":"string","format":"uuid","description":"The mapping's current version."},"upToDate":{"type":"boolean","description":"False when the mapping has changed since the pipeline pinned it; the change needs applying to the pipeline."}},"required":["id","name","status","pinnedMappingId","headMappingId","upToDate"]}},"pipelineCount":{"type":"integer"},"headMappingId":{"type":"string","format":"uuid"}},"required":["pipelines","pipelineCount","headMappingId"]},"example":{"pipelines":[{"id":"00000000-0000-0000-0000-000000000000","name":"string","status":"string","pinnedMappingId":"00000000-0000-0000-0000-000000000000","headMappingId":"00000000-0000-0000-0000-000000000000","upToDate":true}],"pipelineCount":0,"headMappingId":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/{id}/revert":{"post":{"operationId":"RevertMapping","tags":["mappings"],"summary":"Revert Mapping","security":[{"ApiKeyAuth":["mappings:write"]},{"BearerAuth":[]},{"OAuth2":["mappings:write"]}],"description":"Revert a mapping to one of its earlier versions. Saves a NEW version whose content equals the chosen one; history is kept, so the revert is undone the same way. Like every edit it keeps the mapping's current review status, and a pipeline keeps the version it pinned until the change is applied to it (POST /v1/pipelines/:id/apply-mapping). 409 if the chosen version is already the current one.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"integer","minimum":1,"description":"The version number to go back to, from GET /v1/mappings/:id/versions."}},"required":["version"]},"example":{"version":0}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"mappingId":{"type":"string","format":"uuid","description":"The new current version's id."},"version":{"type":"integer","description":"The new current version's number."},"revertedToVersion":{"type":"integer"},"manifest":{"type":"object","properties":{"id":{"type":"string","description":"The id written inside the mapping document. Use the id in the path (or `id` from GET /v1/mappings) to address the mapping."},"version":{"type":"number"},"customerId":{"type":"string"},"sourceConnectionId":{"type":"string"},"targetConnectionId":{"type":"string"},"entityMappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sourceEntityId":{"type":"string"},"targetEntityId":{"type":"string"},"confidence":{"type":"number"},"entityRelationship":{"type":"string","description":"L15 relationship-inferrer's cross-provider equivalence verdict (equivalent / parent_child / related / unrelated) — refines whether the two entities should map at all. Open by design: a novel relationship label still flows through."},"fieldMappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sourceEntityId":{"type":"string"},"sourceFieldId":{"type":"string"},"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"authority":{"type":"string","description":"Known values: provider-wins, native-only, native-override, latest-wins, merge."},"conflictStrategy":{"type":"string","description":"Known values: latest-timestamp, highest-authority, flag-for-review."},"transform":{"type":"string","description":"Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"suggestedTransform":{"type":"string","description":"L17 transform-inferrer's raw OPEN suggestion (identity / unit_conversion / format_conversion / enum_mapping / …) — what the AI proposed before the customer confirmed the executable `transform`. Open by design: a novel transform label still flows through. Drives the transform-override control in the mapping review."},"transformConfig":{"type":"object","additionalProperties":true},"syncTier":{"type":"string","description":"Per-FIELD sync cadence (functionality.md: \"per-field sync tiers\"; VISUAL-MAPPING-SPEC §0.1) — seeded from the tenant's per-entity onboarding selection at pipeline activation, overridable per field in the mapping review. Absent = the pipeline's default cadence. Known values: realtime, near-realtime, periodic, archival."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-link predicate (§7: \"only when type = business\") evaluated against the SOURCE record by the shared field-evaluator — the field syncs only when it holds. Absent = always syncs. A malformed condition evaluates FALSE (fail closed)."},"direction":{"type":"string","description":"Per-FIELD flow direction (VISUAL-MAPPING-SPEC item 11): source-to-target, target-to-source, or bidirectional — any field can flow either way, both ways, or (via omitted) not at all. Absent = inherit the mapping's syncConfig.direction. Enforced by the shared evaluator's pass filter; on the reverse pass a non-invertible transform skips the field (visible in preview) rather than writing a wrongly-transformed value. Known values: source-to-target, target-to-source, bidirectional."},"confidence":{"type":"number"},"matchRationale":{"type":"string","description":"why Layer 5 proposed this pairing"},"customerApproved":{"type":"boolean"},"customerRejected":{"type":"boolean","description":"Customer explicitly marked this match WRONG (audit §2.3) — distinct from customerApproved:false, which also covers never-reviewed. Same optional-for-back-compat pattern as `omitted`. A rejected field is excluded from sync by the shared evaluator (a wrong match must not move data) and is the negative training signal's home. Cleared by a later approve."},"customerModified":{"type":"boolean","description":"customer changed the AI proposal"},"autoApplied":{"type":"boolean","description":"Applied automatically because confidence cleared the tenant's auto-apply threshold (mapping.autoApplyThreshold tunable, §11b) — deliberately NOT customerApproved, which stays a genuine customer signal; an auto-applied field the customer later approves or rejects converts to a real signal. Auto-applied fields skip the review queue but sync like approved ones; the manifest-level approval gate still applies."},"omitted":{"type":"boolean","description":"Customer chose not to sync this field — a business decision, NOT a correctness verdict (reject ≠ omit, VISUAL-MAPPING-SPEC §11a). Never touches customerApproved, feeds no training signal, and is sticky: re-matching carries it forward instead of re-proposing the field. Absent = syncs normally."},"omittedProposalChanged":{"type":"boolean","description":"Set by re-matching when a NEW proposal arrived for a field the customer omitted — surfaced as a note (\"a new proposal exists\"), never auto-restored. Cleared when the customer restores the field."},"manualAuthored":{"type":"boolean","description":"A human authored this link FROM NOTHING — the AI never proposed it (audit §2.4). Distinct from customerModified, which is AI-proposed-then-edited: different provenance, different training signal, and only this one is a durable TENANT FACT. Sticky exactly as `omitted` is: re-matching and healing carry it forward instead of dropping it, because a re-inference must never silently undo a decision a person made. Stays in the tenant's override layer and is NEVER promoted into the shared corpus without explicit vetting — a tenant's anomaly is not the platform's knowledge."},"manualProposalConflict":{"type":"boolean","description":"Set by re-matching when the AI proposed a DIFFERENT target for a source field the customer hand-mapped — surfaced as a note (\"the AI now proposes something else\"), never an auto-overwrite. The manual mapping wins and keeps running. Mirrors omittedProposalChanged; cleared when the customer resolves it."},"matchSource":{"type":"string","description":"Provenance of the proposal this mapping came from (see FieldMatchProposal.matchSource). Lets the review page and the engine comparison say whether a rule, the golden layer, the lake or a model proposed the pair. The API answers a model-proposed pair as plain `l95`: the provider and deployment stay in the stored record and never reach a tenant (DEBT-202)."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within the mapping — the key `dependsOn` and the dispatch ledger reference."},"kind":{"type":"string","description":"OPEN destination kind. 'record' = write into a connected system; 'action' = invoke a capability. Unknown kinds fail loudly at dispatch rather than being silently skipped — a destination nobody delivers is the shipped-but-inert shape."},"label":{"type":"string","description":"Human name shown wherever the destination appears — what the tenant called it, not a generated id."},"connectionId":{"type":"string","description":"For kind=record: which connected system receives it. Absent = the mapping's own target connection."},"targetEntityId":{"type":"string","description":"For kind=record: entity written into. Absent = the field mapping's own targetEntityId."},"targetFieldId":{"type":"string","description":"For kind=record: field written. Absent = the field mapping's own targetFieldId."},"channelType":{"type":"string","description":"For kind=action: HOW to deliver — an OPEN channel type resolved by the notification engine (email / sms / webhook / in_app / …). The same vocabulary alert rules use, so actions ride the ONE hardened delivery path rather than a second transport."},"channelTarget":{"type":"string","description":"For kind=action: WHO receives it (address, number, URL, or a channel id)."},"channelId":{"type":"string","description":"For kind=action: pin a specific notification_channels row instead of resolving the tenant's first verified channel of that type."},"order":{"type":"number","description":"Explicit sequence within the field's destination set. Ordering is REQUIRED, not cosmetic: \"save, and IF that committed, send\" is only expressible when the order is declared rather than inferred from array position."},"dependsOn":{"type":"string","description":"Destination id that must have COMMITTED for THIS record before this one runs. A failed or skipped dependency skips the dependant — the \"if that committed\" half of the ordering guarantee."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-destination predicate over the SOURCE record, evaluated by the shared field-evaluator — the same type and the same semantics as the per-field condition. Absent = always. A malformed condition evaluates FALSE (fail closed)."},"transform":{"type":"string","description":"Per-destination transform. Absent = inherit the field mapping's transform, so a destination only declares what DIFFERS. Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"transformConfig":{"type":"object","additionalProperties":true},"direction":{"type":"string","description":"Per-destination flow direction; absent = inherit the field mapping's. A destination only participates in a pass its direction allows. Known values: source-to-target, target-to-source, bidirectional."},"dedupeKeyFields":{"type":"array","items":{"type":"string"},"description":"Source-record fields forming the idempotency key. Absent, the key is the record's identity plus the value being delivered — so a re-sync of UNCHANGED data dispatches nothing while a genuine change still does. This is not optional decoration: a backfill over an action destination is how a tenant discovers 40,000 text messages."},"maxPerMinute":{"type":"number","description":"Per-tenant ceiling on dispatches to THIS destination. When the trailing minute is already at the ceiling, dispatch to this destination halts for the rest of the run and the skipped count is recorded and surfaced — a safety valve that is visible rather than silent."},"enabled":{"type":"boolean","description":"Absent = enabled. Turning a destination off must not require deleting it, or the only way to pause an action is to lose its configuration."}},"required":["id","kind","label","order"]},"description":"ADDITIONAL destinations this field reaches beyond its primary target — the end of the one-field-one-destination model (§2.3/§3.3). Absent = the field behaves exactly as before, which is why adding fan-out changes nothing for an existing mapping. Dispatched in `order` after the primary sink write, so a record destination and an action destination can be sequenced (\"save, and if that committed, send\")."},"alternatives":{"type":"array","items":{"type":"object","properties":{"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"score":{"type":"number","description":"The number that ranked this candidate, in the units scoreKind names."},"scoreKind":{"type":"string","description":"OPEN vocabulary naming what `score` is: `lexical` (token-overlap rank from explainCandidates, unbounded), `embedding` (cosine similarity, -1..1), `model` (the matching model's own 0..1 confidence for this pair). A novel kind flows through as a string; a UI that does not know it shows no number."},"matchSource":{"type":"string","description":"Which stage ranked it (`embedding-candidate`, `lexical-candidate`, or `l95:<provider>:<deployment>` for a model answer — the API strips the provider and deployment, DEBT-202)."}},"required":["targetEntityId","targetFieldId","score","scoreKind","matchSource"]},"description":"The runners-up the matcher ranked for this source field, best first, never including this mapping's own target (OPEN-WORK 128 d). Read only by the review UI — nothing in sync or resolution reads it. Absent = the matcher ranked nothing else (a rule decided the pair) or the mapping predates the field. Re-matching carries it forward onto an unchanged pair that came back without any."}},"required":["id","sourceEntityId","sourceFieldId","targetEntityId","targetFieldId","authority","conflictStrategy","transform","confidence","matchRationale","customerApproved","customerModified"]}},"matchOn":{"type":"array","items":{"type":"string"},"description":"Target field api names that identify the same real-world record (target-id memory, 2026-10-08), e.g. ['billing_email'] or ['invoice_number']. Before creating a record it has no link for, the sync reads the target entity and links to an existing row whose values on every matchOn field equal the outgoing record's, then updates it instead of creating a duplicate. Empty or absent = no matching. Set with PATCH /v1/mappings/:id/entity-match."},"goldenId":{"type":"object","properties":{"targetField":{"type":"string","description":"Dotted target field the golden record id is written to (`customer_ids.inferrex_id`)."},"matchTargetField":{"type":"string","description":"Dotted target field holding the shared id after projection (`customer_ids.registered`)."},"goldenEntityType":{"type":"string","description":"The golden records searched: their entity type."},"goldenField":{"type":"string","description":"The golden field compared with the shared id, exactly (no case folding: an id is an id)."}},"required":["targetField","matchTargetField","goldenEntityType","goldenField"],"description":"Stamp each outgoing record with the id of the golden record it belongs to (2026-10-27, Bloomreach Engagement phase 1, D13: every command carries the tenant's own id AND the golden id). After the fields are projected, the sync finds the ONE golden record of `goldenEntityType` whose `goldenField` equals the value the record carries at `matchTargetField`, and writes its id at `targetField`. None or several: nothing is written there, and the count is logged. Absent = no stamp. Set by an approved destination setup plan."},"each":{"type":"object","properties":{"field":{"type":"string","description":"Dotted path of the list in the source record (`items`). A value that is not a list sends nothing; an element that is not an object is skipped."},"parentAs":{"type":"string","description":"The key the whole source record is read under while one element is projected (`$parent`): a field mapping reading `$parent.customer_email` reads the source record's own field."},"idField":{"type":"string","description":"The element's own field that identifies it (a line id), so an element keeps its record id (`<record>#<list>[<field>=<value>]`) when lines are inserted or reordered and is sent once (2026-10-28, Sentry on #847). Absent, or an element without a value there: the element is known by its position (`<record>#<list>[<n>]`), and a line inserted or reordered after the record was sent may be sent twice or not at all."}},"required":["field","parentAs"],"description":"One outgoing record per element of a list in the source record (2026-10-28, generic; Bloomreach Engagement: one `purchase_item` event per order line beside the order's `purchase`). The field mappings are projected once per element that is an object, reading the element's own fields by name and the source record's under `parentAs` (`$parent.id`); each result is written to `targetEntityId` as a record of its own, after the source record's own write and only when that write went out (a source record held back, refused or left out by a send rule takes its elements with it). Forward pass only. Absent = one record per source record, as before. Set by an approved destination setup plan."}},"required":["id","sourceEntityId","targetEntityId","confidence","fieldMappings"]},"description":"Each object pairing, with its field mappings: transform, authority, confidence, direction, condition, destinations and review state (customerApproved, customerRejected, omitted, manualAuthored). A field mapping may carry `alternatives`: the target fields the matcher ranked for that source field but did not choose, best first, each { targetEntityId, targetFieldId, score, scoreKind, matchSource }. `score` is a confidence only when scoreKind is `model`; `lexical` is a token-overlap rank and `embedding` a cosine similarity, so never show those as percentages. GET /v1/mappings/:id/field-candidates ranks more, with reasons."},"groupDestinations":{"type":"array","items":{"type":"object","properties":{"group":{"type":"string","description":"The open group label these destinations apply to — matched against InferredField.group."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within the mapping — the key `dependsOn` and the dispatch ledger reference."},"kind":{"type":"string","description":"OPEN destination kind. 'record' = write into a connected system; 'action' = invoke a capability. Unknown kinds fail loudly at dispatch rather than being silently skipped — a destination nobody delivers is the shipped-but-inert shape."},"label":{"type":"string","description":"Human name shown wherever the destination appears — what the tenant called it, not a generated id."},"connectionId":{"type":"string","description":"For kind=record: which connected system receives it. Absent = the mapping's own target connection."},"targetEntityId":{"type":"string","description":"For kind=record: entity written into. Absent = the field mapping's own targetEntityId."},"targetFieldId":{"type":"string","description":"For kind=record: field written. Absent = the field mapping's own targetFieldId."},"channelType":{"type":"string","description":"For kind=action: HOW to deliver — an OPEN channel type resolved by the notification engine (email / sms / webhook / in_app / …). The same vocabulary alert rules use, so actions ride the ONE hardened delivery path rather than a second transport."},"channelTarget":{"type":"string","description":"For kind=action: WHO receives it (address, number, URL, or a channel id)."},"channelId":{"type":"string","description":"For kind=action: pin a specific notification_channels row instead of resolving the tenant's first verified channel of that type."},"order":{"type":"number","description":"Explicit sequence within the field's destination set. Ordering is REQUIRED, not cosmetic: \"save, and IF that committed, send\" is only expressible when the order is declared rather than inferred from array position."},"dependsOn":{"type":"string","description":"Destination id that must have COMMITTED for THIS record before this one runs. A failed or skipped dependency skips the dependant — the \"if that committed\" half of the ordering guarantee."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-destination predicate over the SOURCE record, evaluated by the shared field-evaluator — the same type and the same semantics as the per-field condition. Absent = always. A malformed condition evaluates FALSE (fail closed)."},"transform":{"type":"string","description":"Per-destination transform. Absent = inherit the field mapping's transform, so a destination only declares what DIFFERS. Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"transformConfig":{"type":"object","additionalProperties":true},"direction":{"type":"string","description":"Per-destination flow direction; absent = inherit the field mapping's. A destination only participates in a pass its direction allows. Known values: source-to-target, target-to-source, bidirectional."},"dedupeKeyFields":{"type":"array","items":{"type":"string"},"description":"Source-record fields forming the idempotency key. Absent, the key is the record's identity plus the value being delivered — so a re-sync of UNCHANGED data dispatches nothing while a genuine change still does. This is not optional decoration: a backfill over an action destination is how a tenant discovers 40,000 text messages."},"maxPerMinute":{"type":"number","description":"Per-tenant ceiling on dispatches to THIS destination. When the trailing minute is already at the ceiling, dispatch to this destination halts for the rest of the run and the skipped count is recorded and surfaced — a safety valve that is visible rather than silent."},"enabled":{"type":"boolean","description":"Absent = enabled. Turning a destination off must not require deleting it, or the only way to pause an action is to lose its configuration."}},"required":["id","kind","label","order"]},"description":"The same destination shape a field declares, so there is one vocabulary and one executor rather than a parallel group path."}},"required":["group","destinations"]},"description":"Destinations declared for a whole field group. Absent when every destination is declared per field."},"syncConfig":{"type":"object","properties":{"mode":{"type":"string","description":"Known values: realtime, near-realtime, periodic, archival."},"direction":{"type":"string","description":"Known values: source-to-target, target-to-source, bidirectional."},"schedule":{"type":"string","description":"cron expression for periodic"},"intervalMinutes":{"type":"number","description":"for near-realtime"},"realtimeChannel":{"type":"string","description":"webhook/CDC channel for realtime"},"sourceType":{"type":"string","description":"How the source delivers data — drives the sync dispatch branch. Default (absent) is periodic = the batch job path; realtime subscribes to streamConfig via the QueueClient. Known values: realtime, near-realtime, periodic."},"streamConfig":{"type":"object","properties":{"broker":{"type":"string","description":"Known values: pubsub, nats, kafka, amqp, kinesis."},"topic":{"type":"string"},"offset":{"type":"string","description":"Known values: earliest, latest."}},"required":["broker"],"description":"Per-source stream binding for realtime sources. pubsub/nats resolve via the QueueClient today; kafka/amqp/kinesis are broker clients landing in unit A.5. Open by design — the broker set tracks the QueueClient providers + planned brokers."},"targetType":{"type":"string","description":"Where the synced records land — drives the sync WRITE branch (Phase 2 B.10). Default (absent) is api = the existing HTTP write to the target ConnectionManifest. warehouse → getWarehouseClient().upsert (analytical sink, schema ensured from the mapping); lake → getLakeClient().write (partitioned object-store landing tier). Both the batch and realtime paths flow through the SAME sink. Known values: api, warehouse, lake."},"targetTable":{"type":"string","description":"Explicit warehouse table / lake dataset name override (B.11). When absent the sink derives one table per target entity from the mapping (the targetEntityId apiName, sanitised). Set this to land every entity into one named table."},"batchSize":{"type":"number"},"retryPolicy":{"type":"object","properties":{"maxAttempts":{"type":"number"},"backoffMs":{"type":"number"},"backoffMultiplier":{"type":"number"}},"required":["maxAttempts","backoffMs","backoffMultiplier"]}},"required":["mode","direction","batchSize","retryPolicy"]},"matchedAt":{"type":"string"},"matchedBy":{"type":"string"},"overallConfidence":{"type":"number","description":"0 to 1."},"status":{"type":"string","description":"The status written inside the mapping document. Approving a mapping changes the stored version's status, not this one, so read approval from `status` on GET /v1/mappings. Known values: draft, awaiting-review, approved, active, paused."},"customerApprovedAt":{"type":"string"},"customerApprovedBy":{"type":"string"},"engine":{"type":"string","description":"Which match engine produced the mapping, e.g. v1, v2."},"engineArm":{"type":"string"},"engineFallbackReason":{"type":"string"},"archived":{"type":"boolean","description":"True when the mapping was archived (POST /v1/mappings/:id/archive). An archived mapping is left out of the lists and search but can still be read by id."}},"required":["id","version","customerId","sourceConnectionId","targetConnectionId","entityMappings","syncConfig","matchedAt","matchedBy","overallConfidence","status","archived"],"description":"The new current version's MappingManifest."},"flowsBehind":{"type":"array","items":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"pinnedMappingId":{"type":"string","format":"uuid","description":"The version the flow runs."},"headMappingId":{"type":"string","format":"uuid","description":"The version this edit saved."}},"required":["pipelineId","name","status","pinnedMappingId","headMappingId"]},"description":"The flows (pipelines) still running an older version of this mapping after the edit: each keeps its version until it is moved with POST /v1/pipelines/:id/apply-mapping, naming headMappingId. Empty when no flow is behind. Archived flows are left out."}},"required":["mappingId","version","revertedToVersion","manifest","flowsBehind"]},"example":{"mappingId":"00000000-0000-0000-0000-000000000000","version":0,"revertedToVersion":0,"manifest":{"id":"string","version":0,"customerId":"string","sourceConnectionId":"string","targetConnectionId":"string","entityMappings":[{"id":"string","sourceEntityId":"string","targetEntityId":"string","confidence":0,"entityRelationship":"string","fieldMappings":[{"id":"string","sourceEntityId":"string","sourceFieldId":"string","targetEntityId":"string","targetFieldId":"string","authority":"string","conflictStrategy":"string","transform":"string","suggestedTransform":"string","transformConfig":{},"syncTier":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"direction":"string","confidence":0,"matchRationale":"string","customerApproved":true,"customerRejected":true,"customerModified":true,"autoApplied":true,"omitted":true,"omittedProposalChanged":true,"manualAuthored":true,"manualProposalConflict":true,"matchSource":"string","destinations":[{"id":"string","kind":"string","label":"string","connectionId":"string","targetEntityId":"string","targetFieldId":"string","channelType":"string","channelTarget":"string","channelId":"string","order":0,"dependsOn":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"transform":"string","transformConfig":{},"direction":"string","dedupeKeyFields":["string"],"maxPerMinute":0,"enabled":true}],"alternatives":[{"targetEntityId":"string","targetFieldId":"string","score":0,"scoreKind":"string","matchSource":"string"}]}],"matchOn":["string"],"goldenId":{"targetField":"string","matchTargetField":"string","goldenEntityType":"string","goldenField":"string"},"each":{"field":"string","parentAs":"string","idField":"string"}}],"groupDestinations":[{"group":"string","destinations":[{"id":"string","kind":"string","label":"string","connectionId":"string","targetEntityId":"string","targetFieldId":"string","channelType":"string","channelTarget":"string","channelId":"string","order":0,"dependsOn":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"transform":"string","transformConfig":{},"direction":"string","dedupeKeyFields":["string"],"maxPerMinute":0,"enabled":true}]}],"syncConfig":{"mode":"string","direction":"string","schedule":"string","intervalMinutes":0,"realtimeChannel":"string","sourceType":"string","streamConfig":{"broker":"string","topic":"string","offset":"string"},"targetType":"string","targetTable":"string","batchSize":0,"retryPolicy":{"maxAttempts":0,"backoffMs":0,"backoffMultiplier":0}},"matchedAt":"string","matchedBy":"string","overallConfidence":0,"status":"string","customerApprovedAt":"string","customerApprovedBy":"string","engine":"string","engineArm":"string","engineFallbackReason":"string","archived":true},"flowsBehind":[{"pipelineId":"00000000-0000-0000-0000-000000000000","name":"string","status":"string","pinnedMappingId":"00000000-0000-0000-0000-000000000000","headMappingId":"00000000-0000-0000-0000-000000000000"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/{id}/sample":{"get":{"operationId":"FetchMappingSample","tags":["mappings"],"summary":"Fetch Mapping Sample","security":[{"ApiKeyAuth":["mappings:read"]},{"BearerAuth":[]},{"OAuth2":["mappings:read"]}],"description":"Fetch one real record from one of the mapping’s systems, so you can preview how the mapping would treat it. Uses the connection’s saved address and credentials.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},{"name":"side","in":"query","required":false,"schema":{"type":"string","enum":["source","target"],"description":"Which system to fetch from: source (the default) or target. The target is used to preview syncing in reverse.","default":"source"},"description":"Which system to fetch from: source (the default) or target. The target is used to preview syncing in reverse."},{"name":"entity","in":"query","required":false,"schema":{"type":"string","description":"Which kind of record to fetch. Defaults to the mapping’s first pair."},"description":"Which kind of record to fetch. Defaults to the mapping’s first pair."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"record":{"type":"object","additionalProperties":true,"nullable":true,"description":"The first record returned, or null when the entity has none. The connected system's own record: its keys are that system's field names, so it has no fixed shape."},"entityType":{"type":"string"},"side":{"type":"string"}},"required":["entityType","side"]},"example":{"record":{},"entityType":"string","side":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/{id}/versions":{"get":{"operationId":"ListMappingVersions","tags":["mappings"],"summary":"List Mapping Versions","security":[{"ApiKeyAuth":["mappings:read"]},{"BearerAuth":[]},{"OAuth2":["mappings:read"]}],"description":"The version history of one mapping: the chain from its first version to the current one (any version id in the chain may be passed). Each edit to a mapping saves a new version; a re-match starts a new mapping with its own history. Versions are never deleted.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"mappingId":{"type":"string","format":"uuid","description":"The current version's id."},"versions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"version":{"type":"integer"},"current":{"type":"boolean"},"status":{"type":"string"},"createdAt":{"type":"string"},"createdBy":{"type":"string","nullable":true},"entities":{"type":"integer"},"fields":{"type":"integer"},"approved":{"type":"integer"},"rejected":{"type":"integer"},"omitted":{"type":"integer"}},"required":["id","version","current","status","createdAt","entities","fields","approved","rejected","omitted"]}}},"required":["mappingId","versions"]},"example":{"mappingId":"00000000-0000-0000-0000-000000000000","versions":[{"id":"00000000-0000-0000-0000-000000000000","version":0,"current":true,"status":"string","createdAt":"string","createdBy":"string","entities":0,"fields":0,"approved":0,"rejected":0,"omitted":0}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/{id}/versions/{version}":{"get":{"operationId":"GetMappingVersion","tags":["mappings"],"summary":"Get Mapping Version","security":[{"ApiKeyAuth":["mappings:read"]},{"BearerAuth":[]},{"OAuth2":["mappings:read"]}],"description":"One version of a mapping, by its version number from GET /v1/mappings/:id/versions (any version id in the chain may be passed as :id). A flow keeps the version it pinned until it is moved, so this is how to read what a flow actually runs.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},"description":"The mapping's id (mappingId): a row's mappingId from mappings_list, or any mappingVersionId from its version history. Never a fieldMappingId, entityMappingId, mappingDocumentId, pipeline id or connection id — a pipeline's mapping is `mappingId` on its pipeline mappings list."},{"name":"version","in":"path","required":true,"schema":{"type":"string","description":"The version number, from GET /v1/mappings/:id/versions."},"description":"The version number, from GET /v1/mappings/:id/versions."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"mappingId":{"type":"string","format":"uuid","description":"This version's id."},"version":{"type":"integer"},"current":{"type":"boolean","description":"True when this is the latest version."},"manifest":{"type":"object","properties":{"id":{"type":"string","description":"The id written inside the mapping document. Use the id in the path (or `id` from GET /v1/mappings) to address the mapping."},"version":{"type":"number"},"customerId":{"type":"string"},"sourceConnectionId":{"type":"string"},"targetConnectionId":{"type":"string"},"entityMappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sourceEntityId":{"type":"string"},"targetEntityId":{"type":"string"},"confidence":{"type":"number"},"entityRelationship":{"type":"string","description":"L15 relationship-inferrer's cross-provider equivalence verdict (equivalent / parent_child / related / unrelated) — refines whether the two entities should map at all. Open by design: a novel relationship label still flows through."},"fieldMappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"sourceEntityId":{"type":"string"},"sourceFieldId":{"type":"string"},"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"authority":{"type":"string","description":"Known values: provider-wins, native-only, native-override, latest-wins, merge."},"conflictStrategy":{"type":"string","description":"Known values: latest-timestamp, highest-authority, flag-for-review."},"transform":{"type":"string","description":"Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"suggestedTransform":{"type":"string","description":"L17 transform-inferrer's raw OPEN suggestion (identity / unit_conversion / format_conversion / enum_mapping / …) — what the AI proposed before the customer confirmed the executable `transform`. Open by design: a novel transform label still flows through. Drives the transform-override control in the mapping review."},"transformConfig":{"type":"object","additionalProperties":true},"syncTier":{"type":"string","description":"Per-FIELD sync cadence (functionality.md: \"per-field sync tiers\"; VISUAL-MAPPING-SPEC §0.1) — seeded from the tenant's per-entity onboarding selection at pipeline activation, overridable per field in the mapping review. Absent = the pipeline's default cadence. Known values: realtime, near-realtime, periodic, archival."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-link predicate (§7: \"only when type = business\") evaluated against the SOURCE record by the shared field-evaluator — the field syncs only when it holds. Absent = always syncs. A malformed condition evaluates FALSE (fail closed)."},"direction":{"type":"string","description":"Per-FIELD flow direction (VISUAL-MAPPING-SPEC item 11): source-to-target, target-to-source, or bidirectional — any field can flow either way, both ways, or (via omitted) not at all. Absent = inherit the mapping's syncConfig.direction. Enforced by the shared evaluator's pass filter; on the reverse pass a non-invertible transform skips the field (visible in preview) rather than writing a wrongly-transformed value. Known values: source-to-target, target-to-source, bidirectional."},"confidence":{"type":"number"},"matchRationale":{"type":"string","description":"why Layer 5 proposed this pairing"},"customerApproved":{"type":"boolean"},"customerRejected":{"type":"boolean","description":"Customer explicitly marked this match WRONG (audit §2.3) — distinct from customerApproved:false, which also covers never-reviewed. Same optional-for-back-compat pattern as `omitted`. A rejected field is excluded from sync by the shared evaluator (a wrong match must not move data) and is the negative training signal's home. Cleared by a later approve."},"customerModified":{"type":"boolean","description":"customer changed the AI proposal"},"autoApplied":{"type":"boolean","description":"Applied automatically because confidence cleared the tenant's auto-apply threshold (mapping.autoApplyThreshold tunable, §11b) — deliberately NOT customerApproved, which stays a genuine customer signal; an auto-applied field the customer later approves or rejects converts to a real signal. Auto-applied fields skip the review queue but sync like approved ones; the manifest-level approval gate still applies."},"omitted":{"type":"boolean","description":"Customer chose not to sync this field — a business decision, NOT a correctness verdict (reject ≠ omit, VISUAL-MAPPING-SPEC §11a). Never touches customerApproved, feeds no training signal, and is sticky: re-matching carries it forward instead of re-proposing the field. Absent = syncs normally."},"omittedProposalChanged":{"type":"boolean","description":"Set by re-matching when a NEW proposal arrived for a field the customer omitted — surfaced as a note (\"a new proposal exists\"), never auto-restored. Cleared when the customer restores the field."},"manualAuthored":{"type":"boolean","description":"A human authored this link FROM NOTHING — the AI never proposed it (audit §2.4). Distinct from customerModified, which is AI-proposed-then-edited: different provenance, different training signal, and only this one is a durable TENANT FACT. Sticky exactly as `omitted` is: re-matching and healing carry it forward instead of dropping it, because a re-inference must never silently undo a decision a person made. Stays in the tenant's override layer and is NEVER promoted into the shared corpus without explicit vetting — a tenant's anomaly is not the platform's knowledge."},"manualProposalConflict":{"type":"boolean","description":"Set by re-matching when the AI proposed a DIFFERENT target for a source field the customer hand-mapped — surfaced as a note (\"the AI now proposes something else\"), never an auto-overwrite. The manual mapping wins and keeps running. Mirrors omittedProposalChanged; cleared when the customer resolves it."},"matchSource":{"type":"string","description":"Provenance of the proposal this mapping came from (see FieldMatchProposal.matchSource). Lets the review page and the engine comparison say whether a rule, the golden layer, the lake or a model proposed the pair. The API answers a model-proposed pair as plain `l95`: the provider and deployment stay in the stored record and never reach a tenant (DEBT-202)."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within the mapping — the key `dependsOn` and the dispatch ledger reference."},"kind":{"type":"string","description":"OPEN destination kind. 'record' = write into a connected system; 'action' = invoke a capability. Unknown kinds fail loudly at dispatch rather than being silently skipped — a destination nobody delivers is the shipped-but-inert shape."},"label":{"type":"string","description":"Human name shown wherever the destination appears — what the tenant called it, not a generated id."},"connectionId":{"type":"string","description":"For kind=record: which connected system receives it. Absent = the mapping's own target connection."},"targetEntityId":{"type":"string","description":"For kind=record: entity written into. Absent = the field mapping's own targetEntityId."},"targetFieldId":{"type":"string","description":"For kind=record: field written. Absent = the field mapping's own targetFieldId."},"channelType":{"type":"string","description":"For kind=action: HOW to deliver — an OPEN channel type resolved by the notification engine (email / sms / webhook / in_app / …). The same vocabulary alert rules use, so actions ride the ONE hardened delivery path rather than a second transport."},"channelTarget":{"type":"string","description":"For kind=action: WHO receives it (address, number, URL, or a channel id)."},"channelId":{"type":"string","description":"For kind=action: pin a specific notification_channels row instead of resolving the tenant's first verified channel of that type."},"order":{"type":"number","description":"Explicit sequence within the field's destination set. Ordering is REQUIRED, not cosmetic: \"save, and IF that committed, send\" is only expressible when the order is declared rather than inferred from array position."},"dependsOn":{"type":"string","description":"Destination id that must have COMMITTED for THIS record before this one runs. A failed or skipped dependency skips the dependant — the \"if that committed\" half of the ordering guarantee."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-destination predicate over the SOURCE record, evaluated by the shared field-evaluator — the same type and the same semantics as the per-field condition. Absent = always. A malformed condition evaluates FALSE (fail closed)."},"transform":{"type":"string","description":"Per-destination transform. Absent = inherit the field mapping's transform, so a destination only declares what DIFFERS. Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"transformConfig":{"type":"object","additionalProperties":true},"direction":{"type":"string","description":"Per-destination flow direction; absent = inherit the field mapping's. A destination only participates in a pass its direction allows. Known values: source-to-target, target-to-source, bidirectional."},"dedupeKeyFields":{"type":"array","items":{"type":"string"},"description":"Source-record fields forming the idempotency key. Absent, the key is the record's identity plus the value being delivered — so a re-sync of UNCHANGED data dispatches nothing while a genuine change still does. This is not optional decoration: a backfill over an action destination is how a tenant discovers 40,000 text messages."},"maxPerMinute":{"type":"number","description":"Per-tenant ceiling on dispatches to THIS destination. When the trailing minute is already at the ceiling, dispatch to this destination halts for the rest of the run and the skipped count is recorded and surfaced — a safety valve that is visible rather than silent."},"enabled":{"type":"boolean","description":"Absent = enabled. Turning a destination off must not require deleting it, or the only way to pause an action is to lose its configuration."}},"required":["id","kind","label","order"]},"description":"ADDITIONAL destinations this field reaches beyond its primary target — the end of the one-field-one-destination model (§2.3/§3.3). Absent = the field behaves exactly as before, which is why adding fan-out changes nothing for an existing mapping. Dispatched in `order` after the primary sink write, so a record destination and an action destination can be sequenced (\"save, and if that committed, send\")."},"alternatives":{"type":"array","items":{"type":"object","properties":{"targetEntityId":{"type":"string"},"targetFieldId":{"type":"string"},"score":{"type":"number","description":"The number that ranked this candidate, in the units scoreKind names."},"scoreKind":{"type":"string","description":"OPEN vocabulary naming what `score` is: `lexical` (token-overlap rank from explainCandidates, unbounded), `embedding` (cosine similarity, -1..1), `model` (the matching model's own 0..1 confidence for this pair). A novel kind flows through as a string; a UI that does not know it shows no number."},"matchSource":{"type":"string","description":"Which stage ranked it (`embedding-candidate`, `lexical-candidate`, or `l95:<provider>:<deployment>` for a model answer — the API strips the provider and deployment, DEBT-202)."}},"required":["targetEntityId","targetFieldId","score","scoreKind","matchSource"]},"description":"The runners-up the matcher ranked for this source field, best first, never including this mapping's own target (OPEN-WORK 128 d). Read only by the review UI — nothing in sync or resolution reads it. Absent = the matcher ranked nothing else (a rule decided the pair) or the mapping predates the field. Re-matching carries it forward onto an unchanged pair that came back without any."}},"required":["id","sourceEntityId","sourceFieldId","targetEntityId","targetFieldId","authority","conflictStrategy","transform","confidence","matchRationale","customerApproved","customerModified"]}},"matchOn":{"type":"array","items":{"type":"string"},"description":"Target field api names that identify the same real-world record (target-id memory, 2026-10-08), e.g. ['billing_email'] or ['invoice_number']. Before creating a record it has no link for, the sync reads the target entity and links to an existing row whose values on every matchOn field equal the outgoing record's, then updates it instead of creating a duplicate. Empty or absent = no matching. Set with PATCH /v1/mappings/:id/entity-match."},"goldenId":{"type":"object","properties":{"targetField":{"type":"string","description":"Dotted target field the golden record id is written to (`customer_ids.inferrex_id`)."},"matchTargetField":{"type":"string","description":"Dotted target field holding the shared id after projection (`customer_ids.registered`)."},"goldenEntityType":{"type":"string","description":"The golden records searched: their entity type."},"goldenField":{"type":"string","description":"The golden field compared with the shared id, exactly (no case folding: an id is an id)."}},"required":["targetField","matchTargetField","goldenEntityType","goldenField"],"description":"Stamp each outgoing record with the id of the golden record it belongs to (2026-10-27, Bloomreach Engagement phase 1, D13: every command carries the tenant's own id AND the golden id). After the fields are projected, the sync finds the ONE golden record of `goldenEntityType` whose `goldenField` equals the value the record carries at `matchTargetField`, and writes its id at `targetField`. None or several: nothing is written there, and the count is logged. Absent = no stamp. Set by an approved destination setup plan."},"each":{"type":"object","properties":{"field":{"type":"string","description":"Dotted path of the list in the source record (`items`). A value that is not a list sends nothing; an element that is not an object is skipped."},"parentAs":{"type":"string","description":"The key the whole source record is read under while one element is projected (`$parent`): a field mapping reading `$parent.customer_email` reads the source record's own field."},"idField":{"type":"string","description":"The element's own field that identifies it (a line id), so an element keeps its record id (`<record>#<list>[<field>=<value>]`) when lines are inserted or reordered and is sent once (2026-10-28, Sentry on #847). Absent, or an element without a value there: the element is known by its position (`<record>#<list>[<n>]`), and a line inserted or reordered after the record was sent may be sent twice or not at all."}},"required":["field","parentAs"],"description":"One outgoing record per element of a list in the source record (2026-10-28, generic; Bloomreach Engagement: one `purchase_item` event per order line beside the order's `purchase`). The field mappings are projected once per element that is an object, reading the element's own fields by name and the source record's under `parentAs` (`$parent.id`); each result is written to `targetEntityId` as a record of its own, after the source record's own write and only when that write went out (a source record held back, refused or left out by a send rule takes its elements with it). Forward pass only. Absent = one record per source record, as before. Set by an approved destination setup plan."}},"required":["id","sourceEntityId","targetEntityId","confidence","fieldMappings"]},"description":"Each object pairing, with its field mappings: transform, authority, confidence, direction, condition, destinations and review state (customerApproved, customerRejected, omitted, manualAuthored). A field mapping may carry `alternatives`: the target fields the matcher ranked for that source field but did not choose, best first, each { targetEntityId, targetFieldId, score, scoreKind, matchSource }. `score` is a confidence only when scoreKind is `model`; `lexical` is a token-overlap rank and `embedding` a cosine similarity, so never show those as percentages. GET /v1/mappings/:id/field-candidates ranks more, with reasons."},"groupDestinations":{"type":"array","items":{"type":"object","properties":{"group":{"type":"string","description":"The open group label these destinations apply to — matched against InferredField.group."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable within the mapping — the key `dependsOn` and the dispatch ledger reference."},"kind":{"type":"string","description":"OPEN destination kind. 'record' = write into a connected system; 'action' = invoke a capability. Unknown kinds fail loudly at dispatch rather than being silently skipped — a destination nobody delivers is the shipped-but-inert shape."},"label":{"type":"string","description":"Human name shown wherever the destination appears — what the tenant called it, not a generated id."},"connectionId":{"type":"string","description":"For kind=record: which connected system receives it. Absent = the mapping's own target connection."},"targetEntityId":{"type":"string","description":"For kind=record: entity written into. Absent = the field mapping's own targetEntityId."},"targetFieldId":{"type":"string","description":"For kind=record: field written. Absent = the field mapping's own targetFieldId."},"channelType":{"type":"string","description":"For kind=action: HOW to deliver — an OPEN channel type resolved by the notification engine (email / sms / webhook / in_app / …). The same vocabulary alert rules use, so actions ride the ONE hardened delivery path rather than a second transport."},"channelTarget":{"type":"string","description":"For kind=action: WHO receives it (address, number, URL, or a channel id)."},"channelId":{"type":"string","description":"For kind=action: pin a specific notification_channels row instead of resolving the tenant's first verified channel of that type."},"order":{"type":"number","description":"Explicit sequence within the field's destination set. Ordering is REQUIRED, not cosmetic: \"save, and IF that committed, send\" is only expressible when the order is declared rather than inferred from array position."},"dependsOn":{"type":"string","description":"Destination id that must have COMMITTED for THIS record before this one runs. A failed or skipped dependency skips the dependant — the \"if that committed\" half of the ordering guarantee."},"condition":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the predicate reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"},"match":{"type":"string","description":"How this check and the ones in `also` combine. Absent = all. Known values: all, any."},"also":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Source-record field the check reads"},"op":{"type":"string","description":"Known values: equals, not-equals, contains, greater-than, less-than, present, absent."},"value":{"type":"string","description":"Comparand — unused for present/absent"}},"required":["field","op"]},"description":"More checks, combined with this one by `match`."}},"required":["field","op"],"description":"Per-destination predicate over the SOURCE record, evaluated by the shared field-evaluator — the same type and the same semantics as the per-field condition. Absent = always. A malformed condition evaluates FALSE (fail closed)."},"transform":{"type":"string","description":"Per-destination transform. Absent = inherit the field mapping's transform, so a destination only declares what DIFFERS. Known values: direct, rename, type-cast, format, lookup, formula, concatenate, split, map-values, default-value, golden-lookup."},"transformConfig":{"type":"object","additionalProperties":true},"direction":{"type":"string","description":"Per-destination flow direction; absent = inherit the field mapping's. A destination only participates in a pass its direction allows. Known values: source-to-target, target-to-source, bidirectional."},"dedupeKeyFields":{"type":"array","items":{"type":"string"},"description":"Source-record fields forming the idempotency key. Absent, the key is the record's identity plus the value being delivered — so a re-sync of UNCHANGED data dispatches nothing while a genuine change still does. This is not optional decoration: a backfill over an action destination is how a tenant discovers 40,000 text messages."},"maxPerMinute":{"type":"number","description":"Per-tenant ceiling on dispatches to THIS destination. When the trailing minute is already at the ceiling, dispatch to this destination halts for the rest of the run and the skipped count is recorded and surfaced — a safety valve that is visible rather than silent."},"enabled":{"type":"boolean","description":"Absent = enabled. Turning a destination off must not require deleting it, or the only way to pause an action is to lose its configuration."}},"required":["id","kind","label","order"]},"description":"The same destination shape a field declares, so there is one vocabulary and one executor rather than a parallel group path."}},"required":["group","destinations"]},"description":"Destinations declared for a whole field group. Absent when every destination is declared per field."},"syncConfig":{"type":"object","properties":{"mode":{"type":"string","description":"Known values: realtime, near-realtime, periodic, archival."},"direction":{"type":"string","description":"Known values: source-to-target, target-to-source, bidirectional."},"schedule":{"type":"string","description":"cron expression for periodic"},"intervalMinutes":{"type":"number","description":"for near-realtime"},"realtimeChannel":{"type":"string","description":"webhook/CDC channel for realtime"},"sourceType":{"type":"string","description":"How the source delivers data — drives the sync dispatch branch. Default (absent) is periodic = the batch job path; realtime subscribes to streamConfig via the QueueClient. Known values: realtime, near-realtime, periodic."},"streamConfig":{"type":"object","properties":{"broker":{"type":"string","description":"Known values: pubsub, nats, kafka, amqp, kinesis."},"topic":{"type":"string"},"offset":{"type":"string","description":"Known values: earliest, latest."}},"required":["broker"],"description":"Per-source stream binding for realtime sources. pubsub/nats resolve via the QueueClient today; kafka/amqp/kinesis are broker clients landing in unit A.5. Open by design — the broker set tracks the QueueClient providers + planned brokers."},"targetType":{"type":"string","description":"Where the synced records land — drives the sync WRITE branch (Phase 2 B.10). Default (absent) is api = the existing HTTP write to the target ConnectionManifest. warehouse → getWarehouseClient().upsert (analytical sink, schema ensured from the mapping); lake → getLakeClient().write (partitioned object-store landing tier). Both the batch and realtime paths flow through the SAME sink. Known values: api, warehouse, lake."},"targetTable":{"type":"string","description":"Explicit warehouse table / lake dataset name override (B.11). When absent the sink derives one table per target entity from the mapping (the targetEntityId apiName, sanitised). Set this to land every entity into one named table."},"batchSize":{"type":"number"},"retryPolicy":{"type":"object","properties":{"maxAttempts":{"type":"number"},"backoffMs":{"type":"number"},"backoffMultiplier":{"type":"number"}},"required":["maxAttempts","backoffMs","backoffMultiplier"]}},"required":["mode","direction","batchSize","retryPolicy"]},"matchedAt":{"type":"string"},"matchedBy":{"type":"string"},"overallConfidence":{"type":"number","description":"0 to 1."},"status":{"type":"string","description":"The status written inside the mapping document. Approving a mapping changes the stored version's status, not this one, so read approval from `status` on GET /v1/mappings. Known values: draft, awaiting-review, approved, active, paused."},"customerApprovedAt":{"type":"string"},"customerApprovedBy":{"type":"string"},"engine":{"type":"string","description":"Which match engine produced the mapping, e.g. v1, v2."},"engineArm":{"type":"string"},"engineFallbackReason":{"type":"string"},"archived":{"type":"boolean","description":"True when the mapping was archived (POST /v1/mappings/:id/archive). An archived mapping is left out of the lists and search but can still be read by id."}},"required":["id","version","customerId","sourceConnectionId","targetConnectionId","entityMappings","syncConfig","matchedAt","matchedBy","overallConfidence","status","archived"],"description":"The MappingManifest this version holds."}},"required":["mappingId","version","current","manifest"]},"example":{"mappingId":"00000000-0000-0000-0000-000000000000","version":0,"current":true,"manifest":{"id":"string","version":0,"customerId":"string","sourceConnectionId":"string","targetConnectionId":"string","entityMappings":[{"id":"string","sourceEntityId":"string","targetEntityId":"string","confidence":0,"entityRelationship":"string","fieldMappings":[{"id":"string","sourceEntityId":"string","sourceFieldId":"string","targetEntityId":"string","targetFieldId":"string","authority":"string","conflictStrategy":"string","transform":"string","suggestedTransform":"string","transformConfig":{},"syncTier":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"direction":"string","confidence":0,"matchRationale":"string","customerApproved":true,"customerRejected":true,"customerModified":true,"autoApplied":true,"omitted":true,"omittedProposalChanged":true,"manualAuthored":true,"manualProposalConflict":true,"matchSource":"string","destinations":[{"id":"string","kind":"string","label":"string","connectionId":"string","targetEntityId":"string","targetFieldId":"string","channelType":"string","channelTarget":"string","channelId":"string","order":0,"dependsOn":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"transform":"string","transformConfig":{},"direction":"string","dedupeKeyFields":["string"],"maxPerMinute":0,"enabled":true}],"alternatives":[{"targetEntityId":"string","targetFieldId":"string","score":0,"scoreKind":"string","matchSource":"string"}]}],"matchOn":["string"],"goldenId":{"targetField":"string","matchTargetField":"string","goldenEntityType":"string","goldenField":"string"},"each":{"field":"string","parentAs":"string","idField":"string"}}],"groupDestinations":[{"group":"string","destinations":[{"id":"string","kind":"string","label":"string","connectionId":"string","targetEntityId":"string","targetFieldId":"string","channelType":"string","channelTarget":"string","channelId":"string","order":0,"dependsOn":"string","condition":{"field":"string","op":"string","value":"string","match":"string","also":[{"field":"string","op":"string","value":"string"}]},"transform":"string","transformConfig":{},"direction":"string","dedupeKeyFields":["string"],"maxPerMinute":0,"enabled":true}]}],"syncConfig":{"mode":"string","direction":"string","schedule":"string","intervalMinutes":0,"realtimeChannel":"string","sourceType":"string","streamConfig":{"broker":"string","topic":"string","offset":"string"},"targetType":"string","targetTable":"string","batchSize":0,"retryPolicy":{"maxAttempts":0,"backoffMs":0,"backoffMultiplier":0}},"matchedAt":"string","matchedBy":"string","overallConfidence":0,"status":"string","customerApprovedAt":"string","customerApprovedBy":"string","engine":"string","engineArm":"string","engineFallbackReason":"string","archived":true}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/mappings/targets":{"get":{"operationId":"ListMappingTargets","tags":["mappings"],"summary":"List Mapping Targets","security":[{"ApiKeyAuth":["mappings:read"]},{"BearerAuth":[]},{"OAuth2":["mappings:read"]}],"description":"Your mappings seen from the receiving side: one entry for each kind of record that data is written into, listing every source that feeds it across all your mappings. Answers questions like “what feeds my customer records?”.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"description":"How many entries to return: 1 to 500, 100 if you leave it out.","default":100},"description":"How many entries to return: 1 to 500, 100 if you leave it out."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"targets":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"`<target system>|<target entity>`; unique in the list."},"target":{"type":"string","description":"The target entity's id in the mapping."},"target_system":{"type":"string","description":"The target connection's name, or its id when the connection is not found."},"sources":{"type":"array","items":{"type":"string"},"description":"Each source feeding it, as `<source system> · <source entity>`."},"fields":{"type":"integer","description":"Field mappings into this entity across those mappings."},"omitted":{"type":"integer","description":"Of those, how many a person left out of the sync."},"mappings":{"type":"integer","description":"Mappings that write into this entity."}},"required":["id","target","target_system","sources","fields","omitted","mappings"]},"description":"Most sources first."},"targetCount":{"type":"integer"}},"required":["targets","targetCount"]},"example":{"targets":[{"id":"string","target":"string","target_system":"string","sources":["string"],"fields":0,"omitted":0,"mappings":0}],"targetCount":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/marketing/contacts":{"post":{"operationId":"MarketingContactsUpsert","tags":["marketing"],"summary":"Marketing Contacts Upsert","security":[],"description":"Capture a consent submission and optional call request without activating marketing consent. HMAC-SHA256 service authentication is mandatory; every POST requires Idempotency-Key.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"source":{"type":"string","minLength":1,"maxLength":100},"correlationId":{"type":"string","minLength":1,"maxLength":128},"identity":{"type":"object","properties":{"email":{"type":"string","format":"email","minLength":1,"maxLength":320},"firstName":{"type":"string","minLength":1,"maxLength":100},"lastName":{"type":"string","minLength":1,"maxLength":100},"company":{"type":"string","minLength":1,"maxLength":255},"jobTitle":{"type":"string","minLength":1,"maxLength":255}},"required":["email"]},"callRequest":{"type":"object","properties":{"phone":{"type":"string","minLength":1,"maxLength":32},"message":{"type":"string","minLength":1,"maxLength":1000}},"required":["phone"]},"topics":{"type":"array","items":{"type":"string"},"maxItems":30,"description":"Exact topic IDs from the platform-approved marketing policy. Unknown or duplicate topics are rejected."},"legalVersion":{"type":"string","minLength":1,"maxLength":100},"consentVersion":{"type":"string","minLength":1,"maxLength":100},"consentedAt":{"type":"string","format":"date-time"}},"required":["source","correlationId","identity","topics","legalVersion","consentVersion","consentedAt"]},"example":{"source":"string","correlationId":"string","identity":{"email":"user@example.com","firstName":"string","lastName":"string","company":"string","jobTitle":"string"},"callRequest":{"phone":"string","message":"string"},"topics":["string"],"legalVersion":"string","consentVersion":"string","consentedAt":"2026-01-01T00:00:00Z"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"contactId":{"type":"string","format":"uuid"},"verificationRequired":{"type":"boolean"}},"required":["contactId","verificationRequired"]},"example":{"contactId":"00000000-0000-0000-0000-000000000000","verificationRequired":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/marketing/contacts/{contactId}/verification":{"post":{"operationId":"MarketingVerificationIssue","tags":["marketing"],"summary":"Marketing Verification Issue","security":[],"description":"Send a verification link for the current pending submission matching its capture correlation ID. HMAC-SHA256 service authentication is mandatory; every POST requires Idempotency-Key.","parameters":[{"name":"contactId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"correlationId":{"type":"string","minLength":1,"maxLength":128}},"required":["correlationId"]},"example":{"correlationId":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"accepted":{"type":"boolean"}},"required":["accepted"]},"example":{"accepted":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/marketing/delivery":{"post":{"operationId":"MarketingDelivery","tags":["marketing"],"summary":"Marketing Delivery","security":[],"description":"Deliver an approved marketing template through the marketing email transport (ACS Email) only after locked verification, consent and suppression checks. HMAC-SHA256 service authentication is mandatory; every POST requires Idempotency-Key.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contactId":{"type":"string","format":"uuid"},"topic":{"type":"string","minLength":1,"maxLength":100},"templateId":{"type":"string","minLength":1,"maxLength":100}},"required":["contactId","topic","templateId"]},"example":{"contactId":"00000000-0000-0000-0000-000000000000","topic":"string","templateId":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"deliveryId":{"type":"string","format":"uuid"},"status":{"type":"string"}},"required":["deliveryId","status"]},"example":{"deliveryId":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/marketing/email/delivery-reports":{"post":{"operationId":"MarketingEmailDeliveryReports","tags":["marketing"],"summary":"Marketing Email Delivery Reports","security":[],"description":"Azure Event Grid webhook for Azure Communication Services email delivery reports (Event Grid schema). Answers the SubscriptionValidationEvent handshake, then normalises each Microsoft.Communication.EmailDeliveryReportReceived to {eventId, messageId, occurredAt, status} and applies it idempotently on the event id: Delivered → delivered; Bounced and Suppressed → bounce (suppresses every topic); Quarantined, FilteredSpam and Failed → failed; Expanded is not applied. Authorization: Bearer <Microsoft Entra token issued to Event Grid for INFERREX_EVENTGRID_WEBHOOK_AUDIENCE>.","responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"validationResponse":{"type":"string","description":"The subscription validation code, echoed once when Event Grid validates the subscription."},"applied":{"type":"integer","description":"Delivery reports that changed a delivery."},"skipped":{"type":"integer","description":"Events not applied: redelivered, Expanded, about another resource or another message, or malformed."}}},"example":{"validationResponse":"string","applied":0,"skipped":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/marketing/preferences/consume":{"post":{"operationId":"MarketingPreferencesConsume","tags":["marketing"],"summary":"Marketing Preferences Consume","security":[],"description":"Consume a signed preference link, append consent evidence and suppress opted-out topics immediately. HMAC-SHA256 service authentication is mandatory; every POST requires Idempotency-Key.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","minLength":1,"maxLength":512},"topics":{"type":"array","items":{"type":"string"},"maxItems":30,"description":"Exact topic IDs from the platform-approved marketing policy. Unknown or duplicate topics are rejected."},"unsubscribeAll":{"type":"boolean"},"legalVersion":{"type":"string","minLength":1,"maxLength":100},"consentVersion":{"type":"string","minLength":1,"maxLength":100},"consentedAt":{"type":"string","format":"date-time"}},"required":["token","legalVersion","consentVersion","consentedAt"]},"example":{"token":"string","topics":["string"],"unsubscribeAll":true,"legalVersion":"string","consentVersion":"string","consentedAt":"2026-01-01T00:00:00Z"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"accepted":{"type":"boolean"}},"required":["accepted"]},"example":{"accepted":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/marketing/progression/events":{"post":{"operationId":"MarketingProgressionEvent","tags":["marketing"],"summary":"Marketing Progression Event","security":[],"description":"Record a verified, allow-listed milestone, never passive browsing or behavioural events. HMAC-SHA256 service authentication is mandatory; every POST requires Idempotency-Key.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contactId":{"type":"string","format":"uuid"},"eventId":{"type":"string","minLength":1,"maxLength":128},"milestone":{"type":"string","minLength":1,"maxLength":100},"evidenceId":{"type":"string","minLength":1,"maxLength":255},"occurredAt":{"type":"string","format":"date-time"}},"required":["contactId","eventId","milestone","evidenceId","occurredAt"]},"example":{"contactId":"00000000-0000-0000-0000-000000000000","eventId":"string","milestone":"string","evidenceId":"string","occurredAt":"2026-01-01T00:00:00Z"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"contactId":{"type":"string","format":"uuid"},"state":{"type":"string"}},"required":["contactId","state"]},"example":{"contactId":"00000000-0000-0000-0000-000000000000","state":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/marketing/settings":{"get":{"operationId":"MarketingPublicSettings","tags":["marketing"],"summary":"Marketing Public Settings","security":[],"description":"Return activated subscription choices and consent wording to the signed website broker; never private policy, templates or test mailboxes. HMAC-SHA256 service authentication is mandatory; every POST requires Idempotency-Key.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"revision":{"type":"string","format":"uuid"},"legalVersion":{"type":"string","minLength":1,"maxLength":100},"consentVersion":{"type":"string","minLength":1,"maxLength":100},"consentText":{"type":"string","minLength":1,"maxLength":10000},"topics":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":100},"label":{"type":"string","minLength":1,"maxLength":255},"consentText":{"type":"string","minLength":1,"maxLength":5000}},"required":["id","label","consentText"]}}},"required":["revision","legalVersion","consentVersion","consentText","topics"]},"example":{"revision":"00000000-0000-0000-0000-000000000000","legalVersion":"string","consentVersion":"string","consentText":"string","topics":[{"id":"string","label":"string","consentText":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/marketing/verification/consume":{"post":{"operationId":"MarketingVerificationConsume","tags":["marketing"],"summary":"Marketing Verification Consume","security":[],"description":"Consume a single-use verification link and activate only its submitted topics. HMAC-SHA256 service authentication is mandatory; every POST requires Idempotency-Key.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","minLength":1,"maxLength":512}},"required":["token"]},"example":{"token":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"contactId":{"type":"string","format":"uuid"},"verificationRequired":{"type":"boolean"}},"required":["contactId","verificationRequired"]},"example":{"contactId":"00000000-0000-0000-0000-000000000000","verificationRequired":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/monitoring/health":{"get":{"operationId":"GetConnectionHealth","tags":["monitoring"],"summary":"Get Connection Health","security":[{"ApiKeyAuth":["monitoring:read"]},{"BearerAuth":[]},{"OAuth2":["monitoring:read"]}],"description":"A health score from 0 to 100 for each of your connections, based on the last 24 hours: how many errors there were, how fast and how steady the traffic was, and how much of the time the connection was up.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"connection_id":{"type":"string","format":"uuid"},"display_name":{"type":"string"},"score":{"type":"integer","minimum":0,"maximum":100,"description":"Weighted health score. 0 and not a measurement when `unmeasured`."},"unmeasured":{"type":"boolean","description":"No pipeline events in the last 24 hours, so there is nothing to score. Show \"no activity\", not 0."},"factors":{"type":"object","properties":{"error_rate":{"type":"integer","description":"Share of events that are not errors (weight 40%)."},"latency":{"type":"integer","description":"Inference latency against its baseline (weight 20%); 100 when there is no inference latency to score."},"volume_consistency":{"type":"integer","description":"Penalised by switches between inference modes (weight 20%)."},"uptime":{"type":"integer","description":"Sync success rate (weight 20%)."},"inference_mode_switches":{"type":"integer","description":"Distinct inference modes seen in the window."}},"required":["error_rate","latency","volume_consistency","uptime","inference_mode_switches"],"description":"Each factor 0–100 except inference_mode_switches (a count). All 0 when unmeasured."},"trend":{"type":"string","description":"Today: stable (score above 80, or unmeasured) or degrading. improving is in the type but never computed."},"computed_at":{"type":"string","format":"date-time"}},"required":["connection_id","display_name","score","unmeasured","factors","trend","computed_at"]}}},"required":["data"]},"example":{"data":[{"connection_id":"00000000-0000-0000-0000-000000000000","display_name":"string","score":0,"unmeasured":true,"factors":{"error_rate":0,"latency":0,"volume_consistency":0,"uptime":0,"inference_mode_switches":0},"trend":"string","computed_at":"2026-01-01T00:00:00Z"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/monitoring/summary":{"get":{"operationId":"GetMonitoringSummary","tags":["monitoring"],"summary":"Get Monitoring Summary","security":[{"ApiKeyAuth":["monitoring:read"]},{"BearerAuth":[]},{"OAuth2":["monitoring:read"]}],"description":"An overview of the last 24 hours across your workspace: how many connections are monitored and their average health, how many alerts fired, how many syncs completed or failed, the success rate, how many errors were recorded, and Inferrex’s suggested next steps.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionsMonitored":{"type":"integer"},"healthScoreAvg":{"type":"number","nullable":true},"alertsFiring24h":{"type":"integer"},"syncsCompleted24h":{"type":"integer"},"syncsFailed24h":{"type":"integer"},"syncSuccessRate24h":{"type":"number","nullable":true},"errorEvents24h":{"type":"integer"},"recommendations":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","description":"The sentence to show."},"to":{"type":"string","description":"The app path it links to (/monitoring/health, /monitoring/timeline, /pipelines)."},"tone":{"type":"string","description":"Today: destructive, warning, default."}},"required":["label","to","tone"]},"description":"Suggested next steps, most severe first; empty when nothing needs attention."}},"required":["connectionsMonitored","alertsFiring24h","syncsCompleted24h","syncsFailed24h","errorEvents24h","recommendations"]},"example":{"connectionsMonitored":0,"healthScoreAvg":0,"alertsFiring24h":0,"syncsCompleted24h":0,"syncsFailed24h":0,"syncSuccessRate24h":0,"errorEvents24h":0,"recommendations":[{"label":"string","to":"string","tone":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/notifications":{"get":{"operationId":"ListNotifications","tags":["notifications"],"summary":"List Notifications","security":[{"ApiKeyAuth":["notifications:read"]},{"BearerAuth":[]},{"OAuth2":["notifications:read"]}],"description":"Your workspace’s notifications, newest first, a page at a time.","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Which page to return, starting at 1.","default":1},"description":"Which page to return, starting at 1."},{"name":"pageSize","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"description":"How many notifications per page: 1 to 100, 25 if you leave it out.","default":25},"description":"How many notifications per page: 1 to 100, 25 if you leave it out."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"notifications":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","description":"Open vocabulary, e.g. sync_failure, healing_event, usage_threshold, security_alert, team_invite, system."},"title":{"type":"string"},"body":{"type":"string"},"resourceType":{"type":"string","nullable":true,"description":"What the notification is about, e.g. pipeline, connection, archived-record, workspace."},"resourceId":{"type":"string","nullable":true},"readAt":{"type":"string","nullable":true},"createdAt":{"type":"string"}},"required":["id","type","title","body","resourceType","resourceId","readAt","createdAt"]}},"pagination":{"type":"object","properties":{"page":{"type":"integer"},"pageSize":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"}},"required":["page","pageSize","total","totalPages"]}},"required":["notifications","pagination"]},"example":{"notifications":[{"id":"string","type":"string","title":"string","body":"string","resourceType":"string","resourceId":"string","readAt":"string","createdAt":"string"}],"pagination":{"page":0,"pageSize":0,"total":0,"totalPages":0}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/notifications/{id}/read":{"post":{"operationId":"MarkNotificationRead","tags":["notifications"],"summary":"Mark Notification Read","security":[{"ApiKeyAuth":["notifications:write"]},{"BearerAuth":[]},{"OAuth2":["notifications:write"]}],"description":"Mark one notification as read.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the notification."},"description":"The id of the notification."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]},"example":{"success":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/notifications/read-all":{"post":{"operationId":"MarkAllNotificationsRead","tags":["notifications"],"summary":"Mark All Notifications Read","security":[{"ApiKeyAuth":["notifications:write"]},{"BearerAuth":[]},{"OAuth2":["notifications:write"]}],"description":"Mark all of your workspace’s unread notifications as read. Returns how many were marked.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"markedCount":{"type":"integer"}},"required":["markedCount"]},"example":{"markedCount":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/notifications/unread-count":{"get":{"operationId":"GetUnreadNotificationCount","tags":["notifications"],"summary":"Get Unread Notification Count","security":[{"ApiKeyAuth":["notifications:read"]},{"BearerAuth":[]},{"OAuth2":["notifications:read"]}],"description":"How many of your workspace’s notifications have not been read yet.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"unreadCount":{"type":"integer"}},"required":["unreadCount"]},"example":{"unreadCount":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/oauth/initiate":{"post":{"operationId":"OAuthInitiate","tags":["oauth"],"summary":"OAuth Initiate","security":[{"ApiKeyAuth":["oauth:write"]},{"BearerAuth":[]},{"OAuth2":["oauth:write"]}],"description":"Start signing a connection in to its system with OAuth. Returns the address of the system’s own sign-in page (send the person there) and a one-time state value that expires after 10 minutes. When they approve, the system sends them back to Inferrex, which saves the tokens on the connection.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"providerKey":{"type":"string","description":"The system to sign in to, by its catalogue key."},"connectionId":{"type":"string","format":"uuid","description":"The connection the access is for."},"redirectUri":{"type":"string","format":"uri","description":"Where the system should send the person back to: Inferrex’s OAuth callback address for this system."},"scopes":{"type":"array","items":{"type":"string"},"description":"Optional: the permissions to ask for. Defaults to the ones the system usually needs."},"environmentId":{"type":"string","format":"uuid","description":"Save the tokens for this environment. Leave out for the connection’s main credentials."}},"required":["providerKey","connectionId","redirectUri"]},"example":{"providerKey":"string","connectionId":"00000000-0000-0000-0000-000000000000","redirectUri":"https://example.com","scopes":["string"],"environmentId":"00000000-0000-0000-0000-000000000000"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"authorizeUrl":{"type":"string"},"state":{"type":"string"}},"required":["authorizeUrl","state"]},"example":{"authorizeUrl":"string","state":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/oauth/token":{"post":{"operationId":"OAuthToken","tags":["oauth"],"summary":"OAuth Token","security":[],"description":"Swap an API key for a short-lived access token (the OAuth 2.0 client credentials flow). Post grant_type=client_credentials as a form (application/x-www-form-urlencoded) or as JSON. Authenticate with HTTP Basic (Authorization: Basic base64(client_id:client_secret)) or by sending client_id and client_secret in the body: client_id is your API key’s prefix and client_secret the full key. The token can do what the key can do, or less if you ask for fewer scopes. Send it as Authorization: Bearer <token> and get a new one when it expires. Errors follow RFC 6749: { error, error_description }.","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"grant_type":{"type":"string","description":"Always client_credentials."},"client_id":{"type":"string","description":"Your API key’s prefix. Leave out when you use HTTP Basic."},"client_secret":{"type":"string","description":"Your full API key. Leave out when you use HTTP Basic."},"scope":{"type":"string","description":"Optional: ask for fewer permissions than the key has, as scopes separated by spaces."}}},"example":{"grant_type":"string","client_id":"string","client_secret":"string","scope":"string"}},"application/json":{"schema":{"type":"object","properties":{"grant_type":{"type":"string","description":"Always client_credentials."},"client_id":{"type":"string","description":"Your API key’s prefix. Leave out when you use HTTP Basic."},"client_secret":{"type":"string","description":"Your full API key. Leave out when you use HTTP Basic."},"scope":{"type":"string","description":"Optional: ask for fewer permissions than the key has, as scopes separated by spaces."}}},"example":{"grant_type":"string","client_id":"string","client_secret":"string","scope":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string","description":"Bearer"},"expires_in":{"type":"integer","description":"Seconds until expiry."},"scope":{"type":"string","description":"Space-separated granted scopes."}},"required":["access_token","token_type","expires_in","scope"]},"example":{"access_token":"string","token_type":"string","expires_in":0,"scope":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}},"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}}},"400":{"description":"OAuth 2.0 error (RFC 6749 §5.2).","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"error_description":{"type":"string"}}}}}},"401":{"description":"invalid_client (WWW-Authenticate: Basic when HTTP Basic was used).","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"error_description":{"type":"string"}}}}}},"429":{"description":"OAuth 2.0 error (RFC 6749 §5.2).","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"error_description":{"type":"string"}}}}}},"500":{"description":"OAuth 2.0 error (RFC 6749 §5.2).","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"error_description":{"type":"string"}}}}}},"503":{"description":"OAuth 2.0 error (RFC 6749 §5.2).","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"error_description":{"type":"string"}}}}}}}}},"/v1/onboarding":{"get":{"operationId":"GetOnboarding","tags":["onboarding"],"summary":"Get Onboarding","security":[{"ApiKeyAuth":["onboarding:read"]},{"BearerAuth":[]},{"OAuth2":["onboarding:read"]}],"description":"Where you are in the setup guide: the current step, the systems you have connected so far, your choices, and the pipeline it set up. If you are not in the middle of setup, active is false.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"active":{"type":"boolean"},"id":{"type":"string","format":"uuid","nullable":true},"customerId":{"type":"string","format":"uuid"},"step":{"type":"string","nullable":true},"phase1ConnectionId":{"type":"string","format":"uuid","nullable":true},"phase2ConnectionId":{"type":"string","format":"uuid","nullable":true},"archivalEnabled":{"type":"boolean","nullable":true},"syncTierConfig":{"type":"object","additionalProperties":true,"nullable":true},"pipelineId":{"type":"string","format":"uuid","nullable":true},"createdAt":{"type":"string","nullable":true},"completedAt":{"type":"string","nullable":true}},"required":["active","customerId"]},"example":{"active":true,"id":"00000000-0000-0000-0000-000000000000","customerId":"00000000-0000-0000-0000-000000000000","step":"string","phase1ConnectionId":"00000000-0000-0000-0000-000000000000","phase2ConnectionId":"00000000-0000-0000-0000-000000000000","archivalEnabled":true,"syncTierConfig":{},"pipelineId":"00000000-0000-0000-0000-000000000000","createdAt":"string","completedAt":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/onboarding/archival-analysis":{"get":{"operationId":"GetOnboardingArchivalAnalysis","tags":["onboarding"],"summary":"Get Onboarding Archival Analysis","security":[{"ApiKeyAuth":["onboarding:read"]},{"BearerAuth":[]},{"OAuth2":["onboarding:read"]}],"description":"How much of a connection’s data could be archived: how many kinds of record qualify, and an estimate of the records and the monthly saving. The record count and saving are estimates, because no data has synced yet.","parameters":[{"name":"connectionId","in":"query","required":true,"schema":{"type":"string","format":"uuid","description":"The connection to analyse."},"description":"The connection to analyse."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"eligibleEntities":{"type":"integer"},"estimatedRecords":{"type":"integer","nullable":true},"estimatedMonthlySaving":{"type":"number","nullable":true},"isEstimate":{"type":"boolean"}},"required":["connectionId","eligibleEntities","isEstimate"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","eligibleEntities":0,"estimatedRecords":0,"estimatedMonthlySaving":0,"isEstimate":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/onboarding/entity-sync-tiers":{"get":{"operationId":"GetOnboardingEntitySyncTiers","tags":["onboarding"],"summary":"Get Onboarding Entity Sync Tiers","security":[{"ApiKeyAuth":["onboarding:read"]},{"BearerAuth":[]},{"OAuth2":["onboarding:read"]}],"description":"Suggested sync frequency for each kind of record in a connection, with the reason for each. Used during setup.","parameters":[{"name":"connectionId","in":"query","required":true,"schema":{"type":"string","format":"uuid","description":"The connection to suggest frequencies for."},"description":"The connection to suggest frequencies for."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"suggestions":{"type":"array","items":{"type":"object","properties":{"entityId":{"type":"string"},"displayName":{"type":"string"},"suggestedTier":{"type":"string"},"rationale":{"type":"string"},"confidence":{"type":"number","nullable":true}},"required":["entityId","displayName","suggestedTier","rationale"]}}},"required":["connectionId","suggestions"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","suggestions":[{"entityId":"string","displayName":"string","suggestedTier":"string","rationale":"string","confidence":0}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/onboarding/start":{"post":{"operationId":"StartOnboarding","tags":["onboarding"],"summary":"Start Onboarding","security":[{"ApiKeyAuth":["onboarding:write"]},{"BearerAuth":[]},{"OAuth2":["onboarding:write"]}],"description":"Start the setup guide. If you already have one in progress, that one is returned instead of starting again.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customerId":{"type":"string","format":"uuid"},"step":{"type":"string"}},"required":["id","customerId","step"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customerId":"00000000-0000-0000-0000-000000000000","step":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/onboarding/step":{"post":{"operationId":"AdvanceOnboarding","tags":["onboarding"],"summary":"Advance Onboarding","security":[{"ApiKeyAuth":["onboarding:write"]},{"BearerAuth":[]},{"OAuth2":["onboarding:write"]}],"description":"Save your progress in the setup guide and move to the next step: the systems you connected, your archiving and sync choices, approving the mapping, and finally switching the pipeline on.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"phase1ConnectionId":{"type":"string","format":"uuid","description":"The first system you connected."},"phase2ConnectionId":{"type":"string","format":"uuid","description":"The second system you connected."},"archivalEnabled":{"type":"boolean","description":"Whether to archive old data."},"syncTierConfig":{"type":"object","additionalProperties":true,"description":"Your chosen sync frequency for each kind of record."},"pipelineId":{"type":"string","format":"uuid","description":"The pipeline set up for you."},"mappingApproved":{"type":"boolean","description":"true to approve the mapping between your two systems (the one in mappingId, or else the newest) and create the pipeline that will use it, as a draft."},"mappingId":{"type":"string","format":"uuid","description":"With mappingApproved: the mapping you are approving."},"activate":{"type":"boolean","description":"The last step: true to switch the pipeline on (creating it first if needed) and finish setup."}}},"example":{"phase1ConnectionId":"00000000-0000-0000-0000-000000000000","phase2ConnectionId":"00000000-0000-0000-0000-000000000000","archivalEnabled":true,"syncTierConfig":{},"pipelineId":"00000000-0000-0000-0000-000000000000","mappingApproved":true,"mappingId":"00000000-0000-0000-0000-000000000000","activate":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"step":{"type":"string"}},"required":["id","step"]},"example":{"id":"00000000-0000-0000-0000-000000000000","step":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/openapi.json":{"get":{"operationId":"GetOpenApiSpec","tags":["meta"],"summary":"Get Open Api Spec","security":[],"description":"The full description of this API as an OpenAPI document, the same one published at inferrex.com/openapi.json. No credentials needed, so tools and agents can read every endpoint, parameter and response before signing in.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/operation-scopes":{"get":{"operationId":"OperationScopesList","tags":["core"],"summary":"Operation Scopes List","security":[{"ApiKeyAuth":["operation-scopes:read"]},{"BearerAuth":[]},{"OAuth2":["operation-scopes:read"]}],"description":"List your operation scopes, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"connection_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only operation scopes for this connection. Pass its id."},"description":"Only operation scopes for this connection. Pass its id."},{"name":"scope_type","in":"query","required":false,"schema":{"type":"string","description":"Only operation scopes whose scope type is exactly this."},"description":"Only operation scopes whose scope type is exactly this."},{"name":"scope_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only operation scopes whose scope type contains this text (upper and lower case are treated the same)."},"description":"Only operation scopes whose scope type contains this text (upper and lower case are treated the same)."},{"name":"entity_type","in":"query","required":false,"schema":{"type":"string","description":"Only operation scopes whose entity type is exactly this."},"description":"Only operation scopes whose entity type is exactly this."},{"name":"entity_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only operation scopes whose entity type contains this text (upper and lower case are treated the same)."},"description":"Only operation scopes whose entity type contains this text (upper and lower case are treated the same)."},{"name":"included","in":"query","required":false,"schema":{"type":"boolean","description":"Only operation scopes where included is true, or false for only those where it is false."},"description":"Only operation scopes where included is true, or false for only those where it is false."},{"name":"field_exclusions_contains","in":"query","required":false,"schema":{"type":"string"}},{"name":"date_range_from_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only operation scopes whose date range from is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only operation scopes whose date range from is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"date_range_from_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only operation scopes whose date range from is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only operation scopes whose date range from is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"date_range_to_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only operation scopes whose date range to is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only operation scopes whose date range to is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"date_range_to_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only operation scopes whose date range to is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only operation scopes whose date range to is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"schedule_type","in":"query","required":false,"schema":{"type":"string","description":"Only operation scopes whose schedule type is exactly this."},"description":"Only operation scopes whose schedule type is exactly this."},{"name":"schedule_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only operation scopes whose schedule type contains this text (upper and lower case are treated the same)."},"description":"Only operation scopes whose schedule type contains this text (upper and lower case are treated the same)."},{"name":"schedule_cron","in":"query","required":false,"schema":{"type":"string","description":"Only operation scopes whose schedule cron is exactly this."},"description":"Only operation scopes whose schedule cron is exactly this."},{"name":"schedule_cron_contains","in":"query","required":false,"schema":{"type":"string","description":"Only operation scopes whose schedule cron contains this text (upper and lower case are treated the same)."},"description":"Only operation scopes whose schedule cron contains this text (upper and lower case are treated the same)."},{"name":"schedule_timezone","in":"query","required":false,"schema":{"type":"string","description":"Only operation scopes whose schedule timezone is exactly this."},"description":"Only operation scopes whose schedule timezone is exactly this."},{"name":"schedule_timezone_contains","in":"query","required":false,"schema":{"type":"string","description":"Only operation scopes whose schedule timezone contains this text (upper and lower case are treated the same)."},"description":"Only operation scopes whose schedule timezone contains this text (upper and lower case are treated the same)."},{"name":"max_duration_minutes_gte","in":"query","required":false,"schema":{"type":"number","description":"Only operation scopes whose max duration minutes is this number or more."},"description":"Only operation scopes whose max duration minutes is this number or more."},{"name":"max_duration_minutes_lte","in":"query","required":false,"schema":{"type":"number","description":"Only operation scopes whose max duration minutes is this number or less."},"description":"Only operation scopes whose max duration minutes is this number or less."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many operation scopes to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many operation scopes to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many operation scopes to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many operation scopes to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","connection_id","scope_type","entity_type","included","date_range_from","date_range_to","schedule_type","schedule_cron","schedule_timezone","max_duration_minutes","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns operation scopes where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns operation scopes where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid"},"scope_type":{"type":"string"},"entity_type":{"type":"string"},"included":{"type":"boolean"},"field_exclusions":{"type":"array","items":{"type":"string"}},"filter_conditions":{"type":"object","additionalProperties":true},"date_range_from":{"type":"string","nullable":true},"date_range_to":{"type":"string","nullable":true},"schedule_type":{"type":"string","nullable":true},"schedule_cron":{"type":"string","nullable":true},"schedule_timezone":{"type":"string"},"maintenance_window":{"type":"object","additionalProperties":true,"nullable":true},"max_duration_minutes":{"type":"integer","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","connection_id","scope_type","entity_type"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","scope_type":"string","entity_type":"string","included":true,"field_exclusions":["string"],"filter_conditions":{},"date_range_from":"string","date_range_to":"string","schedule_type":"string","schedule_cron":"string","schedule_timezone":"string","maintenance_window":{},"max_duration_minutes":0,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"OperationScopesCreate","tags":["core"],"summary":"Operation Scopes Create","security":[{"ApiKeyAuth":["operation-scopes:write"]},{"BearerAuth":[]},{"OAuth2":["operation-scopes:write"]}],"description":"Create an operation scope. Returns the new operation scope, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connection_id":{"type":"string","format":"uuid"},"scope_type":{"type":"string"},"entity_type":{"type":"string"},"included":{"type":"boolean"},"field_exclusions":{"type":"array","items":{"type":"string"}},"filter_conditions":{"type":"object","additionalProperties":true},"date_range_from":{"type":"string","nullable":true},"date_range_to":{"type":"string","nullable":true},"schedule_type":{"type":"string","nullable":true},"schedule_cron":{"type":"string","nullable":true},"schedule_timezone":{"type":"string"},"maintenance_window":{"type":"object","additionalProperties":true,"nullable":true},"max_duration_minutes":{"type":"integer","nullable":true}},"required":["connection_id","scope_type","entity_type"]},"example":{"connection_id":"00000000-0000-0000-0000-000000000000","scope_type":"string","entity_type":"string","included":true,"field_exclusions":["string"],"filter_conditions":{},"date_range_from":"string","date_range_to":"string","schedule_type":"string","schedule_cron":"string","schedule_timezone":"string","maintenance_window":{},"max_duration_minutes":0}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid"},"scope_type":{"type":"string"},"entity_type":{"type":"string"},"included":{"type":"boolean"},"field_exclusions":{"type":"array","items":{"type":"string"}},"filter_conditions":{"type":"object","additionalProperties":true},"date_range_from":{"type":"string","nullable":true},"date_range_to":{"type":"string","nullable":true},"schedule_type":{"type":"string","nullable":true},"schedule_cron":{"type":"string","nullable":true},"schedule_timezone":{"type":"string"},"maintenance_window":{"type":"object","additionalProperties":true,"nullable":true},"max_duration_minutes":{"type":"integer","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","connection_id","scope_type","entity_type"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","scope_type":"string","entity_type":"string","included":true,"field_exclusions":["string"],"filter_conditions":{},"date_range_from":"string","date_range_to":"string","schedule_type":"string","schedule_cron":"string","schedule_timezone":"string","maintenance_window":{},"max_duration_minutes":0,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/operation-scopes/{id}":{"delete":{"operationId":"OperationScopesDelete","tags":["core"],"summary":"Operation Scopes Delete","security":[{"ApiKeyAuth":["operation-scopes:delete"]},{"BearerAuth":[]},{"OAuth2":["operation-scopes:delete"]}],"description":"Delete an operation scope permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the operation scope."},"description":"The id of the operation scope."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"OperationScopesGet","tags":["core"],"summary":"Operation Scopes Get","security":[{"ApiKeyAuth":["operation-scopes:read"]},{"BearerAuth":[]},{"OAuth2":["operation-scopes:read"]}],"description":"Get one of your operation scopes by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the operation scope."},"description":"The id of the operation scope."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid"},"scope_type":{"type":"string"},"entity_type":{"type":"string"},"included":{"type":"boolean"},"field_exclusions":{"type":"array","items":{"type":"string"}},"filter_conditions":{"type":"object","additionalProperties":true},"date_range_from":{"type":"string","nullable":true},"date_range_to":{"type":"string","nullable":true},"schedule_type":{"type":"string","nullable":true},"schedule_cron":{"type":"string","nullable":true},"schedule_timezone":{"type":"string"},"maintenance_window":{"type":"object","additionalProperties":true,"nullable":true},"max_duration_minutes":{"type":"integer","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","connection_id","scope_type","entity_type"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","scope_type":"string","entity_type":"string","included":true,"field_exclusions":["string"],"filter_conditions":{},"date_range_from":"string","date_range_to":"string","schedule_type":"string","schedule_cron":"string","schedule_timezone":"string","maintenance_window":{},"max_duration_minutes":0,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"OperationScopesUpdate","tags":["core"],"summary":"Operation Scopes Update","security":[{"ApiKeyAuth":["operation-scopes:write"]},{"BearerAuth":[]},{"OAuth2":["operation-scopes:write"]}],"description":"Change an operation scope. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the operation scope."},"description":"The id of the operation scope."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connection_id":{"type":"string","format":"uuid"},"scope_type":{"type":"string"},"entity_type":{"type":"string"},"included":{"type":"boolean"},"field_exclusions":{"type":"array","items":{"type":"string"}},"filter_conditions":{"type":"object","additionalProperties":true},"date_range_from":{"type":"string","nullable":true},"date_range_to":{"type":"string","nullable":true},"schedule_type":{"type":"string","nullable":true},"schedule_cron":{"type":"string","nullable":true},"schedule_timezone":{"type":"string"},"maintenance_window":{"type":"object","additionalProperties":true,"nullable":true},"max_duration_minutes":{"type":"integer","nullable":true}}},"example":{"connection_id":"00000000-0000-0000-0000-000000000000","scope_type":"string","entity_type":"string","included":true,"field_exclusions":["string"],"filter_conditions":{},"date_range_from":"string","date_range_to":"string","schedule_type":"string","schedule_cron":"string","schedule_timezone":"string","maintenance_window":{},"max_duration_minutes":0}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid"},"scope_type":{"type":"string"},"entity_type":{"type":"string"},"included":{"type":"boolean"},"field_exclusions":{"type":"array","items":{"type":"string"}},"filter_conditions":{"type":"object","additionalProperties":true},"date_range_from":{"type":"string","nullable":true},"date_range_to":{"type":"string","nullable":true},"schedule_type":{"type":"string","nullable":true},"schedule_cron":{"type":"string","nullable":true},"schedule_timezone":{"type":"string"},"maintenance_window":{"type":"object","additionalProperties":true,"nullable":true},"max_duration_minutes":{"type":"integer","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","connection_id","scope_type","entity_type"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","scope_type":"string","entity_type":"string","included":true,"field_exclusions":["string"],"filter_conditions":{},"date_range_from":"string","date_range_to":"string","schedule_type":"string","schedule_cron":"string","schedule_timezone":"string","maintenance_window":{},"max_duration_minutes":0,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/parallel-run-discrepancies":{"get":{"operationId":"ParallelRunDiscrepanciesList","tags":["data_protection"],"summary":"Parallel Run Discrepancies List","security":[{"ApiKeyAuth":["parallel-run-discrepancies:read"]},{"BearerAuth":[]},{"OAuth2":["parallel-run-discrepancies:read"]}],"description":"List your parallel run discrepancies, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"restoration_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only parallel run discrepancies for this restoration. Pass its id."},"description":"Only parallel run discrepancies for this restoration. Pass its id."},{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"record_id","in":"query","required":false,"schema":{"type":"string","description":"Only parallel run discrepancies whose record is exactly this."},"description":"Only parallel run discrepancies whose record is exactly this."},{"name":"record_id_contains","in":"query","required":false,"schema":{"type":"string","description":"Only parallel run discrepancies whose record contains this text (upper and lower case are treated the same)."},"description":"Only parallel run discrepancies whose record contains this text (upper and lower case are treated the same)."},{"name":"field_name","in":"query","required":false,"schema":{"type":"string","description":"Only parallel run discrepancies whose field name is exactly this."},"description":"Only parallel run discrepancies whose field name is exactly this."},{"name":"field_name_contains","in":"query","required":false,"schema":{"type":"string","description":"Only parallel run discrepancies whose field name contains this text (upper and lower case are treated the same)."},"description":"Only parallel run discrepancies whose field name contains this text (upper and lower case are treated the same)."},{"name":"source_provider","in":"query","required":false,"schema":{"type":"string","description":"Only parallel run discrepancies whose source provider is exactly this."},"description":"Only parallel run discrepancies whose source provider is exactly this."},{"name":"source_provider_contains","in":"query","required":false,"schema":{"type":"string","description":"Only parallel run discrepancies whose source provider contains this text (upper and lower case are treated the same)."},"description":"Only parallel run discrepancies whose source provider contains this text (upper and lower case are treated the same)."},{"name":"detected_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only parallel run discrepancies whose detected time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only parallel run discrepancies whose detected time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"detected_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only parallel run discrepancies whose detected time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only parallel run discrepancies whose detected time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many parallel run discrepancies to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many parallel run discrepancies to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many parallel run discrepancies to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many parallel run discrepancies to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","restoration_id","customer_id","record_id","field_name","source_provider","detected_at"],"description":"The field to sort the list by.","default":"detected_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns parallel run discrepancies where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns parallel run discrepancies where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"restoration_id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"record_id":{"type":"string"},"field_name":{"type":"string"},"restored_value":{"type":"object","additionalProperties":true,"nullable":true,"description":"The field value the restoration would write, from the point-in-time snapshot."},"current_value":{"type":"object","additionalProperties":true,"nullable":true,"description":"The field value currently live, compared against the restored value."},"source_provider":{"type":"string"},"detected_at":{"type":"string"}},"required":["restoration_id","customer_id","record_id","field_name","source_provider"]},"example":{"id":"00000000-0000-0000-0000-000000000000","restoration_id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","record_id":"string","field_name":"string","restored_value":{},"current_value":{},"source_provider":"string","detected_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/parallel-run-discrepancies/{id}":{"get":{"operationId":"ParallelRunDiscrepanciesGet","tags":["data_protection"],"summary":"Parallel Run Discrepancies Get","security":[{"ApiKeyAuth":["parallel-run-discrepancies:read"]},{"BearerAuth":[]},{"OAuth2":["parallel-run-discrepancies:read"]}],"description":"Get one of your parallel run discrepancies by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the parallel run discrepancy."},"description":"The id of the parallel run discrepancy."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"restoration_id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"record_id":{"type":"string"},"field_name":{"type":"string"},"restored_value":{"type":"object","additionalProperties":true,"nullable":true,"description":"The field value the restoration would write, from the point-in-time snapshot."},"current_value":{"type":"object","additionalProperties":true,"nullable":true,"description":"The field value currently live, compared against the restored value."},"source_provider":{"type":"string"},"detected_at":{"type":"string"}},"required":["restoration_id","customer_id","record_id","field_name","source_provider"]},"example":{"id":"00000000-0000-0000-0000-000000000000","restoration_id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","record_id":"string","field_name":"string","restored_value":{},"current_value":{},"source_provider":"string","detected_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipeline-events":{"get":{"operationId":"PipelineEventsList","tags":["monitoring"],"summary":"Pipeline Events List","security":[{"ApiKeyAuth":["pipeline-events:read"]},{"BearerAuth":[]},{"OAuth2":["pipeline-events:read"]}],"description":"List your pipeline events, newest first. Filter by any field, or search their text with q. Results come a page at a time: pass the nextCursor from one page to get the next.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"connection_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only pipeline events for this connection. Pass its id."},"description":"Only pipeline events for this connection. Pass its id."},{"name":"pipeline_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only pipeline events for this pipeline. Pass its id."},"description":"Only pipeline events for this pipeline. Pass its id."},{"name":"event_type","in":"query","required":false,"schema":{"type":"string","description":"Only pipeline events whose event type is exactly this."},"description":"Only pipeline events whose event type is exactly this."},{"name":"event_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only pipeline events whose event type contains this text (upper and lower case are treated the same)."},"description":"Only pipeline events whose event type contains this text (upper and lower case are treated the same)."},{"name":"severity","in":"query","required":false,"schema":{"type":"string","description":"Only pipeline events whose severity is exactly this."},"description":"Only pipeline events whose severity is exactly this."},{"name":"severity_contains","in":"query","required":false,"schema":{"type":"string","description":"Only pipeline events whose severity contains this text (upper and lower case are treated the same)."},"description":"Only pipeline events whose severity contains this text (upper and lower case are treated the same)."},{"name":"title","in":"query","required":false,"schema":{"type":"string","description":"Only pipeline events whose title is exactly this."},"description":"Only pipeline events whose title is exactly this."},{"name":"title_contains","in":"query","required":false,"schema":{"type":"string","description":"Only pipeline events whose title contains this text (upper and lower case are treated the same)."},"description":"Only pipeline events whose title contains this text (upper and lower case are treated the same)."},{"name":"source_service","in":"query","required":false,"schema":{"type":"string","description":"Only pipeline events whose source service is exactly this."},"description":"Only pipeline events whose source service is exactly this."},{"name":"source_service_contains","in":"query","required":false,"schema":{"type":"string","description":"Only pipeline events whose source service contains this text (upper and lower case are treated the same)."},"description":"Only pipeline events whose source service contains this text (upper and lower case are treated the same)."},{"name":"observed_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only pipeline events whose observed time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only pipeline events whose observed time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"observed_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only pipeline events whose observed time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only pipeline events whose observed time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many pipeline events to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many pipeline events to return in one page: 1 to 200, 50 if you leave it out."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","description":"Where the next page starts. Leave it out for the first page, then pass the nextCursor value from the previous response."},"description":"Where the next page starts. Leave it out for the first page, then pass the nextCursor value from the previous response."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns pipeline events where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns pipeline events where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid","nullable":true},"pipeline_id":{"type":"string","format":"uuid","nullable":true},"event_type":{"type":"string"},"severity":{"type":"string"},"title":{"type":"string"},"detail":{"type":"object","additionalProperties":true},"source_service":{"type":"string"},"observed_at":{"type":"string"}},"required":["customer_id","event_type","title","source_service"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","pipeline_id":"00000000-0000-0000-0000-000000000000","event_type":"string","severity":"string","title":"string","detail":{},"source_service":"string","observed_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipeline-events/{id}":{"get":{"operationId":"PipelineEventsGet","tags":["monitoring"],"summary":"Pipeline Events Get","security":[{"ApiKeyAuth":["pipeline-events:read"]},{"BearerAuth":[]},{"OAuth2":["pipeline-events:read"]}],"description":"Get one of your pipeline events by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline event."},"description":"The id of the pipeline event."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid","nullable":true},"pipeline_id":{"type":"string","format":"uuid","nullable":true},"event_type":{"type":"string"},"severity":{"type":"string"},"title":{"type":"string"},"detail":{"type":"object","additionalProperties":true},"source_service":{"type":"string"},"observed_at":{"type":"string"}},"required":["customer_id","event_type","title","source_service"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","pipeline_id":"00000000-0000-0000-0000-000000000000","event_type":"string","severity":"string","title":"string","detail":{},"source_service":"string","observed_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipeline-promotions":{"get":{"operationId":"ListPipelinePromotions","tags":["pipelines"],"summary":"List Pipeline Promotions","security":[{"ApiKeyAuth":["pipeline-promotions:read"]},{"BearerAuth":[]},{"OAuth2":["pipeline-promotions:read"]}],"description":"Your pipeline promotions, including those waiting for approval: what each one would change, whether it was approved automatically or by people, who decided, the approvals it needs and has, and which pipeline in the target environment it updated.","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending_approval","applied","rejected","failed"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"promotions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","description":"Known values: pending_approval, applied, rejected, failed."},"risk_level":{"type":"string","description":"Known values: low, medium, high."},"change_count":{"type":"integer","description":"How many changes the promotion carries."},"policy_decision":{"type":"string","nullable":true,"description":"Why the approval policy auto-approved or held it."},"decision_reason":{"type":"string","nullable":true,"description":"The reason the approver gave, or why applying failed."},"requested_by":{"type":"string","nullable":true},"decided_by":{"type":"string","nullable":true,"description":"Who decided: the FINAL approver when several were required, or policy:auto-approve."},"created_at":{"type":"string","format":"date-time"},"decided_at":{"type":"string","format":"date-time","nullable":true},"applied_at":{"type":"string","format":"date-time","nullable":true},"evidence":{"type":"object","properties":{"facts":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"items":{"type":"array","items":{"type":"string"}}},"required":["label","items"]},"description":"Added, Removed, Changed and Routing / sync config, each with up to 25 field paths. Only groups with entries appear."}},"description":"A short summary of what would change. The full list of changes is not in this response."},"source_pipeline_id":{"type":"string","format":"uuid"},"target_pipeline_id":{"type":"string","format":"uuid","nullable":true,"description":"The counterpart in the target environment, once applied."},"pipeline_name":{"type":"string","description":"Name of the pipeline being promoted."},"from_environment":{"type":"string","nullable":true,"description":"Name of the environment it came from."},"to_environment":{"type":"string","nullable":true,"description":"Name of the environment it goes to."},"approvals":{"type":"object","properties":{"required":{"type":"array","items":{"type":"string"},"description":"The roles or teams that must each approve, one person per entry (an entry listed twice needs two people). Empty when no approval policy names approvers."},"received":{"type":"array","items":{"type":"object","properties":{"approver":{"type":"string","format":"uuid","nullable":true,"description":"The approving workspace member (workspace_users.id). Null when an API key or OAuth client approved a change that named no approvers."},"role":{"type":"string","nullable":true,"description":"The required entry this approval filled. Null when the change named no approvers."},"decidedAt":{"type":"string","format":"date-time"}},"required":["approver","role","decidedAt"]},"description":"The approvals recorded so far, oldest first."},"satisfied":{"type":"boolean","description":"True once the change has been approved (by people or automatically by a policy), or every required entry is filled."}},"required":["required","received","satisfied"],"description":"Who must approve this change and who has. Each `required` entry names a workspace role or a workspace team. A person fills an entry when it is their role, a role below theirs (owner fills admin), or a team they belong to. The change applies when every entry is filled by a different person, and the person who requested it cannot fill one. An empty `required` means one approval from anyone allowed to approve applies it."}},"required":["id","status","risk_level","change_count","policy_decision","decision_reason","requested_by","decided_by","created_at","decided_at","applied_at","evidence","source_pipeline_id","target_pipeline_id","pipeline_name","from_environment","to_environment","approvals"]}}},"required":["promotions"]},"example":{"promotions":[{"id":"00000000-0000-0000-0000-000000000000","status":"string","risk_level":"string","change_count":0,"policy_decision":"string","decision_reason":"string","requested_by":"string","decided_by":"string","created_at":"2026-01-01T00:00:00Z","decided_at":"2026-01-01T00:00:00Z","applied_at":"2026-01-01T00:00:00Z","evidence":{"facts":[{"label":"string","items":["string"]}]},"source_pipeline_id":"00000000-0000-0000-0000-000000000000","target_pipeline_id":"00000000-0000-0000-0000-000000000000","pipeline_name":"string","from_environment":"string","to_environment":"string","approvals":{"required":["string"],"received":[{"approver":"00000000-0000-0000-0000-000000000000","role":"string","decidedAt":"2026-01-01T00:00:00Z"}],"satisfied":true}}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipeline-promotions/{promotionId}/approve":{"post":{"operationId":"ApprovePipelinePromotion","tags":["pipelines"],"summary":"Approve Pipeline Promotion","security":[{"ApiKeyAuth":["pipeline-promotions:write"]},{"BearerAuth":[]},{"OAuth2":["pipeline-promotions:write"]}],"description":"Approve a promotion that is waiting for approval. Each person’s approval is recorded. If its approval policy names approvers, the promotion keeps waiting until each one is filled by a different member (by role, a higher role, or team), never by the person who requested it, and the approval that completes it applies it; otherwise your approval applies it. Inferrex applies the pipeline as it is now, not as it was when the promotion was requested, and checks again that every connection is set up in the target environment. The record keeps the changes you were shown when you approved. Refused (403) when your role and teams fill none of the approvals still needed, or you requested the promotion, and (409) when you have already approved it.","parameters":[{"name":"promotionId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the promotion."},"description":"The id of the promotion."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maximum":2000,"description":"An optional note on why you approved it."}}},"example":{"reason":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","description":"`applied` when this approval applied it; `pending_approval` when it still needs other approvers."},"targetPipelineId":{"type":"string","format":"uuid","nullable":true},"approvals":{"type":"object","properties":{"required":{"type":"array","items":{"type":"string"},"description":"The roles or teams that must each approve, one person per entry (an entry listed twice needs two people). Empty when no approval policy names approvers."},"received":{"type":"array","items":{"type":"object","properties":{"approver":{"type":"string","format":"uuid","nullable":true,"description":"The approving workspace member (workspace_users.id). Null when an API key or OAuth client approved a change that named no approvers."},"role":{"type":"string","nullable":true,"description":"The required entry this approval filled. Null when the change named no approvers."},"decidedAt":{"type":"string","format":"date-time"}},"required":["approver","role","decidedAt"]},"description":"The approvals recorded so far, oldest first."},"satisfied":{"type":"boolean","description":"True once the change has been approved (by people or automatically by a policy), or every required entry is filled."}},"required":["required","received","satisfied"],"description":"Who must approve this change and who has. Each `required` entry names a workspace role or a workspace team. A person fills an entry when it is their role, a role below theirs (owner fills admin), or a team they belong to. The change applies when every entry is filled by a different person, and the person who requested it cannot fill one. An empty `required` means one approval from anyone allowed to approve applies it."}},"required":["id","status","approvals"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string","targetPipelineId":"00000000-0000-0000-0000-000000000000","approvals":{"required":["string"],"received":[{"approver":"00000000-0000-0000-0000-000000000000","role":"string","decidedAt":"2026-01-01T00:00:00Z"}],"satisfied":true}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipeline-promotions/{promotionId}/reject":{"post":{"operationId":"RejectPipelinePromotion","tags":["pipelines"],"summary":"Reject Pipeline Promotion","security":[{"ApiKeyAuth":["pipeline-promotions:write"]},{"BearerAuth":[]},{"OAuth2":["pipeline-promotions:write"]}],"description":"Reject a promotion that is waiting for approval. A reason is required. Nothing is changed in the target environment, and the reason is kept so others can see why the change did not go ahead. One rejection is enough, whatever approvals the promotion already has.","parameters":[{"name":"promotionId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the promotion."},"description":"The id of the promotion."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maximum":2000,"description":"Why you are rejecting it. Kept with the promotion so others can see."}},"required":["reason"]},"example":{"reason":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"}},"required":["id","status"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipeline-promotions/approval-ladder":{"get":{"operationId":"GetPromotionApprovalLadder","tags":["pipelines"],"summary":"Get Promotion Approval Ladder","security":[{"ApiKeyAuth":["pipeline-promotions:read"]},{"BearerAuth":[]},{"OAuth2":["pipeline-promotions:read"]}],"description":"The default approval ladder for pipeline promotions. While your workspace has no switched-on approval policy for pipeline promotions, a promotion is decided by the class of the environment it goes to: Development and QA are approved automatically, UAT and Staging automatically when the change is low risk and otherwise by one approver, and Production never automatically, by two approvers. Approvers are other members of your workspace who can edit pipelines, never the person who asked for the promotion, and never more than your workspace has. Evidence such as a CI check or a change ticket is listed but not checked yet, so it does not hold a promotion. A policy of your own replaces the ladder.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"inEffect":{"type":"boolean","description":"True while no switched-on pipeline-promotion policy exists, so the ladder decides promotions. A step between environments with its own policy still uses that policy."},"workspacePolicies":{"type":"array","items":{"type":"string"},"description":"Names of the switched-on pipeline-promotion policies that replace the ladder. Empty while it is in effect."},"rungs":{"type":"array","items":{"type":"object","properties":{"environmentClass":{"type":"string","description":"The class of the environment promoted into. Known values: dev, qa, uat, staging, production."},"autoApproveUpTo":{"type":"string","nullable":true,"description":"The highest risk approved without a person; null when never automatic. Known values: low, medium, high."},"requiredApprovers":{"type":"array","items":{"type":"string"},"description":"One distinct approver per entry, each a workspace role (that role or above) — fewer when the workspace has fewer members who can approve."},"evidence":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"Known values: ci_check, change_ticket."},"checked":{"type":"boolean","description":"False while Inferrex cannot collect this evidence; an unchecked item never holds a promotion."},"note":{"type":"string"}},"required":["kind","checked","note"]},"description":"Evidence the ladder asks for, and whether it is checked yet."}},"required":["environmentClass","autoApproveUpTo","requiredApprovers","evidence"]},"description":"One entry per environment class, lowest first."}},"required":["inEffect","workspacePolicies","rungs"]},"example":{"inEffect":true,"workspacePolicies":["string"],"rungs":[{"environmentClass":"string","autoApproveUpTo":"string","requiredApprovers":["string"],"evidence":[{"kind":"string","checked":true,"note":"string"}]}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipeline-targets":{"get":{"operationId":"PipelineTargetsList","tags":["core"],"summary":"Pipeline Targets List","security":[{"ApiKeyAuth":["pipeline-targets:read"]},{"BearerAuth":[]},{"OAuth2":["pipeline-targets:read"]}],"description":"List your pipeline targets, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"pipeline_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only pipeline targets for this pipeline. Pass its id."},"description":"Only pipeline targets for this pipeline. Pass its id."},{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"target_connection_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only pipeline targets for this target connection. Pass its id."},"description":"Only pipeline targets for this target connection. Pass its id."},{"name":"program_key","in":"query","required":false,"schema":{"type":"string","description":"Only pipeline targets whose program key is exactly this."},"description":"Only pipeline targets whose program key is exactly this."},{"name":"program_key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only pipeline targets whose program key contains this text (upper and lower case are treated the same)."},"description":"Only pipeline targets whose program key contains this text (upper and lower case are treated the same)."},{"name":"destination_kind","in":"query","required":false,"schema":{"type":"string","description":"Only pipeline targets whose destination kind is exactly this."},"description":"Only pipeline targets whose destination kind is exactly this."},{"name":"destination_kind_contains","in":"query","required":false,"schema":{"type":"string","description":"Only pipeline targets whose destination kind contains this text (upper and lower case are treated the same)."},"description":"Only pipeline targets whose destination kind contains this text (upper and lower case are treated the same)."},{"name":"mapping_manifest_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only pipeline targets for this mapping manifest. Pass its id."},"description":"Only pipeline targets for this mapping manifest. Pass its id."},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Only pipeline targets whose status is exactly this."},"description":"Only pipeline targets whose status is exactly this."},{"name":"status_contains","in":"query","required":false,"schema":{"type":"string","description":"Only pipeline targets whose status contains this text (upper and lower case are treated the same)."},"description":"Only pipeline targets whose status contains this text (upper and lower case are treated the same)."},{"name":"last_sync_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only pipeline targets whose last sync time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only pipeline targets whose last sync time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"last_sync_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only pipeline targets whose last sync time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only pipeline targets whose last sync time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"last_attempt_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only pipeline targets whose last attempt time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only pipeline targets whose last attempt time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"last_attempt_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only pipeline targets whose last attempt time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only pipeline targets whose last attempt time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"last_sync_status","in":"query","required":false,"schema":{"type":"string","description":"Only pipeline targets whose last sync status is exactly this."},"description":"Only pipeline targets whose last sync status is exactly this."},{"name":"last_sync_status_contains","in":"query","required":false,"schema":{"type":"string","description":"Only pipeline targets whose last sync status contains this text (upper and lower case are treated the same)."},"description":"Only pipeline targets whose last sync status contains this text (upper and lower case are treated the same)."},{"name":"last_sync_error","in":"query","required":false,"schema":{"type":"string","description":"Only pipeline targets whose last sync error is exactly this."},"description":"Only pipeline targets whose last sync error is exactly this."},{"name":"last_sync_error_contains","in":"query","required":false,"schema":{"type":"string","description":"Only pipeline targets whose last sync error contains this text (upper and lower case are treated the same)."},"description":"Only pipeline targets whose last sync error contains this text (upper and lower case are treated the same)."},{"name":"last_sync_records_written_gte","in":"query","required":false,"schema":{"type":"number","description":"Only pipeline targets whose last sync records written is this number or more."},"description":"Only pipeline targets whose last sync records written is this number or more."},{"name":"last_sync_records_written_lte","in":"query","required":false,"schema":{"type":"number","description":"Only pipeline targets whose last sync records written is this number or less."},"description":"Only pipeline targets whose last sync records written is this number or less."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many pipeline targets to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many pipeline targets to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many pipeline targets to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many pipeline targets to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","pipeline_id","customer_id","target_connection_id","program_key","destination_kind","mapping_manifest_id","status","last_sync_at","last_attempt_at","last_sync_status","last_sync_error","last_sync_records_written","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns pipeline targets where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns pipeline targets where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipeline_id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"target_connection_id":{"type":"string","format":"uuid","nullable":true},"program_key":{"type":"string","nullable":true,"description":"For a program destination: the key of the gamification program this flow scores."},"destination_kind":{"type":"string","description":"connection: a system the flow writes to. program: a gamification program its records score. golden: the golden record."},"mapping_manifest_id":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","description":"Delivery state. New targets start draft; only explicit activate and pause actions change it."},"last_sync_at":{"type":"string","nullable":true,"description":"When at least one record was successfully delivered to this target."},"last_attempt_at":{"type":"string","nullable":true,"description":"When the worker last attempted this target."},"last_sync_status":{"type":"string","nullable":true,"description":"Outcome of this target’s last attempt; does not pause delivery."},"last_sync_error":{"type":"string","nullable":true,"description":"A bounded explanation of the last failed/partial target attempt."},"last_sync_records_written":{"type":"integer","description":"Records delivered on the last target attempt."},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["pipeline_id","customer_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","pipeline_id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","target_connection_id":"00000000-0000-0000-0000-000000000000","program_key":"string","destination_kind":"string","mapping_manifest_id":"00000000-0000-0000-0000-000000000000","status":"string","last_sync_at":"string","last_attempt_at":"string","last_sync_status":"string","last_sync_error":"string","last_sync_records_written":0,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"PipelineTargetsCreate","tags":["pipelines"],"summary":"Pipeline Targets Create","security":[{"ApiKeyAuth":["pipeline-targets:write"]},{"BearerAuth":[]},{"OAuth2":["pipeline-targets:write"]}],"description":"Add an additional destination. It starts as a draft and receives nothing until its own mapping is set and the destination is explicitly activated.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pipeline_id":{"type":"string","format":"uuid"},"target_connection_id":{"type":"string","format":"uuid"},"mapping_manifest_id":{"type":"string","format":"uuid","nullable":true,"description":"A mapping from this pipeline’s source to the additional target."}},"required":["pipeline_id","target_connection_id"]},"example":{"pipeline_id":"00000000-0000-0000-0000-000000000000","target_connection_id":"00000000-0000-0000-0000-000000000000","mapping_manifest_id":"00000000-0000-0000-0000-000000000000"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipeline_id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"target_connection_id":{"type":"string","format":"uuid"},"mapping_manifest_id":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","description":"Always draft on creation."},"last_sync_at":{"type":"string","format":"date-time","nullable":true},"last_attempt_at":{"type":"string","format":"date-time","nullable":true},"last_sync_status":{"type":"string","enum":["succeeded","partial","failed"],"nullable":true},"last_sync_error":{"type":"string","nullable":true},"last_sync_records_written":{"type":"integer"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","pipeline_id","customer_id","target_connection_id","mapping_manifest_id","status","last_sync_at","last_attempt_at","last_sync_status","last_sync_error","last_sync_records_written","created_at","updated_at"]},"example":{"id":"00000000-0000-0000-0000-000000000000","pipeline_id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","target_connection_id":"00000000-0000-0000-0000-000000000000","mapping_manifest_id":"00000000-0000-0000-0000-000000000000","status":"string","last_sync_at":"2026-01-01T00:00:00Z","last_attempt_at":"2026-01-01T00:00:00Z","last_sync_status":"succeeded","last_sync_error":"string","last_sync_records_written":0,"created_at":"2026-01-01T00:00:00Z","updated_at":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipeline-targets/{id}":{"get":{"operationId":"PipelineTargetsGet","tags":["core"],"summary":"Pipeline Targets Get","security":[{"ApiKeyAuth":["pipeline-targets:read"]},{"BearerAuth":[]},{"OAuth2":["pipeline-targets:read"]}],"description":"Get one of your pipeline targets by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline target."},"description":"The id of the pipeline target."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipeline_id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"target_connection_id":{"type":"string","format":"uuid","nullable":true},"program_key":{"type":"string","nullable":true,"description":"For a program destination: the key of the gamification program this flow scores."},"destination_kind":{"type":"string","description":"connection: a system the flow writes to. program: a gamification program its records score. golden: the golden record."},"mapping_manifest_id":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","description":"Delivery state. New targets start draft; only explicit activate and pause actions change it."},"last_sync_at":{"type":"string","nullable":true,"description":"When at least one record was successfully delivered to this target."},"last_attempt_at":{"type":"string","nullable":true,"description":"When the worker last attempted this target."},"last_sync_status":{"type":"string","nullable":true,"description":"Outcome of this target’s last attempt; does not pause delivery."},"last_sync_error":{"type":"string","nullable":true,"description":"A bounded explanation of the last failed/partial target attempt."},"last_sync_records_written":{"type":"integer","description":"Records delivered on the last target attempt."},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["pipeline_id","customer_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","pipeline_id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","target_connection_id":"00000000-0000-0000-0000-000000000000","program_key":"string","destination_kind":"string","mapping_manifest_id":"00000000-0000-0000-0000-000000000000","status":"string","last_sync_at":"string","last_attempt_at":"string","last_sync_status":"string","last_sync_error":"string","last_sync_records_written":0,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"PipelineTargetsUpdate","tags":["pipelines"],"summary":"Pipeline Targets Update","security":[{"ApiKeyAuth":["pipeline-targets:write"]},{"BearerAuth":[]},{"OAuth2":["pipeline-targets:write"]}],"description":"Change an additional destination’s system or mapping. Pause it first; updates never activate or resume delivery. A program destination has neither and cannot be changed: pause it, and turn another on.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"target_connection_id":{"type":"string","format":"uuid"},"mapping_manifest_id":{"type":"string","format":"uuid","nullable":true}}},"example":{"target_connection_id":"00000000-0000-0000-0000-000000000000","mapping_manifest_id":"00000000-0000-0000-0000-000000000000"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipeline_id":{"type":"string","format":"uuid"},"target_connection_id":{"type":"string","format":"uuid"},"mapping_manifest_id":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","pipeline_id","target_connection_id","mapping_manifest_id","status","updated_at"]},"example":{"id":"00000000-0000-0000-0000-000000000000","pipeline_id":"00000000-0000-0000-0000-000000000000","target_connection_id":"00000000-0000-0000-0000-000000000000","mapping_manifest_id":"00000000-0000-0000-0000-000000000000","status":"string","updated_at":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipeline-targets/{id}/activate":{"post":{"operationId":"PipelineTargetActivate","tags":["pipelines"],"summary":"Pipeline Target Activate","security":[{"ApiKeyAuth":["pipeline-targets:write"]},{"BearerAuth":[]},{"OAuth2":["pipeline-targets:write"]}],"description":"Activate one additional destination. Its source and target must belong to this workspace and its own pinned mapping must match that pair. If mapping approval is required, only an approved mapping may be activated. This does not resume the parent pipeline or another paused destination.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"},"alreadyActive":{"type":"boolean"}},"required":["id","status","alreadyActive"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string","alreadyActive":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipeline-targets/{id}/pause":{"post":{"operationId":"PipelineTargetPause","tags":["pipelines"],"summary":"Pipeline Target Pause","security":[{"ApiKeyAuth":["pipeline-targets:write"]},{"BearerAuth":[]},{"OAuth2":["pipeline-targets:write"]}],"description":"Pause one additional destination. It remains paused until explicitly activated again.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"}},"required":["id","status"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines":{"get":{"operationId":"ListPipelines","tags":["pipelines"],"summary":"List Pipelines","security":[{"ApiKeyAuth":["pipelines:read"]},{"BearerAuth":[]},{"OAuth2":["pipelines:read"]}],"description":"List your pipelines in the environment you are working in, newest first, with each one’s status, when it last synced, the system it reads from and its main destination. Archived pipelines are not included. Pass connection_id to list only the pipelines that read from, write to, or have an extra destination in that system.","parameters":[{"name":"connection_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only the pipelines that read from this system, write to it, or have it as an extra destination."},"description":"Only the pipelines that read from this system, write to it, or have it as an extra destination."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"last_sync_at":{"type":"string","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time"},"source_connection_id":{"type":"string","format":"uuid","description":"The system the pipeline reads from."},"target_connection_id":{"type":"string","format":"uuid","nullable":true,"description":"Its main destination; empty for a single-system pipeline. Extra destinations are in pipeline_targets."}},"required":["id","name","status","last_sync_at","created_at","source_connection_id","target_connection_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","name":"string","status":"string","last_sync_at":"2026-01-01T00:00:00Z","created_at":"2026-01-01T00:00:00Z","source_connection_id":"00000000-0000-0000-0000-000000000000","target_connection_id":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"CreatePipeline","tags":["pipelines"],"summary":"Create Pipeline","security":[{"ApiKeyAuth":["pipelines:write"]},{"BearerAuth":[]},{"OAuth2":["pipelines:write"]}],"description":"Create a pipeline that syncs data from one connected system to another. It starts as a draft: review its mapping, then activate it to start syncing. It belongs to the environment you are working in, and runs on its source connection's sync timing until you give it its own (PUT /v1/pipelines/:id/schedule).","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255,"description":"A name for the pipeline."},"description":{"type":"string","description":"An optional note about what the pipeline does."},"sourceConnectionId":{"type":"string","format":"uuid","description":"The connection data is read from."},"targetConnectionId":{"type":"string","format":"uuid","description":"The connection data is written to. Leave it out for a flow whose only destination is the golden record (built from what it reads) or a program that scores what it reads (OPEN-WORK R3, 2026-11-08)."},"mappingManifestId":{"type":"string","format":"uuid","description":"The mapping that says which fields feed which. Optional when you create the pipeline."}},"required":["name","sourceConnectionId"]},"example":{"name":"string","description":"string","sourceConnectionId":"00000000-0000-0000-0000-000000000000","targetConnectionId":"00000000-0000-0000-0000-000000000000","mappingManifestId":"00000000-0000-0000-0000-000000000000"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"}},"required":["id","name","status"]},"example":{"id":"00000000-0000-0000-0000-000000000000","name":"string","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}":{"delete":{"operationId":"ArchivePipeline","tags":["pipelines"],"summary":"Archive Pipeline","security":[{"ApiKeyAuth":["pipelines:delete"]},{"BearerAuth":[]},{"OAuth2":["pipelines:delete"]}],"description":"Archive a pipeline. It stops syncing and drops out of your pipeline list, and its connections can then be archived too. Its sync history is kept. Archiving an already archived pipeline does nothing.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"status":{"type":"string","description":"archived"},"previousStatus":{"type":"string"}},"required":["pipelineId","status","previousStatus"]},"example":{"pipelineId":"00000000-0000-0000-0000-000000000000","status":"string","previousStatus":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"GetPipeline","tags":["pipelines"],"summary":"Get Pipeline","security":[{"ApiKeyAuth":["pipelines:read"]},{"BearerAuth":[]},{"OAuth2":["pipelines:read"]}],"description":"Get one pipeline: its systems, mapping, status, direction and sync settings.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"source_connection_id":{"type":"string","format":"uuid"},"target_connection_id":{"type":"string","format":"uuid","nullable":true,"description":"Empty for a single-system pipeline. Additional targets are in pipeline_targets."},"mapping_manifest_id":{"type":"string","format":"uuid","nullable":true,"description":"The mapping version the pipeline is pinned to."},"status":{"type":"string"},"archival_enabled":{"type":"boolean"},"alert_config":{"type":"object","additionalProperties":true,"description":"Not declared: no code writes it beyond its `{}` default (promotion copies it as is), so it is `{}` today."},"created_at":{"type":"string","format":"date-time"},"activated_at":{"type":"string","format":"date-time","nullable":true},"last_sync_at":{"type":"string","format":"date-time","nullable":true},"direction":{"type":"string"},"schedule_type":{"type":"string","nullable":true},"schedule_cron":{"type":"string","nullable":true},"schedule_timezone":{"type":"string"},"updated_at":{"type":"string","format":"date-time"},"environment_id":{"type":"string","format":"uuid","nullable":true},"promoted_from_pipeline_id":{"type":"string","format":"uuid","nullable":true},"paused_reason":{"type":"string","nullable":true,"description":"Why it is paused: manual, person, auth-failure, rate-limit, schema-change, network, connection-archived or setup-plan. Empty unless paused."},"paused_connection_id":{"type":"string","format":"uuid","nullable":true},"paused_at":{"type":"string","format":"date-time","nullable":true},"trigger_source":{"type":"string","description":"system: the flow runs when its source system is read. flow: it runs on its own schedule."}},"required":["id","customer_id","name","description","source_connection_id","target_connection_id","mapping_manifest_id","status","archival_enabled","alert_config","created_at","activated_at","last_sync_at","direction","schedule_type","schedule_cron","schedule_timezone","updated_at","environment_id","promoted_from_pipeline_id","paused_reason","paused_connection_id","paused_at","trigger_source"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","name":"string","description":"string","source_connection_id":"00000000-0000-0000-0000-000000000000","target_connection_id":"00000000-0000-0000-0000-000000000000","mapping_manifest_id":"00000000-0000-0000-0000-000000000000","status":"string","archival_enabled":true,"alert_config":{},"created_at":"2026-01-01T00:00:00Z","activated_at":"2026-01-01T00:00:00Z","last_sync_at":"2026-01-01T00:00:00Z","direction":"string","schedule_type":"string","schedule_cron":"string","schedule_timezone":"string","updated_at":"2026-01-01T00:00:00Z","environment_id":"00000000-0000-0000-0000-000000000000","promoted_from_pipeline_id":"00000000-0000-0000-0000-000000000000","paused_reason":"string","paused_connection_id":"00000000-0000-0000-0000-000000000000","paused_at":"2026-01-01T00:00:00Z","trigger_source":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"operationId":"UpdatePipeline","tags":["pipelines"],"summary":"Update Pipeline","security":[{"ApiKeyAuth":["pipelines:write"]},{"BearerAuth":[]},{"OAuth2":["pipelines:write"]}],"description":"Change a pipeline’s name, description or sync direction. Anything you leave out stays as it is. Syncing in reverse or in both directions needs a pipeline between two systems with a mapping; otherwise it is refused. A new direction applies from the next sync.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":255,"description":"A new name for the pipeline."},"description":{"type":"string","description":"A new description."},"direction":{"type":"string","enum":["forward","reverse","bidirectional"],"description":"forward: from the source system to the target. reverse: from the target back to the source. bidirectional: both ways on every sync."}}},"example":{"name":"string","description":"string","direction":"forward"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"direction":{"type":"string"},"status":{"type":"string"}},"required":["pipelineId","name","direction","status"]},"example":{"pipelineId":"00000000-0000-0000-0000-000000000000","name":"string","description":"string","direction":"string","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/activate":{"post":{"operationId":"ActivatePipeline","tags":["pipelines"],"summary":"Activate Pipeline","security":[{"ApiKeyAuth":["pipelines:write"]},{"BearerAuth":[]},{"OAuth2":["pipelines:write"]}],"description":"Start a pipeline syncing. Inferrex runs a first full sync straight away and returns a job id you can use to follow its progress. If the pipeline connects two systems, its mapping must be approved first (when your workspace requires that). Works on a draft, paused or reviewing pipeline; activating one that is already active does nothing.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"status":{"type":"string","description":"queued"},"jobId":{"type":"string","format":"uuid","description":"Poll GET /v1/jobs/:id."},"initialSyncJobId":{"type":"string","description":"Deprecated alias of jobId."}},"required":["pipelineId","status","jobId","initialSyncJobId"]},"example":{"pipelineId":"00000000-0000-0000-0000-000000000000","status":"string","jobId":"00000000-0000-0000-0000-000000000000","initialSyncJobId":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/anomalies":{"get":{"operationId":"GetAnomalies","tags":["pipelines"],"summary":"Get Anomalies","security":[{"ApiKeyAuth":["pipelines:read"]},{"BearerAuth":[]},{"OAuth2":["pipelines:read"]}],"description":"Unusual data Inferrex has spotted in a pipeline’s records, such as values of the wrong type or out of the normal range, fields that are suddenly empty, or a sudden change in how often records arrive.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"anomalies":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"severity":{"type":"string"},"type":{"type":"string"},"affected_field":{"type":"string","nullable":true},"description":{"type":"string"},"detected_at":{"type":"string"}},"required":["id","severity","type","description","detected_at"]}}},"required":["pipelineId","anomalies"]},"example":{"pipelineId":"00000000-0000-0000-0000-000000000000","anomalies":[{"id":"00000000-0000-0000-0000-000000000000","severity":"string","type":"string","affected_field":"string","description":"string","detected_at":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/apply-mapping":{"post":{"operationId":"ApplyMappingToPipeline","tags":["pipelines"],"summary":"Apply Mapping To Pipeline","security":[{"ApiKeyAuth":["pipelines:write"]},{"BearerAuth":[]},{"OAuth2":["pipelines:write"]}],"description":"Make a pipeline use the newest version of its mapping. A pipeline keeps using the mapping version it was activated with, so later edits do not affect it until you apply them here. Send the version you reviewed: if the mapping has changed since, this is refused, so you can review the newer version first. Does nothing if the pipeline is already up to date. A pipeline created without a mapping is given the one you send here, if it is the latest version of a mapping between the same two systems; it keeps its status, and turning it on still needs that mapping approved.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mappingVersionId":{"type":"string","format":"uuid","description":"The mapping version you reviewed. It must still be the newest version, so you only ever apply what you have seen. For a pipeline with no mapping yet, the mapping to give it."}},"required":["mappingVersionId"]},"example":{"mappingVersionId":"00000000-0000-0000-0000-000000000000"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"previousMappingId":{"type":"string","format":"uuid","description":"Absent when the pipeline was already at the head."},"appliedMappingId":{"type":"string","format":"uuid"},"upToDate":{"type":"boolean"}},"required":["pipelineId","appliedMappingId","upToDate"]},"example":{"pipelineId":"00000000-0000-0000-0000-000000000000","previousMappingId":"00000000-0000-0000-0000-000000000000","appliedMappingId":"00000000-0000-0000-0000-000000000000","upToDate":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/changes":{"get":{"operationId":"ListFlowChanges","tags":["pipelines"],"summary":"List Flow Changes","security":[{"ApiKeyAuth":["pipelines:read"]},{"BearerAuth":[]},{"OAuth2":["pipelines:read"]}],"description":"A flow's changes made on the canvas or in Destinations: drafts and those waiting for approval first, then the 20 most recent.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The flow."},"description":"The flow."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"changes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipelineId":{"type":"string","format":"uuid"},"kind":{"type":"string","description":"add-destination or remove-destination."},"connectionId":{"type":"string","format":"uuid","description":"The destination system it adds or removes."},"mappingId":{"type":"string","format":"uuid","nullable":true},"pipelineTargetId":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","description":"draft, pending_approval, applied, rejected or discarded."},"riskLevel":{"type":"string","description":"low, medium or high."},"preview":{"type":"object","properties":{"destinationsBefore":{"type":"array","items":{"type":"string"}},"destinationsAfter":{"type":"array","items":{"type":"string"}},"flowStatus":{"type":"string"},"latestDryRun":{"type":"object","properties":{"jobId":{"type":"string","format":"uuid"},"at":{"type":"string","nullable":true},"recordsRead":{"type":"integer"},"wouldWrite":{"type":"integer"}},"required":["jobId","at","recordsRead","wouldWrite"],"nullable":true},"riskReasons":{"type":"array","items":{"type":"string"}}},"required":["destinationsBefore","destinationsAfter","flowStatus","latestDryRun","riskReasons"],"description":"What it does: destinationsBefore and destinationsAfter (connection ids), flowStatus, latestDryRun (jobId, at, recordsRead, wouldWrite, or null) and riskReasons."},"requiredApprovers":{"type":"array","items":{"type":"string"}},"outcome":{"type":"string","nullable":true,"description":"What applying it did, in words."},"createdAt":{"type":"string","format":"date-time"},"decidedAt":{"type":"string","format":"date-time","nullable":true}},"required":["id","pipelineId","kind","connectionId","mappingId","pipelineTargetId","status","riskLevel","preview","requiredApprovers","outcome","createdAt","decidedAt"]}}},"required":["pipelineId","changes"]},"example":{"pipelineId":"00000000-0000-0000-0000-000000000000","changes":[{"id":"00000000-0000-0000-0000-000000000000","pipelineId":"00000000-0000-0000-0000-000000000000","kind":"string","connectionId":"00000000-0000-0000-0000-000000000000","mappingId":"00000000-0000-0000-0000-000000000000","pipelineTargetId":"00000000-0000-0000-0000-000000000000","status":"string","riskLevel":"string","preview":{"destinationsBefore":["string"],"destinationsAfter":["string"],"flowStatus":"string","latestDryRun":{"jobId":"00000000-0000-0000-0000-000000000000","at":"string","recordsRead":0,"wouldWrite":0},"riskReasons":["string"]},"requiredApprovers":["string"],"outcome":"string","createdAt":"2026-01-01T00:00:00Z","decidedAt":"2026-01-01T00:00:00Z"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"CreateFlowChange","tags":["pipelines"],"summary":"Create Flow Change","security":[{"ApiKeyAuth":["pipelines:write"]},{"BearerAuth":[]},{"OAuth2":["pipelines:write"]}],"description":"Draft a change to a flow's destinations. kind add-destination needs connectionId, and mappingId unless the destination is added with no mapping yet (it then waits for one before it can be turned on); remove-destination needs the connectionId of a further destination (not the flow's main one). The draft is not applied: confirm it to apply it, or to send it for approval when its risk needs approval by the workspace's policy. Refused (409) when the flow already writes there, does not write there, or is archived.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The flow."},"description":"The flow."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["add-destination","remove-destination"]},"connectionId":{"type":"string","format":"uuid","description":"The destination system."},"mappingId":{"type":"string","format":"uuid","description":"add-destination: the mapping from the flow's source to that system. Leave it out to add the destination with no mapping yet."}},"required":["kind","connectionId"]},"example":{"kind":"add-destination","connectionId":"00000000-0000-0000-0000-000000000000","mappingId":"00000000-0000-0000-0000-000000000000"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipelineId":{"type":"string","format":"uuid"},"kind":{"type":"string","description":"add-destination or remove-destination."},"connectionId":{"type":"string","format":"uuid","description":"The destination system it adds or removes."},"mappingId":{"type":"string","format":"uuid","nullable":true},"pipelineTargetId":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","description":"draft, pending_approval, applied, rejected or discarded."},"riskLevel":{"type":"string","description":"low, medium or high."},"preview":{"type":"object","properties":{"destinationsBefore":{"type":"array","items":{"type":"string"}},"destinationsAfter":{"type":"array","items":{"type":"string"}},"flowStatus":{"type":"string"},"latestDryRun":{"type":"object","properties":{"jobId":{"type":"string","format":"uuid"},"at":{"type":"string","nullable":true},"recordsRead":{"type":"integer"},"wouldWrite":{"type":"integer"}},"required":["jobId","at","recordsRead","wouldWrite"],"nullable":true},"riskReasons":{"type":"array","items":{"type":"string"}}},"required":["destinationsBefore","destinationsAfter","flowStatus","latestDryRun","riskReasons"],"description":"What it does: destinationsBefore and destinationsAfter (connection ids), flowStatus, latestDryRun (jobId, at, recordsRead, wouldWrite, or null) and riskReasons."},"requiredApprovers":{"type":"array","items":{"type":"string"}},"outcome":{"type":"string","nullable":true,"description":"What applying it did, in words."},"createdAt":{"type":"string","format":"date-time"},"decidedAt":{"type":"string","format":"date-time","nullable":true}},"required":["id","pipelineId","kind","connectionId","mappingId","pipelineTargetId","status","riskLevel","preview","requiredApprovers","outcome","createdAt","decidedAt"]},"example":{"id":"00000000-0000-0000-0000-000000000000","pipelineId":"00000000-0000-0000-0000-000000000000","kind":"string","connectionId":"00000000-0000-0000-0000-000000000000","mappingId":"00000000-0000-0000-0000-000000000000","pipelineTargetId":"00000000-0000-0000-0000-000000000000","status":"string","riskLevel":"string","preview":{"destinationsBefore":["string"],"destinationsAfter":["string"],"flowStatus":"string","latestDryRun":{"jobId":"00000000-0000-0000-0000-000000000000","at":"string","recordsRead":0,"wouldWrite":0},"riskReasons":["string"]},"requiredApprovers":["string"],"outcome":"string","createdAt":"2026-01-01T00:00:00Z","decidedAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/changes/{changeId}/approve":{"post":{"operationId":"ApproveFlowChange","tags":["pipelines"],"summary":"Approve Flow Change","security":[{"ApiKeyAuth":["pipelines:write"]},{"BearerAuth":[]},{"OAuth2":["pipelines:write"]}],"description":"Approve a flow change that is waiting for approval. Each person's approval is recorded; when its required approvers are all filled, each by a different member and not by whoever drafted it, it applies. Refused (403) when you drafted it or fill none of the places left.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"changeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","maximum":2000}}},"example":{"notes":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"change":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipelineId":{"type":"string","format":"uuid"},"kind":{"type":"string","description":"add-destination or remove-destination."},"connectionId":{"type":"string","format":"uuid","description":"The destination system it adds or removes."},"mappingId":{"type":"string","format":"uuid","nullable":true},"pipelineTargetId":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","description":"draft, pending_approval, applied, rejected or discarded."},"riskLevel":{"type":"string","description":"low, medium or high."},"preview":{"type":"object","properties":{"destinationsBefore":{"type":"array","items":{"type":"string"}},"destinationsAfter":{"type":"array","items":{"type":"string"}},"flowStatus":{"type":"string"},"latestDryRun":{"type":"object","properties":{"jobId":{"type":"string","format":"uuid"},"at":{"type":"string","nullable":true},"recordsRead":{"type":"integer"},"wouldWrite":{"type":"integer"}},"required":["jobId","at","recordsRead","wouldWrite"],"nullable":true},"riskReasons":{"type":"array","items":{"type":"string"}}},"required":["destinationsBefore","destinationsAfter","flowStatus","latestDryRun","riskReasons"],"description":"What it does: destinationsBefore and destinationsAfter (connection ids), flowStatus, latestDryRun (jobId, at, recordsRead, wouldWrite, or null) and riskReasons."},"requiredApprovers":{"type":"array","items":{"type":"string"}},"outcome":{"type":"string","nullable":true,"description":"What applying it did, in words."},"createdAt":{"type":"string","format":"date-time"},"decidedAt":{"type":"string","format":"date-time","nullable":true}},"required":["id","pipelineId","kind","connectionId","mappingId","pipelineTargetId","status","riskLevel","preview","requiredApprovers","outcome","createdAt","decidedAt"]},"applied":{"type":"boolean"},"approvals":{"type":"object","properties":{"required":{"type":"array","items":{"type":"string"},"description":"The roles or teams that must each approve, one person per entry (an entry listed twice needs two people). Empty when no approval policy names approvers."},"received":{"type":"array","items":{"type":"object","properties":{"approver":{"type":"string","format":"uuid","nullable":true,"description":"The approving workspace member (workspace_users.id). Null when an API key or OAuth client approved a change that named no approvers."},"role":{"type":"string","nullable":true,"description":"The required entry this approval filled. Null when the change named no approvers."},"decidedAt":{"type":"string","format":"date-time"}},"required":["approver","role","decidedAt"]},"description":"The approvals recorded so far, oldest first."},"satisfied":{"type":"boolean","description":"True once the change has been approved (by people or automatically by a policy), or every required entry is filled."}},"required":["required","received","satisfied"],"description":"Who must approve this change and who has. Each `required` entry names a workspace role or a workspace team. A person fills an entry when it is their role, a role below theirs (owner fills admin), or a team they belong to. The change applies when every entry is filled by a different person, and the person who requested it cannot fill one. An empty `required` means one approval from anyone allowed to approve applies it."}},"required":["change","applied","approvals"]},"example":{"change":{"id":"00000000-0000-0000-0000-000000000000","pipelineId":"00000000-0000-0000-0000-000000000000","kind":"string","connectionId":"00000000-0000-0000-0000-000000000000","mappingId":"00000000-0000-0000-0000-000000000000","pipelineTargetId":"00000000-0000-0000-0000-000000000000","status":"string","riskLevel":"string","preview":{"destinationsBefore":["string"],"destinationsAfter":["string"],"flowStatus":"string","latestDryRun":{"jobId":"00000000-0000-0000-0000-000000000000","at":"string","recordsRead":0,"wouldWrite":0},"riskReasons":["string"]},"requiredApprovers":["string"],"outcome":"string","createdAt":"2026-01-01T00:00:00Z","decidedAt":"2026-01-01T00:00:00Z"},"applied":true,"approvals":{"required":["string"],"received":[{"approver":"00000000-0000-0000-0000-000000000000","role":"string","decidedAt":"2026-01-01T00:00:00Z"}],"satisfied":true}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/changes/{changeId}/confirm":{"post":{"operationId":"ConfirmFlowChange","tags":["pipelines"],"summary":"Confirm Flow Change","security":[{"ApiKeyAuth":["pipelines:write"]},{"BearerAuth":[]},{"OAuth2":["pipelines:write"]}],"description":"Confirm a draft. With no approval policy for flow changes, or one whose limit its risk is within, the change applies now (a destination added is turned on when the flow is live and its mapping allows). Otherwise it waits for approval. applied says which.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"changeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"change":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipelineId":{"type":"string","format":"uuid"},"kind":{"type":"string","description":"add-destination or remove-destination."},"connectionId":{"type":"string","format":"uuid","description":"The destination system it adds or removes."},"mappingId":{"type":"string","format":"uuid","nullable":true},"pipelineTargetId":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","description":"draft, pending_approval, applied, rejected or discarded."},"riskLevel":{"type":"string","description":"low, medium or high."},"preview":{"type":"object","properties":{"destinationsBefore":{"type":"array","items":{"type":"string"}},"destinationsAfter":{"type":"array","items":{"type":"string"}},"flowStatus":{"type":"string"},"latestDryRun":{"type":"object","properties":{"jobId":{"type":"string","format":"uuid"},"at":{"type":"string","nullable":true},"recordsRead":{"type":"integer"},"wouldWrite":{"type":"integer"}},"required":["jobId","at","recordsRead","wouldWrite"],"nullable":true},"riskReasons":{"type":"array","items":{"type":"string"}}},"required":["destinationsBefore","destinationsAfter","flowStatus","latestDryRun","riskReasons"],"description":"What it does: destinationsBefore and destinationsAfter (connection ids), flowStatus, latestDryRun (jobId, at, recordsRead, wouldWrite, or null) and riskReasons."},"requiredApprovers":{"type":"array","items":{"type":"string"}},"outcome":{"type":"string","nullable":true,"description":"What applying it did, in words."},"createdAt":{"type":"string","format":"date-time"},"decidedAt":{"type":"string","format":"date-time","nullable":true}},"required":["id","pipelineId","kind","connectionId","mappingId","pipelineTargetId","status","riskLevel","preview","requiredApprovers","outcome","createdAt","decidedAt"]},"applied":{"type":"boolean"},"reason":{"type":"string"}},"required":["change","applied","reason"]},"example":{"change":{"id":"00000000-0000-0000-0000-000000000000","pipelineId":"00000000-0000-0000-0000-000000000000","kind":"string","connectionId":"00000000-0000-0000-0000-000000000000","mappingId":"00000000-0000-0000-0000-000000000000","pipelineTargetId":"00000000-0000-0000-0000-000000000000","status":"string","riskLevel":"string","preview":{"destinationsBefore":["string"],"destinationsAfter":["string"],"flowStatus":"string","latestDryRun":{"jobId":"00000000-0000-0000-0000-000000000000","at":"string","recordsRead":0,"wouldWrite":0},"riskReasons":["string"]},"requiredApprovers":["string"],"outcome":"string","createdAt":"2026-01-01T00:00:00Z","decidedAt":"2026-01-01T00:00:00Z"},"applied":true,"reason":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/changes/{changeId}/discard":{"post":{"operationId":"DiscardFlowChange","tags":["pipelines"],"summary":"Discard Flow Change","security":[{"ApiKeyAuth":["pipelines:write"]},{"BearerAuth":[]},{"OAuth2":["pipelines:write"]}],"description":"Discard a draft. Only a draft can be discarded; one waiting for approval is rejected instead.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"changeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipelineId":{"type":"string","format":"uuid"},"kind":{"type":"string","description":"add-destination or remove-destination."},"connectionId":{"type":"string","format":"uuid","description":"The destination system it adds or removes."},"mappingId":{"type":"string","format":"uuid","nullable":true},"pipelineTargetId":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","description":"draft, pending_approval, applied, rejected or discarded."},"riskLevel":{"type":"string","description":"low, medium or high."},"preview":{"type":"object","properties":{"destinationsBefore":{"type":"array","items":{"type":"string"}},"destinationsAfter":{"type":"array","items":{"type":"string"}},"flowStatus":{"type":"string"},"latestDryRun":{"type":"object","properties":{"jobId":{"type":"string","format":"uuid"},"at":{"type":"string","nullable":true},"recordsRead":{"type":"integer"},"wouldWrite":{"type":"integer"}},"required":["jobId","at","recordsRead","wouldWrite"],"nullable":true},"riskReasons":{"type":"array","items":{"type":"string"}}},"required":["destinationsBefore","destinationsAfter","flowStatus","latestDryRun","riskReasons"],"description":"What it does: destinationsBefore and destinationsAfter (connection ids), flowStatus, latestDryRun (jobId, at, recordsRead, wouldWrite, or null) and riskReasons."},"requiredApprovers":{"type":"array","items":{"type":"string"}},"outcome":{"type":"string","nullable":true,"description":"What applying it did, in words."},"createdAt":{"type":"string","format":"date-time"},"decidedAt":{"type":"string","format":"date-time","nullable":true}},"required":["id","pipelineId","kind","connectionId","mappingId","pipelineTargetId","status","riskLevel","preview","requiredApprovers","outcome","createdAt","decidedAt"]},"example":{"id":"00000000-0000-0000-0000-000000000000","pipelineId":"00000000-0000-0000-0000-000000000000","kind":"string","connectionId":"00000000-0000-0000-0000-000000000000","mappingId":"00000000-0000-0000-0000-000000000000","pipelineTargetId":"00000000-0000-0000-0000-000000000000","status":"string","riskLevel":"string","preview":{"destinationsBefore":["string"],"destinationsAfter":["string"],"flowStatus":"string","latestDryRun":{"jobId":"00000000-0000-0000-0000-000000000000","at":"string","recordsRead":0,"wouldWrite":0},"riskReasons":["string"]},"requiredApprovers":["string"],"outcome":"string","createdAt":"2026-01-01T00:00:00Z","decidedAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/changes/{changeId}/reject":{"post":{"operationId":"RejectFlowChange","tags":["pipelines"],"summary":"Reject Flow Change","security":[{"ApiKeyAuth":["pipelines:write"]},{"BearerAuth":[]},{"OAuth2":["pipelines:write"]}],"description":"Reject a flow change that is waiting for approval. Nothing about the flow changes.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"changeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maximum":2000}}},"example":{"reason":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipelineId":{"type":"string","format":"uuid"},"kind":{"type":"string","description":"add-destination or remove-destination."},"connectionId":{"type":"string","format":"uuid","description":"The destination system it adds or removes."},"mappingId":{"type":"string","format":"uuid","nullable":true},"pipelineTargetId":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","description":"draft, pending_approval, applied, rejected or discarded."},"riskLevel":{"type":"string","description":"low, medium or high."},"preview":{"type":"object","properties":{"destinationsBefore":{"type":"array","items":{"type":"string"}},"destinationsAfter":{"type":"array","items":{"type":"string"}},"flowStatus":{"type":"string"},"latestDryRun":{"type":"object","properties":{"jobId":{"type":"string","format":"uuid"},"at":{"type":"string","nullable":true},"recordsRead":{"type":"integer"},"wouldWrite":{"type":"integer"}},"required":["jobId","at","recordsRead","wouldWrite"],"nullable":true},"riskReasons":{"type":"array","items":{"type":"string"}}},"required":["destinationsBefore","destinationsAfter","flowStatus","latestDryRun","riskReasons"],"description":"What it does: destinationsBefore and destinationsAfter (connection ids), flowStatus, latestDryRun (jobId, at, recordsRead, wouldWrite, or null) and riskReasons."},"requiredApprovers":{"type":"array","items":{"type":"string"}},"outcome":{"type":"string","nullable":true,"description":"What applying it did, in words."},"createdAt":{"type":"string","format":"date-time"},"decidedAt":{"type":"string","format":"date-time","nullable":true}},"required":["id","pipelineId","kind","connectionId","mappingId","pipelineTargetId","status","riskLevel","preview","requiredApprovers","outcome","createdAt","decidedAt"]},"example":{"id":"00000000-0000-0000-0000-000000000000","pipelineId":"00000000-0000-0000-0000-000000000000","kind":"string","connectionId":"00000000-0000-0000-0000-000000000000","mappingId":"00000000-0000-0000-0000-000000000000","pipelineTargetId":"00000000-0000-0000-0000-000000000000","status":"string","riskLevel":"string","preview":{"destinationsBefore":["string"],"destinationsAfter":["string"],"flowStatus":"string","latestDryRun":{"jobId":"00000000-0000-0000-0000-000000000000","at":"string","recordsRead":0,"wouldWrite":0},"riskReasons":["string"]},"requiredApprovers":["string"],"outcome":"string","createdAt":"2026-01-01T00:00:00Z","decidedAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/dry-run":{"post":{"operationId":"DryRunPipeline","tags":["pipelines"],"summary":"Dry Run Pipeline","security":[{"ApiKeyAuth":["pipelines:write"]},{"BearerAuth":[]},{"OAuth2":["pipelines:write"]}],"description":"Try a pipeline’s sync without writing anything: Inferrex works out what it would change in the target system so you can check it first. A pipeline that is not on yet (draft, paused or waiting for review) can be dry-run before you turn it on; an archived pipeline, one in error, or one with no mapping between two systems is refused. Returns a job id you can use to follow its progress and see the result.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"jobId":{"type":"string","format":"uuid","description":"Poll GET /v1/jobs/:id."},"dryRunJobId":{"type":"string","description":"Deprecated alias of jobId."},"status":{"type":"string","description":"queued"}},"required":["pipelineId","jobId","dryRunJobId","status"]},"example":{"pipelineId":"00000000-0000-0000-0000-000000000000","jobId":"00000000-0000-0000-0000-000000000000","dryRunJobId":"string","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/history":{"get":{"operationId":"GetSyncHistory","tags":["pipelines"],"summary":"Get Sync History","security":[{"ApiKeyAuth":["pipelines:read"]},{"BearerAuth":[]},{"OAuth2":["pipelines:read"]}],"description":"A pipeline’s last 50 syncs, newest first: when each ran, how long it took, and how many records were read, written, skipped or failed.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"history":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"sync_type":{"type":"string"},"status":{"type":"string"},"records_read":{"type":"integer"},"records_written":{"type":"integer"},"records_failed":{"type":"integer"},"records_skipped":{"type":"integer"},"started_at":{"type":"string"},"completed_at":{"type":"string","nullable":true},"duration_ms":{"type":"integer","nullable":true},"dry_run":{"type":"boolean","description":"A dry run: read and converted, nothing written. Its job (GET /v1/jobs/:id, same id) holds what it would have written."}},"required":["id","sync_type","status","records_read","records_written","records_failed","records_skipped","started_at","dry_run"]}}},"required":["pipelineId","history"]},"example":{"pipelineId":"00000000-0000-0000-0000-000000000000","history":[{"id":"00000000-0000-0000-0000-000000000000","sync_type":"string","status":"string","records_read":0,"records_written":0,"records_failed":0,"records_skipped":0,"started_at":"string","completed_at":"string","duration_ms":0,"dry_run":true}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/mappings":{"get":{"operationId":"ListPipelineMappings","tags":["pipelines"],"summary":"List Pipeline Mappings","security":[{"ApiKeyAuth":["pipelines:read"]},{"BearerAuth":[]},{"OAuth2":["pipelines:read"]}],"description":"The field-by-field mapping this pipeline uses: which field in one system feeds which field in the other, and how values are converted.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The pipeline's id (pipelineId), from pipeline_list."},"description":"The pipeline's id (pipelineId), from pipeline_list."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"mappingId":{"type":"string","format":"uuid","nullable":true,"description":"The mapping the pipeline runs (the version it pinned) — the id the /v1/mappings/:id routes take. Null when the pipeline has no mapping."},"mappingLabel":{"type":"string","nullable":true,"description":"That mapping's name for people (see `label` on GET /v1/mappings). Null when the pipeline has no mapping."},"mappings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The field mapping's id — not a mapping id."},"source_entity":{"type":"string"},"source_field":{"type":"string"},"target_entity":{"type":"string"},"target_field":{"type":"string"},"transform":{"type":"string"},"authority":{"type":"string"},"confidence":{"type":"number"},"approved":{"type":"boolean"}},"required":["id","source_entity","source_field","target_entity","target_field","transform","authority","confidence","approved"]},"description":"The FIELD mappings (links) inside that mapping, one row each."}},"required":["pipelineId","mappingId","mappingLabel","mappings"]},"example":{"pipelineId":"00000000-0000-0000-0000-000000000000","mappingId":"00000000-0000-0000-0000-000000000000","mappingLabel":"string","mappings":[{"id":"string","source_entity":"string","source_field":"string","target_entity":"string","target_field":"string","transform":"string","authority":"string","confidence":0,"approved":true}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/pause":{"post":{"operationId":"PausePipeline","tags":["pipelines"],"summary":"Pause Pipeline","security":[{"ApiKeyAuth":["pipelines:write"]},{"BearerAuth":[]},{"OAuth2":["pipelines:write"]}],"description":"Pause an active pipeline. Its scheduled syncs stop until you activate it again. Pausing an already paused pipeline does nothing.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"status":{"type":"string","description":"paused"}},"required":["pipelineId","status"]},"example":{"pipelineId":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/promote":{"post":{"operationId":"PromotePipeline","tags":["pipelines"],"summary":"Promote Pipeline","security":[{"ApiKeyAuth":["pipelines:write"]},{"BearerAuth":[]},{"OAuth2":["pipelines:write"]}],"description":"Copy this pipeline into another of your environments, for example from testing into production. Inferrex works out what would change in that environment and how risky the change is (changes to where data goes or how it syncs count for more than field edits), then checks your approval rules: if they allow it, the change is applied straight away; if not, it waits for someone to approve it. With no approval rule for pipeline promotions, the default approval ladder decides by the class of the target environment. Refused if any connection the pipeline uses is not set up in the target environment, because the pipeline would fail on its first sync.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"toEnvironmentId":{"type":"string","format":"uuid","description":"The environment to copy the pipeline into."}},"required":["toEnvironmentId"]},"example":{"toEnvironmentId":"00000000-0000-0000-0000-000000000000"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["applied","pending_approval"]},"riskLevel":{"type":"string","enum":["low","medium","high"]},"changeCount":{"type":"integer"},"policyDecision":{"type":"string"},"targetPipelineId":{"type":"string","format":"uuid","nullable":true},"firstPromotion":{"type":"boolean"}},"required":["id","status","riskLevel","changeCount","policyDecision","firstPromotion"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"applied","riskLevel":"low","changeCount":0,"policyDecision":"string","targetPipelineId":"00000000-0000-0000-0000-000000000000","firstPromotion":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/quarantine":{"get":{"operationId":"ListPipelineQuarantine","tags":["pipelines"],"summary":"List Pipeline Quarantine","security":[{"ApiKeyAuth":["pipelines:read"]},{"BearerAuth":[]},{"OAuth2":["pipelines:read"]}],"description":"Records this pipeline could not write to the target system, with the reason the target gave. Nothing to do here by hand: the next sync tries each one again, and it leaves this list once it is written. A record held because it has no value for a field the target requires (its reason starts `record_validation:`) is not tried again until it changes: correct it in the source system.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["open","resolved"],"description":"`open`: still to be retried; `resolved`: written on a later sync. Omit for both."},"description":"`open`: still to be retried; `resolved`: written on a later sync. Omit for both."},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":200,"description":"Search the record kind, record id and failure reason."},"description":"Search the record kind, record id and failure reason."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":100}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"quarantined":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"entity_type":{"type":"string","nullable":true},"record_id":{"type":"string","nullable":true},"failure_reason":{"type":"string","nullable":true},"retry_count":{"type":"integer"},"resolved":{"type":"boolean"},"sync_job_id":{"type":"string","format":"uuid","nullable":true},"created_at":{"type":"string"},"held":{"type":"boolean","description":"Held for a missing required field: not retried until it changes in the source or is released."},"released":{"type":"boolean","description":"A held record someone released: the next sync sends it once as it is."}},"required":["id","retry_count","resolved","created_at","held","released"]}}},"required":["pipelineId","quarantined"]},"example":{"pipelineId":"00000000-0000-0000-0000-000000000000","quarantined":[{"id":"00000000-0000-0000-0000-000000000000","entity_type":"string","record_id":"string","failure_reason":"string","retry_count":0,"resolved":true,"sync_job_id":"00000000-0000-0000-0000-000000000000","created_at":"string","held":true,"released":true}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/quarantine/{quarantineId}/release":{"post":{"operationId":"ReleaseQuarantinedRecord","tags":["pipelines"],"summary":"Release Quarantined Record","security":[{"ApiKeyAuth":["pipelines:write"]},{"BearerAuth":[]},{"OAuth2":["pipelines:write"]}],"description":"Send a held record once more, as it is now. A record held because it has no value for a field the destination requires is skipped by every sync until it changes in the source; releasing it lets the next sync send it once without that check, and the destination decides. Refused (404) when the record is not on this pipeline in your workspace, and (409) when it is not held — already written, or an ordinary failed write the next sync retries by itself. Releasing it again does nothing.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."},{"name":"quarantineId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the failed-write row (`id` in GET /v1/pipelines/:id/quarantine)."},"description":"The id of the failed-write row (`id` in GET /v1/pipelines/:id/quarantine)."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"quarantineId":{"type":"string","format":"uuid"},"recordId":{"type":"string","description":"The record's key in the source system."},"released":{"type":"boolean","description":"Always true: the record is released."},"alreadyReleased":{"type":"boolean","description":"True when it was already released; nothing changed."}},"required":["pipelineId","quarantineId","recordId","released","alreadyReleased"]},"example":{"pipelineId":"00000000-0000-0000-0000-000000000000","quarantineId":"00000000-0000-0000-0000-000000000000","recordId":"string","released":true,"alreadyReleased":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/schedule":{"put":{"operationId":"SetPipelineSchedule","tags":["pipelines"],"summary":"Set Pipeline Schedule","security":[{"ApiKeyAuth":["pipelines:write"]},{"BearerAuth":[]},{"OAuth2":["pipelines:write"]}],"description":"Set when a pipeline syncs: in real time, on a timetable, after another sync, or only when you start it. For a timetable, give a cron expression (for example `0 9 * * 1-5` for 9am on weekdays) and, optionally, the time zone it is in. The response shows the next time it will run, so you can check it is what you meant. Setting any of these gives the pipeline its own timing, which its source system's timing never overwrites; send system to follow the source system's timing again.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"scheduleType":{"type":"string","enum":["realtime","scheduled","after_sync","manual","system"],"description":"realtime, scheduled (on the timetable in scheduleCron), after_sync, manual (only when you start it), or system to stop using the pipeline's own timing and follow its source system's again."},"scheduleCron":{"type":"string","description":"The timetable, as a standard five-part cron expression (minute, hour, day of month, month, day of week). Needed when scheduleType is scheduled; ignored otherwise."},"scheduleTimezone":{"type":"string","description":"The time zone the timetable is in, such as Europe/London. UTC if you leave it out."}},"required":["scheduleType"]},"example":{"scheduleType":"realtime","scheduleCron":"string","scheduleTimezone":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"scheduleType":{"type":"string"},"triggerSource":{"type":"string","description":"flow: it runs on its own timing. system: it follows its source system's."},"scheduleCron":{"type":"string"},"scheduleTimezone":{"type":"string"},"nextRunAt":{"type":"string","description":"Next fire time, so the caller can see the schedule was understood as intended."}},"required":["pipelineId","scheduleType","triggerSource","scheduleTimezone"]},"example":{"pipelineId":"00000000-0000-0000-0000-000000000000","scheduleType":"string","triggerSource":"string","scheduleCron":"string","scheduleTimezone":"string","nextRunAt":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/suggestions":{"get":{"operationId":"ListSuggestions","tags":["pipelines"],"summary":"List Suggestions","security":[{"ApiKeyAuth":["pipelines:read"]},{"BearerAuth":[]},{"OAuth2":["pipelines:read"]}],"description":"Inferrex’s open suggestions for improving this pipeline, most confident first, each with the reason for it and, where known, the value it could add.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"suggestions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string"},"title":{"type":"string"},"rationale":{"type":"string"},"estimated_value":{"type":"string","nullable":true},"confidence":{"type":"number"},"surfaced_at":{"type":"string"}},"required":["id","type","title","rationale","confidence","surfaced_at"]}}},"required":["pipelineId","suggestions"]},"example":{"pipelineId":"00000000-0000-0000-0000-000000000000","suggestions":[{"id":"00000000-0000-0000-0000-000000000000","type":"string","title":"string","rationale":"string","estimated_value":"string","confidence":0,"surfaced_at":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/suggestions/{suggestionId}/accept":{"post":{"operationId":"AcceptSuggestion","tags":["pipelines"],"summary":"Accept Suggestion","security":[{"ApiKeyAuth":["pipelines:write"]},{"BearerAuth":[]},{"OAuth2":["pipelines:write"]}],"description":"Accept one of Inferrex’s suggestions for this pipeline. Only an open suggestion can be accepted.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."},{"name":"suggestionId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the suggestion."},"description":"The id of the suggestion."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipeline_id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"type":{"type":"string"},"title":{"type":"string"},"rationale":{"type":"string"},"estimated_value":{"type":"string","nullable":true},"confidence":{"type":"string","description":"NUMERIC(5,4), 0 to 1. Postgres numerics reach JSON as decimal strings, e.g. \"0.8500\"."},"trigger_field":{"type":"string","nullable":true,"description":"Always null today: the suggestion engine's INSERT does not write it (services/suggestion-engine/src/logic.ts:141-151)."},"proposed_connection":{"type":"object","properties":{"systemName":{"type":"string"},"systemKey":{"type":"string","nullable":true,"description":"The catalogue key, when the system is in the library."},"inferenceRequired":{"type":"boolean"},"estimatedSetupTime":{"type":"string"}},"required":["systemName"],"nullable":true,"description":"For new-connection and partner-integration suggestions: the system to connect. Null otherwise."},"status":{"type":"string","description":"accepted"},"surfaced_at":{"type":"string","format":"date-time"},"actioned_at":{"type":"string","format":"date-time"},"triggered_inference_id":{"type":"string","format":"uuid","nullable":true}},"required":["id","pipeline_id","customer_id","type","title","rationale","confidence","status","surfaced_at","actioned_at"]},"example":{"id":"00000000-0000-0000-0000-000000000000","pipeline_id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","type":"string","title":"string","rationale":"string","estimated_value":"string","confidence":"string","trigger_field":"string","proposed_connection":{"systemName":"string","systemKey":"string","inferenceRequired":true,"estimatedSetupTime":"string"},"status":"string","surfaced_at":"2026-01-01T00:00:00Z","actioned_at":"2026-01-01T00:00:00Z","triggered_inference_id":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/suggestions/{suggestionId}/dismiss":{"post":{"operationId":"DismissSuggestion","tags":["pipelines"],"summary":"Dismiss Suggestion","security":[{"ApiKeyAuth":["pipelines:write"]},{"BearerAuth":[]},{"OAuth2":["pipelines:write"]}],"description":"Dismiss one of Inferrex’s suggestions for this pipeline, with a reason (for example “we already send this another way” or “not a system we use”). It is no longer shown, and your reason helps Inferrex make better suggestions for your workspace; it is kept private to you. Only an open suggestion can be dismissed.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."},{"name":"suggestionId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the suggestion."},"description":"The id of the suggestion."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maximum":2000,"description":"Why this suggestion does not fit. Required."}},"required":["reason"]},"example":{"reason":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"}},"required":["id","status"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/{id}/sync":{"post":{"operationId":"TriggerSync","tags":["pipelines"],"summary":"Trigger Sync","security":[{"ApiKeyAuth":["pipelines:write"]},{"BearerAuth":[]},{"OAuth2":["pipelines:write"]}],"description":"Run a sync now on an active pipeline, without waiting for its schedule. By default it syncs only what has changed since the last sync; you can ask for a full sync instead. Returns a job id you can use to follow its progress.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"syncType":{"type":"string","enum":["initial","incremental","full"],"description":"incremental (the default) syncs only what changed since the last sync; full syncs everything; initial runs a first full sync.","default":"incremental"}}},"example":{"syncType":"initial"}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"jobId":{"type":"string","format":"uuid","description":"Poll GET /v1/jobs/:id."},"syncJobId":{"type":"string","description":"Deprecated alias of jobId."},"status":{"type":"string","description":"queued"},"syncType":{"type":"string"}},"required":["pipelineId","jobId","syncJobId","status","syncType"]},"example":{"pipelineId":"00000000-0000-0000-0000-000000000000","jobId":"00000000-0000-0000-0000-000000000000","syncJobId":"string","status":"string","syncType":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/pipelines/attention":{"get":{"operationId":"GetPipelineAttention","tags":["pipelines"],"summary":"Get Pipeline Attention","security":[{"ApiKeyAuth":["pipelines:read"]},{"BearerAuth":[]},{"OAuth2":["pipelines:read"]}],"description":"Each flow (pipeline) with something waiting: how many of its failed writes are still to be retried, and how many repairs need your answer. A flow with neither is left out. Complete counts, not a page.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"flows":{"type":"array","items":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"failedWrites":{"type":"integer","description":"Failed writes not yet written on a retry."},"openRepairs":{"type":"integer","description":"Repair questions waiting for an answer."}},"required":["pipelineId","failedWrites","openRepairs"]}}},"required":["flows"]},"example":{"flows":[{"pipelineId":"00000000-0000-0000-0000-000000000000","failedWrites":0,"openRepairs":0}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/platform-config":{"get":{"operationId":"GetPlatformConfig","tags":["platform_config"],"summary":"Get Platform Config","security":[{"ApiKeyAuth":["platform-config:read"]},{"BearerAuth":[]},{"OAuth2":["platform-config:read"]}],"description":"Your workspace’s settings for how Inferrex behaves (thresholds, time windows, intervals and display options), with the value that applies to you and the details of each setting you can change. Pricing and limits are not included.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"values":{"type":"object","additionalProperties":true},"tunables":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"group":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"valueType":{"type":"string"},"default":{"nullable":true},"min":{"type":"number"},"max":{"type":"number"},"unit":{"type":"string"},"enumValues":{"type":"array","items":{"type":"string"}},"steps":{"type":"array","items":{"type":"number"}}},"required":["key","group","label","valueType"]}}},"required":["values","tunables"]},"example":{"values":{},"tunables":[{"key":"string","group":"string","label":"string","description":"string","valueType":"string","default":null,"min":0,"max":0,"unit":"string","enumValues":["string"],"steps":[0]}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"SetPlatformConfig","tags":["platform_config"],"summary":"Set Platform Config","security":[{"ApiKeyAuth":["platform-config:write"]},{"BearerAuth":[]},{"OAuth2":["platform-config:write"]}],"description":"Change one of your workspace’s settings, or send value: null to go back to the default. Only settings your workspace is allowed to change can be set, and the value must be within the allowed range. A setting that lets assistants act (such as bloomreach.agentApproval) can only be changed by a person in the app: an assistant, an MCP connector or an API key is refused with 403.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","minLength":1,"description":"Which setting to change, by its key."},"value":{"nullable":true,"description":"The new value: a number, text or true/false, depending on the setting. null goes back to the default."}},"required":["key"]},"example":{"key":"string","value":null}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"},"value":{"nullable":true}},"required":["key"]},"example":{"key":"string","value":null}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/platform-value-scores":{"get":{"operationId":"PlatformValueScoresList","tags":["golden_record"],"summary":"Platform Value Scores List","security":[{"ApiKeyAuth":["platform-value-scores:read"]},{"BearerAuth":[]},{"OAuth2":["platform-value-scores:read"]}],"description":"List your platform value scores, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"provider_key","in":"query","required":false,"schema":{"type":"string","description":"Only platform value scores whose provider key is exactly this."},"description":"Only platform value scores whose provider key is exactly this."},{"name":"provider_key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only platform value scores whose provider key contains this text (upper and lower case are treated the same)."},"description":"Only platform value scores whose provider key contains this text (upper and lower case are treated the same)."},{"name":"vendor_key","in":"query","required":false,"schema":{"type":"string","description":"Only platform value scores whose vendor key is exactly this."},"description":"Only platform value scores whose vendor key is exactly this."},{"name":"vendor_key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only platform value scores whose vendor key contains this text (upper and lower case are treated the same)."},"description":"Only platform value scores whose vendor key contains this text (upper and lower case are treated the same)."},{"name":"service_key","in":"query","required":false,"schema":{"type":"string","description":"Only platform value scores whose service key is exactly this."},"description":"Only platform value scores whose service key is exactly this."},{"name":"service_key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only platform value scores whose service key contains this text (upper and lower case are treated the same)."},"description":"Only platform value scores whose service key contains this text (upper and lower case are treated the same)."},{"name":"authority_wins_gte","in":"query","required":false,"schema":{"type":"number","description":"Only platform value scores whose authority wins is this number or more."},"description":"Only platform value scores whose authority wins is this number or more."},{"name":"authority_wins_lte","in":"query","required":false,"schema":{"type":"number","description":"Only platform value scores whose authority wins is this number or less."},"description":"Only platform value scores whose authority wins is this number or less."},{"name":"override_count_gte","in":"query","required":false,"schema":{"type":"number","description":"Only platform value scores whose override count is this number or more."},"description":"Only platform value scores whose override count is this number or more."},{"name":"override_count_lte","in":"query","required":false,"schema":{"type":"number","description":"Only platform value scores whose override count is this number or less."},"description":"Only platform value scores whose override count is this number or less."},{"name":"contribution_ratio_gte","in":"query","required":false,"schema":{"type":"number","description":"Only platform value scores whose contribution ratio is this number or more."},"description":"Only platform value scores whose contribution ratio is this number or more."},{"name":"contribution_ratio_lte","in":"query","required":false,"schema":{"type":"number","description":"Only platform value scores whose contribution ratio is this number or less."},"description":"Only platform value scores whose contribution ratio is this number or less."},{"name":"recommendation_tier","in":"query","required":false,"schema":{"type":"string","description":"Only platform value scores whose recommendation tier is exactly this."},"description":"Only platform value scores whose recommendation tier is exactly this."},{"name":"recommendation_tier_contains","in":"query","required":false,"schema":{"type":"string","description":"Only platform value scores whose recommendation tier contains this text (upper and lower case are treated the same)."},"description":"Only platform value scores whose recommendation tier contains this text (upper and lower case are treated the same)."},{"name":"scored_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only platform value scores whose scored time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only platform value scores whose scored time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"scored_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only platform value scores whose scored time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only platform value scores whose scored time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many platform value scores to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many platform value scores to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many platform value scores to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many platform value scores to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","provider_key","vendor_key","service_key","authority_wins","override_count","contribution_ratio","recommendation_tier","scored_at"],"description":"The field to sort the list by.","default":"scored_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns platform value scores where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns platform value scores where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"provider_key":{"type":"string"},"vendor_key":{"type":"string","nullable":true},"service_key":{"type":"string","nullable":true},"authority_wins":{"type":"integer"},"override_count":{"type":"integer"},"contribution_ratio":{"type":"number"},"recommendation_tier":{"type":"string"},"scored_at":{"type":"string"}},"required":["customer_id","provider_key","recommendation_tier"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","provider_key":"string","vendor_key":"string","service_key":"string","authority_wins":0,"override_count":0,"contribution_ratio":0,"recommendation_tier":"string","scored_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/platform-value-scores/{id}":{"get":{"operationId":"PlatformValueScoresGet","tags":["golden_record"],"summary":"Platform Value Scores Get","security":[{"ApiKeyAuth":["platform-value-scores:read"]},{"BearerAuth":[]},{"OAuth2":["platform-value-scores:read"]}],"description":"Get one of your platform value scores by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the platform value score."},"description":"The id of the platform value score."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"provider_key":{"type":"string"},"vendor_key":{"type":"string","nullable":true},"service_key":{"type":"string","nullable":true},"authority_wins":{"type":"integer"},"override_count":{"type":"integer"},"contribution_ratio":{"type":"number"},"recommendation_tier":{"type":"string"},"scored_at":{"type":"string"}},"required":["customer_id","provider_key","recommendation_tier"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","provider_key":"string","vendor_key":"string","service_key":"string","authority_wins":0,"override_count":0,"contribution_ratio":0,"recommendation_tier":"string","scored_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/platform-value-scores/trigger":{"post":{"operationId":"TriggerScoring","tags":["golden_record"],"summary":"Trigger Scoring","security":[{"ApiKeyAuth":["platform-value-scores:write"]},{"BearerAuth":[]},{"OAuth2":["platform-value-scores:write"]}],"description":"Recalculate how much each of your connected systems contributes to your golden records: how often its values are chosen or overridden, and whether it looks essential or could be consolidated or retired. The new scores are saved and returned.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"jobId":{"type":"string"},"status":{"type":"string"}},"required":["jobId","status"]},"example":{"jobId":"string","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/portal/artifacts/{id}/download":{"post":{"operationId":"RequestPortalDownload","tags":["portal"],"summary":"Request Portal Download","security":[{"ApiKeyAuth":["portal:write"]},{"BearerAuth":[]},{"OAuth2":["portal:write"]}],"description":"Get a download link for one release file. The link expires after a short time, and each download is recorded.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","description":"The release file, as <version>::<file>, from the releases list."},"description":"The release file, as <version>::<file>, from the releases list."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"expiresAt":{"type":"string"}},"required":["url","expiresAt"]},"example":{"url":"string","expiresAt":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/portal/licences":{"get":{"operationId":"ListPortalLicences","tags":["portal"],"summary":"List Portal Licences","security":[{"ApiKeyAuth":["portal:read"]},{"BearerAuth":[]},{"OAuth2":["portal:read"]}],"description":"Your licences for self-hosted Inferrex: level, status and term. Empty if you only use Inferrex in the cloud.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"tier":{"type":"string"},"deploymentMode":{"type":"string"},"status":{"type":"string"},"issuedAt":{"type":"string"},"expiresAt":{"type":"string"},"gracePeriodEnd":{"type":"string"}},"required":["id","tier","deploymentMode","status","issuedAt","expiresAt"]}}},"required":["items"]},"example":{"items":[{"id":"string","tier":"string","deploymentMode":"string","status":"string","issuedAt":"string","expiresAt":"string","gracePeriodEnd":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/portal/licences/{id}/activation-key":{"post":{"operationId":"RevealActivationKey","tags":["portal"],"summary":"Reveal Activation Key","security":[{"ApiKeyAuth":["portal:write"]},{"BearerAuth":[]},{"OAuth2":["portal:write"]}],"description":"Show the activation key for one of your self-hosted licences. The key is rebuilt from the licence each time and is never stored in readable form.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","description":"The id of the licence."},"description":"The id of the licence."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"activationKey":{"type":"string"}},"required":["activationKey"]},"example":{"activationKey":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/portal/releases":{"get":{"operationId":"ListPortalReleases","tags":["portal"],"summary":"List Portal Releases","security":[{"ApiKeyAuth":["portal:read"]},{"BearerAuth":[]},{"OAuth2":["portal:read"]}],"description":"The Inferrex releases your licence lets you download, one entry per file. Empty if your licence does not include downloads.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"version":{"type":"string"},"channel":{"type":"string"},"releasedAt":{"type":"string"},"kind":{"type":"string"},"description":{"type":"string"},"ref":{"type":"string"},"inAirGappedBundle":{"type":"boolean"}},"required":["id","version","channel","releasedAt","kind","description","ref","inAirGappedBundle"]}}},"required":["items"]},"example":{"items":[{"id":"string","version":"string","channel":"string","releasedAt":"string","kind":"string","description":"string","ref":"string","inAirGappedBundle":true}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/portal/support-tickets":{"get":{"operationId":"SupportTicketsList","tags":["portal"],"summary":"Support Tickets List","security":[{"ApiKeyAuth":["portal:read"]},{"BearerAuth":[]},{"OAuth2":["portal:read"]}],"description":"List your support tickets, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"subject","in":"query","required":false,"schema":{"type":"string","description":"Only support tickets whose subject is exactly this."},"description":"Only support tickets whose subject is exactly this."},{"name":"subject_contains","in":"query","required":false,"schema":{"type":"string","description":"Only support tickets whose subject contains this text (upper and lower case are treated the same)."},"description":"Only support tickets whose subject contains this text (upper and lower case are treated the same)."},{"name":"body","in":"query","required":false,"schema":{"type":"string","description":"Only support tickets whose body is exactly this."},"description":"Only support tickets whose body is exactly this."},{"name":"body_contains","in":"query","required":false,"schema":{"type":"string","description":"Only support tickets whose body contains this text (upper and lower case are treated the same)."},"description":"Only support tickets whose body contains this text (upper and lower case are treated the same)."},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Only support tickets whose status is exactly this."},"description":"Only support tickets whose status is exactly this."},{"name":"status_contains","in":"query","required":false,"schema":{"type":"string","description":"Only support tickets whose status contains this text (upper and lower case are treated the same)."},"description":"Only support tickets whose status contains this text (upper and lower case are treated the same)."},{"name":"priority","in":"query","required":false,"schema":{"type":"string","description":"Only support tickets whose priority is exactly this."},"description":"Only support tickets whose priority is exactly this."},{"name":"priority_contains","in":"query","required":false,"schema":{"type":"string","description":"Only support tickets whose priority contains this text (upper and lower case are treated the same)."},"description":"Only support tickets whose priority contains this text (upper and lower case are treated the same)."},{"name":"created_by_email","in":"query","required":false,"schema":{"type":"string","description":"Only support tickets whose created by email is exactly this."},"description":"Only support tickets whose created by email is exactly this."},{"name":"created_by_email_contains","in":"query","required":false,"schema":{"type":"string","description":"Only support tickets whose created by email contains this text (upper and lower case are treated the same)."},"description":"Only support tickets whose created by email contains this text (upper and lower case are treated the same)."},{"name":"resolved_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only support tickets whose resolved time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only support tickets whose resolved time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"resolved_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only support tickets whose resolved time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only support tickets whose resolved time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"external_ref","in":"query","required":false,"schema":{"type":"string","description":"Only support tickets whose external ref is exactly this."},"description":"Only support tickets whose external ref is exactly this."},{"name":"external_ref_contains","in":"query","required":false,"schema":{"type":"string","description":"Only support tickets whose external ref contains this text (upper and lower case are treated the same)."},"description":"Only support tickets whose external ref contains this text (upper and lower case are treated the same)."},{"name":"assigned_to","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only support tickets for this assigned to. Pass its id."},"description":"Only support tickets for this assigned to. Pass its id."},{"name":"assigned_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only support tickets whose assigned time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only support tickets whose assigned time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"assigned_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only support tickets whose assigned time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only support tickets whose assigned time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many support tickets to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many support tickets to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many support tickets to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many support tickets to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","subject","body","status","priority","created_by_email","created_at","updated_at","resolved_at","external_ref","assigned_to","assigned_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns support tickets where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns support tickets where any text field contains it (upper and lower case are treated the same)."},{"name":"status_in","in":"query","required":false,"schema":{"type":"string","description":"Only support tickets whose status is one of these values, separated by commas."},"description":"Only support tickets whose status is one of these values, separated by commas."},{"name":"priority_in","in":"query","required":false,"schema":{"type":"string","description":"Only support tickets whose priority is one of these values, separated by commas."},"description":"Only support tickets whose priority is one of these values, separated by commas."},{"name":"assigned_to_in","in":"query","required":false,"schema":{"type":"string","description":"Only support tickets whose assigned to is one of these values, separated by commas."},"description":"Only support tickets whose assigned to is one of these values, separated by commas."},{"name":"group","in":"query","required":false,"schema":{"type":"string","enum":["status","priority","assigned_to"],"description":"Count support tickets by this field instead of listing them: one count for each value it holds."},"description":"Count support tickets by this field instead of listing them: one count for each value it holds."},{"name":"facets","in":"query","required":false,"schema":{"type":"string","description":"Fields to count values for alongside the list, separated by commas, so you can see what each filter would match."},"description":"Fields to count values for alongside the list, separated by commas, so you can see what each filter would match."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"subject":{"type":"string"},"body":{"type":"string"},"status":{"type":"string"},"priority":{"type":"string"},"created_by_email":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"resolved_at":{"type":"string","nullable":true},"external_ref":{"type":"string","nullable":true},"assigned_to":{"type":"string","format":"uuid","nullable":true},"assigned_at":{"type":"string","nullable":true}},"required":["customer_id","subject","body","created_by_email"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","subject":"string","body":"string","status":"string","priority":"string","created_by_email":"string","created_at":"string","updated_at":"string","resolved_at":"string","external_ref":"string","assigned_to":"00000000-0000-0000-0000-000000000000","assigned_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"SupportTicketsCreate","tags":["portal"],"summary":"Support Tickets Create","security":[{"ApiKeyAuth":["portal:write"]},{"BearerAuth":[]},{"OAuth2":["portal:write"]}],"description":"Create a support ticket. Returns the new support ticket, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"subject":{"type":"string"},"body":{"type":"string"},"status":{"type":"string"},"priority":{"type":"string"}},"required":["subject","body"]},"example":{"subject":"string","body":"string","status":"string","priority":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"subject":{"type":"string"},"body":{"type":"string"},"status":{"type":"string"},"priority":{"type":"string"},"created_by_email":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"resolved_at":{"type":"string","nullable":true},"external_ref":{"type":"string","nullable":true},"assigned_to":{"type":"string","format":"uuid","nullable":true},"assigned_at":{"type":"string","nullable":true}},"required":["customer_id","subject","body","created_by_email"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","subject":"string","body":"string","status":"string","priority":"string","created_by_email":"string","created_at":"string","updated_at":"string","resolved_at":"string","external_ref":"string","assigned_to":"00000000-0000-0000-0000-000000000000","assigned_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/portal/support-tickets/{id}":{"get":{"operationId":"SupportTicketsGet","tags":["portal"],"summary":"Support Tickets Get","security":[{"ApiKeyAuth":["portal:read"]},{"BearerAuth":[]},{"OAuth2":["portal:read"]}],"description":"Get one of your support tickets by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the support ticket."},"description":"The id of the support ticket."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"subject":{"type":"string"},"body":{"type":"string"},"status":{"type":"string"},"priority":{"type":"string"},"created_by_email":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"resolved_at":{"type":"string","nullable":true},"external_ref":{"type":"string","nullable":true},"assigned_to":{"type":"string","format":"uuid","nullable":true},"assigned_at":{"type":"string","nullable":true}},"required":["customer_id","subject","body","created_by_email"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","subject":"string","body":"string","status":"string","priority":"string","created_by_email":"string","created_at":"string","updated_at":"string","resolved_at":"string","external_ref":"string","assigned_to":"00000000-0000-0000-0000-000000000000","assigned_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"SupportTicketsUpdate","tags":["portal"],"summary":"Support Tickets Update","security":[{"ApiKeyAuth":["portal:write"]},{"BearerAuth":[]},{"OAuth2":["portal:write"]}],"description":"Change a support ticket. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the support ticket."},"description":"The id of the support ticket."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"subject":{"type":"string"},"body":{"type":"string"},"status":{"type":"string"},"priority":{"type":"string"}}},"example":{"subject":"string","body":"string","status":"string","priority":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"subject":{"type":"string"},"body":{"type":"string"},"status":{"type":"string"},"priority":{"type":"string"},"created_by_email":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"resolved_at":{"type":"string","nullable":true},"external_ref":{"type":"string","nullable":true},"assigned_to":{"type":"string","format":"uuid","nullable":true},"assigned_at":{"type":"string","nullable":true}},"required":["customer_id","subject","body","created_by_email"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","subject":"string","body":"string","status":"string","priority":"string","created_by_email":"string","created_at":"string","updated_at":"string","resolved_at":"string","external_ref":"string","assigned_to":"00000000-0000-0000-0000-000000000000","assigned_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/portal/support-tickets/{id}/messages":{"get":{"operationId":"ListPortalSupportTicketMessages","tags":["portal"],"summary":"List Portal Support Ticket Messages","security":[{"ApiKeyAuth":["portal:read"]},{"BearerAuth":[]},{"OAuth2":["portal:read"]}],"description":"The replies and messages on your ticket, oldest first. 404 when the ticket is not your workspace's.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"from":{"type":"string","description":"you (anyone in your workspace) or support."},"authorEmail":{"type":"string","nullable":true,"description":"Who in your workspace wrote it; null for the support team."},"body":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","from","authorEmail","body","createdAt"]}}},"required":["messages"]},"example":{"messages":[{"id":"00000000-0000-0000-0000-000000000000","from":"string","authorEmail":"string","body":"string","createdAt":"2026-01-01T00:00:00Z"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"AddPortalSupportTicketMessage","tags":["portal"],"summary":"Add Portal Support Ticket Message","security":[{"ApiKeyAuth":["portal:write"]},{"BearerAuth":[]},{"OAuth2":["portal:write"]}],"description":"Adds your message to the ticket's conversation. 404 when the ticket is not your workspace's.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":20000}},"required":["body"]},"example":{"body":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"from":{"type":"string","description":"you (anyone in your workspace) or support."},"authorEmail":{"type":"string","nullable":true,"description":"Who in your workspace wrote it; null for the support team."},"body":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","from","authorEmail","body","createdAt"]},"reopened":{"type":"boolean","description":"True when the message reopened a resolved or closed ticket."}},"required":["message","reopened"]},"example":{"message":{"id":"00000000-0000-0000-0000-000000000000","from":"string","authorEmail":"string","body":"string","createdAt":"2026-01-01T00:00:00Z"},"reopened":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/pricing":{"get":{"operationId":"GetPricing","tags":["pricing"],"summary":"Get Pricing","security":[{"ApiKeyAuth":["pricing:read"]},{"BearerAuth":[]},{"OAuth2":["pricing:read"]}],"description":"The current pricing catalogue, read from Stripe. If Stripe cannot be reached, you get the prices as last synced from Stripe, with source set to catalogue and asOf saying when they last changed: show them as prices as of that date. If no price is stored, the request fails with 503 and can be retried; a price is never made up. You need to be signed in or use an API key: it is not public.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"source":{"type":"string","description":"Where these prices came from: \"stripe\" (live, possibly via the 1-hour cache) or \"catalogue\" (Stripe was unreachable; the admin billing catalogue as last synced with Stripe — may be out of date). Open vocabulary: treat an unknown value like \"catalogue\"."},"asOf":{"type":"string","format":"date-time","description":"ISO-8601. For source=\"stripe\", when Stripe was read; for source=\"catalogue\", when the stored prices last changed — show \"prices as of <asOf>\"."},"tiers":{"type":"array","items":{"type":"object","properties":{"tier":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"salesLed":{"type":"boolean","description":"True when the rung has no self-serve price: it is agreed in a conversation."},"entitlements":{"type":"object","properties":{"integrations":{"type":"integer"},"relationships":{"type":"integer"},"storage_gb":{"type":"integer"},"ai_operations":{"type":"integer"},"environments":{"type":"integer"},"webhooks":{"type":"integer"},"workflows":{"type":"integer"},"api_keys":{"type":"integer"}},"description":"The rung’s allowances, from its Stripe product. A key is absent when Stripe states none; -1 is no fixed cap."},"prices":{"type":"object","additionalProperties":true,"description":"currency → billing frequency → { amount (minor units), display }. Empty for a sales-led rung."}},"required":["tier","name","description","salesLed","entitlements","prices"]},"description":"Every rung of the environment ladder, lowest first."},"packs":{"type":"array","items":{"type":"object","properties":{"dimension":{"type":"string"},"unit_size":{"type":"integer"},"unit_label":{"type":"string"},"prices":{"type":"object","additionalProperties":true,"description":"currency → { amount (minor units), display }."}},"required":["dimension","unit_size","unit_label","prices"]},"description":"Capacity packs: Stripe products of kind pack."},"currencies":{"type":"array","items":{"type":"string"}}},"required":["source","asOf","tiers","packs","currencies"]},"example":{"source":"string","asOf":"2026-01-01T00:00:00Z","tiers":[{"tier":"string","name":"string","description":"string","salesLed":true,"entitlements":{"integrations":0,"relationships":0,"storage_gb":0,"ai_operations":0,"environments":0,"webhooks":0,"workflows":0,"api_keys":0},"prices":{}}],"packs":[{"dimension":"string","unit_size":0,"unit_label":"string","prices":{}}],"currencies":["string"]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/public/corpus/apis/{apiId}":{"get":{"operationId":"GetPublicCorpusApi","tags":["public_corpus"],"summary":"Get Public Corpus Api","security":[],"description":"Read a verified API and a bounded page of explicitly cleared entity/field names and types. No descriptions, examples or raw specs.","parameters":[{"name":"apiId","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":200}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":20,"description":"Maximum results, at most 20. Defaults to 10."},"description":"Maximum results, at most 20. Defaults to 10."},{"name":"after","in":"query","required":false,"schema":{"type":"string","maxLength":200,"description":"Opaque continuation value returned by the previous page."},"description":"Opaque continuation value returned by the previous page."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"vendorId":{"type":"string"},"productId":{"type":"string"},"version":{"type":"string","nullable":true},"style":{"type":"string","nullable":true},"authTypes":{"type":"array","items":{"type":"string"}},"documentationUrl":{"type":"string","nullable":true},"entities":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","nullable":true}},"required":["name","type"]}},"fieldsTruncated":{"type":"boolean"}},"required":["id","name","fields","fieldsTruncated"]}},"next":{"type":"string","nullable":true},"fieldPublication":{"type":"string"}},"required":["id","name","vendorId","productId","version","style","authTypes","documentationUrl","entities","next","fieldPublication"]},"example":{"id":"string","name":"string","vendorId":"string","productId":"string","version":"string","style":"string","authTypes":["string"],"documentationUrl":"string","entities":[{"id":"string","name":"string","fields":[{"name":"string","type":"string"}],"fieldsTruncated":true}],"next":"string","fieldPublication":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/public/corpus/figures":{"get":{"operationId":"GetPublicCorpusFigures","tags":["public_corpus"],"summary":"Get Public Corpus Figures","security":[],"description":"Read explicitly published claims with their measurement date and source. Missing claims are not zero counts.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"figures":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"value":{"type":"string"},"measuredAt":{"type":"string"},"source":{"type":"string"}},"required":["id","value","measuredAt","source"]}},"status":{"type":"string"}},"required":["figures","status"]},"example":{"figures":[{"id":"string","value":"string","measuredAt":"string","source":"string"}],"status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/public/corpus/overview":{"get":{"operationId":"GetPublicPlatformOverview","tags":["public_corpus"],"summary":"Get Public Platform Overview","security":[],"description":"Read the approved, versioned Inferrex overview. Never infer prices, plans or unsupported claims.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string","nullable":true},"version":{"type":"string","nullable":true},"source":{"type":"string","nullable":true},"status":{"type":"string"}},"required":["text","version","source","status"]},"example":{"text":"string","version":"string","source":"string","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/public/corpus/search":{"get":{"operationId":"SearchPublicCorpus","tags":["public_corpus"],"summary":"Search Public Corpus","security":[],"description":"Search verified public vendor and product facts by name or category. No tenant data or specification bodies.","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":120,"description":"Vendor, product or category text."},"description":"Vendor, product or category text."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":20,"description":"Maximum results, at most 20. Defaults to 10."},"description":"Maximum results, at most 20. Defaults to 10."},{"name":"after","in":"query","required":false,"schema":{"type":"string","maxLength":200,"description":"Opaque continuation value returned by the previous page."},"description":"Opaque continuation value returned by the previous page."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"vendors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"website":{"type":"string","nullable":true},"documentationUrl":{"type":"string","nullable":true},"categories":{"type":"array","items":{"type":"string"}},"styles":{"type":"array","items":{"type":"string"}}},"required":["id","name","website","documentationUrl","categories","styles"]}},"next":{"type":"string","nullable":true}},"required":["vendors","next"]},"example":{"vendors":[{"id":"string","name":"string","website":"string","documentationUrl":"string","categories":["string"],"styles":["string"]}],"next":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/public/corpus/vendors/{vendorId}":{"get":{"operationId":"GetPublicCorpusVendor","tags":["public_corpus"],"summary":"Get Public Corpus Vendor","security":[],"description":"Read a verified vendor and a bounded page of its products. Links and derived facts only.","parameters":[{"name":"vendorId","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":200}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":20,"description":"Maximum results, at most 20. Defaults to 10."},"description":"Maximum results, at most 20. Defaults to 10."},{"name":"after","in":"query","required":false,"schema":{"type":"string","maxLength":200,"description":"Opaque continuation value returned by the previous page."},"description":"Opaque continuation value returned by the previous page."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"website":{"type":"string","nullable":true},"documentationUrl":{"type":"string","nullable":true},"categories":{"type":"array","items":{"type":"string"}},"styles":{"type":"array","items":{"type":"string"}},"products":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"categories":{"type":"array","items":{"type":"string"}},"apis":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"styles":{"type":"array","items":{"type":"string"}}},"required":["id","name","styles"]}},"apisTruncated":{"type":"boolean"}},"required":["id","name","categories","apis","apisTruncated"]}},"next":{"type":"string","nullable":true}},"required":["id","name","website","documentationUrl","categories","styles","products","next"]},"example":{"id":"string","name":"string","website":"string","documentationUrl":"string","categories":["string"],"styles":["string"],"products":[{"id":"string","name":"string","categories":["string"],"apis":[{"id":"string","name":"string","styles":["string"]}],"apisTruncated":true}],"next":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/quarantine":{"get":{"operationId":"ListQuarantine","tags":["pipelines"],"summary":"List Quarantine","security":[{"ApiKeyAuth":["quarantine:read"]},{"BearerAuth":[]},{"OAuth2":["quarantine:read"]}],"description":"Failed writes across every pipeline in the workspace (integrations.quarantine), with filters applied before paging. Supports newest, oldest or most retries first. Read-only; the next sync of a row's pipeline retries it and resolves the row once the write lands. The exception is a record held for a missing required field (`failure_reason` starting `record_validation:`, only while the workspace has `healing.routeSchemaAndRecordFailures` on): it is skipped until it changes in the source or its hold is released (DEBT-199). Rows expire after 30 days. Paged by `limit` / `offset`; there is no total, so a page shorter than `limit` is the last one.","parameters":[{"name":"pipeline_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only this pipeline's failed writes."},"description":"Only this pipeline's failed writes."},{"name":"connection_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only failed writes for flows that read from or write to this system."},"description":"Only failed writes for flows that read from or write to this system."},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["open","resolved"],"description":"`open`: still to be retried; `resolved`: written on a later sync. Omit for both."},"description":"`open`: still to be retried; `resolved`: written on a later sync. Omit for both."},{"name":"entity_type","in":"query","required":false,"schema":{"type":"string","description":"Only this kind of record, compared without regard to case."},"description":"Only this kind of record, compared without regard to case."},{"name":"who","in":"query","required":false,"schema":{"type":"string","enum":["me","nobody"],"description":"Only failed writes assigned to you, or with no assignee."},"description":"Only failed writes assigned to you, or with no assignee."},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":200,"description":"Search pipeline, record kind/id, failure reason and assignee."},"description":"Search pipeline, record kind/id, failure reason and assignee."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["newest","oldest","riskiest"],"default":"newest"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"quarantined":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"entity_type":{"type":"string","nullable":true},"record_id":{"type":"string","nullable":true},"failure_reason":{"type":"string","nullable":true},"retry_count":{"type":"integer"},"resolved":{"type":"boolean"},"sync_job_id":{"type":"string","format":"uuid","nullable":true},"created_at":{"type":"string"},"held":{"type":"boolean","description":"Held for a missing required field: not retried until it changes in the source or is released."},"released":{"type":"boolean","description":"A held record someone released: the next sync sends it once as it is."},"pipeline_id":{"type":"string","format":"uuid"},"pipeline_name":{"type":"string"}},"required":["id","retry_count","resolved","created_at","held","released","pipeline_id","pipeline_name"]}},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["quarantined","limit","offset"]},"example":{"quarantined":[{"id":"00000000-0000-0000-0000-000000000000","entity_type":"string","record_id":"string","failure_reason":"string","retry_count":0,"resolved":true,"sync_job_id":"00000000-0000-0000-0000-000000000000","created_at":"string","held":true,"released":true,"pipeline_id":"00000000-0000-0000-0000-000000000000","pipeline_name":"string"}],"limit":0,"offset":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/reports/query":{"post":{"operationId":"QueryReport","tags":["reports"],"summary":"Query Report","security":[{"ApiKeyAuth":["reports:write"]},{"BearerAuth":[]},{"OAuth2":["reports:write"]}],"description":"One report query (read-only). `parts` names one to four datasets, each with the measures it should answer (all, if none) and its own filters; `groupBy` names the dimensions to group by — `day` and the dataset's own; with two or more parts, only keys every part shares (day, connection, flow, golden type), and the parts are joined on them. `from` / `to` bound the days (UTC, inclusive; default the last 30). Answers at most 200 rows; one part pages with `cursor`, several are marked `truncated` when a part had more. A row carries each grouped dimension under its name and each measure as `<dataset>.<measure>`. Each dataset reports its `asOf` (when its summary was last refreshed for your workspace) and the columns `masked` for your role. Datasets: sync_runs, destination_dispatches, golden_destination_sends, golden_quality, golden_source_share, golden_proposals.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"parts":{"type":"array","items":{"type":"object","properties":{"dataset":{"type":"string","description":"The dataset id."},"measures":{"type":"array","items":{"type":"string"},"description":"Measures to answer. None: all of them."},"filters":{"type":"array","items":{"type":"object","properties":{"dimension":{"type":"string"},"values":{"type":"array","items":{"type":"string"}}},"required":["dimension","values"]},"description":"Each: a dimension of this dataset and the values it may take."}},"required":["dataset"]},"description":"The datasets to read, one to four."},"groupBy":{"type":"array","items":{"type":"string"},"description":"Dimensions to group by, at most 4. None: one row of totals."},"from":{"type":"string","description":"First day, YYYY-MM-DD (UTC). Default: 29 days before `to`."},"to":{"type":"string","description":"Last day, YYYY-MM-DD (UTC), inclusive. Default: today."},"limit":{"type":"integer","minimum":1,"maximum":200,"description":"Rows per page, at most 200 (the default)."},"cursor":{"type":"string","nullable":true,"description":"The `nextCursor` of the previous page (one part only)."}},"required":["parts"]},"example":{"parts":[{"dataset":"string","measures":["string"],"filters":[{"dimension":"string","values":["string"]}]}],"groupBy":["string"],"from":"string","to":"string","limit":0,"cursor":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"groupBy":{"type":"array","items":{"type":"string"}},"from":{"type":"string"},"to":{"type":"string"},"datasets":{"type":"array","items":{"type":"object","properties":{"dataset":{"type":"string"},"owner":{"type":"string","description":"The service that keeps it."},"refresh":{"type":"string","enum":["summary","live"]},"asOf":{"type":"string","nullable":true,"description":"When its figures were last refreshed for your workspace; empty before the first refresh."},"day":{"type":"string","nullable":true,"description":"A level measured each day (golden quality, sends, winning values) read without grouping by day: the one day it read."},"masked":{"type":"array","items":{"type":"string"},"description":"Columns answered empty because your role may not see them."}},"required":["dataset","owner","refresh","masked"]},"description":"One per part, in order."},"rows":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Each grouped dimension under its name (text, or null) and each measure as `<dataset>.<measure>` (a number, or null when masked or absent from that part)."},"nextCursor":{"type":"string","nullable":true},"truncated":{"type":"boolean","description":"Several parts were joined and one had more than one page: the rows are not all there."}},"required":["groupBy","from","to","datasets","rows","truncated"]},"example":{"groupBy":["string"],"from":"string","to":"string","datasets":[{"dataset":"string","owner":"string","refresh":"summary","asOf":"string","day":"string","masked":["string"]}],"rows":[{}],"nextCursor":"string","truncated":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/restoration-requests":{"get":{"operationId":"RestorationRequestsList","tags":["data_protection"],"summary":"Restoration Requests List","security":[{"ApiKeyAuth":["restoration-requests:read"]},{"BearerAuth":[]},{"OAuth2":["restoration-requests:read"]}],"description":"List your restorations, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"target_timestamp_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only restorations whose target timestamp is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only restorations whose target timestamp is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"target_timestamp_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only restorations whose target timestamp is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only restorations whose target timestamp is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Only restorations whose status is exactly this."},"description":"Only restorations whose status is exactly this."},{"name":"status_contains","in":"query","required":false,"schema":{"type":"string","description":"Only restorations whose status contains this text (upper and lower case are treated the same)."},"description":"Only restorations whose status contains this text (upper and lower case are treated the same)."},{"name":"parallel_run","in":"query","required":false,"schema":{"type":"boolean","description":"Only restorations where parallel run is true, or false for only those where it is false."},"description":"Only restorations where parallel run is true, or false for only those where it is false."},{"name":"approved_by","in":"query","required":false,"schema":{"type":"string","description":"Only restorations whose approved by is exactly this."},"description":"Only restorations whose approved by is exactly this."},{"name":"approved_by_contains","in":"query","required":false,"schema":{"type":"string","description":"Only restorations whose approved by contains this text (upper and lower case are treated the same)."},"description":"Only restorations whose approved by contains this text (upper and lower case are treated the same)."},{"name":"approved_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only restorations whose approved time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only restorations whose approved time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"approved_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only restorations whose approved time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only restorations whose approved time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"rejected_by","in":"query","required":false,"schema":{"type":"string","description":"Only restorations whose rejected by is exactly this."},"description":"Only restorations whose rejected by is exactly this."},{"name":"rejected_by_contains","in":"query","required":false,"schema":{"type":"string","description":"Only restorations whose rejected by contains this text (upper and lower case are treated the same)."},"description":"Only restorations whose rejected by contains this text (upper and lower case are treated the same)."},{"name":"rejected_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only restorations whose rejected time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only restorations whose rejected time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"rejected_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only restorations whose rejected time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only restorations whose rejected time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"rejection_reason","in":"query","required":false,"schema":{"type":"string","description":"Only restorations whose rejection reason is exactly this."},"description":"Only restorations whose rejection reason is exactly this."},{"name":"rejection_reason_contains","in":"query","required":false,"schema":{"type":"string","description":"Only restorations whose rejection reason contains this text (upper and lower case are treated the same)."},"description":"Only restorations whose rejection reason contains this text (upper and lower case are treated the same)."},{"name":"records_processed_gte","in":"query","required":false,"schema":{"type":"number","description":"Only restorations whose records processed is this number or more."},"description":"Only restorations whose records processed is this number or more."},{"name":"records_processed_lte","in":"query","required":false,"schema":{"type":"number","description":"Only restorations whose records processed is this number or less."},"description":"Only restorations whose records processed is this number or less."},{"name":"records_failed_gte","in":"query","required":false,"schema":{"type":"number","description":"Only restorations whose records failed is this number or more."},"description":"Only restorations whose records failed is this number or more."},{"name":"records_failed_lte","in":"query","required":false,"schema":{"type":"number","description":"Only restorations whose records failed is this number or less."},"description":"Only restorations whose records failed is this number or less."},{"name":"started_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only restorations whose started time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only restorations whose started time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"started_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only restorations whose started time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only restorations whose started time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"completed_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only restorations whose completed time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only restorations whose completed time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"completed_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only restorations whose completed time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only restorations whose completed time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"completed_by","in":"query","required":false,"schema":{"type":"string","description":"Only restorations whose completed by is exactly this."},"description":"Only restorations whose completed by is exactly this."},{"name":"completed_by_contains","in":"query","required":false,"schema":{"type":"string","description":"Only restorations whose completed by contains this text (upper and lower case are treated the same)."},"description":"Only restorations whose completed by contains this text (upper and lower case are treated the same)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many restorations to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many restorations to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many restorations to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many restorations to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","target_timestamp","status","parallel_run","approved_by","approved_at","rejected_by","rejected_at","rejection_reason","records_processed","records_failed","started_at","completed_at","completed_by","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns restorations where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns restorations where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"target_timestamp":{"type":"string"},"status":{"type":"string"},"resolution_config":{"type":"object","additionalProperties":true},"parallel_run":{"type":"boolean"},"impact_report":{"type":"object","additionalProperties":true,"nullable":true},"verification_report":{"type":"object","additionalProperties":true,"nullable":true},"progress_log":{"type":"object","additionalProperties":true},"approved_by":{"type":"string","nullable":true},"approved_at":{"type":"string","nullable":true},"rejected_by":{"type":"string","nullable":true},"rejected_at":{"type":"string","nullable":true},"rejection_reason":{"type":"string","nullable":true},"records_processed":{"type":"integer"},"records_failed":{"type":"integer"},"started_at":{"type":"string","nullable":true},"completed_at":{"type":"string","nullable":true},"completed_by":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","target_timestamp"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","target_timestamp":"string","status":"string","resolution_config":{},"parallel_run":true,"impact_report":{},"verification_report":{},"progress_log":{},"approved_by":"string","approved_at":"string","rejected_by":"string","rejected_at":"string","rejection_reason":"string","records_processed":0,"records_failed":0,"started_at":"string","completed_at":"string","completed_by":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"RestorationRequestsCreate","tags":["data_protection"],"summary":"Restoration Requests Create","security":[{"ApiKeyAuth":["restoration-requests:write"]},{"BearerAuth":[]},{"OAuth2":["restoration-requests:write"]}],"description":"Create a restoration. Returns the new restoration, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"target_timestamp":{"type":"string"},"resolution_config":{"type":"object","additionalProperties":true},"parallel_run":{"type":"boolean"}},"required":["target_timestamp"]},"example":{"target_timestamp":"string","resolution_config":{},"parallel_run":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"target_timestamp":{"type":"string"},"status":{"type":"string"},"resolution_config":{"type":"object","additionalProperties":true},"parallel_run":{"type":"boolean"},"impact_report":{"type":"object","additionalProperties":true,"nullable":true},"verification_report":{"type":"object","additionalProperties":true,"nullable":true},"progress_log":{"type":"object","additionalProperties":true},"approved_by":{"type":"string","nullable":true},"approved_at":{"type":"string","nullable":true},"rejected_by":{"type":"string","nullable":true},"rejected_at":{"type":"string","nullable":true},"rejection_reason":{"type":"string","nullable":true},"records_processed":{"type":"integer"},"records_failed":{"type":"integer"},"started_at":{"type":"string","nullable":true},"completed_at":{"type":"string","nullable":true},"completed_by":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","target_timestamp"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","target_timestamp":"string","status":"string","resolution_config":{},"parallel_run":true,"impact_report":{},"verification_report":{},"progress_log":{},"approved_by":"string","approved_at":"string","rejected_by":"string","rejected_at":"string","rejection_reason":"string","records_processed":0,"records_failed":0,"started_at":"string","completed_at":"string","completed_by":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/restoration-requests/{id}":{"get":{"operationId":"RestorationRequestsGet","tags":["data_protection"],"summary":"Restoration Requests Get","security":[{"ApiKeyAuth":["restoration-requests:read"]},{"BearerAuth":[]},{"OAuth2":["restoration-requests:read"]}],"description":"Get one of your restorations by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the restoration."},"description":"The id of the restoration."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"target_timestamp":{"type":"string"},"status":{"type":"string"},"resolution_config":{"type":"object","additionalProperties":true},"parallel_run":{"type":"boolean"},"impact_report":{"type":"object","additionalProperties":true,"nullable":true},"verification_report":{"type":"object","additionalProperties":true,"nullable":true},"progress_log":{"type":"object","additionalProperties":true},"approved_by":{"type":"string","nullable":true},"approved_at":{"type":"string","nullable":true},"rejected_by":{"type":"string","nullable":true},"rejected_at":{"type":"string","nullable":true},"rejection_reason":{"type":"string","nullable":true},"records_processed":{"type":"integer"},"records_failed":{"type":"integer"},"started_at":{"type":"string","nullable":true},"completed_at":{"type":"string","nullable":true},"completed_by":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","target_timestamp"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","target_timestamp":"string","status":"string","resolution_config":{},"parallel_run":true,"impact_report":{},"verification_report":{},"progress_log":{},"approved_by":"string","approved_at":"string","rejected_by":"string","rejected_at":"string","rejection_reason":"string","records_processed":0,"records_failed":0,"started_at":"string","completed_at":"string","completed_by":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/restoration-requests/{id}/approve":{"post":{"operationId":"RestorationRequestsApprove","tags":["data_protection"],"summary":"Restoration Requests Approve","security":[{"ApiKeyAuth":["restoration-requests:write"]},{"BearerAuth":[]},{"OAuth2":["restoration-requests:write"]}],"description":"Approve a restoration that is waiting for approval. You need permission to approve restorations. Once approved, it can be run.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the restoration."},"description":"The id of the restoration."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","description":"An optional note, kept with the decision."}}},"example":{"notes":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"}}},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/restoration-requests/{id}/cancel":{"post":{"operationId":"RestorationRequestsCancel","tags":["data_protection"],"summary":"Restoration Requests Cancel","security":[{"ApiKeyAuth":["restoration-requests:write"]},{"BearerAuth":[]},{"OAuth2":["restoration-requests:write"]}],"description":"Cancel a restoration before it runs. Works while it is being previewed, waiting for approval or approved.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the restoration."},"description":"The id of the restoration."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","description":"An optional note, kept with the decision."}}},"example":{"notes":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"}}},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/restoration-requests/{id}/execute":{"post":{"operationId":"RestorationRequestsExecute","tags":["data_protection"],"summary":"Restoration Requests Execute","security":[{"ApiKeyAuth":["restoration-requests:write"]},{"BearerAuth":[]},{"OAuth2":["restoration-requests:write"]}],"description":"Run an approved restoration: put your data back as it was at the restore point, settling any conflicts the way the request says, then check the result. This changes your live data.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the restoration."},"description":"The id of the restoration."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","description":"An optional note, kept with the decision."}}},"example":{"notes":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"}}},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/restoration-requests/{id}/preview":{"post":{"operationId":"RestorationRequestsPreview","tags":["data_protection"],"summary":"Restoration Requests Preview","security":[{"ApiKeyAuth":["restoration-requests:write"]},{"BearerAuth":[]},{"OAuth2":["restoration-requests:write"]}],"description":"Preview a restoration: compare your data as it was at the restore point with how it is now, and show which records and fields would change. Run this before asking for approval.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the restoration."},"description":"The id of the restoration."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","description":"An optional note, kept with the decision."}}},"example":{"notes":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"}}},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/restoration-requests/{id}/reject":{"post":{"operationId":"RestorationRequestsReject","tags":["data_protection"],"summary":"Restoration Requests Reject","security":[{"ApiKeyAuth":["restoration-requests:write"]},{"BearerAuth":[]},{"OAuth2":["restoration-requests:write"]}],"description":"Reject a restoration that is waiting for approval. You need permission to approve restorations, and a reason (up to 1,000 characters) is required. The restoration is cancelled.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the restoration."},"description":"The id of the restoration."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","description":"Why you are rejecting it. Required, up to 1,000 characters."}}},"example":{"reason":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"}}},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/restoration-requests/{id}/request-approval":{"post":{"operationId":"RestorationRequestsRequestApproval","tags":["data_protection"],"summary":"Restoration Requests Request Approval","security":[{"ApiKeyAuth":["restoration-requests:write"]},{"BearerAuth":[]},{"OAuth2":["restoration-requests:write"]}],"description":"Send a previewed restoration for approval. The people who can approve it are notified.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the restoration."},"description":"The id of the restoration."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","description":"An optional note, kept with the decision."}}},"example":{"notes":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"}}},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/restoration-requests/{id}/verify":{"post":{"operationId":"RestorationRequestsVerify","tags":["data_protection"],"summary":"Restoration Requests Verify","security":[{"ApiKeyAuth":["restoration-requests:write"]},{"BearerAuth":[]},{"OAuth2":["restoration-requests:write"]}],"description":"Check a finished restoration: compare the restored values with what was expected for every affected record, and report any that differ.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the restoration."},"description":"The id of the restoration."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","description":"An optional note, kept with the decision."}}},"example":{"notes":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"}}},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/retention-policies":{"get":{"operationId":"RetentionPoliciesList","tags":["data_protection"],"summary":"Retention Policies List","security":[{"ApiKeyAuth":["retention-policies:read"]},{"BearerAuth":[]},{"OAuth2":["retention-policies:read"]}],"description":"List your retention policies, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"connection_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only retention policies for this connection. Pass its id."},"description":"Only retention policies for this connection. Pass its id."},{"name":"entity_type","in":"query","required":false,"schema":{"type":"string","description":"Only retention policies whose entity type is exactly this."},"description":"Only retention policies whose entity type is exactly this."},{"name":"entity_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only retention policies whose entity type contains this text (upper and lower case are treated the same)."},"description":"Only retention policies whose entity type contains this text (upper and lower case are treated the same)."},{"name":"hot_retention_days_gte","in":"query","required":false,"schema":{"type":"number","description":"Only retention policies whose hot retention days is this number or more."},"description":"Only retention policies whose hot retention days is this number or more."},{"name":"hot_retention_days_lte","in":"query","required":false,"schema":{"type":"number","description":"Only retention policies whose hot retention days is this number or less."},"description":"Only retention policies whose hot retention days is this number or less."},{"name":"total_retention_days_gte","in":"query","required":false,"schema":{"type":"number","description":"Only retention policies whose total retention days is this number or more."},"description":"Only retention policies whose total retention days is this number or more."},{"name":"total_retention_days_lte","in":"query","required":false,"schema":{"type":"number","description":"Only retention policies whose total retention days is this number or less."},"description":"Only retention policies whose total retention days is this number or less."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many retention policies to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many retention policies to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many retention policies to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many retention policies to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","connection_id","entity_type","hot_retention_days","total_retention_days","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns retention policies where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns retention policies where any text field contains it (upper and lower case are treated the same)."},{"name":"connection_id_in","in":"query","required":false,"schema":{"type":"string","description":"Only retention policies whose connection is one of these values, separated by commas."},"description":"Only retention policies whose connection is one of these values, separated by commas."},{"name":"group","in":"query","required":false,"schema":{"type":"string","enum":["connection_id"],"description":"Count retention policies by this field instead of listing them: one count for each value it holds."},"description":"Count retention policies by this field instead of listing them: one count for each value it holds."},{"name":"facets","in":"query","required":false,"schema":{"type":"string","description":"Fields to count values for alongside the list, separated by commas, so you can see what each filter would match."},"description":"Fields to count values for alongside the list, separated by commas, so you can see what each filter would match."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid","nullable":true},"entity_type":{"type":"string","nullable":true},"hot_retention_days":{"type":"integer"},"total_retention_days":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","hot_retention_days":0,"total_retention_days":0,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"RetentionPoliciesCreate","tags":["data_protection"],"summary":"Retention Policies Create","security":[{"ApiKeyAuth":["retention-policies:write"]},{"BearerAuth":[]},{"OAuth2":["retention-policies:write"]}],"description":"Create a retention policy. Returns the new retention policy, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connection_id":{"type":"string","format":"uuid","nullable":true},"entity_type":{"type":"string","nullable":true},"hot_retention_days":{"type":"integer"},"total_retention_days":{"type":"integer"}}},"example":{"connection_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","hot_retention_days":0,"total_retention_days":0}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid","nullable":true},"entity_type":{"type":"string","nullable":true},"hot_retention_days":{"type":"integer"},"total_retention_days":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","hot_retention_days":0,"total_retention_days":0,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/retention-policies/{id}":{"delete":{"operationId":"RetentionPoliciesDelete","tags":["data_protection"],"summary":"Retention Policies Delete","security":[{"ApiKeyAuth":["retention-policies:delete"]},{"BearerAuth":[]},{"OAuth2":["retention-policies:delete"]}],"description":"Delete a retention policy permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the retention policy."},"description":"The id of the retention policy."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"RetentionPoliciesGet","tags":["data_protection"],"summary":"Retention Policies Get","security":[{"ApiKeyAuth":["retention-policies:read"]},{"BearerAuth":[]},{"OAuth2":["retention-policies:read"]}],"description":"Get one of your retention policies by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the retention policy."},"description":"The id of the retention policy."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid","nullable":true},"entity_type":{"type":"string","nullable":true},"hot_retention_days":{"type":"integer"},"total_retention_days":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","hot_retention_days":0,"total_retention_days":0,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"RetentionPoliciesUpdate","tags":["data_protection"],"summary":"Retention Policies Update","security":[{"ApiKeyAuth":["retention-policies:write"]},{"BearerAuth":[]},{"OAuth2":["retention-policies:write"]}],"description":"Change a retention policy. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the retention policy."},"description":"The id of the retention policy."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connection_id":{"type":"string","format":"uuid","nullable":true},"entity_type":{"type":"string","nullable":true},"hot_retention_days":{"type":"integer"},"total_retention_days":{"type":"integer"}}},"example":{"connection_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","hot_retention_days":0,"total_retention_days":0}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid","nullable":true},"entity_type":{"type":"string","nullable":true},"hot_retention_days":{"type":"integer"},"total_retention_days":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","hot_retention_days":0,"total_retention_days":0,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/retrieve/{recordId}":{"get":{"operationId":"GetArchivedRecord","tags":["retrieval"],"summary":"Get Archived Record","security":[{"ApiKeyAuth":["retrieve:read"]},{"BearerAuth":[]},{"OAuth2":["retrieve:read"]}],"description":"Get an archived record by its id. If it is in fast storage, it is returned straight away. If it is in long-term storage, Inferrex starts bringing it back (or carries on if already started) and tells you roughly how long it will take.","parameters":[{"name":"recordId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the archived record."},"description":"The id of the archived record."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"string"},"record":{"type":"object","additionalProperties":true},"metadata":{"type":"object","additionalProperties":true},"etaHours":{"type":"number"}},"required":["state"]},"example":{"state":"string","record":{},"metadata":{},"etaHours":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/retrieve/{recordId}/status":{"get":{"operationId":"GetArchivedRecordStatus","tags":["retrieval"],"summary":"Get Archived Record Status","security":[{"ApiKeyAuth":["retrieve:read"]},{"BearerAuth":[]},{"OAuth2":["retrieve:read"]}],"description":"Check whether an archived record in long-term storage is ready to read yet, and roughly how long it will take.","parameters":[{"name":"recordId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the archived record."},"description":"The id of the archived record."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"accessTier":{"type":"string"},"rehydrationStatus":{"type":"string"},"requestedAt":{"type":"string"},"readyAt":{"type":"string"},"etaHours":{"type":"number"}},"required":["accessTier","rehydrationStatus"]},"example":{"accessTier":"string","rehydrationStatus":"string","requestedAt":"string","readyAt":"string","etaHours":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/schema/{entity}":{"get":{"operationId":"GetEntitySchema","tags":["schema"],"summary":"Get Entity Schema","security":[{"ApiKeyAuth":["schema:read"]},{"BearerAuth":[]},{"OAuth2":["schema:read"]}],"description":"The fields of one kind of record, with their types, so an app can display it. Comes from Inferrex’s own definition where there is one, otherwise from what it learned from your connected systems.","parameters":[{"name":"entity","in":"path","required":true,"schema":{"type":"string","description":"The kind of record."},"description":"The kind of record."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","description":"`declared` (the platform's own shape) or `inferred` (observed in this workspace's data)."},"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"},"format":{"type":"string"},"enum":{"type":"array","items":{"type":"string"}},"required":{"type":"boolean"},"readOnly":{"type":"boolean"},"relatedEntity":{"type":"string"},"description":{"type":"string"}},"required":["name","type"]},"nullable":true,"description":"Declared kinds: one entry per field."},"entity":{"type":"object","properties":{"displayName":{"type":"string"},"fields":{"type":"array","items":{"type":"object","properties":{"apiName":{"type":"string"},"displayName":{"type":"string"},"type":{"type":"string"},"required":{"type":"boolean"}},"required":["apiName","displayName","type","required"]}}},"required":["displayName","fields"],"nullable":true,"description":"Inferred kinds: the observed shape."}},"required":["kind"]},"example":{"kind":"string","fields":[{"name":"string","type":"string","format":"string","enum":["string"],"required":true,"readOnly":true,"relatedEntity":"string","description":"string"}],"entity":{"displayName":"string","fields":[{"apiName":"string","displayName":"string","type":"string","required":true}]}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/search":{"get":{"operationId":"Search","tags":["search"],"summary":"Search","security":[{"ApiKeyAuth":["search:read"]},{"BearerAuth":[]},{"OAuth2":["search:read"]}],"description":"Typed hits grouped by type, in a fixed order (system, object, field, pipeline, mapping, record), at most `limit` per type and 50 in all. `q` is trimmed and must be 2 to 100 characters. `types` is a comma-separated subset; omit it for all. Systems match by name or vendor key; objects and fields by name or API name in each live system's current description (a person's corrected field name counts); pipelines by name in the current environment; mappings by the names of their two systems; golden records by word prefix on their display fields (name, title, company and person names; email only for a role that may see personal data). Records need the Unified records module; without it they are listed in `unavailable`. Each hit carries `link`, the app address to open, plus the ids to build another one.","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":2,"maxLength":100,"description":"What to search for. Trimmed; 2 to 100 characters."},"description":"What to search for. Trimmed; 2 to 100 characters."},{"name":"types","in":"query","required":false,"schema":{"type":"string","maxLength":200,"description":"Comma-separated: system, object, field, pipeline, mapping, record. Omit for all. Unknown names are reported in `unavailable`."},"description":"Comma-separated: system, object, field, pipeline, mapping, record. Omit for all. Unknown names are reported in `unavailable`."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":20,"description":"Hits per type.","default":5},"description":"Hits per type."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"q":{"type":"string","description":"The query as searched (trimmed)."},"groups":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"system | object | field | pipeline | mapping | record"},"label":{"type":"string","description":"Plural heading for the group, e.g. \"Systems\"."},"truncated":{"type":"boolean","description":"More matches exist than are shown."},"hits":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"id":{"type":"string","description":"Unique within the type: a system/pipeline/mapping id, `<systemId>:<objectId>` for an object, `<systemId>:<objectId>.<fieldId>` for a field, the golden record's entity cluster id for a record."},"title":{"type":"string"},"subtitle":{"type":"string","nullable":true,"description":"Where it lives, e.g. \"Salesforce · Account\" for a field, or the kind of record."},"link":{"type":"string","description":"App address to open: /systems/:id/review, /systems/:id/objects?object=…[&field=…], /pipelines/:id/overview, /mappings/:id/fields, /records/:kind/:id."},"systemId":{"type":"string","nullable":true,"description":"The system (connection) the hit belongs to."},"objectId":{"type":"string","nullable":true,"description":"Object id within the system's description (objects and fields)."},"fieldId":{"type":"string","nullable":true,"description":"Field id within the object (fields)."},"status":{"type":"string","nullable":true,"description":"Status of a system, pipeline or mapping; `excluded` on a field a person excluded from the system's description."},"sensitivity":{"type":"string","nullable":true,"description":"Data sensitivity class of a field (pii, financial, health, credential)."}},"required":["type","id","title","link"]}}},"required":["type","label","truncated","hits"]},"description":"One group per searched type that matched, in the fixed order. A group the 50-hit total emptied is still listed, with no hits and truncated true."},"unavailable":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"reason":{"type":"string"}},"required":["type","reason"]},"description":"Types asked for but not searched, with why: source_unavailable (the store behind that type did not answer; the other types still did) or unknown_type."}},"required":["q","groups","unavailable"]},"example":{"q":"string","groups":[{"type":"string","label":"string","truncated":true,"hits":[{"type":"string","id":"string","title":"string","subtitle":"string","link":"string","systemId":"string","objectId":"string","fieldId":"string","status":"string","sensitivity":"string"}]}],"unavailable":[{"type":"string","reason":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/secrets":{"get":{"operationId":"TenantSecretsList","tags":["core"],"summary":"Tenant Secrets List","security":[{"ApiKeyAuth":["secrets:read"]},{"BearerAuth":[]},{"OAuth2":["secrets:read"]}],"description":"List your secrets, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"key","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose key is exactly this."},"description":"Only secrets whose key is exactly this."},{"name":"key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose key contains this text (upper and lower case are treated the same)."},"description":"Only secrets whose key contains this text (upper and lower case are treated the same)."},{"name":"source","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose source is exactly this."},"description":"Only secrets whose source is exactly this."},{"name":"source_contains","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose source contains this text (upper and lower case are treated the same)."},"description":"Only secrets whose source contains this text (upper and lower case are treated the same)."},{"name":"value","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose value is exactly this."},"description":"Only secrets whose value is exactly this."},{"name":"value_contains","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose value contains this text (upper and lower case are treated the same)."},"description":"Only secrets whose value contains this text (upper and lower case are treated the same)."},{"name":"auth_method","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose auth method is exactly this."},"description":"Only secrets whose auth method is exactly this."},{"name":"auth_method_contains","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose auth method contains this text (upper and lower case are treated the same)."},"description":"Only secrets whose auth method contains this text (upper and lower case are treated the same)."},{"name":"external_provider","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose external provider is exactly this."},"description":"Only secrets whose external provider is exactly this."},{"name":"external_provider_contains","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose external provider contains this text (upper and lower case are treated the same)."},"description":"Only secrets whose external provider contains this text (upper and lower case are treated the same)."},{"name":"external_ref","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose external ref is exactly this."},"description":"Only secrets whose external ref is exactly this."},{"name":"external_ref_contains","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose external ref contains this text (upper and lower case are treated the same)."},"description":"Only secrets whose external ref contains this text (upper and lower case are treated the same)."},{"name":"external_auth_key","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose external auth key is exactly this."},"description":"Only secrets whose external auth key is exactly this."},{"name":"external_auth_key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose external auth key contains this text (upper and lower case are treated the same)."},"description":"Only secrets whose external auth key contains this text (upper and lower case are treated the same)."},{"name":"user_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only secrets for this user. Pass its id."},"description":"Only secrets for this user. Pass its id."},{"name":"description","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose description is exactly this."},"description":"Only secrets whose description is exactly this."},{"name":"description_contains","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose description contains this text (upper and lower case are treated the same)."},"description":"Only secrets whose description contains this text (upper and lower case are treated the same)."},{"name":"owner_connection_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only secrets for this owner connection. Pass its id."},"description":"Only secrets for this owner connection. Pass its id."},{"name":"purpose","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose purpose is exactly this."},"description":"Only secrets whose purpose is exactly this."},{"name":"purpose_contains","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose purpose contains this text (upper and lower case are treated the same)."},"description":"Only secrets whose purpose contains this text (upper and lower case are treated the same)."},{"name":"identity_source","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose identity source is exactly this."},"description":"Only secrets whose identity source is exactly this."},{"name":"identity_source_contains","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose identity source contains this text (upper and lower case are treated the same)."},"description":"Only secrets whose identity source contains this text (upper and lower case are treated the same)."},{"name":"api_base_url","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose api base url is exactly this."},"description":"Only secrets whose api base url is exactly this."},{"name":"api_base_url_contains","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose api base url contains this text (upper and lower case are treated the same)."},"description":"Only secrets whose api base url contains this text (upper and lower case are treated the same)."},{"name":"tags_contains","in":"query","required":false,"schema":{"type":"string"}},{"name":"value_saved_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only secrets whose value saved time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only secrets whose value saved time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"value_saved_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only secrets whose value saved time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only secrets whose value saved time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"value_saved_by","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose value saved by is exactly this."},"description":"Only secrets whose value saved by is exactly this."},{"name":"value_saved_by_contains","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose value saved by contains this text (upper and lower case are treated the same)."},"description":"Only secrets whose value saved by contains this text (upper and lower case are treated the same)."},{"name":"last_used_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only secrets whose last used time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only secrets whose last used time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"last_used_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only secrets whose last used time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only secrets whose last used time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"last_outcome","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose last outcome is exactly this."},"description":"Only secrets whose last outcome is exactly this."},{"name":"last_outcome_contains","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose last outcome contains this text (upper and lower case are treated the same)."},"description":"Only secrets whose last outcome contains this text (upper and lower case are treated the same)."},{"name":"last_outcome_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only secrets whose last outcome time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only secrets whose last outcome time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"last_outcome_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only secrets whose last outcome time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only secrets whose last outcome time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"last_outcome_status_gte","in":"query","required":false,"schema":{"type":"number","description":"Only secrets whose last outcome status is this number or more."},"description":"Only secrets whose last outcome status is this number or more."},{"name":"last_outcome_status_lte","in":"query","required":false,"schema":{"type":"number","description":"Only secrets whose last outcome status is this number or less."},"description":"Only secrets whose last outcome status is this number or less."},{"name":"last_outcome_detail","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose last outcome detail is exactly this."},"description":"Only secrets whose last outcome detail is exactly this."},{"name":"last_outcome_detail_contains","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose last outcome detail contains this text (upper and lower case are treated the same)."},"description":"Only secrets whose last outcome detail contains this text (upper and lower case are treated the same)."},{"name":"last_outcome_source","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose last outcome source is exactly this."},"description":"Only secrets whose last outcome source is exactly this."},{"name":"last_outcome_source_contains","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose last outcome source contains this text (upper and lower case are treated the same)."},"description":"Only secrets whose last outcome source contains this text (upper and lower case are treated the same)."},{"name":"last_outcome_connection_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only secrets for this last outcome connection. Pass its id."},"description":"Only secrets for this last outcome connection. Pass its id."},{"name":"last_tested_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only secrets whose last tested time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only secrets whose last tested time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"last_tested_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only secrets whose last tested time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only secrets whose last tested time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"failing_since_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only secrets whose failing since is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only secrets whose failing since is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"failing_since_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only secrets whose failing since is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only secrets whose failing since is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"last_notified_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only secrets whose last notified time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only secrets whose last notified time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"last_notified_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only secrets whose last notified time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only secrets whose last notified time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"last_notified_outcome","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose last notified outcome is exactly this."},"description":"Only secrets whose last notified outcome is exactly this."},{"name":"last_notified_outcome_contains","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose last notified outcome contains this text (upper and lower case are treated the same)."},"description":"Only secrets whose last notified outcome contains this text (upper and lower case are treated the same)."},{"name":"rotation_role","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose rotation role is exactly this."},"description":"Only secrets whose rotation role is exactly this."},{"name":"rotation_role_contains","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose rotation role contains this text (upper and lower case are treated the same)."},"description":"Only secrets whose rotation role contains this text (upper and lower case are treated the same)."},{"name":"rotation_of","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose rotation of is exactly this."},"description":"Only secrets whose rotation of is exactly this."},{"name":"rotation_of_contains","in":"query","required":false,"schema":{"type":"string","description":"Only secrets whose rotation of contains this text (upper and lower case are treated the same)."},"description":"Only secrets whose rotation of contains this text (upper and lower case are treated the same)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many secrets to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many secrets to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many secrets to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many secrets to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","key","source","value","auth_method","external_provider","external_ref","external_auth_key","user_id","description","created_at","updated_at","owner_connection_id","purpose","identity_source","api_base_url","value_saved_at","value_saved_by","last_used_at","last_outcome","last_outcome_at","last_outcome_status","last_outcome_detail","last_outcome_source","last_outcome_connection_id","last_tested_at","failing_since","last_notified_at","last_notified_outcome","rotation_role","rotation_of"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns secrets where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns secrets where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"key":{"type":"string"},"source":{"type":"string"},"value":{"type":"string","nullable":true},"auth_method":{"type":"string","nullable":true},"external_provider":{"type":"string","nullable":true},"external_ref":{"type":"string","nullable":true},"external_auth_key":{"type":"string","nullable":true},"user_id":{"type":"string","format":"uuid","nullable":true},"description":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"owner_connection_id":{"type":"string","format":"uuid","nullable":true,"description":"The connection this secret was made for. Empty for a workspace secret any system may name. For a secret kept with its connection (source connection), the connection that holds its value."},"purpose":{"type":"string","nullable":true,"description":"What the secret is for: sign-in, project-token, access-key, vault-reader, inbound-push, webhook-secret, or your own word."},"identity_source":{"type":"string","description":"How its identity is known: recorded when it was saved, derived from its name or the systems that use it, or unknown."},"api_base_url":{"type":"string","nullable":true,"description":"The address of the API it signs in to, as it was when the secret was saved."},"tags":{"type":"array","items":{"type":"string"},"description":"Your own labels for the secret."},"value_saved_at":{"type":"string","nullable":true,"description":"When the value in use was saved or last replaced."},"value_saved_by":{"type":"string","nullable":true,"description":"Who saved or last replaced the value: a workspace member id, or what did it (oauth-consent, migration:V214, …)."},"last_used_at":{"type":"string","nullable":true,"description":"When a sync or a test last signed in with it."},"last_outcome":{"type":"string","nullable":true,"description":"What the API last did with it: accepted, refused, or inconclusive (no clear answer)."},"last_outcome_at":{"type":"string","nullable":true},"last_outcome_status":{"type":"integer","nullable":true,"description":"The HTTP status of that answer, when there was one."},"last_outcome_detail":{"type":"string","nullable":true,"description":"That answer in a sentence, naming the secret, never its value."},"last_outcome_source":{"type":"string","nullable":true,"description":"Where it was learned: rotation-test, test-now, connection-test, sync or bloomreach."},"last_outcome_connection_id":{"type":"string","format":"uuid","nullable":true,"description":"The system that gave that answer."},"last_tested_at":{"type":"string","nullable":true,"description":"When it was last tested on purpose (a rotation test or Test now)."},"failing_since":{"type":"string","nullable":true,"description":"Since when it has been refused; empty while it is accepted or untested."},"last_notified_at":{"type":"string","nullable":true,"description":"When people were last told it failed or recovered."},"last_notified_outcome":{"type":"string","nullable":true},"rotation_role":{"type":"string","nullable":true,"description":"candidate: a new value saved but not in use until a test passes. previous: the value a rotation replaced, kept so it can be put back."},"rotation_of":{"type":"string","nullable":true,"description":"The name of the secret in use that this one stands beside."}},"required":["customer_id","key"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","key":"string","source":"string","value":"string","auth_method":"string","external_provider":"string","external_ref":"string","external_auth_key":"string","user_id":"00000000-0000-0000-0000-000000000000","description":"string","created_at":"string","updated_at":"string","owner_connection_id":"00000000-0000-0000-0000-000000000000","purpose":"string","identity_source":"string","api_base_url":"string","tags":["string"],"value_saved_at":"string","value_saved_by":"string","last_used_at":"string","last_outcome":"string","last_outcome_at":"string","last_outcome_status":0,"last_outcome_detail":"string","last_outcome_source":"string","last_outcome_connection_id":"00000000-0000-0000-0000-000000000000","last_tested_at":"string","failing_since":"string","last_notified_at":"string","last_notified_outcome":"string","rotation_role":"string","rotation_of":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"TenantSecretsCreate","tags":["core"],"summary":"Tenant Secrets Create","security":[{"ApiKeyAuth":["secrets:write"]},{"BearerAuth":[]},{"OAuth2":["secrets:write"]}],"description":"Create a secret. Returns the new secret, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"},"description":{"type":"string","nullable":true},"purpose":{"type":"string","nullable":true,"description":"What the secret is for: sign-in, project-token, access-key, vault-reader, inbound-push, webhook-secret, or your own word."},"tags":{"type":"array","items":{"type":"string"},"description":"Your own labels for the secret."},"personal":{"type":"boolean","description":"Keep this private to you. Omit or set false to share it with the whole workspace."}},"required":["key"]},"example":{"key":"string","description":"string","purpose":"string","tags":["string"],"personal":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"key":{"type":"string"},"source":{"type":"string"},"value":{"type":"string","nullable":true},"auth_method":{"type":"string","nullable":true},"external_provider":{"type":"string","nullable":true},"external_ref":{"type":"string","nullable":true},"external_auth_key":{"type":"string","nullable":true},"user_id":{"type":"string","format":"uuid","nullable":true},"description":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"owner_connection_id":{"type":"string","format":"uuid","nullable":true,"description":"The connection this secret was made for. Empty for a workspace secret any system may name. For a secret kept with its connection (source connection), the connection that holds its value."},"purpose":{"type":"string","nullable":true,"description":"What the secret is for: sign-in, project-token, access-key, vault-reader, inbound-push, webhook-secret, or your own word."},"identity_source":{"type":"string","description":"How its identity is known: recorded when it was saved, derived from its name or the systems that use it, or unknown."},"api_base_url":{"type":"string","nullable":true,"description":"The address of the API it signs in to, as it was when the secret was saved."},"tags":{"type":"array","items":{"type":"string"},"description":"Your own labels for the secret."},"value_saved_at":{"type":"string","nullable":true,"description":"When the value in use was saved or last replaced."},"value_saved_by":{"type":"string","nullable":true,"description":"Who saved or last replaced the value: a workspace member id, or what did it (oauth-consent, migration:V214, …)."},"last_used_at":{"type":"string","nullable":true,"description":"When a sync or a test last signed in with it."},"last_outcome":{"type":"string","nullable":true,"description":"What the API last did with it: accepted, refused, or inconclusive (no clear answer)."},"last_outcome_at":{"type":"string","nullable":true},"last_outcome_status":{"type":"integer","nullable":true,"description":"The HTTP status of that answer, when there was one."},"last_outcome_detail":{"type":"string","nullable":true,"description":"That answer in a sentence, naming the secret, never its value."},"last_outcome_source":{"type":"string","nullable":true,"description":"Where it was learned: rotation-test, test-now, connection-test, sync or bloomreach."},"last_outcome_connection_id":{"type":"string","format":"uuid","nullable":true,"description":"The system that gave that answer."},"last_tested_at":{"type":"string","nullable":true,"description":"When it was last tested on purpose (a rotation test or Test now)."},"failing_since":{"type":"string","nullable":true,"description":"Since when it has been refused; empty while it is accepted or untested."},"last_notified_at":{"type":"string","nullable":true,"description":"When people were last told it failed or recovered."},"last_notified_outcome":{"type":"string","nullable":true},"rotation_role":{"type":"string","nullable":true,"description":"candidate: a new value saved but not in use until a test passes. previous: the value a rotation replaced, kept so it can be put back."},"rotation_of":{"type":"string","nullable":true,"description":"The name of the secret in use that this one stands beside."}},"required":["customer_id","key"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","key":"string","source":"string","value":"string","auth_method":"string","external_provider":"string","external_ref":"string","external_auth_key":"string","user_id":"00000000-0000-0000-0000-000000000000","description":"string","created_at":"string","updated_at":"string","owner_connection_id":"00000000-0000-0000-0000-000000000000","purpose":"string","identity_source":"string","api_base_url":"string","tags":["string"],"value_saved_at":"string","value_saved_by":"string","last_used_at":"string","last_outcome":"string","last_outcome_at":"string","last_outcome_status":0,"last_outcome_detail":"string","last_outcome_source":"string","last_outcome_connection_id":"00000000-0000-0000-0000-000000000000","last_tested_at":"string","failing_since":"string","last_notified_at":"string","last_notified_outcome":"string","rotation_role":"string","rotation_of":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/secrets/{id}":{"delete":{"operationId":"TenantSecretsDelete","tags":["core"],"summary":"Tenant Secrets Delete","security":[{"ApiKeyAuth":["secrets:delete"]},{"BearerAuth":[]},{"OAuth2":["secrets:delete"]}],"description":"Delete a secret permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the secret."},"description":"The id of the secret."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"TenantSecretsGet","tags":["core"],"summary":"Tenant Secrets Get","security":[{"ApiKeyAuth":["secrets:read"]},{"BearerAuth":[]},{"OAuth2":["secrets:read"]}],"description":"Get one of your secrets by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the secret."},"description":"The id of the secret."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"key":{"type":"string"},"source":{"type":"string"},"value":{"type":"string","nullable":true},"auth_method":{"type":"string","nullable":true},"external_provider":{"type":"string","nullable":true},"external_ref":{"type":"string","nullable":true},"external_auth_key":{"type":"string","nullable":true},"user_id":{"type":"string","format":"uuid","nullable":true},"description":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"owner_connection_id":{"type":"string","format":"uuid","nullable":true,"description":"The connection this secret was made for. Empty for a workspace secret any system may name. For a secret kept with its connection (source connection), the connection that holds its value."},"purpose":{"type":"string","nullable":true,"description":"What the secret is for: sign-in, project-token, access-key, vault-reader, inbound-push, webhook-secret, or your own word."},"identity_source":{"type":"string","description":"How its identity is known: recorded when it was saved, derived from its name or the systems that use it, or unknown."},"api_base_url":{"type":"string","nullable":true,"description":"The address of the API it signs in to, as it was when the secret was saved."},"tags":{"type":"array","items":{"type":"string"},"description":"Your own labels for the secret."},"value_saved_at":{"type":"string","nullable":true,"description":"When the value in use was saved or last replaced."},"value_saved_by":{"type":"string","nullable":true,"description":"Who saved or last replaced the value: a workspace member id, or what did it (oauth-consent, migration:V214, …)."},"last_used_at":{"type":"string","nullable":true,"description":"When a sync or a test last signed in with it."},"last_outcome":{"type":"string","nullable":true,"description":"What the API last did with it: accepted, refused, or inconclusive (no clear answer)."},"last_outcome_at":{"type":"string","nullable":true},"last_outcome_status":{"type":"integer","nullable":true,"description":"The HTTP status of that answer, when there was one."},"last_outcome_detail":{"type":"string","nullable":true,"description":"That answer in a sentence, naming the secret, never its value."},"last_outcome_source":{"type":"string","nullable":true,"description":"Where it was learned: rotation-test, test-now, connection-test, sync or bloomreach."},"last_outcome_connection_id":{"type":"string","format":"uuid","nullable":true,"description":"The system that gave that answer."},"last_tested_at":{"type":"string","nullable":true,"description":"When it was last tested on purpose (a rotation test or Test now)."},"failing_since":{"type":"string","nullable":true,"description":"Since when it has been refused; empty while it is accepted or untested."},"last_notified_at":{"type":"string","nullable":true,"description":"When people were last told it failed or recovered."},"last_notified_outcome":{"type":"string","nullable":true},"rotation_role":{"type":"string","nullable":true,"description":"candidate: a new value saved but not in use until a test passes. previous: the value a rotation replaced, kept so it can be put back."},"rotation_of":{"type":"string","nullable":true,"description":"The name of the secret in use that this one stands beside."}},"required":["customer_id","key"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","key":"string","source":"string","value":"string","auth_method":"string","external_provider":"string","external_ref":"string","external_auth_key":"string","user_id":"00000000-0000-0000-0000-000000000000","description":"string","created_at":"string","updated_at":"string","owner_connection_id":"00000000-0000-0000-0000-000000000000","purpose":"string","identity_source":"string","api_base_url":"string","tags":["string"],"value_saved_at":"string","value_saved_by":"string","last_used_at":"string","last_outcome":"string","last_outcome_at":"string","last_outcome_status":0,"last_outcome_detail":"string","last_outcome_source":"string","last_outcome_connection_id":"00000000-0000-0000-0000-000000000000","last_tested_at":"string","failing_since":"string","last_notified_at":"string","last_notified_outcome":"string","rotation_role":"string","rotation_of":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"TenantSecretsUpdate","tags":["core"],"summary":"Tenant Secrets Update","security":[{"ApiKeyAuth":["secrets:write"]},{"BearerAuth":[]},{"OAuth2":["secrets:write"]}],"description":"Change a secret. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the secret."},"description":"The id of the secret."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"},"description":{"type":"string","nullable":true},"purpose":{"type":"string","nullable":true,"description":"What the secret is for: sign-in, project-token, access-key, vault-reader, inbound-push, webhook-secret, or your own word."},"tags":{"type":"array","items":{"type":"string"},"description":"Your own labels for the secret."}}},"example":{"key":"string","description":"string","purpose":"string","tags":["string"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"key":{"type":"string"},"source":{"type":"string"},"value":{"type":"string","nullable":true},"auth_method":{"type":"string","nullable":true},"external_provider":{"type":"string","nullable":true},"external_ref":{"type":"string","nullable":true},"external_auth_key":{"type":"string","nullable":true},"user_id":{"type":"string","format":"uuid","nullable":true},"description":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"owner_connection_id":{"type":"string","format":"uuid","nullable":true,"description":"The connection this secret was made for. Empty for a workspace secret any system may name. For a secret kept with its connection (source connection), the connection that holds its value."},"purpose":{"type":"string","nullable":true,"description":"What the secret is for: sign-in, project-token, access-key, vault-reader, inbound-push, webhook-secret, or your own word."},"identity_source":{"type":"string","description":"How its identity is known: recorded when it was saved, derived from its name or the systems that use it, or unknown."},"api_base_url":{"type":"string","nullable":true,"description":"The address of the API it signs in to, as it was when the secret was saved."},"tags":{"type":"array","items":{"type":"string"},"description":"Your own labels for the secret."},"value_saved_at":{"type":"string","nullable":true,"description":"When the value in use was saved or last replaced."},"value_saved_by":{"type":"string","nullable":true,"description":"Who saved or last replaced the value: a workspace member id, or what did it (oauth-consent, migration:V214, …)."},"last_used_at":{"type":"string","nullable":true,"description":"When a sync or a test last signed in with it."},"last_outcome":{"type":"string","nullable":true,"description":"What the API last did with it: accepted, refused, or inconclusive (no clear answer)."},"last_outcome_at":{"type":"string","nullable":true},"last_outcome_status":{"type":"integer","nullable":true,"description":"The HTTP status of that answer, when there was one."},"last_outcome_detail":{"type":"string","nullable":true,"description":"That answer in a sentence, naming the secret, never its value."},"last_outcome_source":{"type":"string","nullable":true,"description":"Where it was learned: rotation-test, test-now, connection-test, sync or bloomreach."},"last_outcome_connection_id":{"type":"string","format":"uuid","nullable":true,"description":"The system that gave that answer."},"last_tested_at":{"type":"string","nullable":true,"description":"When it was last tested on purpose (a rotation test or Test now)."},"failing_since":{"type":"string","nullable":true,"description":"Since when it has been refused; empty while it is accepted or untested."},"last_notified_at":{"type":"string","nullable":true,"description":"When people were last told it failed or recovered."},"last_notified_outcome":{"type":"string","nullable":true},"rotation_role":{"type":"string","nullable":true,"description":"candidate: a new value saved but not in use until a test passes. previous: the value a rotation replaced, kept so it can be put back."},"rotation_of":{"type":"string","nullable":true,"description":"The name of the secret in use that this one stands beside."}},"required":["customer_id","key"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","key":"string","source":"string","value":"string","auth_method":"string","external_provider":"string","external_ref":"string","external_auth_key":"string","user_id":"00000000-0000-0000-0000-000000000000","description":"string","created_at":"string","updated_at":"string","owner_connection_id":"00000000-0000-0000-0000-000000000000","purpose":"string","identity_source":"string","api_base_url":"string","tags":["string"],"value_saved_at":"string","value_saved_by":"string","last_used_at":"string","last_outcome":"string","last_outcome_at":"string","last_outcome_status":0,"last_outcome_detail":"string","last_outcome_source":"string","last_outcome_connection_id":"00000000-0000-0000-0000-000000000000","last_tested_at":"string","failing_since":"string","last_notified_at":"string","last_notified_outcome":"string","rotation_role":"string","rotation_of":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/secrets/{id}/promote":{"post":{"operationId":"PromoteSecret","tags":["credentials"],"summary":"Promote Secret","security":[{"ApiKeyAuth":["secrets:write"]},{"BearerAuth":[]},{"OAuth2":["secrets:write"]}],"description":"Make a stand-by copy of a secret the one in use. It is tested first against the systems that use the secret; if any refuses it, nothing changes unless force is set.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the stand-by copy."},"description":"The id of the stand-by copy."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"force":{"type":"boolean","description":"Put it in use even if a test does not pass."}}},"example":{"force":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"The secret now holding the new value: the live secret's name when it went live, else the stand-by copy's."},"live":{"type":"boolean","description":"Whether the new value is now in use."},"forced":{"type":"boolean","description":"It went live only because force was set."},"outcome":{"type":"string","description":"The worst test answer: accepted, refused, inconclusive, or untested."},"message":{"type":"string"},"previousKey":{"type":"string","nullable":true,"description":"Where the replaced value is kept, so it can be put back."},"candidateKey":{"type":"string","nullable":true,"description":"The new value's stand-by copy while it waits for a passing test; null once it is live."},"tests":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"connectionName":{"type":"string"},"testOutcome":{"type":"string","description":"The connection test's own answer: signed-in, credentials-rejected, forbidden, not-found, unreachable, redirect or not-testable."},"outcome":{"type":"string","description":"What it means for the secret. accepted: the API took it — a signed-in read of a declared endpoint answered 2xx with data (testOutcome signed-in). refused: 401 or 403. inconclusive: anything else, any 404 and the bare base address included."},"httpStatus":{"type":"integer","nullable":true},"detail":{"type":"string","description":"The answer in plain words. A refusal names the secret, its purpose and who saved it when; never its value."},"testedUrlTemplate":{"type":"string"},"provedBy":{"type":"string","nullable":true,"description":"The endpoint whose answer proved the read; null unless accepted."}},"required":["connectionId","connectionName","testOutcome","outcome","httpStatus","detail","testedUrlTemplate","provedBy"]}}},"required":["key","live","forced","outcome","message","previousKey","candidateKey","tests"]},"example":{"key":"string","live":true,"forced":true,"outcome":"string","message":"string","previousKey":"string","candidateKey":"string","tests":[{"connectionId":"00000000-0000-0000-0000-000000000000","connectionName":"string","testOutcome":"string","outcome":"string","httpStatus":0,"detail":"string","testedUrlTemplate":"string","provedBy":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/secrets/{id}/rotate":{"post":{"operationId":"RotateSecret","tags":["credentials"],"summary":"Rotate Secret","security":[{"ApiKeyAuth":["secrets:write"]},{"BearerAuth":[]},{"OAuth2":["secrets:write"]}],"description":"Rotate a secret safely. The new value is tested against each system that uses the secret before anything switches over; if any refuses it, the old value stays in use and the answer says which system refused and why. Pass force: true to switch anyway. A secret kept in your own vault is rotated there; use Test now afterwards.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the secret."},"description":"The id of the secret."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"value":{"type":"string","maxLength":16384,"description":"The new value: a single key, or a JSON object of fields. Stored encrypted; never returned."},"values":{"type":"object","additionalProperties":true,"description":"The new value by field name, such as {\"username\": \"…\", \"password\": \"…\"}, instead of value."},"authMethod":{"type":"string","maxLength":40,"description":"How the new value signs in, when it changes."},"force":{"type":"boolean","description":"Use the new value even if a test does not pass."}}},"example":{"value":"string","values":{},"authMethod":"string","force":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"The secret now holding the new value: the live secret's name when it went live, else the stand-by copy's."},"live":{"type":"boolean","description":"Whether the new value is now in use."},"forced":{"type":"boolean","description":"It went live only because force was set."},"outcome":{"type":"string","description":"The worst test answer: accepted, refused, inconclusive, or untested."},"message":{"type":"string"},"previousKey":{"type":"string","nullable":true,"description":"Where the replaced value is kept, so it can be put back."},"candidateKey":{"type":"string","nullable":true,"description":"The new value's stand-by copy while it waits for a passing test; null once it is live."},"tests":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"connectionName":{"type":"string"},"testOutcome":{"type":"string","description":"The connection test's own answer: signed-in, credentials-rejected, forbidden, not-found, unreachable, redirect or not-testable."},"outcome":{"type":"string","description":"What it means for the secret. accepted: the API took it — a signed-in read of a declared endpoint answered 2xx with data (testOutcome signed-in). refused: 401 or 403. inconclusive: anything else, any 404 and the bare base address included."},"httpStatus":{"type":"integer","nullable":true},"detail":{"type":"string","description":"The answer in plain words. A refusal names the secret, its purpose and who saved it when; never its value."},"testedUrlTemplate":{"type":"string"},"provedBy":{"type":"string","nullable":true,"description":"The endpoint whose answer proved the read; null unless accepted."}},"required":["connectionId","connectionName","testOutcome","outcome","httpStatus","detail","testedUrlTemplate","provedBy"]}}},"required":["key","live","forced","outcome","message","previousKey","candidateKey","tests"]},"example":{"key":"string","live":true,"forced":true,"outcome":"string","message":"string","previousKey":"string","candidateKey":"string","tests":[{"connectionId":"00000000-0000-0000-0000-000000000000","connectionName":"string","testOutcome":"string","outcome":"string","httpStatus":0,"detail":"string","testedUrlTemplate":"string","provedBy":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/secrets/{id}/share":{"post":{"operationId":"ShareOwnSecret","tags":["core"],"summary":"Share Own Secret","security":[{"ApiKeyAuth":["secrets:write"]},{"BearerAuth":[]},{"OAuth2":["secrets:write"]}],"description":"Share one of your own personal secrets with the whole workspace, so connections can use it. Only the secret’s owner can do this. Refused if the workspace already has a shared secret with the same name. The value is never read.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the secret."},"description":"The id of the secret."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"personal":{"type":"boolean"}},"required":["id","key","personal"]},"example":{"id":"string","key":"string","personal":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/secrets/{id}/test":{"post":{"operationId":"TestSecret","tags":["credentials"],"summary":"Test Secret","security":[{"ApiKeyAuth":["secrets:write"]},{"BearerAuth":[]},{"OAuth2":["secrets:write"]}],"description":"Check, now, that every system using this secret still accepts it. Inferrex makes one signed-in request to each, records what happened on the secret and returns each answer. Only a proven read counts as accepted: a 2xx with data from a declared read endpoint (the provider's test path, a path to read, or a known object's list), named in provedBy. Any 404 (the base address's included), a 400, 429, 5xx, an HTML or error body, or an answer from the bare address is inconclusive. Nothing else changes.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the secret."},"description":"The id of the secret."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"},"outcome":{"type":"string","description":"accepted, refused, inconclusive, or untested (no system uses it)."},"message":{"type":"string"},"tests":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"connectionName":{"type":"string"},"testOutcome":{"type":"string","description":"The connection test's own answer: signed-in, credentials-rejected, forbidden, not-found, unreachable, redirect or not-testable."},"outcome":{"type":"string","description":"What it means for the secret. accepted: the API took it — a signed-in read of a declared endpoint answered 2xx with data (testOutcome signed-in). refused: 401 or 403. inconclusive: anything else, any 404 and the bare base address included."},"httpStatus":{"type":"integer","nullable":true},"detail":{"type":"string","description":"The answer in plain words. A refusal names the secret, its purpose and who saved it when; never its value."},"testedUrlTemplate":{"type":"string"},"provedBy":{"type":"string","nullable":true,"description":"The endpoint whose answer proved the read; null unless accepted."}},"required":["connectionId","connectionName","testOutcome","outcome","httpStatus","detail","testedUrlTemplate","provedBy"]}}},"required":["key","outcome","message","tests"]},"example":{"key":"string","outcome":"string","message":"string","tests":[{"connectionId":"00000000-0000-0000-0000-000000000000","connectionName":"string","testOutcome":"string","outcome":"string","httpStatus":0,"detail":"string","testedUrlTemplate":"string","provedBy":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/secrets/{id}/unshare":{"post":{"operationId":"UnshareOwnSecret","tags":["core"],"summary":"Unshare Own Secret","security":[{"ApiKeyAuth":["secrets:write"]},{"BearerAuth":[]},{"OAuth2":["secrets:write"]}],"description":"Make a workspace-shared secret private to you again. Needs permission to manage users. Refused while any connection uses the secret, because scheduled syncs can only use shared secrets and would stop working. The value is never read.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the secret."},"description":"The id of the secret."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"personal":{"type":"boolean"}},"required":["id","key","personal"]},"example":{"id":"string","key":"string","personal":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/secrets/{id}/withdraw":{"post":{"operationId":"WithdrawOwnTenantSecret","tags":["core"],"summary":"Withdraw Own Tenant Secret","security":[{"ApiKeyAuth":["secrets:write"]},{"BearerAuth":[]},{"OAuth2":["secrets:write"]}],"description":"Delete a personal secret that belongs to a member of your workspace. Needs permission to manage users (admins and the owner have it). The deletion is recorded by the secret’s name and who did it; the value is never read. A secret shared with the whole workspace cannot be deleted this way.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the secret."},"description":"The id of the secret."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"withdrawn":{"type":"boolean"}},"required":["id","key","withdrawn"]},"example":{"id":"string","key":"string","withdrawn":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/settings/api-keys":{"get":{"operationId":"ListApiKeys","tags":["settings"],"summary":"List Api Keys","security":[{"ApiKeyAuth":["settings:read"]},{"BearerAuth":[]},{"OAuth2":["settings:read"]}],"description":"List your workspace’s API keys, newest first: each key’s name, the start of the key so you can recognise it, what it may do, when it was last used, when it expires and whether it still works. The full key is never shown again.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"type":"object","additionalProperties":true}},"required":["keys"]},"example":{"keys":{}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"CreateApiKey","tags":["settings"],"summary":"Create Api Key","security":[{"ApiKeyAuth":["settings:write"]},{"BearerAuth":[]},{"OAuth2":["settings:write"]}],"description":"Create an API key, so a script or another system can use the Inferrex API on your workspace’s behalf. Choose what it may do (its scopes) and, optionally, when it expires. The key itself is shown once, in this response only: copy it somewhere safe. A key can only be given permissions that the key or person creating it already has.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"displayName":{"type":"string","minLength":1,"maxLength":255,"description":"A name to recognise the key by."},"scopes":{"type":"array","items":{"type":"string"},"description":"What the key may do, as scopes such as pipelines:read, or a preset. At least one is required."},"expiresInDays":{"type":"integer","minimum":1,"maximum":365,"description":"How many days until the key stops working, from 1 to 365. Leave out for a key that does not expire."}}},"example":{"displayName":"string","scopes":["string"],"expiresInDays":0}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string"},"prefix":{"type":"string"},"displayName":{"type":"string","nullable":true},"scopes":{"type":"array","items":{"type":"string"}},"expiresAt":{"type":"string","nullable":true},"createdAt":{"type":"string"}},"required":["id","key","prefix","scopes","createdAt"]},"example":{"id":"00000000-0000-0000-0000-000000000000","key":"string","prefix":"string","displayName":"string","scopes":["string"],"expiresAt":"string","createdAt":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/settings/api-keys/{keyId}":{"delete":{"operationId":"RevokeApiKey","tags":["settings"],"summary":"Revoke Api Key","security":[{"ApiKeyAuth":["settings:delete"]},{"BearerAuth":[]},{"OAuth2":["settings:delete"]}],"description":"Revoke an API key so it stops working immediately. This cannot be undone: create a new key if you need one.","parameters":[{"name":"keyId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the API key."},"description":"The id of the API key."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"revoked":{"type":"boolean"}},"required":["revoked"]},"example":{"revoked":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/settings/workspace/mfa":{"get":{"operationId":"GetWorkspaceMfa","tags":["workspace"],"summary":"Get Workspace Mfa","security":[{"ApiKeyAuth":["settings:read"]},{"BearerAuth":[]},{"OAuth2":["settings:read"]}],"description":"Whether your workspace requires two-step sign-in (MFA), and when that was switched on.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"mfaRequired":{"type":"boolean"},"enforcedAt":{"type":"string","nullable":true}},"required":["mfaRequired"]},"example":{"mfaRequired":true,"enforcedAt":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"SetWorkspaceMfa","tags":["workspace"],"summary":"Set Workspace Mfa","security":[{"ApiKeyAuth":["settings:write"]},{"BearerAuth":[]},{"OAuth2":["settings:write"]}],"description":"Switch the requirement for two-step sign-in (MFA) on or off for your workspace. The change is recorded in your audit trail.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mfaRequired":{"type":"boolean","description":"true to require two-step sign-in, false to stop requiring it."}},"required":["mfaRequired"]},"example":{"mfaRequired":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"mfaRequired":{"type":"boolean"},"enforcedAt":{"type":"string","nullable":true}},"required":["mfaRequired"]},"example":{"mfaRequired":true,"enforcedAt":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/settings/workspace/sign-in":{"get":{"operationId":"GetWorkspaceSignInPolicy","tags":["workspace"],"summary":"Get Workspace Sign In Policy","security":[{"ApiKeyAuth":["settings:read"]},{"BearerAuth":[]},{"OAuth2":["settings:read"]}],"description":"Whether people must sign in to this workspace by name before they can use it.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"requireNamedSignin":{"type":"boolean"}},"required":["requireNamedSignin"]},"example":{"requireNamedSignin":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"SetWorkspaceSignInPolicy","tags":["workspace"],"summary":"Set Workspace Sign In Policy","security":[{"ApiKeyAuth":["settings:write"]},{"BearerAuth":[]},{"OAuth2":["settings:write"]}],"description":"Choose whether people must sign in to this workspace by name, for example from its own sign-in link. When on, a member who signed in without naming this workspace cannot use it until they do. The change is recorded in your audit trail.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"requireNamedSignin":{"type":"boolean","description":"true to require signing in to this workspace by name, false to allow any sign-in."}},"required":["requireNamedSignin"]},"example":{"requireNamedSignin":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"requireNamedSignin":{"type":"boolean"}},"required":["requireNamedSignin"]},"example":{"requireNamedSignin":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/suggestions":{"get":{"operationId":"ListWorkspaceSuggestions","tags":["pipelines"],"summary":"List Workspace Suggestions","security":[{"ApiKeyAuth":["suggestions:read"]},{"BearerAuth":[]},{"OAuth2":["suggestions:read"]}],"description":"Pending suggestions across every pipeline in the authenticated workspace, not just the selected environment. Paged by limit and offset, ordered by confidence descending then suggestion id ascending. The total counts all matching suggestions, including when the requested page is empty.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":1000000,"default":0}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"suggestions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipeline_id":{"type":"string","format":"uuid"},"pipeline_name":{"type":"string"},"type":{"type":"string"},"title":{"type":"string"},"rationale":{"type":"string"},"estimated_value":{"type":"string","nullable":true},"confidence":{"type":"number"},"surfaced_at":{"type":"string","format":"date-time"}},"required":["id","pipeline_id","pipeline_name","type","title","rationale","estimated_value","confidence","surfaced_at"]}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["suggestions","total","limit","offset"]},"example":{"suggestions":[{"id":"00000000-0000-0000-0000-000000000000","pipeline_id":"00000000-0000-0000-0000-000000000000","pipeline_name":"string","type":"string","title":"string","rationale":"string","estimated_value":"string","confidence":0,"surfaced_at":"2026-01-01T00:00:00Z"}],"total":0,"limit":0,"offset":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/terms/accept":{"post":{"operationId":"AcceptTerms","tags":["terms"],"summary":"Accept Terms","security":[{"ApiKeyAuth":["terms:write"]},{"BearerAuth":[]},{"OAuth2":["terms:write"]}],"description":"Accept the terms of service. Send the version you were shown; it must be the current one, so your acceptance is recorded against the exact text you read.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"string","description":"The version of the terms you were shown."}},"required":["version"]},"example":{"version":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"accepted":{"type":"boolean"},"version":{"type":"string"},"acceptedAt":{"type":"string"}},"required":["accepted","version","acceptedAt"]},"example":{"accepted":true,"version":"string","acceptedAt":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/terms/status":{"get":{"operationId":"GetTermsStatus","tags":["terms"],"summary":"Get Terms Status","security":[{"ApiKeyAuth":["terms:read"]},{"BearerAuth":[]},{"OAuth2":["terms:read"]}],"description":"Whether your workspace has accepted the current terms of service, which version was accepted and when, and the full text of the current terms.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"accepted":{"type":"boolean"},"currentVersion":{"type":"string"},"acceptedVersion":{"type":"string","nullable":true},"acceptedAt":{"type":"string","nullable":true},"content":{"type":"array","items":{"type":"object","properties":{"heading":{"type":"string"},"body":{"type":"string"}},"required":["heading","body"]}}},"required":["accepted","currentVersion","content"]},"example":{"accepted":true,"currentVersion":"string","acceptedVersion":"string","acceptedAt":"string","content":[{"heading":"string","body":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/unified/records":{"delete":{"operationId":"UnifiedDeleteAction","tags":["unified_api"],"summary":"Unified Delete Action","security":[{"ApiKeyAuth":["unified:delete"]},{"BearerAuth":[]},{"OAuth2":["unified:delete"]}],"description":"Unified API provider deletion is not implemented. After request validation this endpoint returns 501; no provider delete is queued and golden records are unchanged.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"providerKey":{"type":"string","description":"Which connected system to delete from, by its catalogue key."},"externalId":{"type":"string","description":"The record’s id in that system."},"entityType":{"type":"string","description":"The kind of record, such as contact or invoice."}},"required":["providerKey","externalId"]},"example":{"providerKey":"string","externalId":"string","entityType":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","description":"Reserved result shape retained for API compatibility. Production returns the standard 501 error envelope without deleting a record."}},"required":["deleted"]},"example":{"deleted":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"UnifiedListAction","tags":["unified_api"],"summary":"Unified List Action","security":[{"ApiKeyAuth":["unified:read"]},{"BearerAuth":[]},{"OAuth2":["unified:read"]}],"description":"List your golden records, newest first. A golden record is the single, combined version of one real-world thing (a customer, an invoice) built from the records your connected systems hold about it. Filter by kind of record, quality score, how many fields it has or how many systems contributed, and page through with limit and offset.","parameters":[{"name":"entity_type","in":"query","required":false,"schema":{"type":"string","description":"Only golden records of this kind, such as customer or invoice."},"description":"Only golden records of this kind, such as customer or invoice."},{"name":"entity_type_in","in":"query","required":false,"schema":{"type":"string","description":"Only golden records of these kinds, separated by commas."},"description":"Only golden records of these kinds, separated by commas."},{"name":"quality_score_gte","in":"query","required":false,"schema":{"type":"number","description":"Only golden records with a quality score of at least this."},"description":"Only golden records with a quality score of at least this."},{"name":"quality_score_lte","in":"query","required":false,"schema":{"type":"number","description":"Only golden records with a quality score of at most this."},"description":"Only golden records with a quality score of at most this."},{"name":"field_count_gte","in":"query","required":false,"schema":{"type":"number","description":"Only golden records with at least this many fields."},"description":"Only golden records with at least this many fields."},{"name":"field_count_lte","in":"query","required":false,"schema":{"type":"number","description":"Only golden records with at most this many fields."},"description":"Only golden records with at most this many fields."},{"name":"source_count_gte","in":"query","required":false,"schema":{"type":"number","description":"Only golden records built from at least this many systems."},"description":"Only golden records built from at least this many systems."},{"name":"source_count_lte","in":"query","required":false,"schema":{"type":"number","description":"Only golden records built from at most this many systems."},"description":"Only golden records built from at most this many systems."},{"name":"created_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only golden records created on or after this date and time (ISO 8601)."},"description":"Only golden records created on or after this date and time (ISO 8601)."},{"name":"created_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only golden records created on or before this date and time (ISO 8601)."},"description":"Only golden records created on or before this date and time (ISO 8601)."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","description":"The field to sort by: entity_type, quality_score, field_count, source_count, version or created_at."},"description":"The field to sort by: entity_type, quality_score, field_count, source_count, version or created_at."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc or desc."},"description":"Sort direction: asc or desc."},{"name":"group","in":"query","required":false,"schema":{"type":"string","enum":["entity_type"],"description":"Count golden records by kind instead of listing them."},"description":"Count golden records by kind instead of listing them."},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":100,"description":"Search text: golden records whose name, title, company or person name contains it (upper and lower case are treated the same), and their email for a role that may see personal data. Combines with every other filter and with paging."},"description":"Search text: golden records whose name, title, company or person name contains it (upper and lower case are treated the same), and their email for a role that may see personal data. Combines with every other filter and with paging."},{"name":"facets","in":"query","required":false,"schema":{"type":"string","description":"Fields to count values for alongside the list, separated by commas."},"description":"Fields to count values for alongside the list, separated by commas."},{"name":"has_fields","in":"query","required":false,"schema":{"type":"string","maxLength":1500,"description":"Only golden records holding a value in every one of these fields, separated by commas (at most 10), e.g. email. With limit=1, `total` counts them. A field your role may not see is refused (403)."},"description":"Only golden records holding a value in every one of these fields, separated by commas (at most 10), e.g. email. With limit=1, `total` counts them. A field your role may not see is refused (403)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"description":"How many to return in one page: 1 to 100, 50 if you leave it out.","default":50},"description":"How many to return in one page: 1 to 100, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many to skip before this page starts.","default":0},"description":"How many to skip before this page starts."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"records":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"This version's id."},"customer_id":{"type":"string","format":"uuid"},"entity_cluster_id":{"type":"string","format":"uuid","description":"The golden record's stable id across versions — the `:entityClusterId` to open it."},"entity_type":{"type":"string","description":"The kind of record (contact, organisation, …). Open."},"version":{"type":"integer"},"data":{"type":"object","additionalProperties":true,"description":"The merged values, keyed by field name. The customer's own data, so its keys and values are open."},"source_attribution":{"type":"object","additionalProperties":{"type":"object","properties":{"provider":{"type":"string","description":"Provider key of the system whose value won."},"connectionId":{"type":"string","format":"uuid","description":"The connection the winning value came from."},"externalId":{"type":"string","description":"The winning record's id in that system (drives write-back). Absent on records merged before 2026-07-04."},"recordVersion":{"type":"integer"},"observedAt":{"type":"string","format":"date-time","description":"When the field was resolved."},"strategy":{"type":"string","description":"The rule that picked the value. Today: provider_wins, freshest, most_complete, most_accurate, manual. Absent before 2026-07-04."},"ruleApplied":{"type":"boolean","description":"An explicit field authority rule matched (false = the default, freshest). Absent before 2026-07-04."},"confidence":{"type":"number","minimum":0,"maximum":1,"description":"Share of systems that agree with the winning value, reduced when contested. Absent before 2026-07-04."},"contested":{"type":"boolean","description":"Systems disagree on this field beyond the conflict threshold. Absent before 2026-07-04."}},"required":["provider","connectionId","recordVersion","observedAt"]},"description":"Per field of the record, keyed by field name: where the value came from."},"quality_score":{"type":"string","description":"Quality score 0–100 as a decimal string (Postgres NUMERIC), e.g. \"87.50\"."},"field_count":{"type":"integer"},"source_count":{"type":"integer"},"proposal_id":{"type":"string","format":"uuid","nullable":true,"description":"The approved proposal that wrote this version."},"created_at":{"type":"string","format":"date-time"},"redacted_fields":{"type":"array","items":{"type":"string"},"description":"Dotted paths (`data.email`, `data.billing_details.phone`) of the values hidden from your role: pii, financial, credential or health data your role is not granted. Each is answered as null, as the fields route answers it. Empty when nothing is hidden."}},"required":["id","customer_id","entity_cluster_id","entity_type","version","data","source_attribution","quality_score","field_count","source_count","created_at","redacted_fields"]}},"total":{"type":"integer","description":"Rows matching the filters, before paging. Absent when `group` is asked for."},"facets":{"type":"object","properties":{"entity_type":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"count":{"type":"integer"}},"required":["value","count"]}}},"description":"Present when `facets=entity_type` is asked for: value → count over the same filters, at most 50."},"groups":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"count":{"type":"integer"}},"required":["key","count"]},"description":"Present when `group=entity_type` is asked for (records is then empty): one entry per kind of record, most records first, at most 50."},"truncated":{"type":"boolean","description":"With `group`: more than 50 kinds exist and only the first 50 are listed."}},"required":["records"]},"example":{"records":[{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","entity_cluster_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","version":0,"data":{},"source_attribution":{},"quality_score":"string","field_count":0,"source_count":0,"proposal_id":"00000000-0000-0000-0000-000000000000","created_at":"2026-01-01T00:00:00Z","redacted_fields":["string"]}],"total":0,"facets":{"entity_type":[{"value":"string","count":0}]},"groups":[{"key":"string","count":0}],"truncated":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"UnifiedCreateAction","tags":["unified_api"],"summary":"Unified Create Action","security":[{"ApiKeyAuth":["unified:write"]},{"BearerAuth":[]},{"OAuth2":["unified:write"]}],"description":"Unified API provider creation is not implemented. After request validation and translation this endpoint returns 501; no provider write is queued and golden records are unchanged.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"providerKey":{"type":"string","description":"Which connected system to write to, by its catalogue key."},"entityType":{"type":"string","description":"The kind of record to create, such as contact or invoice."},"fields":{"type":"object","additionalProperties":true,"description":"The record’s values, using Inferrex’s standard field names."}},"required":["providerKey","fields"]},"example":{"providerKey":"string","entityType":"string","fields":{}}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Reserved result flag retained for API compatibility. Production writes currently return 501, not a successful result."},"providerKey":{"type":"string"},"connectionId":{"type":"string","description":"The connection the write goes through."},"externalId":{"type":"string","description":"Reserved provider record identifier; no record is created or updated by the current 501 response."},"error":{"type":"string","description":"Present when success is false."},"writePayload":{"type":"object","properties":{"providerKey":{"type":"string"},"connectionId":{"type":"string"},"entityType":{"type":"string"},"providerFields":{"type":"object","additionalProperties":true,"description":"The fields in the system's own names. Its keys are that system's field names, so it has no fixed shape."},"unmappedFields":{"type":"array","items":{"type":"string"},"description":"Common-format fields with no mapping into this system; they were not sent."}},"required":["providerKey","connectionId","entityType","providerFields","unmappedFields"],"description":"Reserved translated-write shape. Current production execution returns 501 without sending or queuing it."}},"required":["success","providerKey","connectionId"]},"example":{"success":true,"providerKey":"string","connectionId":"string","externalId":"string","error":"string","writePayload":{"providerKey":"string","connectionId":"string","entityType":"string","providerFields":{},"unmappedFields":["string"]}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"UnifiedUpdateAction","tags":["unified_api"],"summary":"Unified Update Action","security":[{"ApiKeyAuth":["unified:write"]},{"BearerAuth":[]},{"OAuth2":["unified:write"]}],"description":"Unified API provider updates are not implemented. After request validation and translation this endpoint returns 501; no provider write is queued and golden records are unchanged.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"providerKey":{"type":"string","description":"Which connected system to write to, by its catalogue key."},"externalId":{"type":"string","description":"The record’s id in that system."},"entityType":{"type":"string","description":"The kind of record, such as contact or invoice."},"fields":{"type":"object","additionalProperties":true,"description":"The values to change, using Inferrex’s standard field names."}},"required":["providerKey","externalId","fields"]},"example":{"providerKey":"string","externalId":"string","entityType":"string","fields":{}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Reserved result flag retained for API compatibility. Production writes currently return 501, not a successful result."},"providerKey":{"type":"string"},"connectionId":{"type":"string","description":"The connection the write goes through."},"externalId":{"type":"string","description":"Reserved provider record identifier; no record is created or updated by the current 501 response."},"error":{"type":"string","description":"Present when success is false."},"writePayload":{"type":"object","properties":{"providerKey":{"type":"string"},"connectionId":{"type":"string"},"entityType":{"type":"string"},"providerFields":{"type":"object","additionalProperties":true,"description":"The fields in the system's own names. Its keys are that system's field names, so it has no fixed shape."},"unmappedFields":{"type":"array","items":{"type":"string"},"description":"Common-format fields with no mapping into this system; they were not sent."}},"required":["providerKey","connectionId","entityType","providerFields","unmappedFields"],"description":"Reserved translated-write shape. Current production execution returns 501 without sending or queuing it."}},"required":["success","providerKey","connectionId"]},"example":{"success":true,"providerKey":"string","connectionId":"string","externalId":"string","error":"string","writePayload":{"providerKey":"string","connectionId":"string","entityType":"string","providerFields":{},"unmappedFields":["string"]}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/unified/records/{entityClusterId}":{"get":{"operationId":"UnifiedGetAction","tags":["unified_api"],"summary":"Unified Get Action","security":[{"ApiKeyAuth":["unified:read"]},{"BearerAuth":[]},{"OAuth2":["unified:read"]}],"description":"Get one golden record: its combined values, which system each value came from, its quality score and how many systems contributed.","parameters":[{"name":"entityClusterId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the golden record."},"description":"The id of the golden record."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"This version's id."},"customer_id":{"type":"string","format":"uuid"},"entity_cluster_id":{"type":"string","format":"uuid","description":"The golden record's stable id across versions — the `:entityClusterId` to open it."},"entity_type":{"type":"string","description":"The kind of record (contact, organisation, …). Open."},"version":{"type":"integer"},"data":{"type":"object","additionalProperties":true,"description":"The merged values, keyed by field name. The customer's own data, so its keys and values are open."},"source_attribution":{"type":"object","additionalProperties":{"type":"object","properties":{"provider":{"type":"string","description":"Provider key of the system whose value won."},"connectionId":{"type":"string","format":"uuid","description":"The connection the winning value came from."},"externalId":{"type":"string","description":"The winning record's id in that system (drives write-back). Absent on records merged before 2026-07-04."},"recordVersion":{"type":"integer"},"observedAt":{"type":"string","format":"date-time","description":"When the field was resolved."},"strategy":{"type":"string","description":"The rule that picked the value. Today: provider_wins, freshest, most_complete, most_accurate, manual. Absent before 2026-07-04."},"ruleApplied":{"type":"boolean","description":"An explicit field authority rule matched (false = the default, freshest). Absent before 2026-07-04."},"confidence":{"type":"number","minimum":0,"maximum":1,"description":"Share of systems that agree with the winning value, reduced when contested. Absent before 2026-07-04."},"contested":{"type":"boolean","description":"Systems disagree on this field beyond the conflict threshold. Absent before 2026-07-04."}},"required":["provider","connectionId","recordVersion","observedAt"]},"description":"Per field of the record, keyed by field name: where the value came from."},"quality_score":{"type":"string","description":"Quality score 0–100 as a decimal string (Postgres NUMERIC), e.g. \"87.50\"."},"field_count":{"type":"integer"},"source_count":{"type":"integer"},"proposal_id":{"type":"string","format":"uuid","nullable":true,"description":"The approved proposal that wrote this version."},"created_at":{"type":"string","format":"date-time"},"redacted_fields":{"type":"array","items":{"type":"string"},"description":"Dotted paths (`data.email`, `data.billing_details.phone`) of the values hidden from your role: pii, financial, credential or health data your role is not granted. Each is answered as null, as the fields route answers it. Empty when nothing is hidden."}},"required":["id","customer_id","entity_cluster_id","entity_type","version","data","source_attribution","quality_score","field_count","source_count","created_at","redacted_fields"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","entity_cluster_id":"00000000-0000-0000-0000-000000000000","entity_type":"string","version":0,"data":{},"source_attribution":{},"quality_score":"string","field_count":0,"source_count":0,"proposal_id":"00000000-0000-0000-0000-000000000000","created_at":"2026-01-01T00:00:00Z","redacted_fields":["string"]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/webhooks/subscriptions":{"get":{"operationId":"WebhookSubscriptionsList","tags":["event_subscriptions"],"summary":"Webhook Subscriptions List","security":[{"ApiKeyAuth":["webhooks:read"]},{"BearerAuth":[]},{"OAuth2":["webhooks:read"]}],"description":"List your webhooks, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"url","in":"query","required":false,"schema":{"type":"string","description":"Only webhooks whose url is exactly this."},"description":"Only webhooks whose url is exactly this."},{"name":"url_contains","in":"query","required":false,"schema":{"type":"string","description":"Only webhooks whose url contains this text (upper and lower case are treated the same)."},"description":"Only webhooks whose url contains this text (upper and lower case are treated the same)."},{"name":"description","in":"query","required":false,"schema":{"type":"string","description":"Only webhooks whose description is exactly this."},"description":"Only webhooks whose description is exactly this."},{"name":"description_contains","in":"query","required":false,"schema":{"type":"string","description":"Only webhooks whose description contains this text (upper and lower case are treated the same)."},"description":"Only webhooks whose description contains this text (upper and lower case are treated the same)."},{"name":"secret_ref","in":"query","required":false,"schema":{"type":"string","description":"Only webhooks whose secret ref is exactly this."},"description":"Only webhooks whose secret ref is exactly this."},{"name":"secret_ref_contains","in":"query","required":false,"schema":{"type":"string","description":"Only webhooks whose secret ref contains this text (upper and lower case are treated the same)."},"description":"Only webhooks whose secret ref contains this text (upper and lower case are treated the same)."},{"name":"verified","in":"query","required":false,"schema":{"type":"boolean","description":"Only webhooks where verified is true, or false for only those where it is false."},"description":"Only webhooks where verified is true, or false for only those where it is false."},{"name":"enabled","in":"query","required":false,"schema":{"type":"boolean","description":"Only webhooks where enabled is true, or false for only those where it is false."},"description":"Only webhooks where enabled is true, or false for only those where it is false."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many webhooks to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many webhooks to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many webhooks to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many webhooks to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","url","description","secret_ref","verified","enabled","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns webhooks where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns webhooks where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"url":{"type":"string"},"description":{"type":"string","nullable":true},"event_types":{"type":"array","items":{"type":"string"},"nullable":true,"description":"The event types this address receives, e.g. pipelines.created. Leave empty to receive every event."},"secret_ref":{"type":"string","nullable":true},"verified":{"type":"boolean"},"enabled":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","url"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","url":"string","description":"string","event_types":["string"],"secret_ref":"string","verified":true,"enabled":true,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"WebhookSubscriptionsCreate","tags":["event_subscriptions"],"summary":"Webhook Subscriptions Create","security":[{"ApiKeyAuth":["webhooks:write"]},{"BearerAuth":[]},{"OAuth2":["webhooks:write"]}],"description":"Create a webhook. Returns the new webhook, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"description":{"type":"string","nullable":true},"event_types":{"type":"array","items":{"type":"string"},"nullable":true,"description":"The event types this address receives, e.g. pipelines.created. Leave empty to receive every event."},"enabled":{"type":"boolean"}},"required":["url"]},"example":{"url":"string","description":"string","event_types":["string"],"enabled":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"url":{"type":"string"},"description":{"type":"string","nullable":true},"event_types":{"type":"array","items":{"type":"string"},"nullable":true,"description":"The event types this address receives, e.g. pipelines.created. Leave empty to receive every event."},"secret_ref":{"type":"string","nullable":true},"verified":{"type":"boolean"},"enabled":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","url"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","url":"string","description":"string","event_types":["string"],"secret_ref":"string","verified":true,"enabled":true,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/webhooks/subscriptions/{id}":{"delete":{"operationId":"WebhookSubscriptionsDelete","tags":["event_subscriptions"],"summary":"Webhook Subscriptions Delete","security":[{"ApiKeyAuth":["webhooks:delete"]},{"BearerAuth":[]},{"OAuth2":["webhooks:delete"]}],"description":"Delete a webhook permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the webhook."},"description":"The id of the webhook."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"WebhookSubscriptionsGet","tags":["event_subscriptions"],"summary":"Webhook Subscriptions Get","security":[{"ApiKeyAuth":["webhooks:read"]},{"BearerAuth":[]},{"OAuth2":["webhooks:read"]}],"description":"Get one of your webhooks by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the webhook."},"description":"The id of the webhook."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"url":{"type":"string"},"description":{"type":"string","nullable":true},"event_types":{"type":"array","items":{"type":"string"},"nullable":true,"description":"The event types this address receives, e.g. pipelines.created. Leave empty to receive every event."},"secret_ref":{"type":"string","nullable":true},"verified":{"type":"boolean"},"enabled":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","url"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","url":"string","description":"string","event_types":["string"],"secret_ref":"string","verified":true,"enabled":true,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"WebhookSubscriptionsUpdate","tags":["event_subscriptions"],"summary":"Webhook Subscriptions Update","security":[{"ApiKeyAuth":["webhooks:write"]},{"BearerAuth":[]},{"OAuth2":["webhooks:write"]}],"description":"Change a webhook. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the webhook."},"description":"The id of the webhook."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"description":{"type":"string","nullable":true},"event_types":{"type":"array","items":{"type":"string"},"nullable":true,"description":"The event types this address receives, e.g. pipelines.created. Leave empty to receive every event."},"enabled":{"type":"boolean"}}},"example":{"url":"string","description":"string","event_types":["string"],"enabled":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"url":{"type":"string"},"description":{"type":"string","nullable":true},"event_types":{"type":"array","items":{"type":"string"},"nullable":true,"description":"The event types this address receives, e.g. pipelines.created. Leave empty to receive every event."},"secret_ref":{"type":"string","nullable":true},"verified":{"type":"boolean"},"enabled":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","url"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","url":"string","description":"string","event_types":["string"],"secret_ref":"string","verified":true,"enabled":true,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/webhooks/subscriptions/{id}/secret":{"post":{"operationId":"RotateWebhookSecret","tags":["event_subscriptions"],"summary":"Rotate Webhook Secret","security":[{"ApiKeyAuth":["webhooks:write"]},{"BearerAuth":[]},{"OAuth2":["webhooks:write"]}],"description":"Create a new signing secret for this webhook and return it, once only: copy it somewhere safe. The old secret stops working straight away. Use the secret to check each delivery really came from Inferrex: compute an HMAC-SHA256 of the raw request body with the secret and compare it with the X-Inferrex-Signature header.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the webhook."},"description":"The id of the webhook."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"signingSecret":{"type":"string","description":"Shown once — store it now; it is never returned again."}},"required":["id","signingSecret"]},"example":{"id":"00000000-0000-0000-0000-000000000000","signingSecret":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/webhooks/subscriptions/{id}/test":{"post":{"operationId":"TestWebhookSubscription","tags":["event_subscriptions"],"summary":"Test Webhook Subscription","security":[{"ApiKeyAuth":["webhooks:write"]},{"BearerAuth":[]},{"OAuth2":["webhooks:write"]}],"description":"Send a signed test event to this webhook’s address now and report what happened. If your system answers with success, the webhook is marked as verified. Every delivery is signed: a webhook with no signing secret gets one first (make a new one to copy with the secret route), and nothing is sent if the stored secret cannot be read.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the webhook."},"description":"The id of the webhook."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"delivered":{"type":"boolean"},"status":{"type":"integer","description":"HTTP status returned by the endpoint (omitted on transport failure)."}},"required":["id","delivered"]},"example":{"id":"00000000-0000-0000-0000-000000000000","delivered":true,"status":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/workflow-runs":{"get":{"operationId":"WorkflowRunsList","tags":["workflows"],"summary":"Workflow Runs List","security":[{"ApiKeyAuth":["workflow-runs:read"]},{"BearerAuth":[]},{"OAuth2":["workflow-runs:read"]}],"description":"List your workflow runs, newest first. Filter by any field, or search their text with q. Results come a page at a time: pass the nextCursor from one page to get the next.","parameters":[{"name":"workflow_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only workflow runs for this workflow. Pass its id."},"description":"Only workflow runs for this workflow. Pass its id."},{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"started_by_kind","in":"query","required":false,"schema":{"type":"string","description":"Only workflow runs whose started by kind is exactly this."},"description":"Only workflow runs whose started by kind is exactly this."},{"name":"started_by_kind_contains","in":"query","required":false,"schema":{"type":"string","description":"Only workflow runs whose started by kind contains this text (upper and lower case are treated the same)."},"description":"Only workflow runs whose started by kind contains this text (upper and lower case are treated the same)."},{"name":"started_by_user_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only workflow runs for this started by user. Pass its id."},"description":"Only workflow runs for this started by user. Pass its id."},{"name":"started_by_label","in":"query","required":false,"schema":{"type":"string","description":"Only workflow runs whose started by label is exactly this."},"description":"Only workflow runs whose started by label is exactly this."},{"name":"started_by_label_contains","in":"query","required":false,"schema":{"type":"string","description":"Only workflow runs whose started by label contains this text (upper and lower case are treated the same)."},"description":"Only workflow runs whose started by label contains this text (upper and lower case are treated the same)."},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Only workflow runs whose status is exactly this."},"description":"Only workflow runs whose status is exactly this."},{"name":"status_contains","in":"query","required":false,"schema":{"type":"string","description":"Only workflow runs whose status contains this text (upper and lower case are treated the same)."},"description":"Only workflow runs whose status contains this text (upper and lower case are treated the same)."},{"name":"steps_completed_gte","in":"query","required":false,"schema":{"type":"number","description":"Only workflow runs whose steps completed is this number or more."},"description":"Only workflow runs whose steps completed is this number or more."},{"name":"steps_completed_lte","in":"query","required":false,"schema":{"type":"number","description":"Only workflow runs whose steps completed is this number or less."},"description":"Only workflow runs whose steps completed is this number or less."},{"name":"steps_total_gte","in":"query","required":false,"schema":{"type":"number","description":"Only workflow runs whose steps total is this number or more."},"description":"Only workflow runs whose steps total is this number or more."},{"name":"steps_total_lte","in":"query","required":false,"schema":{"type":"number","description":"Only workflow runs whose steps total is this number or less."},"description":"Only workflow runs whose steps total is this number or less."},{"name":"error_message","in":"query","required":false,"schema":{"type":"string","description":"Only workflow runs whose error message is exactly this."},"description":"Only workflow runs whose error message is exactly this."},{"name":"error_message_contains","in":"query","required":false,"schema":{"type":"string","description":"Only workflow runs whose error message contains this text (upper and lower case are treated the same)."},"description":"Only workflow runs whose error message contains this text (upper and lower case are treated the same)."},{"name":"started_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only workflow runs whose started time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only workflow runs whose started time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"started_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only workflow runs whose started time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only workflow runs whose started time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"completed_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only workflow runs whose completed time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only workflow runs whose completed time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"completed_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only workflow runs whose completed time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only workflow runs whose completed time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"duration_ms_gte","in":"query","required":false,"schema":{"type":"number","description":"Only workflow runs whose duration ms is this number or more."},"description":"Only workflow runs whose duration ms is this number or more."},{"name":"duration_ms_lte","in":"query","required":false,"schema":{"type":"number","description":"Only workflow runs whose duration ms is this number or less."},"description":"Only workflow runs whose duration ms is this number or less."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many workflow runs to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many workflow runs to return in one page: 1 to 200, 50 if you leave it out."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","description":"Where the next page starts. Leave it out for the first page, then pass the nextCursor value from the previous response."},"description":"Where the next page starts. Leave it out for the first page, then pass the nextCursor value from the previous response."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns workflow runs where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns workflow runs where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workflow_id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"trigger_event":{"type":"object","additionalProperties":true,"nullable":true},"started_by_kind":{"type":"string","nullable":true,"description":"What started the run: a person, an API key, a schedule or an event. Empty on older runs."},"started_by_user_id":{"type":"string","format":"uuid","nullable":true,"description":"The workspace member who started it, when a person did."},"started_by_label":{"type":"string","nullable":true,"description":"Who or what to show: the person's name or email at the time, or the event's type."},"step_outputs":{"type":"object","additionalProperties":true,"nullable":true},"status":{"type":"string"},"steps_completed":{"type":"integer"},"steps_total":{"type":"integer"},"error_message":{"type":"string","nullable":true},"error_context":{"type":"object","additionalProperties":true,"nullable":true},"started_at":{"type":"string"},"completed_at":{"type":"string","nullable":true},"duration_ms":{"type":"integer","nullable":true}},"required":["workflow_id","customer_id","steps_total"]},"example":{"id":"00000000-0000-0000-0000-000000000000","workflow_id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","trigger_event":{},"started_by_kind":"string","started_by_user_id":"00000000-0000-0000-0000-000000000000","started_by_label":"string","step_outputs":{},"status":"string","steps_completed":0,"steps_total":0,"error_message":"string","error_context":{},"started_at":"string","completed_at":"string","duration_ms":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workflow-runs/{id}":{"get":{"operationId":"WorkflowRunsGet","tags":["workflows"],"summary":"Workflow Runs Get","security":[{"ApiKeyAuth":["workflow-runs:read"]},{"BearerAuth":[]},{"OAuth2":["workflow-runs:read"]}],"description":"Get one of your workflow runs by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the workflow run."},"description":"The id of the workflow run."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workflow_id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"trigger_event":{"type":"object","additionalProperties":true,"nullable":true},"started_by_kind":{"type":"string","nullable":true,"description":"What started the run: a person, an API key, a schedule or an event. Empty on older runs."},"started_by_user_id":{"type":"string","format":"uuid","nullable":true,"description":"The workspace member who started it, when a person did."},"started_by_label":{"type":"string","nullable":true,"description":"Who or what to show: the person's name or email at the time, or the event's type."},"step_outputs":{"type":"object","additionalProperties":true,"nullable":true},"status":{"type":"string"},"steps_completed":{"type":"integer"},"steps_total":{"type":"integer"},"error_message":{"type":"string","nullable":true},"error_context":{"type":"object","additionalProperties":true,"nullable":true},"started_at":{"type":"string"},"completed_at":{"type":"string","nullable":true},"duration_ms":{"type":"integer","nullable":true}},"required":["workflow_id","customer_id","steps_total"]},"example":{"id":"00000000-0000-0000-0000-000000000000","workflow_id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","trigger_event":{},"started_by_kind":"string","started_by_user_id":"00000000-0000-0000-0000-000000000000","started_by_label":"string","step_outputs":{},"status":"string","steps_completed":0,"steps_total":0,"error_message":"string","error_context":{},"started_at":"string","completed_at":"string","duration_ms":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workflow-runs/{id}/cancel":{"post":{"operationId":"CancelRun","tags":["workflows"],"summary":"Cancel Run","security":[{"ApiKeyAuth":["workflow-runs:write"]},{"BearerAuth":[]},{"OAuth2":["workflow-runs:write"]}],"description":"Stop a workflow run that is still running. It stops before its next step.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the workflow run."},"description":"The id of the workflow run."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]},"example":{"success":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workflows":{"get":{"operationId":"WorkflowsList","tags":["workflows"],"summary":"Workflows List","security":[{"ApiKeyAuth":["workflows:read"]},{"BearerAuth":[]},{"OAuth2":["workflows:read"]}],"description":"List your workflows, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"name","in":"query","required":false,"schema":{"type":"string","description":"Only workflows whose name is exactly this."},"description":"Only workflows whose name is exactly this."},{"name":"name_contains","in":"query","required":false,"schema":{"type":"string","description":"Only workflows whose name contains this text (upper and lower case are treated the same)."},"description":"Only workflows whose name contains this text (upper and lower case are treated the same)."},{"name":"description","in":"query","required":false,"schema":{"type":"string","description":"Only workflows whose description is exactly this."},"description":"Only workflows whose description is exactly this."},{"name":"description_contains","in":"query","required":false,"schema":{"type":"string","description":"Only workflows whose description contains this text (upper and lower case are treated the same)."},"description":"Only workflows whose description contains this text (upper and lower case are treated the same)."},{"name":"enabled","in":"query","required":false,"schema":{"type":"boolean","description":"Only workflows where enabled is true, or false for only those where it is false."},"description":"Only workflows where enabled is true, or false for only those where it is false."},{"name":"last_run_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only workflows whose last run time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only workflows whose last run time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"last_run_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only workflows whose last run time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only workflows whose last run time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"run_count_gte","in":"query","required":false,"schema":{"type":"number","description":"Only workflows whose run count is this number or more."},"description":"Only workflows whose run count is this number or more."},{"name":"run_count_lte","in":"query","required":false,"schema":{"type":"number","description":"Only workflows whose run count is this number or less."},"description":"Only workflows whose run count is this number or less."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many workflows to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many workflows to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many workflows to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many workflows to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","name","description","enabled","last_run_at","run_count","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns workflows where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns workflows where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"trigger_config":{"type":"object","additionalProperties":true,"description":"What starts this workflow: a pipeline event, a schedule, or a manual run."},"steps":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"The ordered steps a run executes, one after another."},"enabled":{"type":"boolean"},"last_run_at":{"type":"string","nullable":true},"run_count":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","name","trigger_config","steps"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","name":"string","description":"string","trigger_config":{},"steps":[{}],"enabled":true,"last_run_at":"string","run_count":0,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"WorkflowsCreate","tags":["workflows"],"summary":"Workflows Create","security":[{"ApiKeyAuth":["workflows:write"]},{"BearerAuth":[]},{"OAuth2":["workflows:write"]}],"description":"Create a workflow. Returns the new workflow, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string","nullable":true},"trigger_config":{"type":"object","additionalProperties":true,"description":"What starts this workflow: a pipeline event, a schedule, or a manual run."},"steps":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"The ordered steps a run executes, one after another."},"enabled":{"type":"boolean"},"last_run_at":{"type":"string","nullable":true},"run_count":{"type":"integer"}},"required":["name","trigger_config","steps"]},"example":{"name":"string","description":"string","trigger_config":{},"steps":[{}],"enabled":true,"last_run_at":"string","run_count":0}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"trigger_config":{"type":"object","additionalProperties":true,"description":"What starts this workflow: a pipeline event, a schedule, or a manual run."},"steps":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"The ordered steps a run executes, one after another."},"enabled":{"type":"boolean"},"last_run_at":{"type":"string","nullable":true},"run_count":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","name","trigger_config","steps"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","name":"string","description":"string","trigger_config":{},"steps":[{}],"enabled":true,"last_run_at":"string","run_count":0,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workflows/{id}":{"delete":{"operationId":"WorkflowsDelete","tags":["workflows"],"summary":"Workflows Delete","security":[{"ApiKeyAuth":["workflows:delete"]},{"BearerAuth":[]},{"OAuth2":["workflows:delete"]}],"description":"Delete a workflow permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the workflow."},"description":"The id of the workflow."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"WorkflowsGet","tags":["workflows"],"summary":"Workflows Get","security":[{"ApiKeyAuth":["workflows:read"]},{"BearerAuth":[]},{"OAuth2":["workflows:read"]}],"description":"Get one of your workflows by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the workflow."},"description":"The id of the workflow."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"trigger_config":{"type":"object","additionalProperties":true,"description":"What starts this workflow: a pipeline event, a schedule, or a manual run."},"steps":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"The ordered steps a run executes, one after another."},"enabled":{"type":"boolean"},"last_run_at":{"type":"string","nullable":true},"run_count":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","name","trigger_config","steps"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","name":"string","description":"string","trigger_config":{},"steps":[{}],"enabled":true,"last_run_at":"string","run_count":0,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"WorkflowsUpdate","tags":["workflows"],"summary":"Workflows Update","security":[{"ApiKeyAuth":["workflows:write"]},{"BearerAuth":[]},{"OAuth2":["workflows:write"]}],"description":"Change a workflow. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the workflow."},"description":"The id of the workflow."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string","nullable":true},"trigger_config":{"type":"object","additionalProperties":true,"description":"What starts this workflow: a pipeline event, a schedule, or a manual run."},"steps":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"The ordered steps a run executes, one after another."},"enabled":{"type":"boolean"},"last_run_at":{"type":"string","nullable":true},"run_count":{"type":"integer"}}},"example":{"name":"string","description":"string","trigger_config":{},"steps":[{}],"enabled":true,"last_run_at":"string","run_count":0}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"trigger_config":{"type":"object","additionalProperties":true,"description":"What starts this workflow: a pipeline event, a schedule, or a manual run."},"steps":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"The ordered steps a run executes, one after another."},"enabled":{"type":"boolean"},"last_run_at":{"type":"string","nullable":true},"run_count":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","name","trigger_config","steps"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","name":"string","description":"string","trigger_config":{},"steps":[{}],"enabled":true,"last_run_at":"string","run_count":0,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workflows/{id}/disable":{"post":{"operationId":"DisableWorkflow","tags":["workflows"],"summary":"Disable Workflow","security":[{"ApiKeyAuth":["workflows:write"]},{"BearerAuth":[]},{"OAuth2":["workflows:write"]}],"description":"Switch a workflow off, so it does not run until you switch it on again.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the workflow."},"description":"The id of the workflow."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]},"example":{"success":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workflows/{id}/enable":{"post":{"operationId":"EnableWorkflow","tags":["workflows"],"summary":"Enable Workflow","security":[{"ApiKeyAuth":["workflows:write"]},{"BearerAuth":[]},{"OAuth2":["workflows:write"]}],"description":"Switch a workflow on, so it can run.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the workflow."},"description":"The id of the workflow."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]},"example":{"success":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workflows/{id}/trigger":{"post":{"operationId":"TriggerWorkflow","tags":["workflows"],"summary":"Trigger Workflow","security":[{"ApiKeyAuth":["workflows:write"]},{"BearerAuth":[]},{"OAuth2":["workflows:write"]}],"description":"Run a workflow now. It must be switched on and have at least one step. Returns the new run’s id; the steps run in order in the background.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the workflow."},"description":"The id of the workflow."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"input":{"type":"object","additionalProperties":true,"description":"Optional data to pass to the first step."}}},"example":{"input":{}}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"runId":{"type":"string","format":"uuid"},"status":{"type":"string"}},"required":["runId","status"]},"example":{"runId":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace-users/{id}/offboard":{"post":{"operationId":"OffboardOwnWorkspaceUser","tags":["core"],"summary":"Offboard Own Workspace User","security":[{"ApiKeyAuth":["workspace-users:write"]},{"BearerAuth":[]},{"OAuth2":["workspace-users:write"]}],"description":"Remove a member from your workspace. Their personal secrets are handled according to your workspace’s setting for this (deleted, or passed to the owner), and then their account is deactivated. Needs permission to manage users. You cannot offboard yourself, and the owner cannot be offboarded until ownership is transferred.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the workspace member."},"description":"The id of the workspace member."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"deactivated":{"type":"boolean"},"secretsPolicy":{"type":"string"},"personalSecretsAffected":{"type":"integer"},"transferredTo":{"type":"string","nullable":true}},"required":["id","deactivated","secretsPolicy","personalSecretsAffected"]},"example":{"id":"string","deactivated":true,"secretsPolicy":"string","personalSecretsAffected":0,"transferredTo":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/accept-invite":{"post":{"operationId":"AcceptInvite","tags":["workspace"],"summary":"Accept Invite","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Accept an invitation to join a workspace, as the person who was invited. You must be signed in with the email address the invite was sent to.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"inviteId":{"type":"string","description":"The invite id, from the invitation link."},"workspaceId":{"type":"string","description":"The workspace you were invited to, from the invitation link."}},"required":["inviteId","workspaceId"]},"example":{"inviteId":"string","workspaceId":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"role":{"type":"string"},"acceptedAt":{"type":"string"},"isActive":{"type":"boolean"}},"required":["id","email","role","acceptedAt","isActive"]},"example":{"id":"string","email":"string","role":"string","acceptedAt":"string","isActive":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/audit-trail":{"get":{"operationId":"PlatformAuditTrailList","tags":["rbac"],"summary":"Platform Audit Trail List","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"List your platform audit trail entries, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"workspace_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"actor_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only platform audit trail entries for this actor. Pass its id."},"description":"Only platform audit trail entries for this actor. Pass its id."},{"name":"actor_type","in":"query","required":false,"schema":{"type":"string","description":"Only platform audit trail entries whose actor type is exactly this."},"description":"Only platform audit trail entries whose actor type is exactly this."},{"name":"actor_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only platform audit trail entries whose actor type contains this text (upper and lower case are treated the same)."},"description":"Only platform audit trail entries whose actor type contains this text (upper and lower case are treated the same)."},{"name":"action","in":"query","required":false,"schema":{"type":"string","description":"Only platform audit trail entries whose action is exactly this."},"description":"Only platform audit trail entries whose action is exactly this."},{"name":"action_contains","in":"query","required":false,"schema":{"type":"string","description":"Only platform audit trail entries whose action contains this text (upper and lower case are treated the same)."},"description":"Only platform audit trail entries whose action contains this text (upper and lower case are treated the same)."},{"name":"resource_type","in":"query","required":false,"schema":{"type":"string","description":"Only platform audit trail entries whose resource type is exactly this."},"description":"Only platform audit trail entries whose resource type is exactly this."},{"name":"resource_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only platform audit trail entries whose resource type contains this text (upper and lower case are treated the same)."},"description":"Only platform audit trail entries whose resource type contains this text (upper and lower case are treated the same)."},{"name":"resource_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only platform audit trail entries for this resource. Pass its id."},"description":"Only platform audit trail entries for this resource. Pass its id."},{"name":"user_agent","in":"query","required":false,"schema":{"type":"string","description":"Only platform audit trail entries whose user agent is exactly this."},"description":"Only platform audit trail entries whose user agent is exactly this."},{"name":"user_agent_contains","in":"query","required":false,"schema":{"type":"string","description":"Only platform audit trail entries whose user agent contains this text (upper and lower case are treated the same)."},"description":"Only platform audit trail entries whose user agent contains this text (upper and lower case are treated the same)."},{"name":"via","in":"query","required":false,"schema":{"type":"string","description":"Only platform audit trail entries whose via is exactly this."},"description":"Only platform audit trail entries whose via is exactly this."},{"name":"via_contains","in":"query","required":false,"schema":{"type":"string","description":"Only platform audit trail entries whose via contains this text (upper and lower case are treated the same)."},"description":"Only platform audit trail entries whose via contains this text (upper and lower case are treated the same)."},{"name":"assistant_action_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only platform audit trail entries for this assistant action. Pass its id."},"description":"Only platform audit trail entries for this assistant action. Pass its id."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many platform audit trail entries to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many platform audit trail entries to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many platform audit trail entries to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many platform audit trail entries to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","workspace_id","actor_id","actor_type","action","resource_type","resource_id","ip_address","user_agent","created_at","via","assistant_action_id"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns platform audit trail entries where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns platform audit trail entries where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid","nullable":true},"actor_id":{"type":"string","format":"uuid","nullable":true},"actor_type":{"type":"string"},"action":{"type":"string"},"resource_type":{"type":"string","nullable":true},"resource_id":{"type":"string","format":"uuid","nullable":true},"before_state":{"type":"object","additionalProperties":true,"nullable":true},"after_state":{"type":"object","additionalProperties":true,"nullable":true},"ip_address":{"type":"string","nullable":true},"user_agent":{"type":"string","nullable":true},"created_at":{"type":"string"},"via":{"type":"string","nullable":true},"assistant_action_id":{"type":"string","format":"uuid","nullable":true}},"required":["actor_type","action"]},"example":{"id":"00000000-0000-0000-0000-000000000000","workspace_id":"00000000-0000-0000-0000-000000000000","actor_id":"00000000-0000-0000-0000-000000000000","actor_type":"string","action":"string","resource_type":"string","resource_id":"00000000-0000-0000-0000-000000000000","before_state":{},"after_state":{},"ip_address":"string","user_agent":"string","created_at":"string","via":"string","assistant_action_id":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/cli-browser-consents":{"get":{"operationId":"ListCliBrowserConsents","tags":["workspace"],"summary":"List Cli Browser Consents","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid","description":"Who agreed (a workspace member id)."},"session_id":{"type":"string","format":"uuid","description":"The cloud shell session it was given in."},"consent_version":{"type":"string","description":"Which wording was accepted."},"consented_at":{"type":"string","format":"date-time"},"ip_address":{"type":"string","nullable":true}},"required":["id","user_id","session_id","consent_version","consented_at","ip_address"]},"example":{"id":"00000000-0000-0000-0000-000000000000","user_id":"00000000-0000-0000-0000-000000000000","session_id":"00000000-0000-0000-0000-000000000000","consent_version":"string","consented_at":"2026-01-01T00:00:00Z","ip_address":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/connections/{id}/scopes":{"delete":{"operationId":"RemoveConnectionScope","tags":["credentials"],"summary":"Remove Connection Scope","security":[{"ApiKeyAuth":["workspace:delete"]},{"BearerAuth":[]},{"OAuth2":["workspace:delete"]}],"description":"Remove one OAuth permission (scope) from a connection’s saved credentials in one environment. If you remove the last one, Inferrex asks for the system’s default permissions next time it signs in. A main sign-in kept as a workspace secret is tested without it first, and changed only if the test passes.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"scope":{"type":"string","description":"The permission to remove, named exactly as the system names it."},"environmentId":{"type":"string","format":"uuid","description":"The environment to remove it from. Leave out for the connection’s main credentials."}},"required":["scope"]},"example":{"scope":"string","environmentId":"00000000-0000-0000-0000-000000000000"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"environmentId":{"type":"string","format":"uuid","nullable":true},"scopes":{"type":"array","items":{"type":"string"},"description":"The scopes the connection asks for now."},"rotation":{"type":"object","properties":{"key":{"type":"string","description":"The secret now holding the new value: the live secret's name when it went live, else the stand-by copy's."},"live":{"type":"boolean","description":"Whether the new value is now in use."},"forced":{"type":"boolean","description":"It went live only because force was set."},"outcome":{"type":"string","description":"The worst test answer: accepted, refused, inconclusive, or untested."},"message":{"type":"string"},"previousKey":{"type":"string","nullable":true,"description":"Where the replaced value is kept, so it can be put back."},"candidateKey":{"type":"string","nullable":true,"description":"The new value's stand-by copy while it waits for a passing test; null once it is live."},"tests":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"connectionName":{"type":"string"},"testOutcome":{"type":"string","description":"The connection test's own answer: signed-in, credentials-rejected, forbidden, not-found, unreachable, redirect or not-testable."},"outcome":{"type":"string","description":"What it means for the secret. accepted: the API took it — a signed-in read of a declared endpoint answered 2xx with data (testOutcome signed-in). refused: 401 or 403. inconclusive: anything else, any 404 and the bare base address included."},"httpStatus":{"type":"integer","nullable":true},"detail":{"type":"string","description":"The answer in plain words. A refusal names the secret, its purpose and who saved it when; never its value."},"testedUrlTemplate":{"type":"string"},"provedBy":{"type":"string","nullable":true,"description":"The endpoint whose answer proved the read; null unless accepted."}},"required":["connectionId","connectionName","testOutcome","outcome","httpStatus","detail","testedUrlTemplate","provedBy"]}}},"required":["key","live","forced","outcome","message","previousKey","candidateKey","tests"],"description":"Main sign-in kept as a workspace secret only: the test of the new list and whether it is in use."}},"required":["connectionId","scopes"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","environmentId":"00000000-0000-0000-0000-000000000000","scopes":["string"],"rotation":{"key":"string","live":true,"forced":true,"outcome":"string","message":"string","previousKey":"string","candidateKey":"string","tests":[{"connectionId":"00000000-0000-0000-0000-000000000000","connectionName":"string","testOutcome":"string","outcome":"string","httpStatus":0,"detail":"string","testedUrlTemplate":"string","provedBy":"string"}]}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"ListConnectionScopes","tags":["credentials"],"summary":"List Connection Scopes","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"The OAuth permissions (scopes) saved with a connection’s credentials, for its main sign-in and for each environment. Scopes are not secret, so they can be shown again.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"scopes":{"type":"array","items":{"type":"object","properties":{"scope":{"type":"string"},"environmentId":{"type":"string","format":"uuid","nullable":true,"description":"Null = the connection’s own (default-environment) credentials."},"authType":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"}},"required":["scope","authType","updatedAt"]}}},"required":["connectionId","scopes"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","scopes":[{"scope":"string","environmentId":"00000000-0000-0000-0000-000000000000","authType":"string","updatedAt":"2026-01-01T00:00:00Z"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"AddConnectionScopes","tags":["credentials"],"summary":"Add Connection Scopes","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Add OAuth permissions (scopes) to a connection’s saved credentials in one environment (its main sign-in unless you pass environmentId). The credentials must already be saved there. The next time Inferrex signs in, it asks for the new set. A main sign-in kept as a workspace secret is tested with the new set first, like a replaced key, and used only if the test passes.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection."},"description":"The id of the connection."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"scopes":{"type":"array","items":{"type":"string"},"description":"The permissions to add, named exactly as the system names them, for example accounting.transactions.read."},"environmentId":{"type":"string","format":"uuid","description":"The environment to add them in. Leave out for the connection’s main credentials."}},"required":["scopes"]},"example":{"scopes":["string"],"environmentId":"00000000-0000-0000-0000-000000000000"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"environmentId":{"type":"string","format":"uuid","nullable":true},"scopes":{"type":"array","items":{"type":"string"},"description":"The scopes the connection asks for now."},"rotation":{"type":"object","properties":{"key":{"type":"string","description":"The secret now holding the new value: the live secret's name when it went live, else the stand-by copy's."},"live":{"type":"boolean","description":"Whether the new value is now in use."},"forced":{"type":"boolean","description":"It went live only because force was set."},"outcome":{"type":"string","description":"The worst test answer: accepted, refused, inconclusive, or untested."},"message":{"type":"string"},"previousKey":{"type":"string","nullable":true,"description":"Where the replaced value is kept, so it can be put back."},"candidateKey":{"type":"string","nullable":true,"description":"The new value's stand-by copy while it waits for a passing test; null once it is live."},"tests":{"type":"array","items":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"connectionName":{"type":"string"},"testOutcome":{"type":"string","description":"The connection test's own answer: signed-in, credentials-rejected, forbidden, not-found, unreachable, redirect or not-testable."},"outcome":{"type":"string","description":"What it means for the secret. accepted: the API took it — a signed-in read of a declared endpoint answered 2xx with data (testOutcome signed-in). refused: 401 or 403. inconclusive: anything else, any 404 and the bare base address included."},"httpStatus":{"type":"integer","nullable":true},"detail":{"type":"string","description":"The answer in plain words. A refusal names the secret, its purpose and who saved it when; never its value."},"testedUrlTemplate":{"type":"string"},"provedBy":{"type":"string","nullable":true,"description":"The endpoint whose answer proved the read; null unless accepted."}},"required":["connectionId","connectionName","testOutcome","outcome","httpStatus","detail","testedUrlTemplate","provedBy"]}}},"required":["key","live","forced","outcome","message","previousKey","candidateKey","tests"],"description":"Main sign-in kept as a workspace secret only: the test of the new list and whether it is in use."}},"required":["connectionId","scopes"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","environmentId":"00000000-0000-0000-0000-000000000000","scopes":["string"],"rotation":{"key":"string","live":true,"forced":true,"outcome":"string","message":"string","previousKey":"string","candidateKey":"string","tests":[{"connectionId":"00000000-0000-0000-0000-000000000000","connectionName":"string","testOutcome":"string","outcome":"string","httpStatus":0,"detail":"string","testedUrlTemplate":"string","provedBy":"string"}]}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/effective-permissions/{userId}":{"get":{"operationId":"GetEffectivePermissions","tags":["workspace"],"summary":"Get Effective Permissions","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"What one member of your workspace is actually allowed to do, taking their role and any extra permissions together.","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The member to check."},"description":"The member to check."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string"},"role":{"type":"string"},"isActive":{"type":"boolean"},"teamIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Teams the member belongs to."},"permissions":{"type":"array","items":{"type":"object","properties":{"resource_type":{"type":"string"},"resource_id":{"type":"string","nullable":true,"description":"Null for a grant over every resource of the type."},"permission":{"type":"string"},"grant":{"type":"string","description":"Known values: allow, deny."},"source":{"type":"string","description":"Known values: role_baseline, explicit_override."}},"required":["resource_type","resource_id","permission","grant","source"]},"description":"One row per resource type and permission the role grants, with an explicit grant replacing the role's, then any explicit grant the role does not cover."}},"required":["userId","role","isActive","teamIds","permissions"]},"example":{"userId":"string","role":"string","isActive":true,"teamIds":["00000000-0000-0000-0000-000000000000"],"permissions":[{"resource_type":"string","resource_id":"string","permission":"string","grant":"string","source":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/entitlements":{"get":{"operationId":"GetEntitlements","tags":["workspace"],"summary":"Get Entitlements","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"The features and modules your workspace has access to, so an app can show only what you can use.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"entitlements":{"type":"array","items":{"type":"string"},"description":"Active entitlement codes, e.g. module_data_protection. Empty when the workspace has none."}},"required":["entitlements"]},"example":{"entitlements":["string"]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/environment":{"get":{"operationId":"GetActiveEnvironment","tags":["workspace"],"summary":"Get Active Environment","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"Which of your environments you are working in for this request: the one you chose (sent in the X-Environment-Id header), or your workspace’s default. pinned is false if the one you chose no longer exists and the default was used instead. Empty when your workspace has no environments.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"class":{"type":"string"},"isDefault":{"type":"boolean"},"pinned":{"type":"boolean"}},"required":["isDefault","pinned"]},"example":{"id":"string","name":"string","class":"string","isDefault":true,"pinned":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/environments":{"get":{"operationId":"EnvironmentsList","tags":["workspace"],"summary":"Environments List","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"List your environments, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"workspace_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"name","in":"query","required":false,"schema":{"type":"string","description":"Only environments whose name is exactly this."},"description":"Only environments whose name is exactly this."},{"name":"name_contains","in":"query","required":false,"schema":{"type":"string","description":"Only environments whose name contains this text (upper and lower case are treated the same)."},"description":"Only environments whose name contains this text (upper and lower case are treated the same)."},{"name":"class","in":"query","required":false,"schema":{"type":"string","description":"Only environments whose class is exactly this."},"description":"Only environments whose class is exactly this."},{"name":"class_contains","in":"query","required":false,"schema":{"type":"string","description":"Only environments whose class contains this text (upper and lower case are treated the same)."},"description":"Only environments whose class contains this text (upper and lower case are treated the same)."},{"name":"is_default","in":"query","required":false,"schema":{"type":"boolean","description":"Only environments where is default is true, or false for only those where it is false."},"description":"Only environments where is default is true, or false for only those where it is false."},{"name":"description","in":"query","required":false,"schema":{"type":"string","description":"Only environments whose description is exactly this."},"description":"Only environments whose description is exactly this."},{"name":"description_contains","in":"query","required":false,"schema":{"type":"string","description":"Only environments whose description contains this text (upper and lower case are treated the same)."},"description":"Only environments whose description contains this text (upper and lower case are treated the same)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many environments to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many environments to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many environments to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many environments to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","workspace_id","name","class","is_default","description","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns environments where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns environments where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"class":{"type":"string","description":"How critical this environment is. Name it whatever you like; the class decides who may deploy into it."},"is_default":{"type":"boolean"},"description":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["workspace_id","name"]},"example":{"id":"00000000-0000-0000-0000-000000000000","workspace_id":"00000000-0000-0000-0000-000000000000","name":"string","class":"string","is_default":true,"description":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"EnvironmentsCreate","tags":["workspace"],"summary":"Environments Create","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Create an environment. Returns the new environment, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"class":{"type":"string","description":"How critical this environment is. Name it whatever you like; the class decides who may deploy into it."},"is_default":{"type":"boolean"},"description":{"type":"string","nullable":true}},"required":["name"]},"example":{"name":"string","class":"string","is_default":true,"description":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"class":{"type":"string","description":"How critical this environment is. Name it whatever you like; the class decides who may deploy into it."},"is_default":{"type":"boolean"},"description":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["workspace_id","name"]},"example":{"id":"00000000-0000-0000-0000-000000000000","workspace_id":"00000000-0000-0000-0000-000000000000","name":"string","class":"string","is_default":true,"description":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/environments/{id}":{"delete":{"operationId":"EnvironmentsDelete","tags":["workspace"],"summary":"Environments Delete","security":[{"ApiKeyAuth":["workspace:delete"]},{"BearerAuth":[]},{"OAuth2":["workspace:delete"]}],"description":"Delete an environment permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the environment."},"description":"The id of the environment."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"EnvironmentsGet","tags":["workspace"],"summary":"Environments Get","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"Get one of your environments by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the environment."},"description":"The id of the environment."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"class":{"type":"string","description":"How critical this environment is. Name it whatever you like; the class decides who may deploy into it."},"is_default":{"type":"boolean"},"description":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["workspace_id","name"]},"example":{"id":"00000000-0000-0000-0000-000000000000","workspace_id":"00000000-0000-0000-0000-000000000000","name":"string","class":"string","is_default":true,"description":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"EnvironmentsUpdate","tags":["workspace"],"summary":"Environments Update","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Change an environment. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the environment."},"description":"The id of the environment."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"class":{"type":"string","description":"How critical this environment is. Name it whatever you like; the class decides who may deploy into it."},"is_default":{"type":"boolean"},"description":{"type":"string","nullable":true}}},"example":{"name":"string","class":"string","is_default":true,"description":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"class":{"type":"string","description":"How critical this environment is. Name it whatever you like; the class decides who may deploy into it."},"is_default":{"type":"boolean"},"description":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["workspace_id","name"]},"example":{"id":"00000000-0000-0000-0000-000000000000","workspace_id":"00000000-0000-0000-0000-000000000000","name":"string","class":"string","is_default":true,"description":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/invite":{"post":{"operationId":"WorkspaceInvite","tags":["workspace"],"summary":"Workspace Invite","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Invite someone to your workspace by email, with a role (viewer, operator, editor or admin). Depending on your invite policy, the invite may need an admin or the owner to approve it first. With email invites, the response says whether the email was sent. Where invites use a one-time password instead, the password is returned once for you to pass on.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"The email address of the person to invite."},"role":{"type":"string","enum":["viewer","operator","editor","admin"],"description":"Their role: viewer, operator, editor or admin."},"displayName":{"type":"string","description":"Their name, as it should appear in the workspace."}},"required":["email"]},"example":{"email":"string","role":"viewer","displayName":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"role":{"type":"string"},"status":{"type":"string"},"tempPassword":{"type":"string"},"invitedAt":{"type":"string"},"emailStatus":{"type":"string","enum":["sent","failed"]}},"required":["id","email","role","status"]},"example":{"id":"string","email":"string","role":"string","status":"string","tempPassword":"string","invitedAt":"string","emailStatus":"sent"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/invite-policy":{"get":{"operationId":"InvitePoliciesList","tags":["workspace"],"summary":"Invite Policies List","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"List your invite policies, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"require_approval","in":"query","required":false,"schema":{"type":"boolean","description":"Only invite policies where require approval is true, or false for only those where it is false."},"description":"Only invite policies where require approval is true, or false for only those where it is false."},{"name":"approver_role","in":"query","required":false,"schema":{"type":"string","description":"Only invite policies whose approver role is exactly this."},"description":"Only invite policies whose approver role is exactly this."},{"name":"approver_role_contains","in":"query","required":false,"schema":{"type":"string","description":"Only invite policies whose approver role contains this text (upper and lower case are treated the same)."},"description":"Only invite policies whose approver role contains this text (upper and lower case are treated the same)."},{"name":"otp_delivery","in":"query","required":false,"schema":{"type":"string","description":"Only invite policies whose otp delivery is exactly this."},"description":"Only invite policies whose otp delivery is exactly this."},{"name":"otp_delivery_contains","in":"query","required":false,"schema":{"type":"string","description":"Only invite policies whose otp delivery contains this text (upper and lower case are treated the same)."},"description":"Only invite policies whose otp delivery contains this text (upper and lower case are treated the same)."},{"name":"otp_channel_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only invite policies for this otp channel. Pass its id."},"description":"Only invite policies for this otp channel. Pass its id."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many invite policies to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many invite policies to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many invite policies to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many invite policies to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","require_approval","approver_role","otp_delivery","otp_channel_id","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns invite policies where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns invite policies where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"require_approval":{"type":"boolean"},"approver_role":{"type":"string"},"otp_delivery":{"type":"string"},"otp_channel_id":{"type":"string","format":"uuid","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","require_approval":true,"approver_role":"string","otp_delivery":"string","otp_channel_id":"00000000-0000-0000-0000-000000000000","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"InvitePoliciesCreate","tags":["workspace"],"summary":"Invite Policies Create","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Create an invite policy. Returns the new invite policy, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"require_approval":{"type":"boolean"},"approver_role":{"type":"string"},"otp_delivery":{"type":"string"},"otp_channel_id":{"type":"string","format":"uuid","nullable":true}}},"example":{"require_approval":true,"approver_role":"string","otp_delivery":"string","otp_channel_id":"00000000-0000-0000-0000-000000000000"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"require_approval":{"type":"boolean"},"approver_role":{"type":"string"},"otp_delivery":{"type":"string"},"otp_channel_id":{"type":"string","format":"uuid","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","require_approval":true,"approver_role":"string","otp_delivery":"string","otp_channel_id":"00000000-0000-0000-0000-000000000000","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/invite-policy/{id}":{"get":{"operationId":"InvitePoliciesGet","tags":["workspace"],"summary":"Invite Policies Get","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"Get one of your invite policies by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the invite policy."},"description":"The id of the invite policy."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"require_approval":{"type":"boolean"},"approver_role":{"type":"string"},"otp_delivery":{"type":"string"},"otp_channel_id":{"type":"string","format":"uuid","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","require_approval":true,"approver_role":"string","otp_delivery":"string","otp_channel_id":"00000000-0000-0000-0000-000000000000","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"InvitePoliciesUpdate","tags":["workspace"],"summary":"Invite Policies Update","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Change an invite policy. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the invite policy."},"description":"The id of the invite policy."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"require_approval":{"type":"boolean"},"approver_role":{"type":"string"},"otp_delivery":{"type":"string"},"otp_channel_id":{"type":"string","format":"uuid","nullable":true}}},"example":{"require_approval":true,"approver_role":"string","otp_delivery":"string","otp_channel_id":"00000000-0000-0000-0000-000000000000"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"require_approval":{"type":"boolean"},"approver_role":{"type":"string"},"otp_delivery":{"type":"string"},"otp_channel_id":{"type":"string","format":"uuid","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","require_approval":true,"approver_role":"string","otp_delivery":"string","otp_channel_id":"00000000-0000-0000-0000-000000000000","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/invites/{id}/preview":{"get":{"operationId":"GetInvitePreview","tags":["workspace"],"summary":"Get Invite Preview","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"Preview an invitation using its id and target workspace from the invite link. Only the signed-in recipient can read it. Unknown invites and recipient or workspace mismatches return the same 404; owned invites already accepted or not ready to accept return 409.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The invite id from the invitation link."},"description":"The invite id from the invitation link."},{"name":"workspaceId","in":"query","required":true,"schema":{"type":"string","format":"uuid","description":"The target workspace from the invitation link (?ws=), not the currently active workspace."},"description":"The target workspace from the invitation link (?ws=), not the currently active workspace."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"workspaceId":{"type":"string","description":"The workspace this invite belongs to."},"workspaceName":{"type":"string","description":"The stored name of the inviting workspace."},"role":{"type":"string","description":"The role stored on the invite, with no fallback role."},"inviter":{"type":"string","nullable":true,"description":"The inviter's stored display name within this workspace, or null when no display name is available."},"expiresAt":{"type":"string","nullable":true,"description":"Null: workspace invites currently persist no expiry timestamp and acceptance does not apply an age-based expiration."}},"required":["workspaceId","workspaceName","role","inviter","expiresAt"]},"example":{"workspaceId":"string","workspaceName":"string","role":"string","inviter":"string","expiresAt":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/ip-allowlist":{"get":{"operationId":"GetIpAllowlist","tags":["workspace"],"summary":"Get Ip Allowlist","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"The internet addresses your team may use Inferrex from. Empty means anywhere.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ipAllowlist":{"type":"array","items":{"type":"string"},"description":"IP addresses and CIDR ranges allowed to use the workspace. Empty when none are set."}},"required":["ipAllowlist"]},"example":{"ipAllowlist":["string"]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"UpdateIpAllowlist","tags":["workspace"],"summary":"Update Ip Allowlist","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Set the internet addresses your team may use Inferrex from, such as your office or VPN. Requests from anywhere else are refused. Give single addresses or ranges (CIDR, for example 203.0.113.0/24). An empty list allows anywhere. Only enforced when your workspace has the IP allowlisting feature.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ipAllowlist":{"type":"array","items":{"type":"string"},"description":"The addresses and ranges to allow. An empty list allows anywhere."}},"required":["ipAllowlist"]},"example":{"ipAllowlist":["string"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ipAllowlist":{"type":"array","items":{"type":"string"},"description":"IP addresses and CIDR ranges allowed to use the workspace. Empty when none are set."}},"required":["ipAllowlist"]},"example":{"ipAllowlist":["string"]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/mcp-oauth/claim":{"post":{"operationId":"ClaimMcpConsent","tags":["mcp_oauth"],"summary":"Claim Mcp Consent","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"requestId":{"type":"string","minLength":1,"maxLength":43}},"required":["requestId"]},"example":{"requestId":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"clientId":{"type":"string","minLength":1,"maxLength":2048},"clientName":{"type":"string","minLength":1,"maxLength":120},"redirectUri":{"type":"string","minLength":1,"maxLength":2048},"resource":{"type":"string","minLength":1,"maxLength":2048},"scopes":{"type":"array","items":{"type":"string"}},"workspaceId":{"type":"string","format":"uuid"},"consentToken":{"type":"string","minLength":1,"maxLength":43},"expiresAt":{"type":"string","format":"date-time"}},"required":["clientId","clientName","redirectUri","resource","scopes","workspaceId","consentToken","expiresAt"]},"example":{"clientId":"string","clientName":"string","redirectUri":"string","resource":"string","scopes":["string"],"workspaceId":"00000000-0000-0000-0000-000000000000","consentToken":"string","expiresAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}},"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}}},"400":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"401":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"403":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"404":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"405":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"429":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"500":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"503":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}}}}},"/v1/workspace/mcp-oauth/consent":{"post":{"operationId":"DecideMcpConsent","tags":["mcp_oauth"],"summary":"Decide Mcp Consent","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"requestId":{"type":"string","minLength":1,"maxLength":43},"consentToken":{"type":"string","minLength":1,"maxLength":43},"approved":{"type":"boolean"}},"required":["requestId","consentToken","approved"]},"example":{"requestId":"string","consentToken":"string","approved":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"redirectUri":{"type":"string","minLength":1,"maxLength":4096}},"required":["redirectUri"]},"example":{"redirectUri":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}},"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}}},"400":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"401":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"403":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"404":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"405":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"429":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"500":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"503":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}}}}},"/v1/workspace/mcp-oauth/grants":{"get":{"operationId":"ListMcpOAuthGrants","tags":["mcp_oauth"],"summary":"List Mcp OAuth Grants","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"parameters":[{"name":"after","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"grants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"clientId":{"type":"string","minLength":1,"maxLength":2048},"scopes":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"revokedAt":{"type":"string","format":"date-time","nullable":true}},"required":["id","clientId","scopes","createdAt","expiresAt","revokedAt"]}},"next":{"type":"string","format":"uuid","nullable":true}},"required":["grants","next"]},"example":{"grants":[{"id":"00000000-0000-0000-0000-000000000000","clientId":"string","scopes":["string"],"createdAt":"2026-01-01T00:00:00Z","expiresAt":"2026-01-01T00:00:00Z","revokedAt":"2026-01-01T00:00:00Z"}],"next":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}},"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}}},"400":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"401":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"403":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"404":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"405":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"429":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"500":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"503":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}}}}},"/v1/workspace/mcp-oauth/grants/{id}/revoke":{"post":{"operationId":"RevokeMcpOAuthGrant","tags":["mcp_oauth"],"summary":"Revoke Mcp OAuth Grant","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}},"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}}},"400":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"401":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"403":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"404":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"405":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"429":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"500":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}},"503":{"description":"OAuth protocol error; response is never cached.","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"string"}}}}}}}}},"/v1/workspace/notification-channels":{"get":{"operationId":"NotificationChannelsList","tags":["workspace"],"summary":"Notification Channels List","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"List your notification channels, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"name","in":"query","required":false,"schema":{"type":"string","description":"Only notification channels whose name is exactly this."},"description":"Only notification channels whose name is exactly this."},{"name":"name_contains","in":"query","required":false,"schema":{"type":"string","description":"Only notification channels whose name contains this text (upper and lower case are treated the same)."},"description":"Only notification channels whose name contains this text (upper and lower case are treated the same)."},{"name":"kind","in":"query","required":false,"schema":{"type":"string","description":"Only notification channels whose kind is exactly this."},"description":"Only notification channels whose kind is exactly this."},{"name":"kind_contains","in":"query","required":false,"schema":{"type":"string","description":"Only notification channels whose kind contains this text (upper and lower case are treated the same)."},"description":"Only notification channels whose kind contains this text (upper and lower case are treated the same)."},{"name":"provider","in":"query","required":false,"schema":{"type":"string","description":"Only notification channels whose provider is exactly this."},"description":"Only notification channels whose provider is exactly this."},{"name":"provider_contains","in":"query","required":false,"schema":{"type":"string","description":"Only notification channels whose provider contains this text (upper and lower case are treated the same)."},"description":"Only notification channels whose provider contains this text (upper and lower case are treated the same)."},{"name":"from_address","in":"query","required":false,"schema":{"type":"string","description":"Only notification channels whose from address is exactly this."},"description":"Only notification channels whose from address is exactly this."},{"name":"from_address_contains","in":"query","required":false,"schema":{"type":"string","description":"Only notification channels whose from address contains this text (upper and lower case are treated the same)."},"description":"Only notification channels whose from address contains this text (upper and lower case are treated the same)."},{"name":"from_name","in":"query","required":false,"schema":{"type":"string","description":"Only notification channels whose from name is exactly this."},"description":"Only notification channels whose from name is exactly this."},{"name":"from_name_contains","in":"query","required":false,"schema":{"type":"string","description":"Only notification channels whose from name contains this text (upper and lower case are treated the same)."},"description":"Only notification channels whose from name contains this text (upper and lower case are treated the same)."},{"name":"domain","in":"query","required":false,"schema":{"type":"string","description":"Only notification channels whose domain is exactly this."},"description":"Only notification channels whose domain is exactly this."},{"name":"domain_contains","in":"query","required":false,"schema":{"type":"string","description":"Only notification channels whose domain contains this text (upper and lower case are treated the same)."},"description":"Only notification channels whose domain contains this text (upper and lower case are treated the same)."},{"name":"credential_ref","in":"query","required":false,"schema":{"type":"string","description":"Only notification channels whose credential ref is exactly this."},"description":"Only notification channels whose credential ref is exactly this."},{"name":"credential_ref_contains","in":"query","required":false,"schema":{"type":"string","description":"Only notification channels whose credential ref contains this text (upper and lower case are treated the same)."},"description":"Only notification channels whose credential ref contains this text (upper and lower case are treated the same)."},{"name":"verified","in":"query","required":false,"schema":{"type":"boolean","description":"Only notification channels where verified is true, or false for only those where it is false."},"description":"Only notification channels where verified is true, or false for only those where it is false."},{"name":"enabled","in":"query","required":false,"schema":{"type":"boolean","description":"Only notification channels where enabled is true, or false for only those where it is false."},"description":"Only notification channels where enabled is true, or false for only those where it is false."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many notification channels to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many notification channels to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many notification channels to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many notification channels to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","name","kind","provider","from_address","from_name","domain","credential_ref","verified","enabled","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns notification channels where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns notification channels where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"kind":{"type":"string"},"provider":{"type":"string","nullable":true},"from_address":{"type":"string","nullable":true},"from_name":{"type":"string","nullable":true},"domain":{"type":"string","nullable":true},"config":{"type":"object","additionalProperties":true,"nullable":true},"credential_ref":{"type":"string","nullable":true},"verified":{"type":"boolean"},"enabled":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","name"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","name":"string","kind":"string","provider":"string","from_address":"string","from_name":"string","domain":"string","config":{},"credential_ref":"string","verified":true,"enabled":true,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"NotificationChannelsCreate","tags":["workspace"],"summary":"Notification Channels Create","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Create a notification channel. Returns the new notification channel, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"kind":{"type":"string"},"provider":{"type":"string","nullable":true},"from_address":{"type":"string","nullable":true},"from_name":{"type":"string","nullable":true},"domain":{"type":"string","nullable":true},"config":{"type":"object","additionalProperties":true,"nullable":true},"enabled":{"type":"boolean"}},"required":["name"]},"example":{"name":"string","kind":"string","provider":"string","from_address":"string","from_name":"string","domain":"string","config":{},"enabled":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"kind":{"type":"string"},"provider":{"type":"string","nullable":true},"from_address":{"type":"string","nullable":true},"from_name":{"type":"string","nullable":true},"domain":{"type":"string","nullable":true},"config":{"type":"object","additionalProperties":true,"nullable":true},"credential_ref":{"type":"string","nullable":true},"verified":{"type":"boolean"},"enabled":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","name"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","name":"string","kind":"string","provider":"string","from_address":"string","from_name":"string","domain":"string","config":{},"credential_ref":"string","verified":true,"enabled":true,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/notification-channels/{id}":{"delete":{"operationId":"NotificationChannelsDelete","tags":["workspace"],"summary":"Notification Channels Delete","security":[{"ApiKeyAuth":["workspace:delete"]},{"BearerAuth":[]},{"OAuth2":["workspace:delete"]}],"description":"Delete a notification channel permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the notification channel."},"description":"The id of the notification channel."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"NotificationChannelsGet","tags":["workspace"],"summary":"Notification Channels Get","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"Get one of your notification channels by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the notification channel."},"description":"The id of the notification channel."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"kind":{"type":"string"},"provider":{"type":"string","nullable":true},"from_address":{"type":"string","nullable":true},"from_name":{"type":"string","nullable":true},"domain":{"type":"string","nullable":true},"config":{"type":"object","additionalProperties":true,"nullable":true},"credential_ref":{"type":"string","nullable":true},"verified":{"type":"boolean"},"enabled":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","name"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","name":"string","kind":"string","provider":"string","from_address":"string","from_name":"string","domain":"string","config":{},"credential_ref":"string","verified":true,"enabled":true,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"NotificationChannelsUpdate","tags":["workspace"],"summary":"Notification Channels Update","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Change a notification channel. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the notification channel."},"description":"The id of the notification channel."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"kind":{"type":"string"},"provider":{"type":"string","nullable":true},"from_address":{"type":"string","nullable":true},"from_name":{"type":"string","nullable":true},"domain":{"type":"string","nullable":true},"config":{"type":"object","additionalProperties":true,"nullable":true},"enabled":{"type":"boolean"}}},"example":{"name":"string","kind":"string","provider":"string","from_address":"string","from_name":"string","domain":"string","config":{},"enabled":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"kind":{"type":"string"},"provider":{"type":"string","nullable":true},"from_address":{"type":"string","nullable":true},"from_name":{"type":"string","nullable":true},"domain":{"type":"string","nullable":true},"config":{"type":"object","additionalProperties":true,"nullable":true},"credential_ref":{"type":"string","nullable":true},"verified":{"type":"boolean"},"enabled":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","name"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","name":"string","kind":"string","provider":"string","from_address":"string","from_name":"string","domain":"string","config":{},"credential_ref":"string","verified":true,"enabled":true,"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/notification-channels/{id}/credential":{"post":{"operationId":"SetChannelCredential","tags":["notifications"],"summary":"Set Channel Credential","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Save the secret one of your notification channels needs to send messages, such as your email server password or SMS provider key. It is encrypted before it is stored and is never shown again. Saving a new secret means the channel must be verified again before it is used. For a webhook channel the secret is the signing secret every message is signed with (X-Inferrex-Signature, HMAC-SHA256 of the body); leave it out and Inferrex makes a new one and returns it once as signingSecret.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the notification channel."},"description":"The id of the notification channel."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"secret":{"type":"string","description":"The secret the channel needs, such as a password or API key. Required except for a webhook channel, where leaving it out makes a new signing secret."},"config":{"type":"object","additionalProperties":true,"nullable":true,"description":"Optional settings to save with it, such as a server address."}}},"example":{"secret":"string","config":{}}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"ok":{"type":"boolean"},"signingSecret":{"type":"string","description":"A webhook channel's new signing secret, when Inferrex made it. Shown once — store it now; it is never returned again."}},"required":["id","ok"]},"example":{"id":"00000000-0000-0000-0000-000000000000","ok":true,"signingSecret":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/notification-channels/{id}/verify":{"post":{"operationId":"VerifyChannel","tags":["notifications"],"summary":"Verify Channel","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Test one of your notification channels with its saved settings and secret (for example by connecting to your email server or calling the webhook) and record whether it worked. A webhook channel's test message is signed like every other; one with no signing secret gets one first (make a new one to copy with the credential route).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the notification channel."},"description":"The id of the notification channel."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"verified":{"type":"boolean"}},"required":["id","verified"]},"example":{"id":"00000000-0000-0000-0000-000000000000","verified":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/overview":{"get":{"operationId":"GetEnvironmentOverview","tags":["workspace"],"summary":"Get Environment Overview","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"A holistic overview of this workspace and environment, with recommendations. Use it FIRST for any broad question — \"give me an overview\", \"how is my environment\", \"any recommendations\", \"what should I fix\", \"what needs attention\". For each module the caller can see (systems, mappings, pipelines, workflows, golden records, gamification, health, repairs, stack insights, vendor API changes, restore and retention, archive, migrations): a one-line summary, counts, and recommendations worst first. Each recommendation has a severity (critical, warning, info), a kind (problem, decision, improvement), a plain-English title and why, evidence naming the records by their human labels with their ids, a link to the page in the Inferrex app where it is fixed, and the tool and arguments that act on it when one exists. A module whose data could not be read just now says so (state: unavailable) instead of failing the whole answer. Start with detail=brief for the whole workspace; then module=<key> for one module's why and evidence in full. Read only.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":20,"description":"Most recommendations returned per module, worst first. Each module's recommendationCount is always the full number.","default":5},"description":"Most recommendations returned per module, worst first. Each module's recommendationCount is always the full number."},{"name":"detail","in":"query","required":false,"schema":{"type":"string","enum":["full","brief"],"description":"brief: a first look at the whole workspace — titles, severities, links, actions and the names in the evidence, without each recommendation's id, why and source, the module counts, or evidence ids and links. full: everything.","default":"full"},"description":"brief: a first look at the whole workspace — titles, severities, links, actions and the names in the evidence, without each recommendation's id, why and source, the module counts, or evidence ids and links. full: everything."},{"name":"module","in":"query","required":false,"schema":{"type":"string","description":"Only these modules, by key, comma-separated (e.g. pipelines,systems) — to read one module in full after a brief look."},"description":"Only these modules, by key, comma-separated (e.g. pipelines,systems) — to read one module in full after a brief look."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"generatedAt":{"type":"string","format":"date-time"},"recommendationCount":{"type":"integer","description":"Across every module, before the per-module limit."},"modules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Known values: systems, mappings, pipelines, workflows, records, gamification, health, repairs, insights, governance, protect, archive, migrations."},"label":{"type":"string","description":"The module's name as the app shows it."},"link":{"type":"string","description":"The module's page in the Inferrex app."},"state":{"type":"string","description":"Known values: ok (every source answered), partial (some did not), unavailable (none did — nothing else in the entry is reliable)."},"summary":{"type":"string","description":"One plain-English sentence."},"counts":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"value":{"type":"integer"}},"required":["key","label","value"]},"description":"Left out when detail=brief."},"recommendationCount":{"type":"integer","description":"Every recommendation the module has, before the limit."},"recommendations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable for the same finding: module:rule[:subject]. Left out when detail=brief."},"module":{"type":"string","description":"Left out when detail=brief."},"severity":{"type":"string","description":"Known values: critical, warning, info."},"kind":{"type":"string","description":"Known values: problem (something is broken), decision (waiting for a person), improvement (could be better)."},"title":{"type":"string","description":"Plain English, naming records by name."},"why":{"type":"string","description":"Why it matters, in plain English. Left out when detail=brief."},"evidence":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","description":"The human name of the record, or what the figure counts."},"id":{"type":"string","nullable":true,"description":"Null when detail=brief."},"count":{"type":"number","nullable":true},"link":{"type":"string","nullable":true,"description":"Its page in the Inferrex app. Null when detail=brief."}},"required":["label","id","count","link"]},"description":"The records or figures it rests on, at most five (the last may be \"N more\")."},"link":{"type":"string","description":"Where to act, in the Inferrex app."},"action":{"type":"object","properties":{"label":{"type":"string"},"tool":{"type":"string","nullable":true,"description":"The Ask Inferrex / MCP tool name."},"arguments":{"type":"object","additionalProperties":true}},"required":["label","tool","arguments"],"nullable":true,"description":"The tool that acts on it, when there is one. A change still needs the user to confirm it."},"source":{"type":"string","description":"The route the finding came from, e.g. GET /v1/intelligence/insights. Left out when detail=brief."}},"required":["severity","kind","title","evidence","link","action"]},"description":"Worst first, at most `limit`."}},"required":["key","label","link","state","summary","recommendationCount","recommendations"]},"description":"Only the modules the caller can read, in the app's navigation order."}},"required":["generatedAt","recommendationCount","modules"]},"example":{"generatedAt":"2026-01-01T00:00:00Z","recommendationCount":0,"modules":[{"key":"string","label":"string","link":"string","state":"string","summary":"string","counts":[{"key":"string","label":"string","value":0}],"recommendationCount":0,"recommendations":[{"id":"string","module":"string","severity":"string","kind":"string","title":"string","why":"string","evidence":[{"label":"string","id":"string","count":0,"link":"string"}],"link":"string","action":{"label":"string","tool":"string","arguments":{}},"source":"string"}]}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/permissions":{"get":{"operationId":"ResourcePermissionsList","tags":["rbac"],"summary":"Resource Permissions List","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"List your resource permissions, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"workspace_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"user_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only resource permissions for this user. Pass its id."},"description":"Only resource permissions for this user. Pass its id."},{"name":"resource_type","in":"query","required":false,"schema":{"type":"string","description":"Only resource permissions whose resource type is exactly this."},"description":"Only resource permissions whose resource type is exactly this."},{"name":"resource_type_contains","in":"query","required":false,"schema":{"type":"string","description":"Only resource permissions whose resource type contains this text (upper and lower case are treated the same)."},"description":"Only resource permissions whose resource type contains this text (upper and lower case are treated the same)."},{"name":"resource_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only resource permissions for this resource. Pass its id."},"description":"Only resource permissions for this resource. Pass its id."},{"name":"permission","in":"query","required":false,"schema":{"type":"string","description":"Only resource permissions whose permission is exactly this."},"description":"Only resource permissions whose permission is exactly this."},{"name":"permission_contains","in":"query","required":false,"schema":{"type":"string","description":"Only resource permissions whose permission contains this text (upper and lower case are treated the same)."},"description":"Only resource permissions whose permission contains this text (upper and lower case are treated the same)."},{"name":"effect","in":"query","required":false,"schema":{"type":"string","description":"Only resource permissions whose effect is exactly this."},"description":"Only resource permissions whose effect is exactly this."},{"name":"effect_contains","in":"query","required":false,"schema":{"type":"string","description":"Only resource permissions whose effect contains this text (upper and lower case are treated the same)."},"description":"Only resource permissions whose effect contains this text (upper and lower case are treated the same)."},{"name":"granted_by","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only resource permissions for this granted by. Pass its id."},"description":"Only resource permissions for this granted by. Pass its id."},{"name":"granted_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only resource permissions whose granted time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only resource permissions whose granted time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"granted_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only resource permissions whose granted time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only resource permissions whose granted time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many resource permissions to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many resource permissions to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many resource permissions to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many resource permissions to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","workspace_id","user_id","resource_type","resource_id","permission","effect","granted_by","granted_at"],"description":"The field to sort the list by.","default":"granted_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns resource permissions where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns resource permissions where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"resource_type":{"type":"string"},"resource_id":{"type":"string","format":"uuid","nullable":true},"permission":{"type":"string"},"effect":{"type":"string"},"granted_by":{"type":"string","format":"uuid","nullable":true},"granted_at":{"type":"string"}},"required":["workspace_id","user_id","resource_type","permission","effect"]},"example":{"id":"00000000-0000-0000-0000-000000000000","workspace_id":"00000000-0000-0000-0000-000000000000","user_id":"00000000-0000-0000-0000-000000000000","resource_type":"string","resource_id":"00000000-0000-0000-0000-000000000000","permission":"string","effect":"string","granted_by":"00000000-0000-0000-0000-000000000000","granted_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"ResourcePermissionsCreate","tags":["rbac"],"summary":"Resource Permissions Create","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Create a resource permission. Returns the new resource permission, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"user_id":{"type":"string","format":"uuid"},"resource_type":{"type":"string"},"resource_id":{"type":"string","format":"uuid","nullable":true},"permission":{"type":"string"},"effect":{"type":"string"},"granted_at":{"type":"string"}},"required":["user_id","resource_type","permission","effect"]},"example":{"user_id":"00000000-0000-0000-0000-000000000000","resource_type":"string","resource_id":"00000000-0000-0000-0000-000000000000","permission":"string","effect":"string","granted_at":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"resource_type":{"type":"string"},"resource_id":{"type":"string","format":"uuid","nullable":true},"permission":{"type":"string"},"effect":{"type":"string"},"granted_by":{"type":"string","format":"uuid","nullable":true},"granted_at":{"type":"string"}},"required":["workspace_id","user_id","resource_type","permission","effect"]},"example":{"id":"00000000-0000-0000-0000-000000000000","workspace_id":"00000000-0000-0000-0000-000000000000","user_id":"00000000-0000-0000-0000-000000000000","resource_type":"string","resource_id":"00000000-0000-0000-0000-000000000000","permission":"string","effect":"string","granted_by":"00000000-0000-0000-0000-000000000000","granted_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/permissions/{id}":{"delete":{"operationId":"ResourcePermissionsDelete","tags":["rbac"],"summary":"Resource Permissions Delete","security":[{"ApiKeyAuth":["workspace:delete"]},{"BearerAuth":[]},{"OAuth2":["workspace:delete"]}],"description":"Delete a resource permission permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the resource permission."},"description":"The id of the resource permission."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/pipelines/{id}/connection-access":{"get":{"operationId":"ListPipelineConnectionAccess","tags":["pipelines"],"summary":"List Pipeline Connection Access","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"What this pipeline is allowed to do to each connection it uses: only read from it, or read and write. The same connection can be read-only in one pipeline and writable in another. A connection with no setting is read and write.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","format":"uuid"},"connections":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid"},"connection_name":{"type":"string","nullable":true},"role":{"type":"string","enum":["source","target","destination"]},"access_level":{"type":"string","enum":["read","read_write"]},"explicit":{"type":"boolean","description":"True when a level was set for this pipeline; false = the read_write default."},"pipeline_writes":{"type":"boolean","description":"Whether this pipeline’s direction writes to the connection at all."}},"required":["id","connection_id","role","access_level","explicit","pipeline_writes"]}}},"required":["pipelineId","connections"]},"example":{"pipelineId":"00000000-0000-0000-0000-000000000000","connections":[{"id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","connection_name":"string","role":"source","access_level":"read","explicit":true,"pipeline_writes":true}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"SetPipelineConnectionAccess","tags":["pipelines"],"summary":"Set Pipeline Connection Access","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Set what this pipeline is allowed to do to one of its connections. Read only: the pipeline will never write to that system. Read and write: it writes to it where its sync direction says to.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the pipeline."},"description":"The id of the pipeline."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","description":"The connection to set access for."},"accessLevel":{"type":"string","enum":["read","read_write"],"description":"read (read only) or read_write (read and write)."}},"required":["connectionId","accessLevel"]},"example":{"connectionId":"00000000-0000-0000-0000-000000000000","accessLevel":"read"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pipeline_id":{"type":"string","format":"uuid"},"connection_id":{"type":"string","format":"uuid"},"access_level":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","pipeline_id","connection_id","access_level","updated_at"]},"example":{"id":"00000000-0000-0000-0000-000000000000","pipeline_id":"00000000-0000-0000-0000-000000000000","connection_id":"00000000-0000-0000-0000-000000000000","access_level":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/promotion-edges":{"get":{"operationId":"PromotionEdgesList","tags":["workspace"],"summary":"Promotion Edges List","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"List your promotion edges, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"from_environment_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only promotion edges for this from environment. Pass its id."},"description":"Only promotion edges for this from environment. Pass its id."},{"name":"to_environment_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only promotion edges for this to environment. Pass its id."},"description":"Only promotion edges for this to environment. Pass its id."},{"name":"enabled","in":"query","required":false,"schema":{"type":"boolean","description":"Only promotion edges where enabled is true, or false for only those where it is false."},"description":"Only promotion edges where enabled is true, or false for only those where it is false."},{"name":"approval_policy_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only promotion edges for this approval policy. Pass its id."},"description":"Only promotion edges for this approval policy. Pass its id."},{"name":"description","in":"query","required":false,"schema":{"type":"string","description":"Only promotion edges whose description is exactly this."},"description":"Only promotion edges whose description is exactly this."},{"name":"description_contains","in":"query","required":false,"schema":{"type":"string","description":"Only promotion edges whose description contains this text (upper and lower case are treated the same)."},"description":"Only promotion edges whose description contains this text (upper and lower case are treated the same)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many promotion edges to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many promotion edges to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many promotion edges to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many promotion edges to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","from_environment_id","to_environment_id","enabled","approval_policy_id","description","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns promotion edges where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns promotion edges where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"from_environment_id":{"type":"string","format":"uuid","description":"The environment a pipeline is promoted from."},"to_environment_id":{"type":"string","format":"uuid","description":"The environment a pipeline is promoted to. Inferrex also checks separately that you are allowed to deploy into it."},"enabled":{"type":"boolean","description":"Switch off to pause this step. A switched-off step is refused, just like one that does not exist, but keeps its approval settings."},"approval_policy_id":{"type":"string","format":"uuid","nullable":true,"description":"The approval rule for this step. Leave empty to use your workspace’s general approval rule for pipeline promotions."},"description":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","from_environment_id","to_environment_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","from_environment_id":"00000000-0000-0000-0000-000000000000","to_environment_id":"00000000-0000-0000-0000-000000000000","enabled":true,"approval_policy_id":"00000000-0000-0000-0000-000000000000","description":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"PromotionEdgesCreate","tags":["workspace"],"summary":"Promotion Edges Create","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Create a promotion edge. Returns the new promotion edge, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"from_environment_id":{"type":"string","format":"uuid","description":"The environment a pipeline is promoted from."},"to_environment_id":{"type":"string","format":"uuid","description":"The environment a pipeline is promoted to. Inferrex also checks separately that you are allowed to deploy into it."},"enabled":{"type":"boolean","description":"Switch off to pause this step. A switched-off step is refused, just like one that does not exist, but keeps its approval settings."},"approval_policy_id":{"type":"string","format":"uuid","nullable":true,"description":"The approval rule for this step. Leave empty to use your workspace’s general approval rule for pipeline promotions."},"description":{"type":"string","nullable":true}},"required":["from_environment_id","to_environment_id"]},"example":{"from_environment_id":"00000000-0000-0000-0000-000000000000","to_environment_id":"00000000-0000-0000-0000-000000000000","enabled":true,"approval_policy_id":"00000000-0000-0000-0000-000000000000","description":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"from_environment_id":{"type":"string","format":"uuid","description":"The environment a pipeline is promoted from."},"to_environment_id":{"type":"string","format":"uuid","description":"The environment a pipeline is promoted to. Inferrex also checks separately that you are allowed to deploy into it."},"enabled":{"type":"boolean","description":"Switch off to pause this step. A switched-off step is refused, just like one that does not exist, but keeps its approval settings."},"approval_policy_id":{"type":"string","format":"uuid","nullable":true,"description":"The approval rule for this step. Leave empty to use your workspace’s general approval rule for pipeline promotions."},"description":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","from_environment_id","to_environment_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","from_environment_id":"00000000-0000-0000-0000-000000000000","to_environment_id":"00000000-0000-0000-0000-000000000000","enabled":true,"approval_policy_id":"00000000-0000-0000-0000-000000000000","description":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/promotion-edges/{id}":{"delete":{"operationId":"PromotionEdgesDelete","tags":["workspace"],"summary":"Promotion Edges Delete","security":[{"ApiKeyAuth":["workspace:delete"]},{"BearerAuth":[]},{"OAuth2":["workspace:delete"]}],"description":"Delete a promotion edge permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the promotion edge."},"description":"The id of the promotion edge."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"PromotionEdgesGet","tags":["workspace"],"summary":"Promotion Edges Get","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"Get one of your promotion edges by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the promotion edge."},"description":"The id of the promotion edge."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"from_environment_id":{"type":"string","format":"uuid","description":"The environment a pipeline is promoted from."},"to_environment_id":{"type":"string","format":"uuid","description":"The environment a pipeline is promoted to. Inferrex also checks separately that you are allowed to deploy into it."},"enabled":{"type":"boolean","description":"Switch off to pause this step. A switched-off step is refused, just like one that does not exist, but keeps its approval settings."},"approval_policy_id":{"type":"string","format":"uuid","nullable":true,"description":"The approval rule for this step. Leave empty to use your workspace’s general approval rule for pipeline promotions."},"description":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","from_environment_id","to_environment_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","from_environment_id":"00000000-0000-0000-0000-000000000000","to_environment_id":"00000000-0000-0000-0000-000000000000","enabled":true,"approval_policy_id":"00000000-0000-0000-0000-000000000000","description":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"PromotionEdgesUpdate","tags":["workspace"],"summary":"Promotion Edges Update","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Change a promotion edge. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the promotion edge."},"description":"The id of the promotion edge."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"from_environment_id":{"type":"string","format":"uuid","description":"The environment a pipeline is promoted from."},"to_environment_id":{"type":"string","format":"uuid","description":"The environment a pipeline is promoted to. Inferrex also checks separately that you are allowed to deploy into it."},"enabled":{"type":"boolean","description":"Switch off to pause this step. A switched-off step is refused, just like one that does not exist, but keeps its approval settings."},"approval_policy_id":{"type":"string","format":"uuid","nullable":true,"description":"The approval rule for this step. Leave empty to use your workspace’s general approval rule for pipeline promotions."},"description":{"type":"string","nullable":true}}},"example":{"from_environment_id":"00000000-0000-0000-0000-000000000000","to_environment_id":"00000000-0000-0000-0000-000000000000","enabled":true,"approval_policy_id":"00000000-0000-0000-0000-000000000000","description":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"from_environment_id":{"type":"string","format":"uuid","description":"The environment a pipeline is promoted from."},"to_environment_id":{"type":"string","format":"uuid","description":"The environment a pipeline is promoted to. Inferrex also checks separately that you are allowed to deploy into it."},"enabled":{"type":"boolean","description":"Switch off to pause this step. A switched-off step is refused, just like one that does not exist, but keeps its approval settings."},"approval_policy_id":{"type":"string","format":"uuid","nullable":true,"description":"The approval rule for this step. Leave empty to use your workspace’s general approval rule for pipeline promotions."},"description":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","from_environment_id","to_environment_id"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","from_environment_id":"00000000-0000-0000-0000-000000000000","to_environment_id":"00000000-0000-0000-0000-000000000000","enabled":true,"approval_policy_id":"00000000-0000-0000-0000-000000000000","description":"string","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/promotion-edges/standard":{"post":{"operationId":"SeedStandardPromotionEdges","tags":["workspace"],"summary":"Seed Standard Promotion Edges","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Set up the usual promotion path between your environments: development, then QA, UAT, staging and production, linking only the ones you have. Steps you already have are kept as they are, so running it again does nothing new. Environments that do not fit this path are left for you to place.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"created":{"type":"integer"},"existing":{"type":"integer"},"edges":{"type":"array","items":{"type":"object","properties":{"from":{"type":"string","format":"uuid","description":"Environment id."},"to":{"type":"string","format":"uuid","description":"Environment id."}},"required":["from","to"]},"description":"Every link of the standard path over this workspace's environments, new and already present."}},"required":["created","existing","edges"]},"example":{"created":0,"existing":0,"edges":[{"from":"00000000-0000-0000-0000-000000000000","to":"00000000-0000-0000-0000-000000000000"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/review-assignments":{"get":{"operationId":"ReviewAssignmentsList","tags":["workspace"],"summary":"Review Assignments List","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"List your review assignments, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"item_kind","in":"query","required":false,"schema":{"type":"string","description":"Only review assignments whose item kind is exactly this."},"description":"Only review assignments whose item kind is exactly this."},{"name":"item_kind_contains","in":"query","required":false,"schema":{"type":"string","description":"Only review assignments whose item kind contains this text (upper and lower case are treated the same)."},"description":"Only review assignments whose item kind contains this text (upper and lower case are treated the same)."},{"name":"item_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only review assignments for this item. Pass its id."},"description":"Only review assignments for this item. Pass its id."},{"name":"assignee_user_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only review assignments for this assignee user. Pass its id."},"description":"Only review assignments for this assignee user. Pass its id."},{"name":"assignee_email","in":"query","required":false,"schema":{"type":"string","description":"Only review assignments whose assignee email is exactly this."},"description":"Only review assignments whose assignee email is exactly this."},{"name":"assignee_email_contains","in":"query","required":false,"schema":{"type":"string","description":"Only review assignments whose assignee email contains this text (upper and lower case are treated the same)."},"description":"Only review assignments whose assignee email contains this text (upper and lower case are treated the same)."},{"name":"assignee_name","in":"query","required":false,"schema":{"type":"string","description":"Only review assignments whose assignee name is exactly this."},"description":"Only review assignments whose assignee name is exactly this."},{"name":"assignee_name_contains","in":"query","required":false,"schema":{"type":"string","description":"Only review assignments whose assignee name contains this text (upper and lower case are treated the same)."},"description":"Only review assignments whose assignee name contains this text (upper and lower case are treated the same)."},{"name":"assigned_by","in":"query","required":false,"schema":{"type":"string","description":"Only review assignments whose assigned by is exactly this."},"description":"Only review assignments whose assigned by is exactly this."},{"name":"assigned_by_contains","in":"query","required":false,"schema":{"type":"string","description":"Only review assignments whose assigned by contains this text (upper and lower case are treated the same)."},"description":"Only review assignments whose assigned by contains this text (upper and lower case are treated the same)."},{"name":"assigned_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only review assignments whose assigned time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only review assignments whose assigned time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"assigned_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only review assignments whose assigned time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only review assignments whose assigned time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many review assignments to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many review assignments to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many review assignments to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many review assignments to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","item_kind","item_id","assignee_user_id","assignee_email","assignee_name","assigned_by","assigned_at"],"description":"The field to sort the list by.","default":"assigned_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns review assignments where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns review assignments where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"item_kind":{"type":"string","description":"What kind of item it is: a safety stop, a failed write, a repair question, a golden record change, a promotion, a first load or an invite."},"item_id":{"type":"string","format":"uuid","description":"The item's own id in its list (the safety stop, failed write, repair, change, promotion, first load or invite)."},"assignee_user_id":{"type":"string","format":"uuid","description":"The teammate looking at it."},"assignee_email":{"type":"string","description":"The member's email when it was assigned."},"assignee_name":{"type":"string","nullable":true,"description":"The member's name when it was assigned, if they have one."},"assigned_by":{"type":"string","description":"Who assigned it (their email)."},"assigned_at":{"type":"string"}},"required":["customer_id","item_kind","item_id","assignee_user_id","assignee_email","assigned_by"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","item_kind":"string","item_id":"00000000-0000-0000-0000-000000000000","assignee_user_id":"00000000-0000-0000-0000-000000000000","assignee_email":"string","assignee_name":"string","assigned_by":"string","assigned_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"AssignReviewItem","tags":["workspace"],"summary":"Assign Review Item","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Say who is looking at an item in the Review queue: a safety stop, failed write, repair question, golden-record change, promotion, first load or held invite. Pass assignee \"me\" to take it yourself, or a member's id to hand it to them. One person per item; assigning again replaces them. 400 when the member is not an active member of this workspace.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"itemKind":{"type":"string","minLength":1,"maxLength":40,"description":"What kind of item it is: a safety stop, a failed write, a repair question, a golden record change, a promotion, a first load or an invite."},"itemId":{"type":"string","format":"uuid","description":"The item's id."},"assignee":{"type":"string","minLength":1,"maxLength":64,"description":"\"me\" to take it yourself, or the member id of the teammate to assign."}},"required":["itemKind","itemId","assignee"]},"example":{"itemKind":"string","itemId":"00000000-0000-0000-0000-000000000000","assignee":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"item_kind":{"type":"string"},"item_id":{"type":"string","format":"uuid"},"assignee_user_id":{"type":"string","format":"uuid"},"assignee_email":{"type":"string"},"assignee_name":{"type":"string","nullable":true},"assigned_by":{"type":"string"},"assigned_at":{"type":"string","format":"date-time"}},"required":["id","item_kind","item_id","assignee_user_id","assignee_email","assignee_name","assigned_by","assigned_at"]},"example":{"id":"00000000-0000-0000-0000-000000000000","item_kind":"string","item_id":"00000000-0000-0000-0000-000000000000","assignee_user_id":"00000000-0000-0000-0000-000000000000","assignee_email":"string","assignee_name":"string","assigned_by":"string","assigned_at":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/review-assignments/{id}":{"delete":{"operationId":"ReviewAssignmentsDelete","tags":["workspace"],"summary":"Review Assignments Delete","security":[{"ApiKeyAuth":["workspace:delete"]},{"BearerAuth":[]},{"OAuth2":["workspace:delete"]}],"description":"Delete a review assignment permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the review assignment."},"description":"The id of the review assignment."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/saved-views":{"get":{"operationId":"SavedViewsList","tags":["workspace"],"summary":"Saved Views List","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"List your saved views, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"customer_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"user_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only saved views for this user. Pass its id."},"description":"Only saved views for this user. Pass its id."},{"name":"list_key","in":"query","required":false,"schema":{"type":"string","description":"Only saved views whose list key is exactly this."},"description":"Only saved views whose list key is exactly this."},{"name":"list_key_contains","in":"query","required":false,"schema":{"type":"string","description":"Only saved views whose list key contains this text (upper and lower case are treated the same)."},"description":"Only saved views whose list key contains this text (upper and lower case are treated the same)."},{"name":"name","in":"query","required":false,"schema":{"type":"string","description":"Only saved views whose name is exactly this."},"description":"Only saved views whose name is exactly this."},{"name":"name_contains","in":"query","required":false,"schema":{"type":"string","description":"Only saved views whose name contains this text (upper and lower case are treated the same)."},"description":"Only saved views whose name contains this text (upper and lower case are treated the same)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many saved views to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many saved views to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many saved views to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many saved views to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","customer_id","user_id","list_key","name","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns saved views where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns saved views where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid","nullable":true},"list_key":{"type":"string","description":"Which list the view is of, e.g. flows."},"name":{"type":"string","description":"What the person called the view."},"view":{"type":"object","additionalProperties":true,"description":"What the view shows: search (text), filter (the list's filter key) and sort (the list's sort key)."},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","list_key","name"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","user_id":"00000000-0000-0000-0000-000000000000","list_key":"string","name":"string","view":{},"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"SavedViewsCreate","tags":["workspace"],"summary":"Saved Views Create","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Create a saved view. Returns the new saved view, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"list_key":{"type":"string","description":"Which list the view is of, e.g. flows."},"name":{"type":"string","description":"What the person called the view."},"view":{"type":"object","additionalProperties":true,"description":"What the view shows: search (text), filter (the list's filter key) and sort (the list's sort key)."},"personal":{"type":"boolean","description":"Keep this private to you. Omit or set false to share it with the whole workspace."}},"required":["list_key","name"]},"example":{"list_key":"string","name":"string","view":{},"personal":true}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid","nullable":true},"list_key":{"type":"string","description":"Which list the view is of, e.g. flows."},"name":{"type":"string","description":"What the person called the view."},"view":{"type":"object","additionalProperties":true,"description":"What the view shows: search (text), filter (the list's filter key) and sort (the list's sort key)."},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","list_key","name"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","user_id":"00000000-0000-0000-0000-000000000000","list_key":"string","name":"string","view":{},"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/saved-views/{id}":{"delete":{"operationId":"SavedViewsDelete","tags":["workspace"],"summary":"Saved Views Delete","security":[{"ApiKeyAuth":["workspace:delete"]},{"BearerAuth":[]},{"OAuth2":["workspace:delete"]}],"description":"Delete a saved view permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the saved view."},"description":"The id of the saved view."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"SavedViewsUpdate","tags":["workspace"],"summary":"Saved Views Update","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Change a saved view. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the saved view."},"description":"The id of the saved view."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"list_key":{"type":"string","description":"Which list the view is of, e.g. flows."},"name":{"type":"string","description":"What the person called the view."},"view":{"type":"object","additionalProperties":true,"description":"What the view shows: search (text), filter (the list's filter key) and sort (the list's sort key)."}}},"example":{"list_key":"string","name":"string","view":{}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid","nullable":true},"list_key":{"type":"string","description":"Which list the view is of, e.g. flows."},"name":{"type":"string","description":"What the person called the view."},"view":{"type":"object","additionalProperties":true,"description":"What the view shows: search (text), filter (the list's filter key) and sort (the list's sort key)."},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["customer_id","list_key","name"]},"example":{"id":"00000000-0000-0000-0000-000000000000","customer_id":"00000000-0000-0000-0000-000000000000","user_id":"00000000-0000-0000-0000-000000000000","list_key":"string","name":"string","view":{},"created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/schema-contributions/{id}/approve":{"post":{"operationId":"ApproveSchemaContribution","tags":["workspace"],"summary":"Approve Schema Contribution","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"state":{"type":"string","enum":["requested","approved","declined"]}},"required":["id","state"]},"example":{"id":"00000000-0000-0000-0000-000000000000","state":"requested"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/schema-contributions/{id}/decline":{"post":{"operationId":"DeclineSchemaContribution","tags":["workspace"],"summary":"Decline Schema Contribution","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","maxLength":2000}}},"example":{"note":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"state":{"type":"string","enum":["requested","approved","declined"]}},"required":["id","state"]},"example":{"id":"00000000-0000-0000-0000-000000000000","state":"requested"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/secrets/failing":{"get":{"operationId":"ListFailingSecrets","tags":["credentials"],"summary":"List Failing Secrets","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"The secrets your systems are refusing right now: which secret, which system, since when and why. Empty when every secret in use was last accepted or has not been tested. Values are never returned.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"secrets":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string"},"purpose":{"type":"string","nullable":true},"connectionId":{"type":"string","format":"uuid","nullable":true},"systemName":{"type":"string","nullable":true},"failingSince":{"type":"string","format":"date-time","nullable":true},"lastOutcomeAt":{"type":"string","format":"date-time","nullable":true},"httpStatus":{"type":"integer","nullable":true},"reason":{"type":"string","nullable":true},"learnedFrom":{"type":"string","nullable":true,"description":"rotation-test, test-now, connection-test, oauth-consent, sync or bloomreach."}},"required":["id","key","purpose","connectionId","systemName","failingSince","lastOutcomeAt","httpStatus","reason","learnedFrom"]}}},"required":["secrets"]},"example":{"secrets":[{"id":"00000000-0000-0000-0000-000000000000","key":"string","purpose":"string","connectionId":"00000000-0000-0000-0000-000000000000","systemName":"string","failingSince":"2026-01-01T00:00:00Z","lastOutcomeAt":"2026-01-01T00:00:00Z","httpStatus":0,"reason":"string","learnedFrom":"string"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/sso/providers":{"get":{"operationId":"ListSsoProviders","tags":["sso"],"summary":"List Sso Providers","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"Your workspace’s single sign-on providers, and how many you can have. Only the workspace owner can see them.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"providers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"providerId":{"type":"string"},"type":{"type":"string","enum":["saml","oidc"]},"displayName":{"type":"string"},"enabled":{"type":"boolean"},"createdAt":{"type":"string"}},"required":["id","providerId","type","displayName","enabled","createdAt"]}},"maxProviders":{"type":"integer"},"deploymentMode":{"type":"string"},"sovereignMode":{"type":"boolean"}},"required":["providers","maxProviders","deploymentMode","sovereignMode"]},"example":{"providers":[{"id":"00000000-0000-0000-0000-000000000000","providerId":"string","type":"saml","displayName":"string","enabled":true,"createdAt":"string"}],"maxProviders":0,"deploymentMode":"string","sovereignMode":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"CreateSsoProvider","tags":["sso"],"summary":"Create Sso Provider","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Add a single sign-on provider (SAML or OIDC), so your team signs in with your company’s identity provider. Only the workspace owner can do this, and a workspace can have up to 5 providers. SAML needs the identity provider’s entity id, sign-in URL and certificate; OIDC needs the client id and issuer.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"providerId":{"type":"string","minLength":1,"maxLength":64,"description":"A short id for this provider, unique in your workspace."},"displayName":{"type":"string","minLength":1,"maxLength":128,"description":"The name people see on the sign-in button."},"type":{"type":"string","enum":["saml","oidc"],"description":"saml or oidc."},"redirectUri":{"type":"string","format":"uri","maxLength":2048,"description":"Where the identity provider returns the user after sign-in: the OIDC redirect URI, or the SAML Assertion Consumer Service (ACS) URL. http(s) only."},"groupsClaim":{"type":"string","minLength":1,"maxLength":256,"description":"The claim (OIDC) or attribute (SAML) that carries the user's group memberships, read by the role mapping. Default: groups."},"idpEntityId":{"type":"string","maxLength":1024,"description":"SAML: your identity provider’s entity id."},"ssoUrl":{"type":"string","maxLength":2048,"description":"SAML: your identity provider’s sign-in URL."},"certificate":{"type":"string","description":"SAML: your identity provider’s signing certificate."},"spEntityId":{"type":"string","minLength":1,"maxLength":1024,"description":"SAML only, required: Inferrex's service-provider entity ID, as registered with the identity provider."},"audience":{"type":"string","minLength":1,"maxLength":1024,"description":"SAML only: the audience the assertion must name. Default: spEntityId."},"spPrivateKey":{"type":"string","maxLength":16384,"description":"SAML only: PEM private key used to sign the AuthnRequest. Stored encrypted; never returned."},"clientId":{"type":"string","maxLength":1024,"description":"OIDC: the client id your identity provider gave Inferrex."},"issuer":{"type":"string","maxLength":2048,"description":"OIDC: your identity provider’s issuer URL."},"clientSecret":{"type":"string","maxLength":2048,"description":"OIDC: the client secret, if your provider uses one."},"scopes":{"type":"string","minLength":1,"maxLength":1024,"description":"OIDC only: space-separated scopes to request. Default: openid email profile."}},"required":["providerId","displayName","type","redirectUri"]},"example":{"providerId":"string","displayName":"string","type":"saml","redirectUri":"https://example.com","groupsClaim":"string","idpEntityId":"string","ssoUrl":"string","certificate":"string","spEntityId":"string","audience":"string","spPrivateKey":"string","clientId":"string","issuer":"string","clientSecret":"string","scopes":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"type":"object","additionalProperties":true},"sovereignMode":{"type":"boolean"}},"required":["provider","sovereignMode"]},"example":{"provider":{},"sovereignMode":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/sso/providers/{providerId}":{"delete":{"operationId":"DeleteSsoProvider","tags":["sso"],"summary":"Delete Sso Provider","security":[{"ApiKeyAuth":["workspace:delete"]},{"BearerAuth":[]},{"OAuth2":["workspace:delete"]}],"description":"Remove a single sign-on provider from your workspace. Only the workspace owner can do this.","parameters":[{"name":"providerId","in":"path","required":true,"schema":{"type":"string","description":"The id of the provider."},"description":"The id of the provider."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}},"required":["deleted"]},"example":{"deleted":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/sso/role-mapping":{"get":{"operationId":"GetSsoRoleMapping","tags":["sso"],"summary":"Get Sso Role Mapping","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"Which Inferrex role each identity-provider group is given when people sign in through single sign-on. Only the workspace owner can see it.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"mappings":{"type":"array","items":{"type":"object","properties":{"group":{"type":"string","description":"The group name as the identity provider sends it."},"role":{"type":"string","enum":["viewer","operator","editor","admin"]}},"required":["group","role"]}},"maxEntries":{"type":"integer"}},"required":["mappings","maxEntries"]},"example":{"mappings":[{"group":"string","role":"viewer"}],"maxEntries":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"UpdateSsoRoleMapping","tags":["sso"],"summary":"Update Sso Role Mapping","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Set which Inferrex role people get when they sign in through single sign-on, based on the groups they belong to in your identity provider. Send the complete list (up to 50 entries) each time. Only the workspace owner can do this.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mappings":{"type":"array","items":{"type":"object","properties":{"group":{"type":"string","description":"The group name as the identity provider sends it."},"role":{"type":"string","enum":["viewer","operator","editor","admin"]}},"required":["group","role"]},"maximum":50,"description":"The complete list of {group, role} pairs, up to 50."}},"required":["mappings"]},"example":{"mappings":[{"group":"string","role":"viewer"}]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"mappings":{"type":"array","items":{"type":"object","properties":{"group":{"type":"string","description":"The group name as the identity provider sends it."},"role":{"type":"string","enum":["viewer","operator","editor","admin"]}},"required":["group","role"]}},"updatedAt":{"type":"string","format":"date-time"}},"required":["mappings","updatedAt"]},"example":{"mappings":[{"group":"string","role":"viewer"}],"updatedAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://913g6.wiremockapi.cloud","description":"Sandbox mock (part 2)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/support-access/current-session":{"get":{"operationId":"GetCurrentSupportSession","tags":["support_access"],"summary":"Get Current Support Session","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"The support view this request belongs to. Answers only for a support session.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"sessionId":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"workspaceName":{"type":"string"},"staffEmail":{"type":"string"},"reason":{"type":"string"},"startedAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"}},"required":["sessionId","workspaceId","workspaceName","staffEmail","reason","startedAt","expiresAt"]},"example":{"sessionId":"00000000-0000-0000-0000-000000000000","workspaceId":"00000000-0000-0000-0000-000000000000","workspaceName":"string","staffEmail":"string","reason":"string","startedAt":"2026-01-01T00:00:00Z","expiresAt":"2026-01-01T00:00:00Z"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/workspace/support-access/grants":{"get":{"operationId":"ListSupportAccessGrants","tags":["support_access"],"summary":"List Support Access Grants","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"Grants of read-only access to Inferrex support, newest first, with their status (active, expired or revoked) and how many support views were opened under each.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"grants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"grantedByEmail":{"type":"string"},"note":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"revokedAt":{"type":"string","format":"date-time","nullable":true},"revokedByEmail":{"type":"string","nullable":true},"status":{"type":"string","enum":["active","expired","revoked"]},"sessionCount":{"type":"integer"}},"required":["id","grantedByEmail","createdAt","expiresAt","status","sessionCount"]}},"total":{"type":"integer"}},"required":["grants","total"]},"example":{"grants":[{"id":"00000000-0000-0000-0000-000000000000","grantedByEmail":"string","note":"string","createdAt":"2026-01-01T00:00:00Z","expiresAt":"2026-01-01T00:00:00Z","revokedAt":"2026-01-01T00:00:00Z","revokedByEmail":"string","status":"active","sessionCount":0}],"total":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"GrantSupportAccess","tags":["support_access"],"summary":"Grant Support Access","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Give Inferrex support read-only access to this workspace for a fixed time. They can see what you see, as a viewer, but cannot change anything or read any secret. Only one grant can be active; revoke it to end access early.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"durationHours":{"type":"integer","minimum":1,"maximum":720,"description":"How long the grant lasts, in hours. The longest allowed is the platform setting supportAccess.maxGrantHours (7 days unless changed)."},"note":{"type":"string","maxLength":500,"description":"What you would like help with, shown to Inferrex staff."}},"required":["durationHours"]},"example":{"durationHours":0,"note":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"grantedByEmail":{"type":"string"},"note":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["active"]}},"required":["id","grantedByEmail","createdAt","expiresAt","status"]},"example":{"id":"00000000-0000-0000-0000-000000000000","grantedByEmail":"string","note":"string","createdAt":"2026-01-01T00:00:00Z","expiresAt":"2026-01-01T00:00:00Z","status":"active"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/workspace/support-access/grants/{id}/revoke":{"post":{"operationId":"RevokeSupportAccess","tags":["support_access"],"summary":"Revoke Support Access","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"End Inferrex support's access now. Any support view open under the grant stops working at its next request.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The grant."},"description":"The grant."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["revoked","expired"]},"revokedAt":{"type":"string","format":"date-time","nullable":true},"endedSessions":{"type":"integer","description":"Support views that were open and are now ended."}},"required":["id","status","endedSessions"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"revoked","revokedAt":"2026-01-01T00:00:00Z","endedSessions":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/workspace/support-access/sessions":{"get":{"operationId":"ListSupportSessions","tags":["support_access"],"summary":"List Support Sessions","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"Every read-only support view Inferrex staff opened in this workspace: who, why, when, how it ended, and the pages it showed.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"sessions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"grantId":{"type":"string","format":"uuid"},"staffEmail":{"type":"string"},"reason":{"type":"string"},"startedAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"endedAt":{"type":"string","format":"date-time","nullable":true},"endReason":{"type":"string","nullable":true,"description":"ended_by_staff, grant_revoked, grant_expired or expired; null while active."},"status":{"type":"string","enum":["active","ended"]},"lastSeenAt":{"type":"string","format":"date-time","nullable":true},"viewCount":{"type":"integer"},"pages":{"type":"array","items":{"type":"string"},"description":"The app pages the view showed, as the support view named them."}},"required":["id","grantId","staffEmail","reason","startedAt","expiresAt","status","viewCount","pages"]}},"total":{"type":"integer"}},"required":["sessions","total"]},"example":{"sessions":[{"id":"00000000-0000-0000-0000-000000000000","grantId":"00000000-0000-0000-0000-000000000000","staffEmail":"string","reason":"string","startedAt":"2026-01-01T00:00:00Z","expiresAt":"2026-01-01T00:00:00Z","endedAt":"2026-01-01T00:00:00Z","endReason":"string","status":"active","lastSeenAt":"2026-01-01T00:00:00Z","viewCount":0,"pages":["string"]}],"total":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/workspace/support-access/sessions/{id}/views":{"get":{"operationId":"ListSupportSessionViews","tags":["support_access"],"summary":"List Support Session Views","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"Each page and read one support view made, from the audit trail, newest first, including anything it was refused.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The support view (session)."},"description":"The support view (session)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"views":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"at":{"type":"string","format":"date-time"},"outcome":{"type":"string","enum":["viewed","refused"]},"page":{"type":"string","nullable":true,"description":"The app page, as the support view named it (a label, not proof)."},"method":{"type":"string"},"path":{"type":"string","description":"The API read, as the server saw it."},"staffEmail":{"type":"string"},"refusal":{"type":"string","nullable":true,"description":"Why a refused read was refused."}},"required":["id","at","outcome","method","path","staffEmail"]}},"total":{"type":"integer"}},"required":["views","total"]},"example":{"views":[{"id":"00000000-0000-0000-0000-000000000000","at":"2026-01-01T00:00:00Z","outcome":"viewed","page":"string","method":"string","path":"string","staffEmail":"string","refusal":"string"}],"total":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/workspace/team-members":{"get":{"operationId":"TeamMembersList","tags":["rbac"],"summary":"Team Members List","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"List your team members, newest first. Filter by any field. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"workspace_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"added_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only team members whose added time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only team members whose added time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"added_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only team members whose added time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only team members whose added time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"added_by","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only team members for this added by. Pass its id."},"description":"Only team members for this added by. Pass its id."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many team members to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many team members to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many team members to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many team members to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["team_id","user_id","workspace_id","added_at","added_by"],"description":"The field to sort the list by.","default":"added_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"added_at":{"type":"string"},"added_by":{"type":"string","format":"uuid","nullable":true}},"required":["workspace_id"]},"example":{"team_id":"00000000-0000-0000-0000-000000000000","user_id":"00000000-0000-0000-0000-000000000000","workspace_id":"00000000-0000-0000-0000-000000000000","added_at":"string","added_by":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"TeamMembersCreate","tags":["rbac"],"summary":"Team Members Create","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Create a team member. Returns the new team member, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"added_at":{"type":"string"}}},"example":{"team_id":"00000000-0000-0000-0000-000000000000","user_id":"00000000-0000-0000-0000-000000000000","added_at":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"added_at":{"type":"string"},"added_by":{"type":"string","format":"uuid","nullable":true}},"required":["workspace_id"]},"example":{"team_id":"00000000-0000-0000-0000-000000000000","user_id":"00000000-0000-0000-0000-000000000000","workspace_id":"00000000-0000-0000-0000-000000000000","added_at":"string","added_by":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/team-members/{teamId}/{userId}":{"delete":{"operationId":"RemoveTeamMember","tags":["workspace"],"summary":"Remove Team Member","security":[{"ApiKeyAuth":["workspace:delete"]},{"BearerAuth":[]},{"OAuth2":["workspace:delete"]}],"description":"Remove a member from a team. They stay in the workspace.","parameters":[{"name":"teamId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the team."},"description":"The id of the team."},{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The member to remove from the team."},"description":"The member to remove from the team."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]},"example":{"success":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/team-resources":{"get":{"operationId":"TeamResourcesList","tags":["rbac"],"summary":"Team Resources List","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"List your team resources, newest first. Filter by any field. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"workspace_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"tagged_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only team resources whose tagged time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only team resources whose tagged time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"tagged_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only team resources whose tagged time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only team resources whose tagged time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"tagged_by","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only team resources for this tagged by. Pass its id."},"description":"Only team resources for this tagged by. Pass its id."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many team resources to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many team resources to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many team resources to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many team resources to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["team_id","resource_type","resource_id","workspace_id","tagged_at","tagged_by"],"description":"The field to sort the list by.","default":"tagged_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"resource_type":{"type":"string"},"resource_id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"tagged_at":{"type":"string"},"tagged_by":{"type":"string","format":"uuid","nullable":true}},"required":["workspace_id"]},"example":{"team_id":"00000000-0000-0000-0000-000000000000","resource_type":"string","resource_id":"00000000-0000-0000-0000-000000000000","workspace_id":"00000000-0000-0000-0000-000000000000","tagged_at":"string","tagged_by":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"TeamResourcesCreate","tags":["rbac"],"summary":"Team Resources Create","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Create a team resource. Returns the new team resource, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"resource_type":{"type":"string"},"resource_id":{"type":"string","format":"uuid"},"tagged_at":{"type":"string"}}},"example":{"team_id":"00000000-0000-0000-0000-000000000000","resource_type":"string","resource_id":"00000000-0000-0000-0000-000000000000","tagged_at":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"resource_type":{"type":"string"},"resource_id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"tagged_at":{"type":"string"},"tagged_by":{"type":"string","format":"uuid","nullable":true}},"required":["workspace_id"]},"example":{"team_id":"00000000-0000-0000-0000-000000000000","resource_type":"string","resource_id":"00000000-0000-0000-0000-000000000000","workspace_id":"00000000-0000-0000-0000-000000000000","tagged_at":"string","tagged_by":"00000000-0000-0000-0000-000000000000"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/team-resources/{teamId}/{resourceType}/{resourceId}":{"delete":{"operationId":"RemoveTeamResource","tags":["workspace"],"summary":"Remove Team Resource","security":[{"ApiKeyAuth":["workspace:delete"]},{"BearerAuth":[]},{"OAuth2":["workspace:delete"]}],"description":"Stop a team having access to one connection, pipeline, environment or workspace.","parameters":[{"name":"teamId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the team."},"description":"The id of the team."},{"name":"resourceType","in":"path","required":true,"schema":{"type":"string","enum":["connection","pipeline","environment","workspace"],"description":"What kind of thing it is: connection, pipeline, environment or workspace."},"description":"What kind of thing it is: connection, pipeline, environment or workspace."},{"name":"resourceId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the connection, pipeline, environment or workspace."},"description":"The id of the connection, pipeline, environment or workspace."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]},"example":{"success":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/teams":{"get":{"operationId":"TeamsList","tags":["rbac"],"summary":"Teams List","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"List your teams, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"workspace_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"name","in":"query","required":false,"schema":{"type":"string","description":"Only teams whose name is exactly this."},"description":"Only teams whose name is exactly this."},{"name":"name_contains","in":"query","required":false,"schema":{"type":"string","description":"Only teams whose name contains this text (upper and lower case are treated the same)."},"description":"Only teams whose name contains this text (upper and lower case are treated the same)."},{"name":"description","in":"query","required":false,"schema":{"type":"string","description":"Only teams whose description is exactly this."},"description":"Only teams whose description is exactly this."},{"name":"description_contains","in":"query","required":false,"schema":{"type":"string","description":"Only teams whose description contains this text (upper and lower case are treated the same)."},"description":"Only teams whose description contains this text (upper and lower case are treated the same)."},{"name":"created_by","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only teams for this created by. Pass its id."},"description":"Only teams for this created by. Pass its id."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many teams to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many teams to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many teams to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many teams to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","workspace_id","name","description","created_by","created_at","updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns teams where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns teams where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"created_by":{"type":"string","format":"uuid"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["workspace_id","name","created_by"]},"example":{"id":"00000000-0000-0000-0000-000000000000","workspace_id":"00000000-0000-0000-0000-000000000000","name":"string","description":"string","created_by":"00000000-0000-0000-0000-000000000000","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"TeamsCreate","tags":["rbac"],"summary":"Teams Create","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Create a team. Returns the new team, including the id it was given.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string","nullable":true}},"required":["name"]},"example":{"name":"string","description":"string"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"created_by":{"type":"string","format":"uuid"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["workspace_id","name","created_by"]},"example":{"id":"00000000-0000-0000-0000-000000000000","workspace_id":"00000000-0000-0000-0000-000000000000","name":"string","description":"string","created_by":"00000000-0000-0000-0000-000000000000","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/teams/{id}":{"delete":{"operationId":"TeamsDelete","tags":["rbac"],"summary":"Teams Delete","security":[{"ApiKeyAuth":["workspace:delete"]},{"BearerAuth":[]},{"OAuth2":["workspace:delete"]}],"description":"Delete a team permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the team."},"description":"The id of the team."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"TeamsGet","tags":["rbac"],"summary":"Teams Get","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"Get one of your teams by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the team."},"description":"The id of the team."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"created_by":{"type":"string","format":"uuid"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["workspace_id","name","created_by"]},"example":{"id":"00000000-0000-0000-0000-000000000000","workspace_id":"00000000-0000-0000-0000-000000000000","name":"string","description":"string","created_by":"00000000-0000-0000-0000-000000000000","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"TeamsUpdate","tags":["rbac"],"summary":"Teams Update","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Change a team. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the team."},"description":"The id of the team."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string","nullable":true}}},"example":{"name":"string","description":"string"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"created_by":{"type":"string","format":"uuid"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["workspace_id","name","created_by"]},"example":{"id":"00000000-0000-0000-0000-000000000000","workspace_id":"00000000-0000-0000-0000-000000000000","name":"string","description":"string","created_by":"00000000-0000-0000-0000-000000000000","created_at":"string","updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/transfer-ownership":{"post":{"operationId":"TransferOwnership","tags":["workspace"],"summary":"Transfer Ownership","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Make another member the owner of this workspace. Only the current owner can do this, and the new owner must be an active member. You become an admin, and you and the new owner are both emailed.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetUserId":{"type":"string","format":"uuid","description":"The member who will become the owner."}},"required":["targetUserId"]},"example":{"targetUserId":"00000000-0000-0000-0000-000000000000"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"previousOwnerId":{"type":"string"},"newOwnerId":{"type":"string"}},"required":["success","previousOwnerId","newOwnerId"]},"example":{"success":true,"previousOwnerId":"string","newOwnerId":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/usage":{"get":{"operationId":"GetWorkspaceUsage","tags":["workspace"],"summary":"Get Workspace Usage","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"How much of your allowance you have used in a period: AI operations, storage, connected systems, relationships between systems, workflows and environments, each with its limit. Also the number of records, which is shown as usage and has no limit. Also shows recent monthly history, any packs you have added, and whether you are over any limit.","parameters":[{"name":"period","in":"query","required":false,"schema":{"type":"string","enum":["current","previous","trailing_30d"],"description":"current (this billing period, the default), previous, or trailing_30d (the last 30 days).","default":"current"},"description":"current (this billing period, the default), previous, or trailing_30d (the last 30 days)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"period_start":{"type":"string"},"period_end":{"type":"string"},"ai_operations":{"type":"integer"},"ai_operations_limit":{"type":"integer"},"records":{"type":"integer","description":"Records held this period. Shown as usage; there is no records limit."},"storage_gb":{"type":"number"},"storage_limit_gb":{"type":"integer"},"integrations":{"type":"integer"},"integrations_limit":{"type":"integer"},"workflows":{"type":"integer","description":"Workflows in the workspace. Shown as usage; there is no workflows limit."},"relationships":{"type":"integer"},"relationships_limit":{"type":"integer"},"integrations_pct":{"type":"number","nullable":true},"relationships_pct":{"type":"number","nullable":true},"environments":{"type":"integer"},"environments_limit":{"type":"integer"},"overage_state":{"type":"string"},"internal":{"type":"boolean","description":"True for an internal (Inferrex) workspace: it has no limits, and every limit above is -1."},"history":{"type":"array","items":{"type":"object","properties":{"period_month":{"type":"string","description":"YYYY-MM."},"integrations_active":{"type":"integer"},"records_processed":{"type":"integer"},"storage_gb":{"type":"number"},"ai_inference_units":{"type":"integer","description":"AI operations that month."}},"required":["period_month","integrations_active","records_processed","storage_gb","ai_inference_units"]},"description":"Up to six most recent months, newest first."},"forecast":{"type":"object","properties":{"days_elapsed":{"type":"integer"},"days_in_month":{"type":"integer"},"systems_at_month_end":{"type":"integer","description":"Today's connection count (a stock, not a projection)."},"relationships_at_month_end":{"type":"integer","description":"Today's relationship count (a stock, not a projection)."}},"required":["days_elapsed","days_in_month","systems_at_month_end","relationships_at_month_end"]},"overage_status":{"type":"object","properties":{"state":{"type":"string","description":"Today: none, recorded, review (a commercial review is open for the period)."},"amount_cents":{"type":"integer","description":"The review amount, else the first charge of the latest period; 0 when none. Not an invoice."},"currency":{"type":"string","description":"Lower-case ISO code from the charge row."},"period_start":{"type":"string","nullable":true,"description":"Start of the latest period with charges (YYYY-MM-DD), or null."},"dimensions":{"type":"array","items":{"type":"string"},"description":"The dimensions charged in that period."}},"required":["state","amount_cents","currency","dimensions"]},"purchased_packs":{"type":"array","items":{"type":"object","properties":{"dimension":{"type":"string","description":"Today: systems, relationships, analyses."},"unit_size":{"type":"integer","description":"Units the pack added to the allowance."},"amount_pence":{"type":"integer","description":"The price recorded when it was taken."},"currency":{"type":"string"},"purchased_at":{"type":"string","description":"Postgres timestamptz text (created_at::TEXT, e.g. \"2026-10-01 09:00:00.123+00\"), not ISO 8601."}},"required":["dimension","unit_size","amount_pence","currency","purchased_at"]},"description":"Newest first."},"gamification":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether the workspace has the gamification add-on."},"events":{"type":"integer","description":"Events scored in the period."},"bytes":{"type":"integer","description":"Their size: the bytes of event data passed through the module."},"included_events":{"type":"integer","nullable":true,"description":"Events included per month; null = none set, so nothing is billed as overage."},"included_bytes":{"type":"integer","nullable":true},"limit_events":{"type":"integer","nullable":true,"description":"Events per month past which new events are not scored; null = no limit."},"limit_bytes":{"type":"integer","nullable":true},"billable_events":{"type":"integer","description":"Events past the included volume that are billed."},"billable_bytes":{"type":"integer"},"state":{"type":"string","description":"within, over-included or limit-reached."}},"required":["enabled","events","bytes","billable_events","billable_bytes","state"],"description":"The gamification add-on in this period: events and bytes passed through it, against the workspace's volumes."}},"required":["period_start","period_end","ai_operations","ai_operations_limit","records","storage_gb","storage_limit_gb","integrations","integrations_limit","workflows","relationships","relationships_limit","environments","environments_limit","overage_state","internal","history","forecast","overage_status","purchased_packs","gamification"]},"example":{"period_start":"string","period_end":"string","ai_operations":0,"ai_operations_limit":0,"records":0,"storage_gb":0,"storage_limit_gb":0,"integrations":0,"integrations_limit":0,"workflows":0,"relationships":0,"relationships_limit":0,"integrations_pct":0,"relationships_pct":0,"environments":0,"environments_limit":0,"overage_state":"string","internal":true,"history":[{"period_month":"string","integrations_active":0,"records_processed":0,"storage_gb":0,"ai_inference_units":0}],"forecast":{"days_elapsed":0,"days_in_month":0,"systems_at_month_end":0,"relationships_at_month_end":0},"overage_status":{"state":"string","amount_cents":0,"currency":"string","period_start":"string","dimensions":["string"]},"purchased_packs":[{"dimension":"string","unit_size":0,"amount_pence":0,"currency":"string","purchased_at":"string"}],"gamification":{"enabled":true,"events":0,"bytes":0,"included_events":0,"included_bytes":0,"limit_events":0,"limit_bytes":0,"billable_events":0,"billable_bytes":0,"state":"string"}}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/users":{"get":{"operationId":"WorkspaceUsersList","tags":["rbac"],"summary":"Workspace Users List","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"List your workspace users, newest first. Filter by any field, or search their text with q. Results come a page at a time: use limit and offset to move through them.","parameters":[{"name":"workspace_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},"description":"Your workspace. You only ever see your own workspace’s records, so there is no need to set this."},{"name":"auth_subject_id","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose auth subject is exactly this."},"description":"Only workspace users whose auth subject is exactly this."},{"name":"auth_subject_id_contains","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose auth subject contains this text (upper and lower case are treated the same)."},"description":"Only workspace users whose auth subject contains this text (upper and lower case are treated the same)."},{"name":"email","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose email is exactly this."},"description":"Only workspace users whose email is exactly this."},{"name":"email_contains","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose email contains this text (upper and lower case are treated the same)."},"description":"Only workspace users whose email contains this text (upper and lower case are treated the same)."},{"name":"display_name","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose display name is exactly this."},"description":"Only workspace users whose display name is exactly this."},{"name":"display_name_contains","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose display name contains this text (upper and lower case are treated the same)."},"description":"Only workspace users whose display name contains this text (upper and lower case are treated the same)."},{"name":"role","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose role is exactly this."},"description":"Only workspace users whose role is exactly this."},{"name":"role_contains","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose role contains this text (upper and lower case are treated the same)."},"description":"Only workspace users whose role contains this text (upper and lower case are treated the same)."},{"name":"invited_by","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only workspace users for this invited by. Pass its id."},"description":"Only workspace users for this invited by. Pass its id."},{"name":"invited_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only workspace users whose invited time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only workspace users whose invited time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"invited_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only workspace users whose invited time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only workspace users whose invited time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"accepted_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only workspace users whose accepted time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only workspace users whose accepted time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"accepted_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only workspace users whose accepted time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only workspace users whose accepted time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"is_active","in":"query","required":false,"schema":{"type":"boolean","description":"Only workspace users where is active is true, or false for only those where it is false."},"description":"Only workspace users where is active is true, or false for only those where it is false."},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose status is exactly this."},"description":"Only workspace users whose status is exactly this."},{"name":"status_contains","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose status contains this text (upper and lower case are treated the same)."},"description":"Only workspace users whose status contains this text (upper and lower case are treated the same)."},{"name":"last_login_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only workspace users whose last login time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only workspace users whose last login time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"last_login_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only workspace users whose last login time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only workspace users whose last login time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"last_login_ip","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose last login ip is exactly this."},"description":"Only workspace users whose last login ip is exactly this."},{"name":"last_login_ip_contains","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose last login ip contains this text (upper and lower case are treated the same)."},"description":"Only workspace users whose last login ip contains this text (upper and lower case are treated the same)."},{"name":"last_active_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only workspace users whose last active time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only workspace users whose last active time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"last_active_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only workspace users whose last active time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only workspace users whose last active time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"source","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose source is exactly this."},"description":"Only workspace users whose source is exactly this."},{"name":"source_contains","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose source contains this text (upper and lower case are treated the same)."},"description":"Only workspace users whose source contains this text (upper and lower case are treated the same)."},{"name":"sso_provider_id","in":"query","required":false,"schema":{"type":"string","format":"uuid","description":"Only workspace users for this sso provider. Pass its id."},"description":"Only workspace users for this sso provider. Pass its id."},{"name":"entra_object_id","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose entra object is exactly this."},"description":"Only workspace users whose entra object is exactly this."},{"name":"entra_object_id_contains","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose entra object contains this text (upper and lower case are treated the same)."},"description":"Only workspace users whose entra object contains this text (upper and lower case are treated the same)."},{"name":"entra_provision_state","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose entra provision state is exactly this."},"description":"Only workspace users whose entra provision state is exactly this."},{"name":"entra_provision_state_contains","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose entra provision state contains this text (upper and lower case are treated the same)."},"description":"Only workspace users whose entra provision state contains this text (upper and lower case are treated the same)."},{"name":"entra_provision_error","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose entra provision error is exactly this."},"description":"Only workspace users whose entra provision error is exactly this."},{"name":"entra_provision_error_contains","in":"query","required":false,"schema":{"type":"string","description":"Only workspace users whose entra provision error contains this text (upper and lower case are treated the same)."},"description":"Only workspace users whose entra provision error contains this text (upper and lower case are treated the same)."},{"name":"entra_provision_updated_at_gte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only workspace users whose entra provision updated time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only workspace users whose entra provision updated time is on or after this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"entra_provision_updated_at_lte","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Only workspace users whose entra provision updated time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},"description":"Only workspace users whose entra provision updated time is on or before this date and time (ISO 8601, e.g. 2026-01-31T09:00:00Z)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"How many workspace users to return in one page: 1 to 200, 50 if you leave it out.","default":50},"description":"How many workspace users to return in one page: 1 to 200, 50 if you leave it out."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"How many workspace users to skip before this page starts. Add the page size to it to get the next page.","default":0},"description":"How many workspace users to skip before this page starts. Add the page size to it to get the next page."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["id","workspace_id","auth_subject_id","email","display_name","role","invited_by","invited_at","accepted_at","is_active","status","last_login_at","last_login_ip","created_at","updated_at","last_active_at","source","sso_provider_id","entra_object_id","entra_provision_state","entra_provision_error","entra_provision_updated_at"],"description":"The field to sort the list by.","default":"created_at"},"description":"The field to sort the list by."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first.","default":"desc"},"description":"Sort direction: asc for oldest, smallest or A first; desc for newest, largest or Z first."},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search text. Returns workspace users where any text field contains it (upper and lower case are treated the same)."},"description":"Search text. Returns workspace users where any text field contains it (upper and lower case are treated the same)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"auth_subject_id":{"type":"string"},"email":{"type":"string"},"display_name":{"type":"string","nullable":true},"role":{"type":"string"},"invited_by":{"type":"string","format":"uuid","nullable":true},"invited_at":{"type":"string","nullable":true},"accepted_at":{"type":"string","nullable":true},"is_active":{"type":"boolean"},"status":{"type":"string"},"last_login_at":{"type":"string","nullable":true},"last_login_ip":{"type":"string","nullable":true},"notification_preferences":{"type":"object","properties":{"sync_failure":{"type":"string","enum":["in_app","email","both","mute"]},"healing_event":{"type":"string","enum":["in_app","email","both","mute"]},"usage_threshold":{"type":"string","enum":["in_app","email","both","mute"]},"security_alert":{"type":"string","enum":["in_app","email","both","mute"]},"team_invite":{"type":"string","enum":["in_app","email","both","mute"]},"system":{"type":"string","enum":["in_app","email","both","mute"]}},"description":"Per kind of notification: in the app, by email, both, or not at all. A kind left out uses the default."},"created_at":{"type":"string"},"updated_at":{"type":"string"},"last_active_at":{"type":"string","nullable":true},"source":{"type":"string","nullable":true},"sso_provider_id":{"type":"string","format":"uuid","nullable":true},"entra_object_id":{"type":"string","nullable":true},"entra_provision_state":{"type":"string","nullable":true},"entra_provision_error":{"type":"string","nullable":true},"entra_provision_updated_at":{"type":"string","nullable":true}},"required":["workspace_id","auth_subject_id","email"]},"example":{"id":"00000000-0000-0000-0000-000000000000","workspace_id":"00000000-0000-0000-0000-000000000000","auth_subject_id":"string","email":"string","display_name":"string","role":"string","invited_by":"00000000-0000-0000-0000-000000000000","invited_at":"string","accepted_at":"string","is_active":true,"status":"string","last_login_at":"string","last_login_ip":"string","notification_preferences":{"sync_failure":"in_app","healing_event":"in_app","usage_threshold":"in_app","security_alert":"in_app","team_invite":"in_app","system":"in_app"},"created_at":"string","updated_at":"string","last_active_at":"string","source":"string","sso_provider_id":"00000000-0000-0000-0000-000000000000","entra_object_id":"string","entra_provision_state":"string","entra_provision_error":"string","entra_provision_updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/users/{id}":{"delete":{"operationId":"WorkspaceUsersDelete","tags":["rbac"],"summary":"Workspace Users Delete","security":[{"ApiKeyAuth":["workspace:delete"]},{"BearerAuth":[]},{"OAuth2":["workspace:delete"]}],"description":"Delete a workspace user permanently. This cannot be undone, but the deletion is recorded in your audit trail.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the workspace user."},"description":"The id of the workspace user."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"204":{"description":"Success","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"WorkspaceUsersGet","tags":["rbac"],"summary":"Workspace Users Get","security":[{"ApiKeyAuth":["workspace:read"]},{"BearerAuth":[]},{"OAuth2":["workspace:read"]}],"description":"Get one of your workspace users by its id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the workspace user."},"description":"The id of the workspace user."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"auth_subject_id":{"type":"string"},"email":{"type":"string"},"display_name":{"type":"string","nullable":true},"role":{"type":"string"},"invited_by":{"type":"string","format":"uuid","nullable":true},"invited_at":{"type":"string","nullable":true},"accepted_at":{"type":"string","nullable":true},"is_active":{"type":"boolean"},"status":{"type":"string"},"last_login_at":{"type":"string","nullable":true},"last_login_ip":{"type":"string","nullable":true},"notification_preferences":{"type":"object","properties":{"sync_failure":{"type":"string","enum":["in_app","email","both","mute"]},"healing_event":{"type":"string","enum":["in_app","email","both","mute"]},"usage_threshold":{"type":"string","enum":["in_app","email","both","mute"]},"security_alert":{"type":"string","enum":["in_app","email","both","mute"]},"team_invite":{"type":"string","enum":["in_app","email","both","mute"]},"system":{"type":"string","enum":["in_app","email","both","mute"]}},"description":"Per kind of notification: in the app, by email, both, or not at all. A kind left out uses the default."},"created_at":{"type":"string"},"updated_at":{"type":"string"},"last_active_at":{"type":"string","nullable":true},"source":{"type":"string","nullable":true},"sso_provider_id":{"type":"string","format":"uuid","nullable":true},"entra_object_id":{"type":"string","nullable":true},"entra_provision_state":{"type":"string","nullable":true},"entra_provision_error":{"type":"string","nullable":true},"entra_provision_updated_at":{"type":"string","nullable":true}},"required":["workspace_id","auth_subject_id","email"]},"example":{"id":"00000000-0000-0000-0000-000000000000","workspace_id":"00000000-0000-0000-0000-000000000000","auth_subject_id":"string","email":"string","display_name":"string","role":"string","invited_by":"00000000-0000-0000-0000-000000000000","invited_at":"string","accepted_at":"string","is_active":true,"status":"string","last_login_at":"string","last_login_ip":"string","notification_preferences":{"sync_failure":"in_app","healing_event":"in_app","usage_threshold":"in_app","security_alert":"in_app","team_invite":"in_app","system":"in_app"},"created_at":"string","updated_at":"string","last_active_at":"string","source":"string","sso_provider_id":"00000000-0000-0000-0000-000000000000","entra_object_id":"string","entra_provision_state":"string","entra_provision_error":"string","entra_provision_updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"WorkspaceUsersUpdate","tags":["rbac"],"summary":"Workspace Users Update","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Change a workspace user. Send only the fields you want to change; anything you leave out stays as it is.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the workspace user."},"description":"The id of the workspace user."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"display_name":{"type":"string","nullable":true},"role":{"type":"string"},"notification_preferences":{"type":"object","additionalProperties":true}}},"example":{"email":"string","display_name":"string","role":"string","notification_preferences":{}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"auth_subject_id":{"type":"string"},"email":{"type":"string"},"display_name":{"type":"string","nullable":true},"role":{"type":"string"},"invited_by":{"type":"string","format":"uuid","nullable":true},"invited_at":{"type":"string","nullable":true},"accepted_at":{"type":"string","nullable":true},"is_active":{"type":"boolean"},"status":{"type":"string"},"last_login_at":{"type":"string","nullable":true},"last_login_ip":{"type":"string","nullable":true},"notification_preferences":{"type":"object","properties":{"sync_failure":{"type":"string","enum":["in_app","email","both","mute"]},"healing_event":{"type":"string","enum":["in_app","email","both","mute"]},"usage_threshold":{"type":"string","enum":["in_app","email","both","mute"]},"security_alert":{"type":"string","enum":["in_app","email","both","mute"]},"team_invite":{"type":"string","enum":["in_app","email","both","mute"]},"system":{"type":"string","enum":["in_app","email","both","mute"]}},"description":"Per kind of notification: in the app, by email, both, or not at all. A kind left out uses the default."},"created_at":{"type":"string"},"updated_at":{"type":"string"},"last_active_at":{"type":"string","nullable":true},"source":{"type":"string","nullable":true},"sso_provider_id":{"type":"string","format":"uuid","nullable":true},"entra_object_id":{"type":"string","nullable":true},"entra_provision_state":{"type":"string","nullable":true},"entra_provision_error":{"type":"string","nullable":true},"entra_provision_updated_at":{"type":"string","nullable":true}},"required":["workspace_id","auth_subject_id","email"]},"example":{"id":"00000000-0000-0000-0000-000000000000","workspace_id":"00000000-0000-0000-0000-000000000000","auth_subject_id":"string","email":"string","display_name":"string","role":"string","invited_by":"00000000-0000-0000-0000-000000000000","invited_at":"string","accepted_at":"string","is_active":true,"status":"string","last_login_at":"string","last_login_ip":"string","notification_preferences":{"sync_failure":"in_app","healing_event":"in_app","usage_threshold":"in_app","security_alert":"in_app","team_invite":"in_app","system":"in_app"},"created_at":"string","updated_at":"string","last_active_at":"string","source":"string","sso_provider_id":"00000000-0000-0000-0000-000000000000","entra_object_id":"string","entra_provision_state":"string","entra_provision_error":"string","entra_provision_updated_at":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/users/{id}/anonymise":{"post":{"operationId":"AnonymiseWorkspaceUser","tags":["core"],"summary":"Anonymise Workspace User","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Erase a member of YOUR workspace by anonymising them: email, name, identity-provider subject and last login IP are replaced, the member is deactivated and their personal Ask Inferrex memories move to the workspace first. The member id is kept, so audit and memory trails stay intact and traceable. Workspace owners and admins only (manage_users); refuses yourself and an owner (transfer ownership first). Cannot be undone.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"anonymised":{"type":"boolean"},"memoriesReassigned":{"type":"integer"}},"required":["id","anonymised","memoriesReassigned"]},"example":{"id":"00000000-0000-0000-0000-000000000000","anonymised":true,"memoriesReassigned":0}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/users/{id}/approve-invite":{"post":{"operationId":"ApproveInvite","tags":["workspace"],"summary":"Approve Invite","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Approve an invite that is waiting for approval. The person is sent a one-time password the way your invite policy says: by email, or shown here once for you to pass on. Only someone in the role your invite policy names can approve.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the invited member."},"description":"The id of the invited member."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","nullable":true},"status":{"type":"string"},"delivery":{"type":"string","nullable":true},"tempPassword":{"type":"string","nullable":true},"emailStatus":{"type":"string","enum":["sent","failed"]}},"required":["id","status"]},"example":{"id":"00000000-0000-0000-0000-000000000000","email":"string","status":"string","delivery":"string","tempPassword":"string","emailStatus":"sent"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspace/users/{id}/reject-invite":{"post":{"operationId":"RejectInvite","tags":["workspace"],"summary":"Reject Invite","security":[{"ApiKeyAuth":["workspace:write"]},{"BearerAuth":[]},{"OAuth2":["workspace:write"]}],"description":"Turn down an invite that is waiting for approval. The person is not added to the workspace.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of the invited member."},"description":"The id of the invited member."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Unique key to make this request safe to retry — the first response is cached and replayed for any retry with the same key (24h)."}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"}},"required":["id","status"]},"example":{"id":"00000000-0000-0000-0000-000000000000","status":"string"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]},"/v1/workspaces":{"get":{"operationId":"ListMyWorkspaces","tags":["workspace"],"summary":"List My Workspaces","security":[{"ApiKeyAuth":["workspaces:read"]},{"BearerAuth":[]},{"OAuth2":["workspaces:read"]}],"description":"The workspaces you belong to, with your role in each. A workspace that requires you to sign in to it by name only appears once you have done so. An API key or OAuth client-credentials token sees only the one workspace it was issued for, with the role api_key or oauth_client.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"workspaces":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","description":"The workspace name, or its contact email when it has none."},"role":{"type":"string","description":"Your role in it (owner, admin, editor, viewer, …), or api_key / oauth_client for a machine credential."},"tier":{"type":"string","description":"The workspace's plan tier, as stored. Show it as a label, never as a price."},"status":{"type":"string","description":"The workspace account status, as stored."},"active":{"type":"boolean","description":"The workspace this request acted on: the X-Workspace-Id it sent, else the default."},"requiresNamedSignin":{"type":"boolean","description":"This workspace must be named at sign-in, and is listed only because this session did. Absent for a machine credential."}},"required":["id","name","role","tier","status","active"]}}},"required":["workspaces"]},"example":{"workspaces":[{"id":"00000000-0000-0000-0000-000000000000","name":"string","role":"string","tier":"string","status":"string","active":true,"requiresNamedSignin":true}]}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"servers":[{"url":"https://e1dk9.wiremockapi.cloud","description":"Sandbox mock (part 1)"},{"url":"https://api.inferrex.com","description":"Production"}]}},"components":{"securitySchemes":{"Handler_basic":{"type":"http","scheme":"basic","description":"Send Authorization: Basic <token>. Verified by the route handler, not workspace authentication."},"Handler_player":{"type":"http","scheme":"player","description":"Send Authorization: Player <token>. Verified by the route handler, not workspace authentication."},"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Workspace-scoped API key. Each key carries a subset of the 120 scopes (see x-api-scopes); a call needs the scope its operation declares."},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Firebase ID token (interactive sessions)."},"OAuth2":{"type":"oauth2","description":"Machine-to-machine client-credentials flow for agents (shares the API-key scope catalog).","flows":{"clientCredentials":{"tokenUrl":"https://api.inferrex.com/v1/oauth/token","scopes":{"alert-deliveries:read":"read access to alert-deliveries","alert-rules:delete":"delete access to alert-rules","alert-rules:read":"read access to alert-rules","alert-rules:write":"write access to alert-rules","approval-policies:delete":"delete access to approval-policies","approval-policies:read":"read access to approval-policies","approval-policies:write":"write access to approval-policies","archival:read":"read access to archival","archival:write":"write access to archival","assistant:delete":"delete access to assistant","assistant:read":"read access to assistant","assistant:write":"write access to assistant","billing:read":"read access to billing","billing:write":"write access to billing","bloomreach:delete":"delete access to bloomreach","bloomreach:read":"read access to bloomreach","bloomreach:write":"write access to bloomreach","canonical-proposals:read":"read access to canonical-proposals","canonical-proposals:write":"write access to canonical-proposals","circuit-breaker-policies:delete":"delete access to circuit-breaker-policies","circuit-breaker-policies:read":"read access to circuit-breaker-policies","circuit-breaker-policies:write":"write access to circuit-breaker-policies","circuit-breakers:read":"read access to circuit-breakers","circuit-breakers:write":"write access to circuit-breakers","cli-snippets:delete":"delete access to cli-snippets","cli-snippets:read":"read access to cli-snippets","cli-snippets:write":"write access to cli-snippets","cli-socket-tickets:write":"write access to cli-socket-tickets","connection-environment-bindings:delete":"delete access to connection-environment-bindings","connection-environment-bindings:read":"read access to connection-environment-bindings","connection-environment-bindings:write":"write access to connection-environment-bindings","connections:delete":"delete access to connections","connections:read":"read access to connections","connections:write":"write access to connections","events:read":"read access to events","events:write":"write access to events","field-authority-rules:delete":"delete access to field-authority-rules","field-authority-rules:read":"read access to field-authority-rules","field-authority-rules:write":"write access to field-authority-rules","gamification:delete":"delete access to gamification","gamification:read":"read access to gamification","gamification:write":"write access to gamification","golden-records:read":"read access to golden-records","golden-records:write":"write access to golden-records","governance:read":"read access to governance","heals:read":"read access to heals","heals:write":"write access to heals","hooks:receive":"receive access to hooks","initial-loads:read":"read access to initial-loads","initial-loads:write":"write access to initial-loads","intelligence:delete":"delete access to intelligence","intelligence:read":"read access to intelligence","intelligence:write":"write access to intelligence","jobs:read":"read access to jobs","jobs:write":"write access to jobs","library:read":"read access to library","library:write":"write access to library","licence:write":"write access to licence","mappings:read":"read access to mappings","mappings:write":"write access to mappings","monitoring:read":"read access to monitoring","notifications:read":"read access to notifications","notifications:write":"write access to notifications","oauth:write":"write access to oauth","onboarding:read":"read access to onboarding","onboarding:write":"write access to onboarding","operation-scopes:delete":"delete access to operation-scopes","operation-scopes:read":"read access to operation-scopes","operation-scopes:write":"write access to operation-scopes","parallel-run-discrepancies:read":"read access to parallel-run-discrepancies","pipeline-events:read":"read access to pipeline-events","pipeline-promotions:read":"read access to pipeline-promotions","pipeline-promotions:write":"write access to pipeline-promotions","pipeline-targets:read":"read access to pipeline-targets","pipeline-targets:write":"write access to pipeline-targets","pipelines:delete":"delete access to pipelines","pipelines:read":"read access to pipelines","pipelines:write":"write access to pipelines","platform-config:read":"read access to platform-config","platform-config:write":"write access to platform-config","platform-value-scores:read":"read access to platform-value-scores","platform-value-scores:write":"write access to platform-value-scores","portal:read":"read access to portal","portal:write":"write access to portal","pricing:read":"read access to pricing","quarantine:read":"read access to quarantine","reports:write":"write access to reports","restoration-requests:read":"read access to restoration-requests","restoration-requests:write":"write access to restoration-requests","retention-policies:delete":"delete access to retention-policies","retention-policies:read":"read access to retention-policies","retention-policies:write":"write access to retention-policies","retrieve:read":"read access to retrieve","schema:read":"read access to schema","search:read":"read access to search","secrets:delete":"delete access to secrets","secrets:read":"read access to secrets","secrets:write":"write access to secrets","settings:delete":"delete access to settings","settings:read":"read access to settings","settings:write":"write access to settings","suggestions:read":"read access to suggestions","terms:read":"read access to terms","terms:write":"write access to terms","unified:delete":"delete access to unified","unified:read":"read access to unified","unified:write":"write access to unified","webhooks:delete":"delete access to webhooks","webhooks:read":"read access to webhooks","webhooks:write":"write access to webhooks","workflow-runs:read":"read access to workflow-runs","workflow-runs:write":"write access to workflow-runs","workflows:delete":"delete access to workflows","workflows:read":"read access to workflows","workflows:write":"write access to workflows","workspace-users:write":"write access to workspace-users","workspace:delete":"delete access to workspace","workspace:read":"read access to workspace","workspace:write":"write access to workspace","workspaces:read":"read access to workspaces"}}}}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string","description":"Stable machine-readable error code"},"message":{"type":"string","description":"Human-readable description"},"retryable":{"type":"boolean","description":"Whether retrying the same request unchanged could succeed (transient vs. client error)."},"docs_url":{"type":"string","format":"uri","description":"Docs anchor for this error code — an agent can self-correct without a human."},"requestId":{"type":"string","description":"Correlation id for support"}},"required":["error","message","retryable","docs_url"]}},"responses":{"BadRequest":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"bad_request","message":"Invalid request","retryable":false,"docs_url":"https://inferrex.com/docs/errors#bad_request"}}}},"Unauthorized":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"unauthorized","message":"Missing or invalid credentials","retryable":false,"docs_url":"https://inferrex.com/docs/errors#unauthorized"}}}},"Forbidden":{"description":"Not permitted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"forbidden","message":"Not permitted","retryable":false,"docs_url":"https://inferrex.com/docs/errors#forbidden"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"not_found","message":"Resource not found","retryable":false,"docs_url":"https://inferrex.com/docs/errors#not_found"}}}},"RateLimited":{"description":"Rate limit exceeded — retry after the period in the Retry-After header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"rate_limited","message":"Rate limit exceeded — retry after the period in the Retry-After header","retryable":true,"docs_url":"https://inferrex.com/docs/errors#rate_limited"}}},"headers":{"X-RateLimit-Limit":{"description":"Sustained request ceiling for your tier (requests/minute).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current burst budget.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"UTC epoch seconds when the budget refills to full.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Draft RateLimit header — same value as X-RateLimit-Limit.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Draft RateLimit header — same value as X-RateLimit-Remaining.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Draft RateLimit header — seconds until the budget refills to full.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}}}}}