openapi: 3.2.0 info: title: Taskfolk Developer API version: 1.0.0 description: Public REST API for Taskfolk (taskfolk.ai). All endpoints require a workspace-scoped bearer API key. Paths are nested under `/v1/workspaces/{slug}/…`. servers: - url: https://taskfolk.ai/api security: - bearerAuth: [] tags: - name: Developer paths: /v1/workspaces/{slug}/api-keys: get: summary: List API keys. tags: - Developer security: - bearerAuth: - api_keys:read parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string required: false name: cursor in: query - schema: type: - integer - 'null' required: false name: limit in: query responses: '200': description: Success. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/ApiKey' pagination: $ref: '#/components/schemas/Pagination' required: - data - pagination '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' post: summary: Create an API key. Plaintext is returned exactly once. tags: - Developer security: - bearerAuth: - api_keys:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/ApiKeyCreateInput' responses: '201': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/CreatedApiKey' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/workspaces/{slug}/api-keys/{id}: get: summary: API key detail. tags: - Developer security: - bearerAuth: - api_keys:read parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… required: true name: id in: path responses: '200': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/ApiKey' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' patch: summary: Update API key rate limit. tags: - Developer security: - bearerAuth: - api_keys:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… required: true name: id in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/ApiKeyPatchInput' responses: '200': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/ApiKey' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' delete: summary: Revoke an API key. tags: - Developer security: - bearerAuth: - api_keys:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… required: true name: id in: path responses: '200': description: Success. content: application/json: schema: type: object properties: data: type: object properties: id: type: string revoked: type: boolean enum: - true required: - id - revoked required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/workspaces/{slug}/api-keys/{id}/usage: get: summary: Per-day request/error/latency rollup for a single API key (max 90-day window). tags: - Developer security: - bearerAuth: - api_keys:read parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… required: true name: id in: path - schema: type: string example: '2026-05-17' description: Start date (YYYY-MM-DD). Defaults to 30 days ago. Window capped at 90 days. required: false description: Start date (YYYY-MM-DD). Defaults to 30 days ago. Window capped at 90 days. name: from in: query - schema: type: string example: '2026-06-15' description: End date (YYYY-MM-DD). Defaults to today. required: false description: End date (YYYY-MM-DD). Defaults to today. name: to in: query responses: '200': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/ApiKeyUsage' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/workspaces/{slug}/webhooks: get: summary: List webhooks. tags: - Developer security: - bearerAuth: - webhooks:read parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string required: false name: cursor in: query - schema: type: - integer - 'null' required: false name: limit in: query responses: '200': description: Success. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/Webhook' pagination: $ref: '#/components/schemas/Pagination' required: - data - pagination '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' post: summary: Create a webhook. Signing secret is returned exactly once. tags: - Developer security: - bearerAuth: - webhooks:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/WebhookCreateInput' responses: '201': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/CreatedWebhook' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/workspaces/{slug}/webhooks/{id}: get: summary: Webhook detail. tags: - Developer security: - bearerAuth: - webhooks:read parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… required: true name: id in: path responses: '200': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/Webhook' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' patch: summary: Update or re-enable a webhook. tags: - Developer security: - bearerAuth: - webhooks:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… required: true name: id in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/WebhookPatchInput' responses: '200': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/Webhook' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' delete: summary: Delete a webhook. tags: - Developer security: - bearerAuth: - webhooks:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… required: true name: id in: path responses: '200': description: Success. content: application/json: schema: type: object properties: data: type: object properties: id: type: string deleted: type: boolean enum: - true required: - id - deleted required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/workspaces/{slug}/webhooks/{id}/deliveries: get: summary: List recent webhook delivery history. tags: - Developer security: - bearerAuth: - webhooks:read parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… required: true name: id in: path - schema: type: string required: false name: cursor in: query - schema: type: - integer - 'null' required: false name: limit in: query responses: '200': description: Success. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/WebhookDelivery' pagination: $ref: '#/components/schemas/Pagination' required: - data - pagination '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/workspaces/{slug}/webhooks/{id}/rotate-secret: post: summary: Rotate webhook signing secret. New secret is returned exactly once. tags: - Developer security: - bearerAuth: - webhooks:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… required: true name: id in: path responses: '200': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/CreatedWebhook' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/workspaces/{slug}/webhooks/{id}/test: post: summary: Send one signed webhook.test delivery to the endpoint. tags: - Developer security: - bearerAuth: - webhooks:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: 019e6f12-… required: true name: id in: path responses: '202': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/WebhookDelivery' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/workspaces/{slug}/oauth-apps: get: summary: List OAuth apps. tags: - Developer security: - bearerAuth: - oauth_apps:read parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string required: false name: cursor in: query - schema: type: - integer - 'null' required: false name: limit in: query responses: '200': description: Success. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/OauthApp' pagination: $ref: '#/components/schemas/Pagination' required: - data - pagination '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' post: summary: Register an OAuth app. client_secret is returned exactly once (null for public/PKCE clients). tags: - Developer security: - bearerAuth: - oauth_apps:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/OauthAppCreateInput' responses: '201': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/CreatedOauthApp' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/workspaces/{slug}/oauth-apps/{clientId}: get: summary: OAuth app detail. tags: - Developer security: - bearerAuth: - oauth_apps:read parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: utoc_... description: OAuth app client ID. required: true description: OAuth app client ID. name: clientId in: path responses: '200': description: Success. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/OauthApp' required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' delete: summary: Revoke an OAuth app. tags: - Developer security: - bearerAuth: - oauth_apps:write parameters: - schema: type: string example: taskfolk description: Workspace slug. required: true description: Workspace slug. name: slug in: path - schema: type: string example: utoc_... description: OAuth app client ID. required: true description: OAuth app client ID. name: clientId in: path responses: '200': description: Success. content: application/json: schema: type: object properties: data: type: object properties: client_id: type: string revoked: type: boolean enum: - true required: - client_id - revoked required: - data '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: Missing / invalid API key. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Key lacks the required scope. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Resource not found (or cross-workspace — never leaked). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' components: schemas: Pagination: type: object properties: next_cursor: type: - string - 'null' example: null required: - next_cursor CreatedOauthApp: allOf: - $ref: '#/components/schemas/OauthApp' - type: object properties: client_secret: type: - string - 'null' example: utos_... description: Returned exactly once on create. Null for public (PKCE) clients. required: - client_secret OauthApp: type: object properties: client_id: type: string example: utoc_... name: type: string example: My CI Integration redirect_uris: type: array items: type: string format: uri example: - https://example.com/callback scopes: type: array items: type: string example: - issues:read - comments:write is_public: type: boolean description: True = PKCE public client (no secret). created_at: type: string format: date-time example: '2026-05-28T14:30:00Z' required: - client_id - name - redirect_uris - scopes - is_public - created_at ApiKeyPatchInput: type: object properties: name: type: string minLength: 1 maxLength: 80 rate_limit_per_minute: type: - integer - 'null' minimum: 1 maximum: 100000 expires_at: type: - string - 'null' format: date-time example: '2026-05-28T14:30:00Z' OauthAppCreateInput: type: object properties: name: type: string minLength: 1 maxLength: 120 example: My CI Integration redirect_uris: type: array items: type: string format: uri minItems: 1 maxItems: 20 example: - https://example.com/callback scopes: type: array items: type: string minItems: 1 example: - issues:read is_public: type: boolean description: Set true for PKCE public clients (no secret). example: false required: - name - redirect_uris - scopes ApiKeyUsageDayPoint: type: object properties: date: type: string example: '2026-06-15' requests: type: integer errors: type: integer p50_ms: type: integer p95_ms: type: integer p99_ms: type: integer required: - date - requests - errors - p50_ms - p95_ms - p99_ms WebhookPatchInput: type: object properties: url: type: string format: uri event_types: type: array items: type: string minItems: 1 enabled: type: boolean CreatedApiKey: allOf: - $ref: '#/components/schemas/ApiKey' - type: object properties: plaintext: type: string example: tfk_live_abcd1234... description: Returned exactly once on create. Store it securely. required: - plaintext WebhookCreateInput: type: object properties: url: type: string format: uri example: https://example.com/taskfolk/webhook event_types: type: array items: type: string minItems: 1 example: - '*' required: - url - event_types Webhook: type: object properties: id: type: string url: type: string format: uri example: https://example.com/taskfolk/webhook event_types: type: array items: type: string example: - issue.created - comment.created secret_prefix: type: string disabled_at: type: - string - 'null' format: date-time example: '2026-05-28T14:30:00Z' last_delivery_at: type: - string - 'null' format: date-time example: '2026-05-28T14:30:00Z' last_delivery_status: type: - integer - 'null' created_by: type: string created_at: type: string format: date-time example: '2026-05-28T14:30:00Z' required: - id - url - event_types - secret_prefix - disabled_at - last_delivery_at - last_delivery_status - created_by - created_at ErrorEnvelope: type: object properties: error: type: object properties: code: type: string enum: - unauthorized - forbidden - not_found - validation - rate_limited - conflict - idempotency_violation - internal_error example: validation message: type: string example: Label "foo" does not exist on this project. details: type: object additionalProperties: {} required: - code - message required: - error CreatedWebhook: allOf: - $ref: '#/components/schemas/Webhook' - type: object properties: secret: type: string example: utwhsec_... description: Returned exactly once on create or rotation. required: - secret ApiKeyCreateInput: type: object properties: name: type: string minLength: 1 maxLength: 80 scopes: type: array items: type: string minItems: 1 project_ids: type: - array - 'null' items: type: string expires_at: type: - string - 'null' format: date-time example: '2026-05-28T14:30:00Z' rate_limit_per_minute: type: - integer - 'null' minimum: 1 maximum: 100000 required: - name - scopes ApiKey: type: object properties: id: type: string name: type: string example: CI deploy bot prefix: type: string example: tfk_live_abcd scopes: type: array items: type: string example: - issues:read - issues:write project_ids: type: - array - 'null' items: type: string rate_limit_per_minute: type: - integer - 'null' created_by: type: string created_at: type: string format: date-time example: '2026-05-28T14:30:00Z' expires_at: type: - string - 'null' format: date-time example: '2026-05-28T14:30:00Z' last_used_at: type: - string - 'null' format: date-time example: '2026-05-28T14:30:00Z' last_used_ip: type: - string - 'null' revoked_at: type: - string - 'null' format: date-time example: '2026-05-28T14:30:00Z' revoke_reason: type: - string - 'null' required: - id - name - prefix - scopes - project_ids - rate_limit_per_minute - created_by - created_at - expires_at - last_used_at - last_used_ip - revoked_at - revoke_reason WebhookDelivery: type: object properties: delivery_id: type: string event_type: type: string example: webhook.test attempt: type: integer example: 1 status: type: integer example: 200 latency_ms: type: integer example: 123 error: type: string final: type: integer example: 1 ts: type: string format: date-time example: '2026-05-28T14:30:00Z' required: - delivery_id - event_type - attempt - status - latency_ms - error - final - ts ApiKeyUsage: type: object properties: key_id: type: string from: type: string example: '2026-05-17' to: type: string example: '2026-06-15' granularity: type: string enum: - day series: type: array items: $ref: '#/components/schemas/ApiKeyUsageDayPoint' totals: type: object properties: requests: type: integer errors: type: integer p95_ms: type: integer required: - requests - errors - p95_ms required: - key_id - from - to - granularity - series - totals securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: API key description: 'Workspace API key. Send as `Authorization: Bearer tfk_live_…`. Each key is bound to exactly one workspace and carries a set of scopes.'