{"openapi":"3.1.0","info":{"title":"OutDo Data API","description":"The public REST API for the OutDo platform: authentication, the workspace model (workspaces, modules, rails, features, columns, views), row data, aggregates, and files.\n\n### Authentication\nSign in with `POST /v1/auth/token` to obtain a bearer token, then click **Authorize** and paste the `access_token`. Every request runs with the signed-in user's own permissions — the API enforces the platform's row-level security and never widens access.\n\n### Conventions\n- **Errors** follow RFC 7807 (`application/problem+json`); `422` responses carry an actionable `detail`.\n- **Pagination** is cursor-based: pass `next_cursor` from the previous page back as `cursor`.\n- **Idempotency**: send an `Idempotency-Key` header on any POST to make retries safe.\n- **Rate limits** apply per client; `429` responses carry a `Retry-After` header.\n- **Versioning**: this surface is `/v1`; breaking changes ship under a new prefix.\n\nMachine-readable structure: `GET /v1/schema` (the caller's visible model) and `GET /v1/schema/definitions` (what each entity's config accepts).","contact":{"name":"OutDo","url":"https://out-do.app/"},"version":"0.1.0"},"paths":{"/v1/health":{"get":{"tags":["health"],"summary":"Liveness probe","description":"Unauthenticated. Touches no downstream service — safe for load-balancer checks.","operationId":"health","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthOut"}}}}}}},"/v1/auth/token":{"post":{"tags":["auth"],"summary":"Sign in with email and password","description":"Exchanges OutDo credentials for a bearer session. Authentication failures return a generic 401 (no cause disclosed) and the endpoint is strictly rate-limited.","operationId":"auth_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"401":{"description":"Authentication failed (generic; no cause disclosed)."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."}}}},"/v1/auth/refresh":{"post":{"tags":["auth"],"summary":"Refresh an access token","description":"Exchanges a refresh token for a new session; the previous refresh token is rotated.","operationId":"auth_refresh","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"401":{"description":"Authentication failed (generic; no cause disclosed)."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."}}}},"/v1/organizations":{"get":{"tags":["organizations"],"summary":"List organizations","description":"Cursor-paginated. Returns the organizations the caller owns or belongs to.","operationId":"list_organizations","security":[{"HTTPBearer":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor taken from `next_cursor` of the previous page.","title":"Cursor"},"description":"Opaque cursor taken from `next_cursor` of the previous page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page size, 1 to 200. Defaults to 25.","default":25,"title":"Limit"},"description":"Page size, 1 to 200. Defaults to 25."},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_OrganizationOut_"}}}},"401":{"description":"Not authenticated."},"422":{"description":"Validation error (e.g. a malformed cursor)."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/organizations/{organization_id}":{"get":{"tags":["organizations"],"summary":"Get an organization","description":"Returns 404 when the organization does not exist or is not visible to the caller.","operationId":"get_organization","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Organization Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/workspaces":{"get":{"tags":["workspaces"],"summary":"List workspaces","description":"Cursor-paginated. Returns only what row-level security lets the caller see.","operationId":"list_workspaces","security":[{"HTTPBearer":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor taken from `next_cursor` of the previous page.","title":"Cursor"},"description":"Opaque cursor taken from `next_cursor` of the previous page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page size, 1 to 200. Defaults to 25.","default":25,"title":"Limit"},"description":"Page size, 1 to 200. Defaults to 25."},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_WorkspaceOut_"}}}},"401":{"description":"Not authenticated."},"422":{"description":"Validation error (e.g. a malformed cursor)."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}},"post":{"tags":["workspaces"],"summary":"Create a workspace","description":"The caller must be a member of the target organization.","operationId":"create_workspace","security":[{"HTTPBearer":[]}],"parameters":[{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceCreateIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceOut"}}}},"401":{"description":"Not authenticated."},"403":{"description":"Permission denied."},"404":{"description":"Not found / not visible."},"409":{"description":"Conflict."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/workspaces/{workspace_id}":{"get":{"tags":["workspaces"],"summary":"Get a workspace","description":"Returns 404 when the workspace does not exist or is not visible to the caller.","operationId":"get_workspace","security":[{"HTTPBearer":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Workspace Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"503":{"description":"Upstream data store unavailable."}}},"patch":{"tags":["workspaces"],"summary":"Update a workspace","description":"Partial update — only the fields present in the request body are changed.","operationId":"update_workspace","security":[{"HTTPBearer":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Workspace Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspacePatchIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceOut"}}}},"401":{"description":"Not authenticated."},"403":{"description":"Permission denied."},"404":{"description":"Not found / not visible."},"409":{"description":"Conflict."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}},"delete":{"tags":["workspaces"],"summary":"Delete a workspace","description":"Destructive: the database cascades to every module, rail, feature, row, and view inside. A non-empty workspace returns 409 unless `force=true`.","operationId":"delete_workspace","security":[{"HTTPBearer":[]}],"parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Workspace Id"}},{"name":"force","in":"query","required":false,"schema":{"type":"boolean","description":"Confirm deleting a NON-EMPTY workspace.","default":false,"title":"Force"},"description":"Confirm deleting a NON-EMPTY workspace."},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Not authenticated."},"403":{"description":"Permission denied."},"404":{"description":"Not found / not visible."},"409":{"description":"Not empty — repeat with force=true to cascade."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/modules":{"get":{"tags":["modules"],"summary":"List modules","description":"Cursor-paginated. Optionally filtered to a single workspace.","operationId":"list_modules","security":[{"HTTPBearer":[]}],"parameters":[{"name":"workspace_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Only modules of this workspace.","title":"Workspace Id"},"description":"Only modules of this workspace."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor taken from `next_cursor` of the previous page.","title":"Cursor"},"description":"Opaque cursor taken from `next_cursor` of the previous page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page size, 1 to 200. Defaults to 25.","default":25,"title":"Limit"},"description":"Page size, 1 to 200. Defaults to 25."},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ModuleOut_"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}},"post":{"tags":["modules"],"summary":"Create a module","description":"The organization is derived from the parent workspace — it is never accepted from the client.","operationId":"create_module","security":[{"HTTPBearer":[]}],"parameters":[{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModuleCreateIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModuleOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."},"403":{"description":"Permission denied."},"409":{"description":"Conflict."}}}},"/v1/modules/{module_id}":{"get":{"tags":["modules"],"summary":"Get a module","description":"Returns 404 when the module does not exist or is not visible to the caller.","operationId":"get_module","security":[{"HTTPBearer":[]}],"parameters":[{"name":"module_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Module Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModuleOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}},"patch":{"tags":["modules"],"summary":"Update a module","description":"Partial update — only the fields present in the request body are changed.","operationId":"update_module","security":[{"HTTPBearer":[]}],"parameters":[{"name":"module_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Module Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModulePatchIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModuleOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."},"403":{"description":"Permission denied."},"409":{"description":"Conflict."}}},"delete":{"tags":["modules"],"summary":"Delete a module","description":"A module that still has rails returns 409 unless `force=true` (rails cascade).","operationId":"delete_module","security":[{"HTTPBearer":[]}],"parameters":[{"name":"module_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Module Id"}},{"name":"force","in":"query","required":false,"schema":{"type":"boolean","description":"Confirm deleting a module that still has rails.","default":false,"title":"Force"},"description":"Confirm deleting a module that still has rails."},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Not authenticated."},"403":{"description":"Permission denied."},"404":{"description":"Not found / not visible."},"409":{"description":"Not empty — repeat with force=true to cascade."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/rails":{"get":{"tags":["rails"],"summary":"List rails","description":"Cursor-paginated. Optionally filtered to a single module.","operationId":"list_rails","security":[{"HTTPBearer":[]}],"parameters":[{"name":"module_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Only rails of this module.","title":"Module Id"},"description":"Only rails of this module."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor taken from `next_cursor` of the previous page.","title":"Cursor"},"description":"Opaque cursor taken from `next_cursor` of the previous page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page size, 1 to 200. Defaults to 25.","default":25,"title":"Limit"},"description":"Page size, 1 to 200. Defaults to 25."},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_RailOut_"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}},"post":{"tags":["rails"],"summary":"Create a rail","description":"The organization is derived from the parent module. `config` lists the views the rail shows; an object is accepted and normalized to the platform's single-item-list shape.","operationId":"create_rail","security":[{"HTTPBearer":[]}],"parameters":[{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RailCreateIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RailOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."},"403":{"description":"Permission denied."},"409":{"description":"Conflict."}}}},"/v1/rails/{rail_id}":{"get":{"tags":["rails"],"summary":"Get a rail","description":"Returns 404 when the rail does not exist or is not visible to the caller.","operationId":"get_rail","security":[{"HTTPBearer":[]}],"parameters":[{"name":"rail_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Rail Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RailOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}},"patch":{"tags":["rails"],"summary":"Update a rail","description":"Partial update — only the fields present in the request body are changed.","operationId":"update_rail","security":[{"HTTPBearer":[]}],"parameters":[{"name":"rail_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Rail Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RailPatchIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RailOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."},"403":{"description":"Permission denied."},"409":{"description":"Conflict."}}},"delete":{"tags":["rails"],"summary":"Delete a rail","description":"Removes the navigation entry; the views it pointed at are not touched.","operationId":"delete_rail","security":[{"HTTPBearer":[]}],"parameters":[{"name":"rail_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Rail Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Not authenticated."},"403":{"description":"Permission denied."},"404":{"description":"Not found / not visible."},"409":{"description":"Not empty — repeat with force=true to cascade."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/features":{"get":{"tags":["features"],"summary":"List features","description":"Cursor-paginated. Optionally filtered to a single workspace.","operationId":"list_features","security":[{"HTTPBearer":[]}],"parameters":[{"name":"workspace_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Only features of this workspace.","title":"Workspace Id"},"description":"Only features of this workspace."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor taken from `next_cursor` of the previous page.","title":"Cursor"},"description":"Opaque cursor taken from `next_cursor` of the previous page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page size, 1 to 200. Defaults to 25.","default":25,"title":"Limit"},"description":"Page size, 1 to 200. Defaults to 25."},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_FeatureOut_"}}}},"401":{"description":"Not authenticated."},"422":{"description":"Validation error (e.g. a malformed cursor)."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}},"post":{"tags":["features"],"summary":"Create a feature","description":"The organization is derived from the parent workspace — it is never accepted from the client.","operationId":"create_feature","security":[{"HTTPBearer":[]}],"parameters":[{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureCreateIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."},"403":{"description":"Permission denied."},"409":{"description":"Conflict."}}}},"/v1/features/{feature_id}":{"get":{"tags":["features"],"summary":"Get a feature","description":"Returns 404 when the feature does not exist or is not visible to the caller.","operationId":"get_feature","security":[{"HTTPBearer":[]}],"parameters":[{"name":"feature_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feature Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}},"patch":{"tags":["features"],"summary":"Update a feature","description":"Partial update — only the fields present in the request body are changed.","operationId":"update_feature","security":[{"HTTPBearer":[]}],"parameters":[{"name":"feature_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feature Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeaturePatchIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."},"403":{"description":"Permission denied."},"409":{"description":"Conflict."}}},"delete":{"tags":["features"],"summary":"Delete a feature","description":"Destructive: the database cascades to the feature's rows, columns, and views. A feature that still has rows returns 409 unless `force=true`.","operationId":"delete_feature","security":[{"HTTPBearer":[]}],"parameters":[{"name":"feature_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feature Id"}},{"name":"force","in":"query","required":false,"schema":{"type":"boolean","description":"Confirm deleting a feature that still has rows.","default":false,"title":"Force"},"description":"Confirm deleting a feature that still has rows."},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Not authenticated."},"403":{"description":"Permission denied."},"404":{"description":"Not found / not visible."},"409":{"description":"Not empty — repeat with force=true to cascade."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/features/{feature_id}/columns":{"get":{"tags":["features"],"summary":"List columns","description":"All column definitions of the feature, in display order.","operationId":"list_feature_columns","security":[{"HTTPBearer":[]}],"parameters":[{"name":"feature_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feature Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FeatureColumnOut"},"title":"Response List Feature Columns"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}},"post":{"tags":["features"],"summary":"Create a column","description":"`type` and `default_component` are validated against the platform registries — see GET /v1/schema/definitions for the allowed values.","operationId":"create_feature_column","security":[{"HTTPBearer":[]}],"parameters":[{"name":"feature_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feature Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ColumnCreateIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureColumnOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."},"403":{"description":"Permission denied."},"409":{"description":"Conflict."}}}},"/v1/features/{feature_id}/columns/{column_id}":{"patch":{"tags":["features"],"summary":"Update a column","description":"Partial update — only the fields present in the request body are changed.","operationId":"update_feature_column","security":[{"HTTPBearer":[]}],"parameters":[{"name":"feature_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feature Id"}},{"name":"column_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Column Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ColumnPatchIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureColumnOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."},"403":{"description":"Permission denied."},"409":{"description":"Conflict."}}},"delete":{"tags":["features"],"summary":"Delete a column","description":"Removes the column DEFINITION. Row data keeps the orphaned key — it simply stops being displayed and validated.","operationId":"delete_feature_column","security":[{"HTTPBearer":[]}],"parameters":[{"name":"feature_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feature Id"}},{"name":"column_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Column Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Not authenticated."},"403":{"description":"Permission denied."},"404":{"description":"Not found / not visible."},"409":{"description":"Not empty — repeat with force=true to cascade."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/features/{feature_id}/rows":{"get":{"tags":["rows"],"summary":"List rows","description":"Cursor-paginated. Supports filtering (`filter`, `match`), sorting (`sort`), and response-side projection (`fields`) — see each parameter for the grammar.","operationId":"list_rows","security":[{"HTTPBearer":[]}],"parameters":[{"name":"feature_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feature Id"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor taken from `next_cursor` of the previous page.","title":"Cursor"},"description":"Opaque cursor taken from `next_cursor` of the previous page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page size, 1 to 200. Defaults to 25.","default":25,"title":"Limit"},"description":"Page size, 1 to 200. Defaults to 25."},{"name":"filter","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Repeatable `column:op:value`, combined with AND (or OR via `match=any`). Text ops (`data->>col` as text): eq, neq, gt, gte, lt, lte, like, ilike (`*` wildcards), contains, ncontains, startswith, endswith (case-insensitive substring/prefix/suffix), in (`status:in:open|closed`), is (null|true|false). Numeric ops (`data->col` as JSONB, correct numeric order for stored JSON numbers): eqn, neqn, gtn, gten, ltn, lten. Any op can be negated with the `not.` prefix (`status:not.eq:closed`). Columns are the row data keys plus id/created_at/updated_at.","title":"Filter"},"description":"Repeatable `column:op:value`, combined with AND (or OR via `match=any`). Text ops (`data->>col` as text): eq, neq, gt, gte, lt, lte, like, ilike (`*` wildcards), contains, ncontains, startswith, endswith (case-insensitive substring/prefix/suffix), in (`status:in:open|closed`), is (null|true|false). Numeric ops (`data->col` as JSONB, correct numeric order for stored JSON numbers): eqn, neqn, gtn, gten, ltn, lten. Any op can be negated with the `not.` prefix (`status:not.eq:closed`). Columns are the row data keys plus id/created_at/updated_at."},{"name":"match","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"How the filters combine: `all` (AND, default) or `any` (OR).","title":"Match"},"description":"How the filters combine: `all` (AND, default) or `any` (OR)."},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Sort key: `column` asc, `-column` desc. Changes the cursor scheme — do not mix cursors across sorts.","title":"Sort"},"description":"Sort key: `column` asc, `-column` desc. Changes the cursor scheme — do not mix cursors across sorts."},{"name":"fields","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated projection of the row `data` keys, e.g. `fields=title,amount`.","title":"Fields"},"description":"Comma-separated projection of the row `data` keys, e.g. `fields=title,amount`."},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_RowOut_"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error (e.g. a malformed cursor)."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}},"post":{"tags":["rows"],"summary":"Create a row","description":"`data` is validated against the feature's column definitions by default — see the `validate` parameter. Send an `Idempotency-Key` header to make retries safe.","operationId":"create_row","security":[{"HTTPBearer":[]}],"parameters":[{"name":"feature_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feature Id"}},{"name":"validate","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Write validation against the feature's columns: `on` (default — required columns present, typed columns storable), `strict` (also rejects unknown data keys), `off`.","title":"Validate"},"description":"Write validation against the feature's columns: `on` (default — required columns present, typed columns storable), `strict` (also rejects unknown data keys), `off`."},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RowCreateIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RowOut"}}}},"401":{"description":"Not authenticated."},"403":{"description":"Permission denied for this operation."},"404":{"description":"Not found / not visible."},"409":{"description":"The write conflicts with current state."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/features/{feature_id}/rows:aggregate":{"get":{"tags":["rows"],"summary":"Aggregate rows (count, sum, avg)","description":"`count` is exact and accepts the same filters as the list endpoint. `sum`/`avg` compute over a capped sample (10,000 rows — narrow with filters beyond that); non-numeric values are skipped and reported via `rows_considered`.","operationId":"aggregate_rows","security":[{"HTTPBearer":[]}],"parameters":[{"name":"feature_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feature Id"}},{"name":"op","in":"query","required":true,"schema":{"enum":["count","sum","avg"],"type":"string","title":"Op"}},{"name":"column","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Row data key (required for sum/avg).","title":"Column"},"description":"Row data key (required for sum/avg)."},{"name":"filter","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Repeatable `column:op:value`, combined with AND (or OR via `match=any`). Text ops (`data->>col` as text): eq, neq, gt, gte, lt, lte, like, ilike (`*` wildcards), contains, ncontains, startswith, endswith (case-insensitive substring/prefix/suffix), in (`status:in:open|closed`), is (null|true|false). Numeric ops (`data->col` as JSONB, correct numeric order for stored JSON numbers): eqn, neqn, gtn, gten, ltn, lten. Any op can be negated with the `not.` prefix (`status:not.eq:closed`). Columns are the row data keys plus id/created_at/updated_at.","title":"Filter"},"description":"Repeatable `column:op:value`, combined with AND (or OR via `match=any`). Text ops (`data->>col` as text): eq, neq, gt, gte, lt, lte, like, ilike (`*` wildcards), contains, ncontains, startswith, endswith (case-insensitive substring/prefix/suffix), in (`status:in:open|closed`), is (null|true|false). Numeric ops (`data->col` as JSONB, correct numeric order for stored JSON numbers): eqn, neqn, gtn, gten, ltn, lten. Any op can be negated with the `not.` prefix (`status:not.eq:closed`). Columns are the row data keys plus id/created_at/updated_at."},{"name":"match","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"How the filters combine: `all` (AND, default) or `any` (OR).","title":"Match"},"description":"How the filters combine: `all` (AND, default) or `any` (OR)."},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AggregateOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error (e.g. a malformed cursor)."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/features/{feature_id}/rows/{row_id}":{"get":{"tags":["rows"],"summary":"Get a row","description":"Returns 404 when the row does not exist or is not visible to the caller.","operationId":"get_row","security":[{"HTTPBearer":[]}],"parameters":[{"name":"feature_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feature Id"}},{"name":"row_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Row Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RowOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error (e.g. a malformed cursor)."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}},"patch":{"tags":["rows"],"summary":"Update a row","description":"Replaces the whole `data` object by default; with `merge=true` the payload is shallow-merged over the current data and a `null` value removes the key.","operationId":"update_row","security":[{"HTTPBearer":[]}],"parameters":[{"name":"feature_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feature Id"}},{"name":"row_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Row Id"}},{"name":"validate","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Write validation against the feature's columns: `on` (default — required columns present, typed columns storable), `strict` (also rejects unknown data keys), `off`.","title":"Validate"},"description":"Write validation against the feature's columns: `on` (default — required columns present, typed columns storable), `strict` (also rejects unknown data keys), `off`."},{"name":"merge","in":"query","required":false,"schema":{"type":"boolean","description":"true → shallow-merge the payload over the current data (a null value removes the key); false (default) → replace the whole data object.","default":false,"title":"Merge"},"description":"true → shallow-merge the payload over the current data (a null value removes the key); false (default) → replace the whole data object."},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RowUpdateIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RowOut"}}}},"401":{"description":"Not authenticated."},"403":{"description":"Permission denied for this operation."},"404":{"description":"Not found / not visible."},"409":{"description":"The write conflicts with current state."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}},"delete":{"tags":["rows"],"summary":"Delete a row","description":"Returns 204 on success; 404 when the row does not exist, is not visible, or the caller may not delete it.","operationId":"delete_row","security":[{"HTTPBearer":[]}],"parameters":[{"name":"feature_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feature Id"}},{"name":"row_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Row Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Not authenticated."},"403":{"description":"Permission denied for this operation."},"404":{"description":"Not found / not visible."},"409":{"description":"The write conflicts with current state."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/features/{feature_id}/rows:batch":{"post":{"tags":["rows"],"summary":"Create rows in bulk","description":"Up to 500 rows in one atomic insert — if any row is rejected, the whole batch rolls back. Validation errors name the offending row (`rows[i]: …`).","operationId":"create_rows_batch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"feature_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Feature Id"}},{"name":"validate","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Write validation against the feature's columns: `on` (default — required columns present, typed columns storable), `strict` (also rejects unknown data keys), `off`.","title":"Validate"},"description":"Write validation against the feature's columns: `on` (default — required columns present, typed columns storable), `strict` (also rejects unknown data keys), `off`."},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RowsBatchIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RowsBatchOut"}}}},"401":{"description":"Not authenticated."},"403":{"description":"Permission denied for this operation."},"404":{"description":"Not found / not visible."},"409":{"description":"The write conflicts with current state."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/views":{"get":{"tags":["views"],"summary":"List views","description":"Cursor-paginated. Optionally filtered to a single feature.","operationId":"list_views","security":[{"HTTPBearer":[]}],"parameters":[{"name":"feature_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Only views of this feature.","title":"Feature Id"},"description":"Only views of this feature."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor taken from `next_cursor` of the previous page.","title":"Cursor"},"description":"Opaque cursor taken from `next_cursor` of the previous page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page size, 1 to 200. Defaults to 25.","default":25,"title":"Limit"},"description":"Page size, 1 to 200. Defaults to 25."},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ViewOut_"}}}},"401":{"description":"Not authenticated."},"422":{"description":"Validation error (e.g. a malformed cursor)."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}},"post":{"tags":["views"],"summary":"Create a view","description":"`type` is validated against the view registry (see GET /v1/schema/definitions). `config` accepts an object or a list and is normalized to the platform's single-item-list shape.","operationId":"create_view","security":[{"HTTPBearer":[]}],"parameters":[{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ViewCreateIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ViewOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."},"403":{"description":"Permission denied."},"409":{"description":"Conflict."}}}},"/v1/views/{view_id}":{"get":{"tags":["views"],"summary":"Get a view","description":"Returns 404 when the view does not exist or is not visible to the caller.","operationId":"get_view","security":[{"HTTPBearer":[]}],"parameters":[{"name":"view_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"View Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ViewOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}},"patch":{"tags":["views"],"summary":"Update a view","description":"Partial update — only the fields present in the request body are changed.","operationId":"update_view","security":[{"HTTPBearer":[]}],"parameters":[{"name":"view_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"View Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ViewPatchIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ViewOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."},"403":{"description":"Permission denied."},"409":{"description":"Conflict."}}},"delete":{"tags":["views"],"summary":"Delete a view","description":"Removes the saved view; the feature's data is not touched.","operationId":"delete_view","security":[{"HTTPBearer":[]}],"parameters":[{"name":"view_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"View Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Not authenticated."},"403":{"description":"Permission denied."},"404":{"description":"Not found / not visible."},"409":{"description":"Not empty — repeat with force=true to cascade."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/schema":{"get":{"tags":["schema"],"summary":"Get the workspace model","description":"Workspaces → features → columns + views, nested. Structure only (no rows). `truncated: true` means a size cap was hit — narrow with `workspace_id`.","operationId":"get_schema","security":[{"HTTPBearer":[]}],"parameters":[{"name":"workspace_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Workspace Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchemaOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Workspace not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/schema/definitions":{"get":{"tags":["schema"],"summary":"Get configuration definitions","description":"Static, versioned reference for programmatic builders (the AI MCP): allowed column types and components, view types and their config shapes, feature/workspace/rail/module config keys, row-data and file-metadata conventions. The write endpoints validate against these same allow-lists.","operationId":"get_schema_definitions","security":[{"HTTPBearer":[]}],"parameters":[{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Schema Definitions"}}}},"401":{"description":"Not authenticated."},"429":{"description":"Rate limited."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/files":{"post":{"tags":["files"],"summary":"Upload a file","description":"Multipart upload. The object path is built server-side as `feature_{feature_id}/column_{column_id}/{timestamp}_{fileName}`; the response is the exact metadata object a `file` component stores in row data.","operationId":"upload_file","security":[{"HTTPBearer":[]}],"parameters":[{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_file"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileOut"}}}},"401":{"description":"Not authenticated."},"403":{"description":"Permission denied for this file."},"404":{"description":"Not found / not visible."},"409":{"description":"A file already exists at this path."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream store unavailable."}}}},"/v1/files/sign":{"get":{"tags":["files"],"summary":"Create a signed download URL","description":"Returns a time-limited URL (1 minute to 7 days, default 1 hour) for a stored object. Visibility follows the same permissions as the file's feature.","operationId":"sign_file_url","security":[{"HTTPBearer":[]}],"parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","description":"The stored object path (FileOut.path).","title":"Path"},"description":"The stored object path (FileOut.path)."},{"name":"expires_in","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Lifetime in seconds, 60 to 604800. Defaults to 3600.","title":"Expires In"},"description":"Lifetime in seconds, 60 to 604800. Defaults to 3600."},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignedUrlOut"}}}},"401":{"description":"Not authenticated."},"403":{"description":"Permission denied for this file."},"404":{"description":"Not found / not visible."},"409":{"description":"A file already exists at this path."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream store unavailable."}}}},"/v1/workflows":{"get":{"tags":["workflows"],"summary":"List workflows","description":"Cursor-paginated. Optionally filtered to a single workspace.","operationId":"list_workflows","security":[{"HTTPBearer":[]}],"parameters":[{"name":"workspace_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Only workflows of this workspace.","title":"Workspace Id"},"description":"Only workflows of this workspace."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor taken from `next_cursor` of the previous page.","title":"Cursor"},"description":"Opaque cursor taken from `next_cursor` of the previous page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page size, 1 to 200. Defaults to 25.","default":25,"title":"Limit"},"description":"Page size, 1 to 200. Defaults to 25."},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_WorkflowOut_"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/workflows/{workflow_id}":{"get":{"tags":["workflows"],"summary":"Get a workflow","description":"Returns 404 when the workflow does not exist or is not visible to the caller.","operationId":"get_workflow","security":[{"HTTPBearer":[]}],"parameters":[{"name":"workflow_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Workflow Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/workflows/{workflow_id}/trigger":{"post":{"tags":["workflows"],"summary":"Trigger a workflow run","description":"Queues one run of the workflow with the given input and returns it immediately (202 — execution is asynchronous). Poll the run's `status` until it reaches `success`, `failed`, or `cancelled`. Inactive workflows return 409. Send an `Idempotency-Key` header to make retries safe.","operationId":"trigger_workflow","security":[{"HTTPBearer":[]}],"parameters":[{"name":"workflow_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Workflow Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowTriggerIn"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowRunOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."},"403":{"description":"Permission denied."},"409":{"description":"The workflow is not active."}}}},"/v1/workflows/{workflow_id}/runs":{"get":{"tags":["workflows"],"summary":"List runs of a workflow","description":"Newest first. Cursor-paginated.","operationId":"list_workflow_runs","security":[{"HTTPBearer":[]}],"parameters":[{"name":"workflow_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Workflow Id"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor taken from `next_cursor` of the previous page.","title":"Cursor"},"description":"Opaque cursor taken from `next_cursor` of the previous page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page size, 1 to 200. Defaults to 25.","default":25,"title":"Limit"},"description":"Page size, 1 to 200. Defaults to 25."},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_WorkflowRunOut_"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/workflows/{workflow_id}/runs/{run_id}":{"get":{"tags":["workflows"],"summary":"Get a workflow run","description":"Returns 404 when the run does not exist or is not visible to the caller.","operationId":"get_workflow_run","security":[{"HTTPBearer":[]}],"parameters":[{"name":"workflow_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Workflow Id"}},{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Run Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowRunOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/api-keys":{"post":{"tags":["api-keys"],"summary":"Create an API key","description":"Mints a scoped API key backed by a machine user. The response carries the plaintext `secret` **once** — store it now, it cannot be retrieved again. The key acts as a member of the organization with the given role and scopes; requires permission to manage the organization's keys.","operationId":"create_api_key","security":[{"HTTPBearer":[]}],"parameters":[{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreateIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreatedOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."},"403":{"description":"Not allowed to manage keys for this organization."}}},"get":{"tags":["api-keys"],"summary":"List API keys","description":"Cursor-paginated. Returns key metadata (never the secret). Optionally filtered to one organization.","operationId":"list_api_keys","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Only keys of this organization.","title":"Organization Id"},"description":"Only keys of this organization."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque cursor taken from `next_cursor` of the previous page.","title":"Cursor"},"description":"Opaque cursor taken from `next_cursor` of the previous page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page size, 1 to 200. Defaults to 25.","default":25,"title":"Limit"},"description":"Page size, 1 to 200. Defaults to 25."},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ApiKeyOut_"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}}},"/v1/api-keys/{key_id}":{"get":{"tags":["api-keys"],"summary":"Get an API key","description":"Returns key metadata (never the secret). 404 when not visible to the caller.","operationId":"get_api_key","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Key Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyOut"}}}},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."}}},"delete":{"tags":["api-keys"],"summary":"Revoke an API key","description":"Revokes the key and tears down its machine user's membership immediately — the key can no longer authenticate. Idempotent.","operationId":"revoke_api_key","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Key Id"}},{"name":"x-outdo-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Outdo-Service-Key"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Not authenticated."},"404":{"description":"Not found / not visible."},"422":{"description":"Validation error."},"429":{"description":"Rate limited."},"503":{"description":"Upstream data store unavailable."},"403":{"description":"Not allowed to manage keys for this organization."}}}}},"components":{"schemas":{"AggregateOut":{"properties":{"op":{"type":"string","title":"Op"},"column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Column"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"rows_considered":{"type":"integer","title":"Rows Considered"}},"type":"object","required":["op","rows_considered"],"title":"AggregateOut","description":"Result of rows:aggregate. `value` is null for avg over zero numeric values;\n`rows_considered` is the number of values that entered the computation (for count,\nthe count itself)."},"ApiKeyCreateIn":{"properties":{"organization_id":{"type":"string","title":"Organization Id"},"workspace_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workspace Id"},"name":{"type":"string","maxLength":120,"minLength":1,"title":"Name"},"role":{"type":"string","enum":["admin","dev","user","view"],"title":"Role","default":"user"},"scopes":{"items":{"type":"string","enum":["read","write"]},"type":"array","minItems":1,"title":"Scopes"},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At"}},"type":"object","required":["organization_id","name"],"title":"ApiKeyCreateIn"},"ApiKeyCreatedOut":{"properties":{"id":{"type":"string","title":"Id"},"organization_id":{"type":"string","title":"Organization Id"},"workspace_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workspace Id"},"name":{"type":"string","title":"Name"},"key_prefix":{"type":"string","title":"Key Prefix"},"role":{"type":"string","title":"Role"},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At"},"revoked_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revoked At"},"last_used_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Used At"},"secret":{"type":"string","title":"Secret"}},"type":"object","required":["id","organization_id","name","key_prefix","role","scopes","secret"],"title":"ApiKeyCreatedOut","description":"The creation response — carries the one-time plaintext `secret`. Store it now; it\ncannot be retrieved again."},"ApiKeyOut":{"properties":{"id":{"type":"string","title":"Id"},"organization_id":{"type":"string","title":"Organization Id"},"workspace_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workspace Id"},"name":{"type":"string","title":"Name"},"key_prefix":{"type":"string","title":"Key Prefix"},"role":{"type":"string","title":"Role"},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At"},"revoked_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revoked At"},"last_used_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Used At"}},"type":"object","required":["id","organization_id","name","key_prefix","role","scopes"],"title":"ApiKeyOut","description":"A key's metadata. The secret is NEVER part of this — see ApiKeyCreatedOut."},"Body_upload_file":{"properties":{"feature_id":{"type":"string","format":"uuid","title":"Feature Id"},"column_id":{"type":"string","format":"uuid","title":"Column Id"},"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["feature_id","column_id","file"],"title":"Body_upload_file"},"ColumnCreateIn":{"properties":{"name":{"type":"string","maxLength":64,"minLength":1,"title":"Name"},"label":{"type":"string","maxLength":120,"minLength":1,"title":"Label"},"type":{"type":"string","title":"Type","default":"text"},"default_component":{"type":"string","title":"Default Component","default":"textfield"},"config":{"additionalProperties":true,"type":"object","title":"Config"},"required":{"type":"boolean","title":"Required","default":false},"read_only":{"type":"boolean","title":"Read Only","default":false},"hidden":{"type":"boolean","title":"Hidden","default":false},"order":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Order"},"initial_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Initial Value"}},"type":"object","required":["name","label"],"title":"ColumnCreateIn","description":"A column definition; `type` and `default_component` are validated against the\nplatform registries (see GET /v1/schema/definitions)."},"ColumnPatchIn":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":64,"minLength":1},{"type":"null"}],"title":"Name"},"label":{"anyOf":[{"type":"string","maxLength":120,"minLength":1},{"type":"null"}],"title":"Label"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type"},"default_component":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Component"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config"},"required":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Required"},"read_only":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Read Only"},"hidden":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hidden"},"order":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Order"},"initial_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Initial Value"}},"type":"object","title":"ColumnPatchIn"},"FeatureColumnOut":{"properties":{"id":{"type":"string","title":"Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"label":{"type":"string","title":"Label"},"type":{"type":"string","title":"Type"},"config":{"additionalProperties":true,"type":"object","title":"Config"},"feature_id":{"type":"string","title":"Feature Id"},"default_component":{"type":"string","title":"Default Component"},"initial_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Initial Value"},"read_only":{"type":"boolean","title":"Read Only"},"required":{"type":"boolean","title":"Required"},"hidden":{"type":"boolean","title":"Hidden"},"order":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Order"}},"type":"object","required":["id","label","type","config","feature_id","default_component","read_only","required","hidden"],"title":"FeatureColumnOut","description":"A column definition: how a row-data key is typed, edited, and displayed."},"FeatureCreateIn":{"properties":{"workspace_id":{"type":"string","title":"Workspace Id"},"name":{"type":"string","maxLength":120,"minLength":1,"title":"Name"},"label":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Label"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config"}},"type":"object","required":["workspace_id","name"],"title":"FeatureCreateIn","description":"`organization_id` is NEVER accepted — derived from the parent workspace."},"FeatureOut":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"workspace_id":{"type":"string","title":"Workspace Id"},"organization_id":{"type":"string","title":"Organization Id"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config"}},"type":"object","required":["id","name","workspace_id","organization_id"],"title":"FeatureOut","description":"A feature — a data table whose rows are described by its column definitions."},"FeaturePatchIn":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":120,"minLength":1},{"type":"null"}],"title":"Name"},"label":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Label"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config"}},"type":"object","title":"FeaturePatchIn"},"FileOut":{"properties":{"path":{"type":"string","title":"Path"},"fileName":{"type":"string","title":"Filename"},"mimeType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mimetype"},"fileSize":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Filesize"},"syncStatus":{"type":"string","title":"Syncstatus","default":"synced"}},"type":"object","required":["path","fileName"],"title":"FileOut"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthOut":{"properties":{"status":{"type":"string","title":"Status","default":"ok"}},"type":"object","title":"HealthOut","description":"Liveness response."},"ModuleCreateIn":{"properties":{"workspace_id":{"type":"string","title":"Workspace Id"},"name":{"type":"string","maxLength":120,"minLength":1,"title":"Name"},"label":{"type":"string","maxLength":120,"minLength":1,"title":"Label"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon"}},"type":"object","required":["workspace_id","name","label"],"title":"ModuleCreateIn","description":"`organization_id` is NEVER accepted — derived from the parent workspace."},"ModuleOut":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"label":{"type":"string","title":"Label"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon"},"workspace_id":{"type":"string","title":"Workspace Id"},"organization_id":{"type":"string","title":"Organization Id"},"default_rail_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Rail Id"},"rail_order_config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Rail Order Config"}},"type":"object","required":["id","name","label","workspace_id","organization_id"],"title":"ModuleOut"},"ModulePatchIn":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":120,"minLength":1},{"type":"null"}],"title":"Name"},"label":{"anyOf":[{"type":"string","maxLength":120,"minLength":1},{"type":"null"}],"title":"Label"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon"},"default_rail_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Rail Id"},"rail_order_config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Rail Order Config"}},"type":"object","title":"ModulePatchIn"},"OrganizationOut":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"}},"type":"object","required":["id","name"],"title":"OrganizationOut","description":"An organization — the tenancy root that owns workspaces and memberships."},"Page_ApiKeyOut_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ApiKeyOut"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["items"],"title":"Page[ApiKeyOut]"},"Page_FeatureOut_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/FeatureOut"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["items"],"title":"Page[FeatureOut]"},"Page_ModuleOut_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ModuleOut"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["items"],"title":"Page[ModuleOut]"},"Page_OrganizationOut_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/OrganizationOut"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["items"],"title":"Page[OrganizationOut]"},"Page_RailOut_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/RailOut"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["items"],"title":"Page[RailOut]"},"Page_RowOut_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/RowOut"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["items"],"title":"Page[RowOut]"},"Page_ViewOut_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ViewOut"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["items"],"title":"Page[ViewOut]"},"Page_WorkflowOut_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/WorkflowOut"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["items"],"title":"Page[WorkflowOut]"},"Page_WorkflowRunOut_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/WorkflowRunOut"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["items"],"title":"Page[WorkflowRunOut]"},"Page_WorkspaceOut_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/WorkspaceOut"},"type":"array","title":"Items"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["items"],"title":"Page[WorkspaceOut]"},"RailCreateIn":{"properties":{"module_id":{"type":"string","title":"Module Id"},"label":{"type":"string","maxLength":120,"minLength":1,"title":"Label"},"path":{"type":"string","title":"Path","default":""},"config":{"anyOf":[{"items":{},"type":"array"},{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config"}},"type":"object","required":["module_id","label"],"title":"RailCreateIn","description":"`organization_id` is NEVER accepted — derived from the parent module."},"RailOut":{"properties":{"id":{"type":"string","title":"Id"},"label":{"type":"string","title":"Label"},"path":{"type":"string","title":"Path"},"module_id":{"type":"string","title":"Module Id"},"organization_id":{"type":"string","title":"Organization Id"},"config":{"anyOf":[{"items":{},"type":"array"},{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config"}},"type":"object","required":["id","label","path","module_id","organization_id"],"title":"RailOut"},"RailPatchIn":{"properties":{"label":{"anyOf":[{"type":"string","maxLength":120,"minLength":1},{"type":"null"}],"title":"Label"},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path"},"config":{"anyOf":[{"items":{},"type":"array"},{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config"}},"type":"object","title":"RailPatchIn"},"RefreshRequest":{"properties":{"refresh_token":{"type":"string","title":"Refresh Token"}},"type":"object","required":["refresh_token"],"title":"RefreshRequest","description":"A refresh token for POST /v1/auth/refresh."},"RowCreateIn":{"properties":{"data":{"additionalProperties":true,"type":"object","title":"Data"}},"type":"object","title":"RowCreateIn","description":"The row payload. `organization_id` is NEVER accepted from the client — the service\nderives it from the parent feature, so a caller cannot mislabel a row's tenancy."},"RowOut":{"properties":{"id":{"type":"string","title":"Id"},"feature_id":{"type":"string","title":"Feature Id"},"organization_id":{"type":"string","title":"Organization Id"},"data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"},{"type":"null"}],"title":"Data"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By"},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"},"updated_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated By"}},"type":"object","required":["id","feature_id","organization_id"],"title":"RowOut","description":"A feature row. `data` is a JSON object keyed by column name."},"RowUpdateIn":{"properties":{"data":{"additionalProperties":true,"type":"object","title":"Data"}},"type":"object","required":["data"],"title":"RowUpdateIn"},"RowsBatchIn":{"properties":{"rows":{"items":{"$ref":"#/components/schemas/RowCreateIn"},"type":"array","maxItems":500,"minItems":1,"title":"Rows"}},"type":"object","required":["rows"],"title":"RowsBatchIn","description":"Bulk create: up to 500 rows, inserted ATOMICALLY (one PostgREST call — any rejected\nrow rolls back the whole batch)."},"RowsBatchOut":{"properties":{"items":{"items":{"$ref":"#/components/schemas/RowOut"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count"}},"type":"object","required":["items","count"],"title":"RowsBatchOut"},"SchemaCounts":{"properties":{"workspaces":{"type":"integer","title":"Workspaces"},"modules":{"type":"integer","title":"Modules"},"rails":{"type":"integer","title":"Rails"},"features":{"type":"integer","title":"Features"},"columns":{"type":"integer","title":"Columns"},"views":{"type":"integer","title":"Views"}},"type":"object","required":["workspaces","modules","rails","features","columns","views"],"title":"SchemaCounts"},"SchemaFeatureOut":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"workspace_id":{"type":"string","title":"Workspace Id"},"organization_id":{"type":"string","title":"Organization Id"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config"},"columns":{"items":{"$ref":"#/components/schemas/FeatureColumnOut"},"type":"array","title":"Columns"},"views":{"items":{"$ref":"#/components/schemas/ViewOut"},"type":"array","title":"Views"}},"type":"object","required":["id","name","workspace_id","organization_id","columns","views"],"title":"SchemaFeatureOut"},"SchemaModuleOut":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"label":{"type":"string","title":"Label"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icon"},"workspace_id":{"type":"string","title":"Workspace Id"},"default_rail_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Rail Id"},"rails":{"items":{"$ref":"#/components/schemas/RailOut"},"type":"array","title":"Rails"}},"type":"object","required":["id","name","label","workspace_id","rails"],"title":"SchemaModuleOut"},"SchemaOut":{"properties":{"workspaces":{"items":{"$ref":"#/components/schemas/SchemaWorkspaceOut"},"type":"array","title":"Workspaces"},"counts":{"$ref":"#/components/schemas/SchemaCounts"},"truncated":{"type":"boolean","title":"Truncated"}},"type":"object","required":["workspaces","counts","truncated"],"title":"SchemaOut","description":"The caller's entire visible model in one response. `truncated: true` means a size\ncap was hit — narrow the request with `workspace_id`."},"SchemaWorkspaceOut":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"organization_id":{"type":"string","title":"Organization Id"},"default_module_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Module Id"},"modules":{"items":{"$ref":"#/components/schemas/SchemaModuleOut"},"type":"array","title":"Modules"},"features":{"items":{"$ref":"#/components/schemas/SchemaFeatureOut"},"type":"array","title":"Features"}},"type":"object","required":["id","name","organization_id","modules","features"],"title":"SchemaWorkspaceOut"},"SignedUrlOut":{"properties":{"url":{"type":"string","title":"Url"},"expires_in":{"type":"integer","title":"Expires In"}},"type":"object","required":["url","expires_in"],"title":"SignedUrlOut"},"TokenRequest":{"properties":{"email":{"type":"string","title":"Email"},"password":{"type":"string","title":"Password"}},"type":"object","required":["email","password"],"title":"TokenRequest","description":"Credentials for POST /v1/auth/token (delegated to Supabase GoTrue).\n\n`email` is a plain str (no EmailStr) — GoTrue is the credential authority; the API does\nnot pre-validate the address shape, it simply forwards. A missing field still → 422 (A9)."},"TokenResponse":{"properties":{"access_token":{"type":"string","title":"Access Token"},"refresh_token":{"type":"string","title":"Refresh Token"},"expires_in":{"type":"integer","title":"Expires In"}},"type":"object","required":["access_token","refresh_token","expires_in"],"title":"TokenResponse","description":"The Supabase session triple returned on a clean login/refresh."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"ViewCreateIn":{"properties":{"feature_id":{"type":"string","title":"Feature Id"},"name":{"type":"string","maxLength":120,"minLength":1,"title":"Name"},"label":{"type":"string","maxLength":120,"minLength":1,"title":"Label"},"type":{"type":"string","title":"Type"},"config":{"anyOf":[{"items":{},"type":"array"},{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config"}},"type":"object","required":["feature_id","name","label","type"],"title":"ViewCreateIn","description":"`organization_id` is NEVER accepted — derived from the parent feature. `type` is\nvalidated against the view registry (see GET /v1/schema/definitions)."},"ViewOut":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"label":{"type":"string","title":"Label"},"type":{"type":"string","title":"Type"},"config":{"anyOf":[{"items":{},"type":"array"},{"additionalProperties":true,"type":"object"}],"title":"Config"},"feature_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Feature Id"},"organization_id":{"type":"string","title":"Organization Id"}},"type":"object","required":["id","name","label","type","config","organization_id"],"title":"ViewOut","description":"A saved view over a feature (table, kanban, form, …)."},"ViewPatchIn":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":120,"minLength":1},{"type":"null"}],"title":"Name"},"label":{"anyOf":[{"type":"string","maxLength":120,"minLength":1},{"type":"null"}],"title":"Label"},"config":{"anyOf":[{"items":{},"type":"array"},{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config"}},"type":"object","title":"ViewPatchIn"},"WorkflowOut":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"workspace_id":{"type":"string","title":"Workspace Id"},"organization_id":{"type":"string","title":"Organization Id"},"is_active":{"type":"boolean","title":"Is Active"},"trigger_config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"},{"type":"null"}],"title":"Trigger Config"}},"type":"object","required":["id","name","workspace_id","organization_id","is_active"],"title":"WorkflowOut","description":"A workflow definition. Triggerable via the API when active."},"WorkflowRunOut":{"properties":{"id":{"type":"string","title":"Id"},"workflow_id":{"type":"string","title":"Workflow Id"},"workspace_id":{"type":"string","title":"Workspace Id"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At"},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At"},"triggered_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Triggered By"},"trigger_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Trigger Type"},"input_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"},{"type":"null"}],"title":"Input Data"},"output_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"},{"type":"null"}],"title":"Output Data"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"steps_executed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Steps Executed"},"total_steps":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Steps"},"is_dry_run":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Dry Run"}},"type":"object","required":["id","workflow_id","workspace_id"],"title":"WorkflowRunOut","description":"One execution of a workflow (a `WorkflowLog` row). Poll until `status` reaches\n`success`, `failed`, or `cancelled`."},"WorkflowTriggerIn":{"properties":{"input_data":{"additionalProperties":true,"type":"object","title":"Input Data"},"dry_run":{"type":"boolean","title":"Dry Run","default":false}},"type":"object","title":"WorkflowTriggerIn","description":"Trigger payload: optional input context handed to the run."},"WorkspaceCreateIn":{"properties":{"organization_id":{"type":"string","title":"Organization Id"},"name":{"type":"string","maxLength":120,"minLength":1,"title":"Name"},"label":{"type":"string","maxLength":120,"minLength":1,"title":"Label"},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone"},"visibility_policy":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Visibility Policy"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config"}},"type":"object","required":["organization_id","name","label"],"title":"WorkspaceCreateIn","description":"Payload for creating a workspace. The caller must belong to the organization."},"WorkspaceOut":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"organization_id":{"type":"string","title":"Organization Id"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone"},"visibility_policy":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Visibility Policy"},"default_module_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Module Id"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config"}},"type":"object","required":["id","name","organization_id"],"title":"WorkspaceOut","description":"A workspace — the top-level container for modules, features, and views."},"WorkspacePatchIn":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":120,"minLength":1},{"type":"null"}],"title":"Name"},"label":{"anyOf":[{"type":"string","maxLength":120,"minLength":1},{"type":"null"}],"title":"Label"},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone"},"visibility_policy":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Visibility Policy"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config"},"module_order_config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Module Order Config"},"default_module_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Module Id"}},"type":"object","title":"WorkspacePatchIn","description":"Partial update — only the provided fields change (exclude_unset semantics)."}},"securitySchemes":{"HTTPBearer":{"type":"http","description":"A Supabase user JWT (from POST /v1/auth/token) OR a scoped API key (outdo_sk_…).","scheme":"bearer","bearerFormat":"JWT"}}},"tags":[{"name":"health","description":"Service liveness."},{"name":"auth","description":"Sign-in and token refresh, delegated to the platform's identity provider."},{"name":"organizations","description":"Organizations the caller belongs to."},{"name":"workspaces","description":"Workspaces — the top-level containers of the model."},{"name":"modules","description":"Navigation modules inside a workspace."},{"name":"rails","description":"Navigation rails inside a module; a rail's config lists the views it shows."},{"name":"features","description":"Features (data tables) and their column definitions."},{"name":"rows","description":"Row data: CRUD, bulk insert, filtering, sorting, and aggregates."},{"name":"views","description":"Saved views over a feature (table, kanban, form, …)."},{"name":"schema","description":"The caller's whole visible model in one call, plus config definitions."},{"name":"files","description":"File uploads and signed downloads for file columns."},{"name":"workflows","description":"Workflow definitions, triggering, and run status."},{"name":"api-keys","description":"Scoped API keys (machine identities) — create, list, and revoke."}]}