# Audit and egress The audit log and its hash-chain check, and what each app is allowed to reach. 21 routes, from the API’s own OpenAPI document. URL: https://docs.qaldy.com/reference/api/security/ 21 routes. Every path starts at `https://cloud-api.qaldy.com`. Sign-in, tokens, errors and limits are on the [overview](https://docs.qaldy.com/reference/api/). ## Routes | Method | Path | What it does | |---|---|---| | [[GET]] | [`/​v1/​apps/​{id}/​flow`](#get-v1-apps-id-flow) | One app's data flow: what it reads, where it can send, and the policy in words | | [[GET]] | [`/​v1/​workspaces/​{ws}/​audit`](#get-v1-workspaces-ws-audit) | The audit log, newest first: ids and metadata only (workspace admins) | | [[GET]] | [`/​v1/​workspaces/​{ws}/​audit/​checkpoints`](#get-v1-workspaces-ws-audit-checkpoints) | Signed daily checkpoints of the audit chain, and the key that checks them (admins) | | [[POST]] | [`/​v1/​workspaces/​{ws}/​audit/​checkpoints`](#post-v1-workspaces-ws-audit-checkpoints) | Sign a checkpoint of the chain now, if it moved since the last one (admins) | | [[GET]] | [`/​v1/​workspaces/​{ws}/​audit/​export`](#get-v1-workspaces-ws-audit-export) | The audit chain as JSON Lines, oldest first, up to 10,000 events (admins) | | [[GET]] | [`/​v1/​workspaces/​{ws}/​audit/​sinks`](#get-v1-workspaces-ws-audit-sinks) | Where this workspace streams its audit log (admins) | | [[POST]] | [`/​v1/​workspaces/​{ws}/​audit/​sinks`](#post-v1-workspaces-ws-audit-sinks) | Stream the audit log to an HTTPS webhook or an S3 bucket (admins) | | [[PATCH]] | [`/​v1/​workspaces/​{ws}/​audit/​sinks/​{id}`](#patch-v1-workspaces-ws-audit-sinks-id) | Rename, pause or resume a destination (admins) | | [[DELETE]] | [`/​v1/​workspaces/​{ws}/​audit/​sinks/​{id}`](#delete-v1-workspaces-ws-audit-sinks-id) | Stop streaming to a destination and forget it (admins) | | [[POST]] | [`/​v1/​workspaces/​{ws}/​audit/​sinks/​{id}/​test`](#post-v1-workspaces-ws-audit-sinks-id-test) | Send one test message to a destination (admins) | | [[GET]] | [`/​v1/​workspaces/​{ws}/​audit/​verify`](#get-v1-workspaces-ws-audit-verify) | Recompute this workspace's audit chain now (workspace admins) | | [[PUT]] | [`/​v1/​workspaces/​{ws}/​connections/​{id}/​expiry`](#put-v1-workspaces-ws-connections-id-expiry) | Record the day a connection’s key stops working, or clear it (admins) | | [[POST]] | [`/​v1/​workspaces/​{ws}/​connections/​{id}/​rotation`](#post-v1-workspaces-ws-connections-id-rotation) | Replace a connection’s key in place: the old one serves until the new one works (admins) | | [[DELETE]] | [`/​v1/​workspaces/​{ws}/​connections/​{id}/​rotation`](#delete-v1-workspaces-ws-connections-id-rotation) | Throw the waiting key away; the old one stays (admins) | | [[POST]] | [`/​v1/​workspaces/​{ws}/​connections/​{id}/​rotation/​check`](#post-v1-workspaces-ws-connections-id-rotation-check) | Try the waiting key again (admins) | | [[POST]] | [`/​v1/​workspaces/​{ws}/​connections/​{id}/​rotation/​switch`](#post-v1-workspaces-ws-connections-id-rotation-switch) | Use the waiting key without a successful check; the audit log says so (admins) | | [[GET]] | [`/​v1/​workspaces/​{ws}/​flow`](#get-v1-workspaces-ws-flow) | The information-flow policy, what can be labelled and what the gate decided (admins) | | [[PUT]] | [`/​v1/​workspaces/​{ws}/​flow`](#put-v1-workspaces-ws-flow) | Replace the information-flow policy (admins). The revision you started from must still be current | | [[GET]] | [`/​v1/​workspaces/​{ws}/​security/​egress`](#get-v1-workspaces-ws-security-egress) | What each app may reach, and the calls the gate refused (workspace admins) | | [[GET]] | [`/​v1/​workspaces/​{ws}/​security/​keys`](#get-v1-workspaces-ws-security-keys) | Sealed keys: when stored, rotated and due to expire, never the keys (admins) | | [[POST]] | [`/​v1/​workspaces/​{ws}/​security/​panic`](#post-v1-workspaces-ws-security-panic) | Revoke every token, session, backend key, connection key and webhook secret at once (admins) | ## Reference ### [[GET]] `/v1/apps/{id}/flow` One app's data flow: what it reads, where it can send, and the policy in words. - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** `can_view` on the app; tokens: no | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `id` | path | string | yes | 1 to 128 characters | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `appId` | string | yes | at least 1 characters | | `name` | string | yes | at least 1 characters | | `status` | "draft" · "building" · "healthy" · "warning" · "failing" · "paused" | yes | | | `active` | boolean | yes | | | `held` | "pii" · "financial" · "secret"[] | yes | | | `sources` | object[] | yes | | | `sources[].kind` | "table" · "connection" | yes | | | `sources[].key` | string | yes | 1 to 100 characters | | `sources[].name` | string | yes | 1 to 120 characters | | `sources[].labels` | "pii" · "financial" · "secret"[] | yes | | | `sources[].columns` | string[] | yes | up to 32 items | | `sinks` | object[] | yes | | | `sinks[].destination` | string | yes | up to 300 characters | | `sinks[].kind` | "connector" · "http" · "host" · "ai" | yes | | | `sinks[].name` | string | yes | 1 to 253 characters | | `sinks[].action` | string or null | yes | up to 64 characters | | `sinks[].scope` | string or null | yes | up to 100 characters | | `sinks[].reason` | string or null | yes | up to 200 characters | | `sinks[].verdicts` | object[] | yes | | | `limits` | object | yes | | | `limits.requestBytes` | integer | yes | 256 to 262144 | | `limits.runBytes` | integer | yes | 1024 to 4194304 | | `decisions` | object[] | yes | | | `decisions[].at` | string (date-time) | yes | | | `decisions[].decision` | "blocked" · "allowed" | yes | | | `decisions[].appId` | string | yes | at least 1 characters | | `decisions[].appName` | string or null | yes | | | `decisions[].runId` | string or null | yes | | | `decisions[].labels` | "pii" · "financial" · "secret"[] | yes | | | `decisions[].destination` | string | yes | up to 300 characters | …and 3 more fields. The full schema is in [openapi.json](https://docs.qaldy.com/openapi.json). Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[GET]] `/v1/workspaces/{ws}/audit` The audit log, newest first: ids and metadata only (workspace admins). - **Authentication:** the console’s session cookie. - **Token:** a personal access token or an MCP sign-in with the `read` scope. - **Who:** admin; tokens: yes, read scope | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | | `action` | query | string | | up to 64 characters | | `actor` | query | string | | 1 to 128 characters | | `appId` | query | string | | 1 to 128 characters | | `limit` | query | integer | | 1 to 200. default 50 | | `cursor` | query | string | | up to 200 characters | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `items` | object[] | yes | | | `items[].seq` | integer | yes | at least 1 | | `items[].at` | string (date-time) | yes | | | `items[].actor` | object | yes | | | `items[].action` | string | yes | 1 to 64 characters | | `items[].target` | object | yes | | | `items[].data` | map of any or null | yes | | | `items[].prevHash` | string | yes | | | `items[].hash` | string | yes | | | `nextCursor` | string or null | yes | | Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[GET]] `/v1/workspaces/{ws}/audit/checkpoints` Signed daily checkpoints of the audit chain, and the key that checks them (admins). - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** admin; console only | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | | `limit` | query | integer | | 1 to 200. default 30 | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `configured` | boolean | yes | | | `keyId` | string or null | yes | | | `publicKey` | string or null | yes | | | `keySource` | "dedicated" · "derived" · "dev" · null or null | yes | | | `vault` | boolean | yes | | | `items` | object[] | yes | | | `items[].workspaceId` | string | yes | at least 1 characters | | `items[].seq` | integer | yes | at least 1 | | `items[].hash` | string | yes | | | `items[].at` | string (date-time) | yes | | | `items[].keyId` | string | yes | | | `items[].signature` | string | yes | | | `items[].anchoredAt` | string (date-time) or null | | | Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[POST]] `/v1/workspaces/{ws}/audit/checkpoints` Sign a checkpoint of the chain now, if it moved since the last one (admins). - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** admin; console only | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `configured` | boolean | yes | | | `keyId` | string or null | yes | | | `publicKey` | string or null | yes | | | `keySource` | "dedicated" · "derived" · "dev" · null or null | yes | | | `vault` | boolean | yes | | | `items` | object[] | yes | | | `items[].workspaceId` | string | yes | at least 1 characters | | `items[].seq` | integer | yes | at least 1 | | `items[].hash` | string | yes | | | `items[].at` | string (date-time) | yes | | | `items[].keyId` | string | yes | | | `items[].signature` | string | yes | | | `items[].anchoredAt` | string (date-time) or null | | | Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[GET]] `/v1/workspaces/{ws}/audit/export` The audit chain as JSON Lines, oldest first, up to 10,000 events (admins). - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** admin; console only | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | | `fromSeq` | query | integer | | at least 1. default 1 | | `limit` | query | integer | | 1 to 10000. default 5000 | **Response 200**: JSON Lines (served as application/x-ndjson): one event per line. `x-qaldy-export-next` names the next `fromSeq`, if any. ### [[GET]] `/v1/workspaces/{ws}/audit/sinks` Where this workspace streams its audit log (admins). - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** admin; console only | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `items` | object[] | yes | | | `items[].id` | string | yes | at least 1 characters | | `items[].kind` | "webhook" · "s3" | yes | | | `items[].name` | string | yes | at least 1 characters | | `items[].target` | string | yes | at least 1 characters | | `items[].status` | "active" · "paused" · "failing" | yes | | | `items[].preview` | boolean | yes | | | `items[].createdAt` | string (date-time) | yes | | | `items[].lastOkAt` | string (date-time) or null | yes | | | `items[].lastAttemptAt` | string (date-time) or null | yes | | | `items[].lastError` | "rejected" · "unreachable" · "timeout" · "private_address" · "dns_failed" · "tls" · "credentials_unavailable" · "role_denied" · … or null | yes | | | `items[].failures` | integer | yes | at least 0 | | `items[].deliveredSeq` | integer | yes | at least 0 | | `items[].behind` | integer | yes | at least 0 | | `items[].externalId` | string or null | yes | | | `s3Available` | boolean | yes | | | `s3Principal` | string or null | yes | | | `max` | integer | yes | at least 1 | Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[POST]] `/v1/workspaces/{ws}/audit/sinks` Stream the audit log to an HTTPS webhook or an S3 bucket (admins). - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** admin; console only | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | **Request body** (`application/json`) An empty object: `{}`. **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `sink` | object | yes | | | `sink.id` | string | yes | at least 1 characters | | `sink.kind` | "webhook" · "s3" | yes | | | `sink.name` | string | yes | at least 1 characters | | `sink.target` | string | yes | at least 1 characters | | `sink.status` | "active" · "paused" · "failing" | yes | | | `sink.preview` | boolean | yes | | | `sink.createdAt` | string (date-time) | yes | | | `sink.lastOkAt` | string (date-time) or null | yes | | | `sink.lastAttemptAt` | string (date-time) or null | yes | | | `sink.lastError` | "rejected" · "unreachable" · "timeout" · "private_address" · "dns_failed" · "tls" · "credentials_unavailable" · "role_denied" · … or null | yes | | | `sink.failures` | integer | yes | at least 0 | | `sink.deliveredSeq` | integer | yes | at least 0 | | `sink.behind` | integer | yes | at least 0 | | `sink.externalId` | string or null | yes | | | `signingSecret` | string or null | yes | | Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[PATCH]] `/v1/workspaces/{ws}/audit/sinks/{id}` Rename, pause or resume a destination (admins). - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** admin; console only | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | | `id` | path | string | yes | 1 to 64 characters | **Request body** (`application/json`) | Field | Type | Required | Notes | |---|---|---|---| | `name` | string | | 1 to 60 characters | | `state` | "active" · "paused" | | | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `id` | string | yes | at least 1 characters | | `kind` | "webhook" · "s3" | yes | | | `name` | string | yes | at least 1 characters | | `target` | string | yes | at least 1 characters | | `status` | "active" · "paused" · "failing" | yes | | | `preview` | boolean | yes | | | `createdAt` | string (date-time) | yes | | | `lastOkAt` | string (date-time) or null | yes | | | `lastAttemptAt` | string (date-time) or null | yes | | | `lastError` | "rejected" · "unreachable" · "timeout" · "private_address" · "dns_failed" · "tls" · "credentials_unavailable" · "role_denied" · … or null | yes | | | `failures` | integer | yes | at least 0 | | `deliveredSeq` | integer | yes | at least 0 | | `behind` | integer | yes | at least 0 | | `externalId` | string or null | yes | | Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[DELETE]] `/v1/workspaces/{ws}/audit/sinks/{id}` Stop streaming to a destination and forget it (admins). - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** admin; console only | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | | `id` | path | string | yes | 1 to 64 characters | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `ok` | true | yes | | Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[POST]] `/v1/workspaces/{ws}/audit/sinks/{id}/test` Send one test message to a destination (admins). - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** admin; console only | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | | `id` | path | string | yes | 1 to 64 characters | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `ok` | boolean | yes | | | `error` | "rejected" · "unreachable" · "timeout" · "private_address" · "dns_failed" · "tls" · "credentials_unavailable" · "role_denied" · … or null | yes | | | `sink` | object | yes | | | `sink.id` | string | yes | at least 1 characters | | `sink.kind` | "webhook" · "s3" | yes | | | `sink.name` | string | yes | at least 1 characters | | `sink.target` | string | yes | at least 1 characters | | `sink.status` | "active" · "paused" · "failing" | yes | | | `sink.preview` | boolean | yes | | | `sink.createdAt` | string (date-time) | yes | | | `sink.lastOkAt` | string (date-time) or null | yes | | | `sink.lastAttemptAt` | string (date-time) or null | yes | | | `sink.lastError` | "rejected" · "unreachable" · "timeout" · "private_address" · "dns_failed" · "tls" · "credentials_unavailable" · "role_denied" · … or null | yes | | | `sink.failures` | integer | yes | at least 0 | | `sink.deliveredSeq` | integer | yes | at least 0 | | `sink.behind` | integer | yes | at least 0 | | `sink.externalId` | string or null | yes | | Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[GET]] `/v1/workspaces/{ws}/audit/verify` Recompute this workspace's audit chain now (workspace admins). - **Authentication:** the console’s session cookie. - **Token:** a personal access token or an MCP sign-in with the `read` scope. - **Who:** admin; tokens: yes, read scope | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `ok` | boolean | yes | | | `count` | integer | yes | at least 0 | | `headPrefix` | string or null | yes | | | `checkedAt` | string (date-time) | yes | | | `broken` | object or null | yes | | | `broken.seq` | integer | yes | at least 0 | | `broken.reason` | "seq-gap" · "prev-hash" · "hash" · "invalid-row" · "head" | yes | | | `checkpoint` | object | | | | `checkpoint.state` | "ok" · "none" · "not_configured" · "failed" | yes | | | `checkpoint.total` | integer | yes | at least 0 | | `checkpoint.last` | object or null | yes | | | `checkpoint.failure` | object or null | yes | | Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[PUT]] `/v1/workspaces/{ws}/connections/{id}/expiry` Record the day a connection’s key stops working, or clear it (admins). - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** admin; console only | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | | `id` | path | string | yes | 1 to 128 characters | **Request body** (`application/json`) | Field | Type | Required | Notes | |---|---|---|---| | `expiresAt` | string (date-time) or null | yes | | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `connectionId` | string | yes | at least 1 characters | | `connectorId` | "shop" · "stripe" · "gmail" · "telegram" · "sheets" · "slack" · "kaspi" · "1c" · … | yes | | | `displayName` | string | yes | at least 1 characters | | `sealedTo` | string or null | yes | | | `storedAt` | string (date-time) or null | yes | | | `rotatedAt` | string (date-time) or null | yes | | | `expiresAt` | string (date-time) or null | yes | | | `expiry` | "none" · "ok" · "soon" · "expired" | yes | | | `daysLeft` | integer or null | yes | | | `revokedAt` | string (date-time) or null | yes | | | `rotation` | object or null | yes | | | `rotation.since` | string (date-time) | yes | | | `rotation.reason` | "auth_rejected" · "upstream_error" · "upstream_failed" · "dns_failed" · "private_address" · "secret_unavailable" · "not_connected" · "gate_unreachable" · … or null | yes | | | `rotation.checkedAt` | string (date-time) or null | yes | | Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[POST]] `/v1/workspaces/{ws}/connections/{id}/rotation` Replace a connection’s key in place: the old one serves until the new one works (admins). - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** admin; console only | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | | `id` | path | string | yes | 1 to 128 characters | **Request body** (`application/json`) | Field | Type | Required | Notes | |---|---|---|---| | `secret` | string | yes | 1 to 4096 characters | | `expiresAt` | string (date-time) or null | | | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `outcome` | "rotated" · "pending" · "rejected" | yes | | | `reason` | "auth_rejected" · "upstream_error" · "upstream_failed" · "dns_failed" · "private_address" · "secret_unavailable" · "not_connected" · "gate_unreachable" · … or null | yes | | | `checked` | "gate" · "format" · "none" | yes | | | `key` | object | yes | | | `key.connectionId` | string | yes | at least 1 characters | | `key.connectorId` | "shop" · "stripe" · "gmail" · "telegram" · "sheets" · "slack" · "kaspi" · "1c" · … | yes | | | `key.displayName` | string | yes | at least 1 characters | | `key.sealedTo` | string or null | yes | | | `key.storedAt` | string (date-time) or null | yes | | | `key.rotatedAt` | string (date-time) or null | yes | | | `key.expiresAt` | string (date-time) or null | yes | | | `key.expiry` | "none" · "ok" · "soon" · "expired" | yes | | | `key.daysLeft` | integer or null | yes | | | `key.revokedAt` | string (date-time) or null | yes | | | `key.rotation` | object or null | yes | | Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[DELETE]] `/v1/workspaces/{ws}/connections/{id}/rotation` Throw the waiting key away; the old one stays (admins). - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** admin; console only | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | | `id` | path | string | yes | 1 to 128 characters | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `connectionId` | string | yes | at least 1 characters | | `connectorId` | "shop" · "stripe" · "gmail" · "telegram" · "sheets" · "slack" · "kaspi" · "1c" · … | yes | | | `displayName` | string | yes | at least 1 characters | | `sealedTo` | string or null | yes | | | `storedAt` | string (date-time) or null | yes | | | `rotatedAt` | string (date-time) or null | yes | | | `expiresAt` | string (date-time) or null | yes | | | `expiry` | "none" · "ok" · "soon" · "expired" | yes | | | `daysLeft` | integer or null | yes | | | `revokedAt` | string (date-time) or null | yes | | | `rotation` | object or null | yes | | | `rotation.since` | string (date-time) | yes | | | `rotation.reason` | "auth_rejected" · "upstream_error" · "upstream_failed" · "dns_failed" · "private_address" · "secret_unavailable" · "not_connected" · "gate_unreachable" · … or null | yes | | | `rotation.checkedAt` | string (date-time) or null | yes | | Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[POST]] `/v1/workspaces/{ws}/connections/{id}/rotation/check` Try the waiting key again (admins). - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** admin; console only | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | | `id` | path | string | yes | 1 to 128 characters | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `outcome` | "rotated" · "pending" · "rejected" | yes | | | `reason` | "auth_rejected" · "upstream_error" · "upstream_failed" · "dns_failed" · "private_address" · "secret_unavailable" · "not_connected" · "gate_unreachable" · … or null | yes | | | `checked` | "gate" · "format" · "none" | yes | | | `key` | object | yes | | | `key.connectionId` | string | yes | at least 1 characters | | `key.connectorId` | "shop" · "stripe" · "gmail" · "telegram" · "sheets" · "slack" · "kaspi" · "1c" · … | yes | | | `key.displayName` | string | yes | at least 1 characters | | `key.sealedTo` | string or null | yes | | | `key.storedAt` | string (date-time) or null | yes | | | `key.rotatedAt` | string (date-time) or null | yes | | | `key.expiresAt` | string (date-time) or null | yes | | | `key.expiry` | "none" · "ok" · "soon" · "expired" | yes | | | `key.daysLeft` | integer or null | yes | | | `key.revokedAt` | string (date-time) or null | yes | | | `key.rotation` | object or null | yes | | Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[POST]] `/v1/workspaces/{ws}/connections/{id}/rotation/switch` Use the waiting key without a successful check; the audit log says so (admins). - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** admin; console only | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | | `id` | path | string | yes | 1 to 128 characters | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `outcome` | "rotated" · "pending" · "rejected" | yes | | | `reason` | "auth_rejected" · "upstream_error" · "upstream_failed" · "dns_failed" · "private_address" · "secret_unavailable" · "not_connected" · "gate_unreachable" · … or null | yes | | | `checked` | "gate" · "format" · "none" | yes | | | `key` | object | yes | | | `key.connectionId` | string | yes | at least 1 characters | | `key.connectorId` | "shop" · "stripe" · "gmail" · "telegram" · "sheets" · "slack" · "kaspi" · "1c" · … | yes | | | `key.displayName` | string | yes | at least 1 characters | | `key.sealedTo` | string or null | yes | | | `key.storedAt` | string (date-time) or null | yes | | | `key.rotatedAt` | string (date-time) or null | yes | | | `key.expiresAt` | string (date-time) or null | yes | | | `key.expiry` | "none" · "ok" · "soon" · "expired" | yes | | | `key.daysLeft` | integer or null | yes | | | `key.revokedAt` | string (date-time) or null | yes | | | `key.rotation` | object or null | yes | | Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[GET]] `/v1/workspaces/{ws}/flow` The information-flow policy, what can be labelled and what the gate decided (admins). - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** admin; tokens: no | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `workspaceId` | string | yes | at least 1 characters | | `policy` | object | yes | | | `policy.sources` | object[] | yes | up to 200 items | | `policy.allow` | object[] | yes | up to 300 items | | `policy.limits` | object | yes | | | `policy.revision` | integer | yes | 0 to 1000000000 | | `apps` | object[] | yes | | | `apps[].appId` | string | yes | at least 1 characters | | `apps[].name` | string | yes | at least 1 characters | | `apps[].status` | "draft" · "building" · "healthy" · "warning" · "failing" · "paused" | yes | | | `apps[].tables` | object[] | yes | | | `apps[].held` | "pii" · "financial" · "secret"[] | yes | | | `connections` | object[] | yes | | | `connections[].key` | string | yes | | | `connections[].name` | string | yes | 1 to 120 characters | | `connections[].provider` | "sheets" · "http" | yes | | | `connections[].labels` | "pii" · "financial" · "secret"[] | yes | | | `connections[].apps` | integer | yes | at least 0 | | `destinations` | object[] | yes | | | `destinations[].destination` | string | yes | up to 300 characters | | `destinations[].kind` | "connector" · "http" · "host" · "ai" | yes | | | `destinations[].name` | string | yes | 1 to 253 characters | | `destinations[].action` | string or null | yes | up to 64 characters | | `destinations[].apps` | integer | yes | at least 1 | | `decisions` | object[] | yes | | | `decisions[].at` | string (date-time) | yes | | | `decisions[].decision` | "blocked" · "allowed" | yes | | | `decisions[].appId` | string | yes | at least 1 characters | | `decisions[].appName` | string or null | yes | | | `decisions[].runId` | string or null | yes | | …and 5 more fields. The full schema is in [openapi.json](https://docs.qaldy.com/openapi.json). Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[PUT]] `/v1/workspaces/{ws}/flow` Replace the information-flow policy (admins). The revision you started from must still be current. - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** admin; tokens: no | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | **Request body** (`application/json`) | Field | Type | Required | Notes | |---|---|---|---| | `sources` | object[] | yes | up to 200 items | | `allow` | object[] | yes | up to 300 items | | `allow[].label` | "pii" · "financial" · "secret" | yes | | | `allow[].to` | string | yes | up to 300 characters | | `limits` | object | yes | | | `limits.requestBytes` | integer | yes | 256 to 262144 | | `limits.runBytes` | integer | yes | 1024 to 4194304 | | `revision` | integer | yes | at least 0 | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `workspaceId` | string | yes | at least 1 characters | | `policy` | object | yes | | | `policy.sources` | object[] | yes | up to 200 items | | `policy.allow` | object[] | yes | up to 300 items | | `policy.limits` | object | yes | | | `policy.revision` | integer | yes | 0 to 1000000000 | | `apps` | object[] | yes | | | `apps[].appId` | string | yes | at least 1 characters | | `apps[].name` | string | yes | at least 1 characters | | `apps[].status` | "draft" · "building" · "healthy" · "warning" · "failing" · "paused" | yes | | | `apps[].tables` | object[] | yes | | | `apps[].held` | "pii" · "financial" · "secret"[] | yes | | | `connections` | object[] | yes | | | `connections[].key` | string | yes | | | `connections[].name` | string | yes | 1 to 120 characters | | `connections[].provider` | "sheets" · "http" | yes | | | `connections[].labels` | "pii" · "financial" · "secret"[] | yes | | | `connections[].apps` | integer | yes | at least 0 | | `destinations` | object[] | yes | | | `destinations[].destination` | string | yes | up to 300 characters | | `destinations[].kind` | "connector" · "http" · "host" · "ai" | yes | | | `destinations[].name` | string | yes | 1 to 253 characters | | `destinations[].action` | string or null | yes | up to 64 characters | | `destinations[].apps` | integer | yes | at least 1 | | `decisions` | object[] | yes | | | `decisions[].at` | string (date-time) | yes | | | `decisions[].decision` | "blocked" · "allowed" | yes | | | `decisions[].appId` | string | yes | at least 1 characters | | `decisions[].appName` | string or null | yes | | | `decisions[].runId` | string or null | yes | | …and 5 more fields. The full schema is in [openapi.json](https://docs.qaldy.com/openapi.json). Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[GET]] `/v1/workspaces/{ws}/security/egress` What each app may reach, and the calls the gate refused (workspace admins). - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** admin | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `workspaceId` | string | yes | at least 1 characters | | `windowDays` | integer | yes | at least 1 | | `apps` | object[] | yes | | | `apps[].appId` | string | yes | at least 1 characters | | `apps[].name` | string | yes | at least 1 characters | | `apps[].status` | "draft" · "building" · "healthy" · "warning" · "failing" · "paused" | yes | | | `apps[].category` | "interface" · "data" · "messaging" · "money" · "ai" · "time" · "people" · "growth" | yes | | | `apps[].connectors` | object[] | yes | | | `apps[].extraDomains` | object[] | yes | | | `apps[].blocked` | integer | yes | at least 0 | | `apps[].lastBlockedAt` | string (date-time) or null | yes | | | `apps[].lastBlockedHost` | string or null | yes | | Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[GET]] `/v1/workspaces/{ws}/security/keys` Sealed keys: when stored, rotated and due to expire, never the keys (admins). - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** admin; console only | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `items` | object[] | yes | | | `items[].connectionId` | string | yes | at least 1 characters | | `items[].connectorId` | "shop" · "stripe" · "gmail" · "telegram" · "sheets" · "slack" · "kaspi" · "1c" · … | yes | | | `items[].displayName` | string | yes | at least 1 characters | | `items[].sealedTo` | string or null | yes | | | `items[].storedAt` | string (date-time) or null | yes | | | `items[].rotatedAt` | string (date-time) or null | yes | | | `items[].expiresAt` | string (date-time) or null | yes | | | `items[].expiry` | "none" · "ok" · "soon" · "expired" | yes | | | `items[].daysLeft` | integer or null | yes | | | `items[].revokedAt` | string (date-time) or null | yes | | | `items[].rotation` | object or null | yes | | Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)). ### [[POST]] `/v1/workspaces/{ws}/security/panic` Revoke every token, session, backend key, connection key and webhook secret at once (admins). - **Authentication:** the console’s session cookie. - **Token:** not available. This route is for a signed-in person in the console (`403 console_only` for a token). - **Who:** admin; signed-in person only, never a token | Parameter | In | Type | Required | Notes | |---|---|---|---|---| | `ws` | path | string | yes | 1 to 128 characters | **Request body** (`application/json`) | Field | Type | Required | Notes | |---|---|---|---| | `confirm` | string | yes | 1 to 80 characters | | `reason` | string | | up to 200 characters | **Response 200** | Field | Type | Required | Notes | |---|---|---|---| | `at` | string (date-time) | yes | | | `revoked` | object | yes | | | `revoked.accessTokens` | integer | yes | at least 0 | | `revoked.backendKeys` | integer | yes | at least 0 | | `revoked.sessions` | integer | yes | at least 0 | | `revoked.connectorKeys` | integer | yes | at least 0 | | `revoked.webhookSecrets` | integer | yes | at least 0 | | `others` | map of integer | | default [object Object] | | `connections` | string[] | yes | | Errors: `400`, `401`, `403`, `404`, `409`, `429` (the error format is on the [overview](https://docs.qaldy.com/reference/api/#errors)).