{"openapi":"3.1.0","info":{"title":"GET /api/v1/tokens","version":"1.0.0","description":"List tokens"},"servers":[{"url":"https://api.ondayzero.com","description":"Production"}],"paths":{"/api/v1/tokens":{"get":{"tags":["api-tokens"],"summary":"List tokens","description":"List all API tokens for current user","operationId":"list_tokens","parameters":[{"name":"include_revoked","in":"query","required":false,"schema":{"type":"boolean","description":"Include revoked tokens","default":false,"title":"Include Revoked"},"description":"Include revoked tokens"},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Cursor for pagination","title":"Cursor"},"description":"Cursor for pagination"},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":1000,"minimum":1},{"type":"null"}],"description":"Pagination limit","title":"Limit"},"description":"Pagination limit"},{"name":"direction","in":"query","required":false,"schema":{"type":"string","description":"Pagination direction: 'next' or 'prev'","default":"next","title":"Direction"},"description":"Pagination direction: 'next' or 'prev'"},{"name":"include_total_count","in":"query","required":false,"schema":{"type":"boolean","description":"Whether to include total count (expensive - avoid if possible)","default":false,"title":"Include Total Count"},"description":"Whether to include total count (expensive - avoid if possible)"},{"name":"sort_by","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Column name to sort by (e.g. 'created_at', 'amount', 'name'). When changing sort, reset cursor to None.","title":"Sort By"},"description":"Column name to sort by (e.g. 'created_at', 'amount', 'name'). When changing sort, reset cursor to None."},{"name":"descending","in":"query","required":false,"schema":{"type":"boolean","description":"Sort direction: true for descending (newest/largest first), false for ascending","default":true,"title":"Descending"},"description":"Sort direction: true for descending (newest/largest first), false for ascending"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_APITokenListResponse_"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"list_tokens_api_v1_tokens_get"}}},"components":{"schemas":{"APITokenListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/APITokenResponse"},"type":"array","title":"Items","description":"List of items"},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Total number of items (null when not calculated for performance)"},"limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Limit","description":"Pagination limit"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Cursor for next page"},"prev_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prev Cursor","description":"Cursor for previous page"},"has_next":{"type":"boolean","title":"Has Next","description":"Whether there are more items"},"has_prev":{"type":"boolean","title":"Has Prev","description":"Whether there are previous items"}},"type":"object","required":["items","has_next","has_prev"],"title":"APITokenListResponse","description":"Paginated list of API tokens with cursor-based navigation."},"APITokenResponse":{"properties":{"id":{"type":"string","title":"Id","description":"Token record ID"},"jti":{"type":"string","title":"Jti","description":"Unique token identifier (JWT ID)"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Human-readable token name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional token description"},"token_prefix":{"type":"string","title":"Token Prefix","description":"First characters of the token for display (e.g. dz_abc...)"},"token_type":{"type":"string","title":"Token Type","description":"Token type (always 'api')","default":"api"},"scopes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scopes","description":"Space-separated token scopes"},"allowed_ips":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Allowed Ips","description":"IPs/CIDRs this token may be used from; null means any IP"},"rate_limit_per_minute":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rate Limit Per Minute","description":"Requests per minute this token may make; null = platform default"},"business_ids":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Business Ids","description":"Businesses this token is limited to; null means every business the owner can reach"},"status":{"type":"string","enum":["active","rotating","revoked","expired"],"title":"Status","description":"Lifecycle: `active`; `rotating` (replaced, still valid until `grace_until`); `revoked`; `expired`.","default":"active"},"rotated_from_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rotated From Id","description":"The token this one replaced, when minted by rotation"},"rotated_to_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rotated To Id","description":"The replacement token, once this one has been rotated"},"grace_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Grace Until","description":"After rotation: the instant this token stops working. Null when not rotated."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the token was created"},"last_used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Used At","description":"Last time the token was used for authentication"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"When the token expires (null = never)"},"revoked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Revoked At","description":"When the token was revoked (null = active)"},"revocation_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revocation Reason","description":"Reason the token was revoked"}},"type":"object","required":["id","jti","token_prefix","created_at"],"title":"APITokenResponse","description":"Response schema for API token metadata (without the actual JWT)."},"SuccessEnvelope_APITokenListResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/APITokenListResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[APITokenListResponse]"},"ErrorResponse":{"title":"ErrorResponse","type":"object","description":"Envelope returned by every non-2xx response. Branch on `code` (stable) rather than `message` (human-readable, may change).","required":["error","message","code"],"properties":{"error":{"type":"string","description":"Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`."},"message":{"type":"string","description":"Human-readable explanation, safe to show to end users."},"code":{"type":"string","description":"Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`)."},"request_id":{"type":"string","description":"Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied."},"errors":{"type":"object","additionalProperties":{"type":"string"},"description":"Field-level validation messages keyed by field name. Present on 400/422 validation failures only."}}}},"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Token","description":"API token authentication. Format: `Bearer dz_...`"}}},"security":[{"BearerAuth":[]}]}