SageOx API Keys API
The API Keys API from SageOx — 2 operation(s) for api keys.
The API Keys API from SageOx — 2 operation(s) for api keys.
openapi: 3.1.0
info:
title: SageOx Admin API Keys API
version: 1.0.0
description: "# API Reference\n\n## Overview\n\nSageOx is a platform that captures team knowledge from discussions, decisions, and work context into a Ledger (per-repo historical record) and Team Context (team-wide shared knowledge). The SageOx API provides programmatic access to manage repositories, recordings, notifications, and team data with high performance and reliability.\n\n## Base URLs\n\n| Environment | URL |\n|---|---|\n| Local Development | `http://localhost:3000` |\n| Test | `https://test.sageox.ai` |\n| Production | `https://sageox.ai` |\n\n## Authentication\n\nAll requests to the SageOx API require authentication via JWT tokens issued by the Better Auth service.\n\nInclude your token in the `Authorization` header:\n```\nAuthorization: Bearer <token>\n```\n\n**Initial Auth Flow (CLI)**\n- CLI initiates device flow to obtain initial credentials\n- Exchange device code for JWT token\n- Store token securely for subsequent API requests\n- Refresh token when expired\n\n**Authenticated Endpoints**\n- Pass JWT in `Authorization: Bearer <token>` header\n- Tokens contain user identity and team membership\n- Invalid or expired tokens return 401 Unauthorized\n\n## Response Format\n\n### Success\nStandard response format with optional pagination metadata:\n```json\n{\n \"success\": true,\n \"data\": { ... }\n}\n```\n\n### Error\nAll errors follow a consistent format:\n```json\n{\n \"success\": false,\n \"error\": \"Human-readable error description\"\n}\n```\n\n**Status Codes**\n- `400` — Bad Request: Invalid parameters or malformed request\n- `401` — Unauthorized: Missing or invalid authentication token\n- `403` — Forbidden: Insufficient permissions for this resource\n- `404` — Not Found: Resource does not exist\n- `409` — Conflict: Request conflicts with current state (e.g., duplicate)\n- `429` — Rate Limited: Too many requests; retry with backoff\n- `500` — Internal Error: Server error; contact support if persistent\n\n## Pagination\n\nList endpoints support cursor-based pagination via query parameters:\n\n**Query Parameters**\n- `limit` — Number of results per page (default: 20, max: 100)\n- `offset` — Number of results to skip (default: 0)\n\n**Response Metadata**\nList responses include pagination info:\n```json\n{\n \"success\": true,\n \"data\": [ ... ],\n \"meta\": {\n \"total\": 150,\n \"limit\": 20,\n \"offset\": 0,\n \"hasMore\": true\n }\n}\n```\n\n## ID Formats\n\nResources use standardized ID formats for easy identification:\n\n| Resource | Format | Length | Example |\n|---|---|---|---|\n| Team | `team_<cuid2>` | 10 chars | `team_abc1234567` |\n| User | `usr_<cuid2>` | 10 chars | `usr_xyz9876543` |\n| Repository | `repo_<uuidv7>` | 36 chars | `repo_01934f5a-8b9c-7def-abcd-0123456789ab` |\n| Recording | `rec_<uuidv7>` | 36 chars | `rec_01934f5a-8b9c-7def-abcd-0123456789ab` |\n| Image | `img_<uuidv7>` | 36 chars | `img_01934f5a-8b9c-7def-abcd-0123456789ab` |\n| Notification | `notif_<cuid2>` | 14 chars | `notif_ab1cd2ef3g` |\n\nUse these IDs for all API operations. IDs are unique across environments.\n\n## Rate Limiting\n\nThe API applies rate limiting to protect against abuse and ensure fair access:\n\n**Authenticated Endpoints**\n- Limited per user: depends on subscription tier\n- Quota resets hourly\n\n**Unauthenticated Endpoints**\n- Limited per IP address\n- More restrictive than authenticated limits\n\nWhen rate limited, the API returns `429 Too Many Requests`. Retry requests with exponential backoff:\n```\nwait = min(2^attempt * 100ms, 10s)\n```\n\n## Timestamps\n\nAll timestamps in API responses use RFC 3339 / ISO 8601 format in UTC:\n```\n2025-12-03T10:30:00Z\n```\n\nUse this format when providing timestamps in requests as well. The API rejects timestamps in other formats.\n\n## SDKs & Tools\n\n- **OpenAPI Spec** — Full schema available at `/api/openapi.json`\n- **Postman Collection** — Import from `/api/postman.json` for interactive exploration\n- **CLI** — Use `ox` CLI for command-line access\n"
contact:
name: SageOx Team
license:
name: MIT
servers:
- url: http://localhost:3000
description: Devcontainer
- url: https://test.sageox.ai
description: Test
- url: https://sageox.ai
description: Production
security:
- bearerAuth: []
tags:
- name: API Keys
paths:
/api/v1/api-keys:
post:
operationId: createAPIKey
summary: Create API key
description: 'Creates a new API key for the authenticated user. The full key is returned
only once and must be stored securely. The key can be used for API
authentication via Bearer token. Optionally specify an expiration period.
'
tags:
- API Keys
security:
- BearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- name
properties:
name:
type: string
description: Human-readable name for the API key (1-255 characters)
example: Production API Key
expires_in_days:
type: integer
nullable: true
description: Optional expiration period in days from now
minimum: 1
example: 365
examples:
with_expiration:
summary: Create key with 365-day expiration
value:
name: Production API Key
expires_in_days: 365
no_expiration:
summary: Create key with no expiration
value:
name: Permanent API Key
responses:
'201':
description: API key created successfully
content:
application/json:
schema:
type: object
required:
- id
- name
- key_prefix
- created_at
- key
properties:
id:
type: string
format: uuid
description: Unique API key identifier
example: 550e8400-e29b-41d4-a716-446655440000
name:
type: string
description: Key name
example: Production API Key
key_prefix:
type: string
description: First 8 characters of the key (safe to log)
example: mk_aB1cD2e
key:
type: string
description: Full API key (only returned on creation)
example: mk_aB1cD2eF3gH4iJ5kL6mN7oP8qR9sTu
created_at:
type: string
format: date-time
description: Key creation timestamp
example: '2025-01-20T15:30:00Z'
expires_at:
type: string
format: date-time
nullable: true
description: Key expiration timestamp (null if no expiration)
example: '2026-01-20T15:30:00Z'
last_used_at:
type: string
format: date-time
nullable: true
description: Last usage timestamp (null if never used)
example: null
'400':
description: Invalid request parameters
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
missing_name:
value:
success: false
error: name is required
invalid_expiration:
value:
success: false
error: expires_in_days must be positive
'401':
description: Unauthorized - missing or invalid authentication
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
get:
operationId: listAPIKeys
summary: List API keys
description: 'Returns all active (non-revoked) API keys for the authenticated user.
Full key values are never returned - only the prefix (first 8 chars) for
identification, creation date, and usage information.
'
tags:
- API Keys
security:
- BearerAuth: []
responses:
'200':
description: API keys retrieved successfully
content:
application/json:
schema:
type: object
required:
- keys
properties:
keys:
type: array
items:
type: object
required:
- id
- name
- key_prefix
- created_at
properties:
id:
type: string
format: uuid
description: Unique API key identifier
example: 550e8400-e29b-41d4-a716-446655440000
name:
type: string
description: Key name
example: Production API Key
key_prefix:
type: string
description: First 8 characters of the key
example: mk_aB1cD2e
created_at:
type: string
format: date-time
description: Key creation timestamp
example: '2025-01-20T15:30:00Z'
expires_at:
type: string
format: date-time
nullable: true
description: Key expiration timestamp (null if no expiration)
example: '2026-01-20T15:30:00Z'
last_used_at:
type: string
format: date-time
nullable: true
description: Last usage timestamp
example: '2025-01-20T16:45:00Z'
'401':
description: Unauthorized - missing or invalid authentication
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/v1/api-keys/{id}:
delete:
operationId: revokeAPIKey
summary: Revoke API key
description: 'Revokes (soft-deletes) an API key. The key cannot be used for authentication
after revocation. Revocation is permanent and cannot be undone.
'
tags:
- API Keys
security:
- BearerAuth: []
parameters:
- name: id
in: path
required: true
description: API key UUID to revoke
schema:
type: string
format: uuid
example: 550e8400-e29b-41d4-a716-446655440000
responses:
'204':
description: API key revoked successfully
'400':
description: Invalid key ID format
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
invalid_id:
value:
success: false
error: invalid key id format
'401':
description: Unauthorized - missing or invalid authentication
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: Forbidden - not the owner of this key
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
not_owner:
value:
success: false
error: not the owner of this key
'404':
description: API key not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
components:
schemas:
ErrorResponse:
type: object
description: Standard error response returned by all endpoints on failure.
required:
- success
- error
properties:
success:
type: boolean
description: Always `false` for error responses.
enum:
- false
error:
type: string
description: Human-readable error message describing what went wrong. Do not parse this programmatically — use HTTP status codes for control flow.
example: Invalid request parameters
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: 'JWT token obtained from the auth service (/api/auth/token).
Token is validated using JWKS from the auth service.
Required claims: sub (user_id), email, name, tier.
'