Files
Primora/apps/backend/openapi/openapi.yaml
T
Tomas DvorakandDevin 9e9a3d5f98 feat: phase 7 automation & realtime — scheduled jobs, domain events, SSE
Scheduled jobs (migration 00009): cron expressions + @every descriptors,
in-process scheduler (15s scan, missed-run collapse), signed HTTP POST
delivery (X-Primora-Signature), AES-256-GCM sealed secrets returned once,
run history with status/duration/http-code, manual execution, retention
pruning. Viewer reads, admin/developer writes.

Domain events: publishEvent fans document/object/issue/deploy/job
mutations to realtime subscribers and matching webhooks through one
path. Webhook event filter extended to job.run, document.*, object.*.

Realtime: GET /projects/:id/realtime/stream SSE with 25s keepalives and
?token=/?api_key= auth for EventSource clients.

Automation dashboard page: Schedules tab (CRUD, run history, manual run,
secret-once banner) + Live events tab (live badge, pause/clear). Demo
mode parity. primora jobs:* CLI group, six primora_*_job* MCP tools,
AutomationService in the generated client.

Fixes folded in: gzip middleware buffered SSE flushes (broke EventSource
on both streams — */stream now bypasses compression); event payloads
double-marshaled json.RawMessage as base64; compose hardcoded localhost
trusted origins so non-default ports broke sign-in; frontend auth base
URL baked an absolute localhost instead of resolving /auth on origin.

Verified live: stack up on :8085, signed delivery HMAC-checked at sink,
@every 30s schedule firing, run history rendering, document.created
landing in the live events feed.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-18 15:15:01 +02:00

3537 lines
93 KiB
YAML

openapi: 3.1.0
info:
title: Primora API
version: 0.2.14
description: Core Primora platform API for tenancy, storage, API keys, and audit operations.
servers:
- url: /api/v1
tags:
- name: Health
- name: Platform
- name: Organizations
- name: Projects
- name: Storage
- name: Collections
- name: Databases
- name: Telemetry
- name: Integrations
- name: Webhooks
- name: Automation
paths:
/health/liveness:
get:
tags: [Health]
operationId: getLiveness
responses:
"200":
description: Liveness check
content:
application/json:
schema:
$ref: "#/components/schemas/HealthStatus"
/health/readiness:
get:
tags: [Health]
operationId: getReadiness
responses:
"200":
description: Readiness check
content:
application/json:
schema:
$ref: "#/components/schemas/ReadinessStatus"
/metrics:
get:
tags: [Health]
operationId: getMetrics
summary: Prometheus text exposition of platform HTTP metrics
responses:
"200":
description: Prometheus metrics
content:
text/plain:
schema:
type: string
/me:
get:
tags: [Platform]
operationId: getMe
security:
- bearerAuth: []
responses:
"200":
description: Current authenticated user and tenancy summary
content:
application/json:
schema:
$ref: "#/components/schemas/MeResponse"
"401":
$ref: "#/components/responses/ErrorResponse"
/bootstrap:
post:
tags: [Platform]
operationId: bootstrapPlatform
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/BootstrapRequest"
responses:
"201":
description: Platform bootstrapped
content:
application/json:
schema:
$ref: "#/components/schemas/BootstrapResponse"
"409":
$ref: "#/components/responses/ErrorResponse"
/organizations:
get:
tags: [Organizations]
operationId: listOrganizations
security:
- bearerAuth: []
responses:
"200":
description: Organizations for the current user
content:
application/json:
schema:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/OrganizationMembership"
required: [items]
post:
tags: [Organizations]
operationId: createOrganization
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateOrganizationRequest"
responses:
"201":
description: Organization created
content:
application/json:
schema:
$ref: "#/components/schemas/OrganizationMembership"
/organizations/{organizationID}:
patch:
tags: [Organizations]
operationId: updateOrganization
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/OrganizationID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateOrganizationRequest"
responses:
"204":
description: Organization updated
delete:
tags: [Organizations]
operationId: deleteOrganization
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/OrganizationID"
responses:
"204":
description: Organization deleted
/organizations/{organizationID}/members:
get:
tags: [Organizations]
operationId: listOrganizationMembers
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/OrganizationID"
responses:
"200":
description: Members of an organization
content:
application/json:
schema:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/OrganizationMember"
required: [items]
/organizations/{organizationID}/members/{userID}:
patch:
tags: [Organizations]
operationId: updateOrganizationMemberRole
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/OrganizationID"
- $ref: "#/components/parameters/UserID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateOrganizationMemberRoleRequest"
responses:
"200":
description: Organization member role updated
content:
application/json:
schema:
$ref: "#/components/schemas/OrganizationMember"
delete:
tags: [Organizations]
operationId: removeOrganizationMember
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/OrganizationID"
- $ref: "#/components/parameters/UserID"
responses:
"204":
description: Organization member removed
/organizations/{organizationID}/projects:
get:
tags: [Projects]
operationId: listProjects
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/OrganizationID"
- $ref: "#/components/parameters/AuditQuery"
responses:
"200":
description: Projects within an organization
content:
application/json:
schema:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/Project"
required: [items]
post:
tags: [Projects]
operationId: createProject
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/OrganizationID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateProjectRequest"
responses:
"201":
description: Project created
content:
application/json:
schema:
$ref: "#/components/schemas/Project"
/organizations/{organizationID}/invitations:
get:
tags: [Organizations]
operationId: listOrganizationInvitations
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/OrganizationID"
responses:
"200":
description: Invitations for an organization
content:
application/json:
schema:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/OrganizationInvitation"
required: [items]
post:
tags: [Organizations]
operationId: createInvitation
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/OrganizationID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateInvitationRequest"
responses:
"201":
description: Invitation created
content:
application/json:
schema:
$ref: "#/components/schemas/Invitation"
/organizations/{organizationID}/invitations/{invitationID}:
delete:
tags: [Organizations]
operationId: revokeInvitation
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/OrganizationID"
- $ref: "#/components/parameters/InvitationID"
responses:
"204":
description: Invitation revoked
/invitations/accept:
post:
tags: [Organizations]
operationId: acceptInvitation
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AcceptInvitationRequest"
responses:
"204":
description: Invitation accepted
/projects/{projectID}/overview:
get:
tags: [Projects]
operationId: getProjectOverview
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
responses:
"200":
description: Aggregated project overview metrics
content:
application/json:
schema:
$ref: "#/components/schemas/ProjectOverview"
/projects/{projectID}/api-keys:
get:
tags: [Projects]
operationId: listApiKeys
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
responses:
"200":
description: API keys for a project
content:
application/json:
schema:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/ApiKey"
required: [items]
post:
tags: [Projects]
operationId: createApiKey
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateApiKeyRequest"
responses:
"201":
description: API key created
content:
application/json:
schema:
$ref: "#/components/schemas/CreatedApiKey"
/projects/{projectID}:
patch:
tags: [Projects]
operationId: updateProject
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateProjectRequest"
responses:
"204":
description: Project updated
delete:
tags: [Projects]
operationId: deleteProject
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
responses:
"204":
description: Project deleted
/projects/{projectID}/members:
get:
tags: [Projects]
operationId: listProjectMembers
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
responses:
"200":
description: Members of a project
content:
application/json:
schema:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/ProjectMember"
required: [items]
/projects/{projectID}/members/{userID}:
patch:
tags: [Projects]
operationId: updateProjectMemberRole
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/UserID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateProjectMemberRoleRequest"
responses:
"200":
description: Project member role updated
content:
application/json:
schema:
$ref: "#/components/schemas/ProjectMember"
delete:
tags: [Projects]
operationId: removeProjectMember
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/UserID"
responses:
"204":
description: Project member removed
/projects/{projectID}/api-keys/{apiKeyID}:
delete:
tags: [Projects]
operationId: revokeApiKey
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/ApiKeyID"
responses:
"204":
description: API key revoked
/projects/{projectID}/buckets:
get:
tags: [Storage]
operationId: listBuckets
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/AuditQuery"
responses:
"200":
description: Buckets for a project
content:
application/json:
schema:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/Bucket"
required: [items]
post:
tags: [Storage]
operationId: createBucket
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateBucketRequest"
responses:
"201":
description: Bucket created
content:
application/json:
schema:
$ref: "#/components/schemas/Bucket"
/projects/{projectID}/audit-logs:
get:
tags: [Projects]
operationId: listAuditLogs
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/AuditQuery"
- $ref: "#/components/parameters/AuditAction"
- $ref: "#/components/parameters/PaginationLimit"
- $ref: "#/components/parameters/PaginationOffset"
responses:
"200":
description: Audit logs for a project
content:
application/json:
schema:
$ref: "#/components/schemas/AuditLogListResponse"
/buckets/{bucketID}/objects:
get:
tags: [Storage]
operationId: listBucketObjects
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/BucketID"
- $ref: "#/components/parameters/AuditQuery"
- $ref: "#/components/parameters/PaginationLimit"
- $ref: "#/components/parameters/PaginationOffset"
responses:
"200":
description: Bucket objects
content:
application/json:
schema:
$ref: "#/components/schemas/BucketObjectListResponse"
post:
tags: [Storage]
operationId: uploadBucketObject
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/BucketID"
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
properties:
objectKey:
type: string
file:
type: string
format: binary
required: [file]
responses:
"201":
description: Bucket object created
content:
application/json:
schema:
$ref: "#/components/schemas/BucketObject"
/buckets/{bucketID}/object-copies:
post:
tags: [Storage]
operationId: copyBucketObject
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/BucketID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CopyBucketObjectRequest"
responses:
"201":
description: Bucket object copied
content:
application/json:
schema:
$ref: "#/components/schemas/BucketObject"
/buckets/{bucketID}:
patch:
tags: [Storage]
operationId: updateBucket
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/BucketID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateBucketRequest"
responses:
"204":
description: Bucket updated
delete:
tags: [Storage]
operationId: deleteBucket
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/BucketID"
responses:
"204":
description: Bucket deleted
/buckets/{bucketID}/objects/{objectKey}:
get:
tags: [Storage]
operationId: downloadBucketObject
security:
- bearerAuth: []
- apiKeyAuth: []
- {}
parameters:
- $ref: "#/components/parameters/BucketID"
- $ref: "#/components/parameters/ObjectKey"
responses:
"200":
description: Bucket object bytes
content:
application/octet-stream:
schema:
type: string
format: binary
patch:
tags: [Storage]
operationId: updateBucketObject
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/BucketID"
- $ref: "#/components/parameters/ObjectKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateBucketObjectRequest"
responses:
"204":
description: Bucket object updated
delete:
tags: [Storage]
operationId: deleteBucketObject
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/BucketID"
- $ref: "#/components/parameters/ObjectKey"
responses:
"204":
description: Bucket object deleted
/projects/{projectID}/collections:
get:
tags: [Collections]
operationId: listCollections
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
responses:
"200":
description: List of collections in the project
content:
application/json:
schema:
$ref: "#/components/schemas/CollectionListResponse"
post:
tags: [Collections]
operationId: createCollection
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateCollectionRequest"
responses:
"201":
description: Collection created
content:
application/json:
schema:
$ref: "#/components/schemas/Collection"
/projects/{projectID}/collections/{collectionID}:
get:
tags: [Collections]
operationId: getCollection
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/CollectionID"
responses:
"200":
description: Collection details
content:
application/json:
schema:
$ref: "#/components/schemas/Collection"
patch:
tags: [Collections]
operationId: updateCollection
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/CollectionID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateCollectionRequest"
responses:
"200":
description: Collection updated
content:
application/json:
schema:
$ref: "#/components/schemas/Collection"
delete:
tags: [Collections]
operationId: deleteCollection
security:
- bearerAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/CollectionID"
responses:
"204":
description: Collection deleted
/collections/{collectionID}/documents:
get:
tags: [Collections]
operationId: listDocuments
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/CollectionID"
- $ref: "#/components/parameters/PaginationLimit"
- $ref: "#/components/parameters/PaginationOffset"
responses:
"200":
description: List of documents in the collection
content:
application/json:
schema:
$ref: "#/components/schemas/DocumentListResponse"
post:
tags: [Collections]
operationId: createDocument
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/CollectionID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateDocumentRequest"
responses:
"201":
description: Document created
content:
application/json:
schema:
$ref: "#/components/schemas/Document"
/collections/{collectionID}/documents/{documentID}:
get:
tags: [Collections]
operationId: getDocument
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/CollectionID"
- $ref: "#/components/parameters/DocumentID"
responses:
"200":
description: Document details
content:
application/json:
schema:
$ref: "#/components/schemas/Document"
patch:
tags: [Collections]
operationId: updateDocument
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/CollectionID"
- $ref: "#/components/parameters/DocumentID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateDocumentRequest"
responses:
"200":
description: Document updated
content:
application/json:
schema:
$ref: "#/components/schemas/Document"
delete:
tags: [Collections]
operationId: deleteDocument
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/CollectionID"
- $ref: "#/components/parameters/DocumentID"
responses:
"204":
description: Document deleted
/db/status:
get:
tags: [Databases]
operationId: getDbxStatus
security:
- bearerAuth: []
- apiKeyAuth: []
responses:
"200":
description: DBX subprocess availability
content:
application/json:
schema:
$ref: "#/components/schemas/DBXStatus"
/projects/{projectID}/db-connections:
get:
tags: [Databases]
operationId: listDbConnections
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
responses:
"200":
description: Saved database connections for the project
content:
application/json:
schema:
$ref: "#/components/schemas/DBConnectionListResponse"
"401":
$ref: "#/components/responses/ErrorResponse"
post:
tags: [Databases]
operationId: createDbConnection
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateDBConnectionRequest"
responses:
"201":
description: Connection created
content:
application/json:
schema:
$ref: "#/components/schemas/DBConnection"
"401":
$ref: "#/components/responses/ErrorResponse"
"409":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/db-connections/{connectionID}:
delete:
tags: [Databases]
operationId: deleteDbConnection
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/ConnectionID"
responses:
"204":
description: Connection deleted
"404":
$ref: "#/components/responses/ErrorResponse"
"409":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/db-connections/{connectionID}/test:
post:
tags: [Databases]
operationId: testDbConnection
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/ConnectionID"
responses:
"200":
description: Connectivity probe result
content:
application/json:
schema:
$ref: "#/components/schemas/DBConnectionTestResult"
"404":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/db-connections/{connectionID}/databases:
get:
tags: [Databases]
operationId: listDbDatabases
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/ConnectionID"
responses:
"200":
description: Databases reachable through the connection
content:
application/json:
schema:
$ref: "#/components/schemas/DBDatabaseListResponse"
"404":
$ref: "#/components/responses/ErrorResponse"
"502":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/db-connections/{connectionID}/tables:
get:
tags: [Databases]
operationId: listDbTables
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/ConnectionID"
- $ref: "#/components/parameters/DatabaseQuery"
- $ref: "#/components/parameters/SchemaQuery"
responses:
"200":
description: Tables, views, or collections in the connection
content:
application/json:
schema:
$ref: "#/components/schemas/DBTableListResponse"
"404":
$ref: "#/components/responses/ErrorResponse"
"502":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/db-connections/{connectionID}/describe:
get:
tags: [Databases]
operationId: describeDbTable
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/ConnectionID"
- $ref: "#/components/parameters/TableQuery"
- $ref: "#/components/parameters/DatabaseQuery"
- $ref: "#/components/parameters/SchemaQuery"
responses:
"200":
description: Column definitions for a table
content:
application/json:
schema:
$ref: "#/components/schemas/DBDescribeResponse"
"404":
$ref: "#/components/responses/ErrorResponse"
"502":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/db-connections/{connectionID}/schema:
get:
tags: [Databases]
operationId: getDbSchemaContext
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/ConnectionID"
- $ref: "#/components/parameters/DatabaseQuery"
- $ref: "#/components/parameters/SchemaQuery"
responses:
"200":
description: Compact schema context for the connection
content:
application/json:
schema:
$ref: "#/components/schemas/DBSchemaContextResponse"
"404":
$ref: "#/components/responses/ErrorResponse"
"502":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/db-connections/{connectionID}/foreign-keys:
get:
tags: [Databases]
operationId: listDbForeignKeys
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/ConnectionID"
- $ref: "#/components/parameters/DatabaseQuery"
- $ref: "#/components/parameters/SchemaQuery"
responses:
"200":
description: Foreign key edges for the schema graph
content:
application/json:
schema:
$ref: "#/components/schemas/DBForeignKeysResponse"
"404":
$ref: "#/components/responses/ErrorResponse"
"502":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/db-connections/{connectionID}/query:
post:
tags: [Databases]
operationId: executeDbQuery
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/ConnectionID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DBQueryRequest"
responses:
"200":
description: Query result (at most 100 rows)
content:
application/json:
schema:
$ref: "#/components/schemas/DBQueryResponse"
"404":
$ref: "#/components/responses/ErrorResponse"
"502":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/db-connections/{connectionID}/redis:
post:
tags: [Databases]
operationId: executeDbRedisCommand
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/ConnectionID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DBRedisRequest"
responses:
"200":
description: Redis command output
content:
application/json:
schema:
$ref: "#/components/schemas/DBRedisResponse"
"404":
$ref: "#/components/responses/ErrorResponse"
"502":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/db-connections/{connectionID}/transfer:
post:
tags: [Databases]
operationId: transferDbRows
summary: Move query results from this connection to another saved connection
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/ConnectionID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DBTransferRequest"
responses:
"200":
description: Transfer result
content:
application/json:
schema:
$ref: "#/components/schemas/DBTransferResponse"
"404":
$ref: "#/components/responses/ErrorResponse"
"502":
$ref: "#/components/responses/ErrorResponse"
/ingest:
post:
tags: [Telemetry]
operationId: ingestTelemetry
summary: Ingest one telemetry event or a batch of up to 500
security:
- apiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/IngestRequest"
responses:
"202":
description: Accepted event count
content:
application/json:
schema:
$ref: "#/components/schemas/IngestResponse"
"400":
$ref: "#/components/responses/ErrorResponse"
"401":
$ref: "#/components/responses/ErrorResponse"
"413":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/events:
get:
tags: [Telemetry]
operationId: listTelemetryEvents
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- name: type
in: query
schema:
type: string
enum: [error, metric, log, heartbeat, event]
- name: component
in: query
schema:
type: string
- name: fingerprint
in: query
schema:
type: string
- name: before
in: query
schema:
type: integer
- name: limit
in: query
schema:
type: integer
responses:
"200":
description: Telemetry events, newest first
content:
application/json:
schema:
$ref: "#/components/schemas/TelemetryEventListResponse"
"401":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/issues:
get:
tags: [Telemetry]
operationId: listTelemetryIssues
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- name: days
in: query
schema:
type: integer
responses:
"200":
description: Error groups by fingerprint
content:
application/json:
schema:
$ref: "#/components/schemas/TelemetryIssueListResponse"
"401":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/components:
get:
tags: [Telemetry]
operationId: listTelemetryComponents
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
responses:
"200":
description: Registered telemetry components
content:
application/json:
schema:
$ref: "#/components/schemas/TelemetryComponentListResponse"
"401":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/components/{componentID}:
delete:
tags: [Telemetry]
operationId: deleteTelemetryComponent
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/ComponentID"
responses:
"204":
description: Component deleted
"401":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/telemetry/stats:
get:
tags: [Telemetry]
operationId: getTelemetryStats
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- name: window
in: query
schema:
type: string
enum: [1h, 24h, 7d, 30d]
responses:
"200":
description: Aggregated telemetry statistics
content:
application/json:
schema:
$ref: "#/components/schemas/TelemetryStats"
"401":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/telemetry/metrics/series:
get:
tags: [Telemetry]
operationId: getTelemetryMetricSeries
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- name: name
in: query
required: true
schema:
type: string
- name: window
in: query
schema:
type: string
enum: [1h, 24h, 7d, 30d]
responses:
"200":
description: Aggregated metric series
content:
application/json:
schema:
$ref: "#/components/schemas/MetricSeriesResponse"
"401":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/telemetry/stream:
get:
tags: [Telemetry]
operationId: streamTelemetryEvents
summary: Server-sent events stream of live telemetry. EventSource clients pass `?api_key=` or `?token=` since headers cannot be set.
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- name: api_key
in: query
schema:
type: string
- name: token
in: query
schema:
type: string
responses:
"200":
description: text/event-stream of TelemetryEvent messages
"401":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/integrations:
get:
tags: [Integrations]
operationId: listIntegrations
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
responses:
"200":
description: External service integrations for the project
content:
application/json:
schema:
$ref: "#/components/schemas/IntegrationListResponse"
"401":
$ref: "#/components/responses/ErrorResponse"
post:
tags: [Integrations]
operationId: createIntegration
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateIntegrationRequest"
responses:
"201":
description: Integration created
content:
application/json:
schema:
$ref: "#/components/schemas/Integration"
"401":
$ref: "#/components/responses/ErrorResponse"
"409":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/integrations/{integrationID}:
delete:
tags: [Integrations]
operationId: deleteIntegration
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/IntegrationID"
responses:
"204":
description: Integration deleted
"404":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/integrations/{integrationID}/test:
post:
tags: [Integrations]
operationId: testIntegration
summary: Health check — HTTP GET against the integration's base URL with stored credentials (~5s timeout). Updates status and last_health_at.
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/IntegrationID"
responses:
"200":
description: Connectivity probe result
content:
application/json:
schema:
$ref: "#/components/schemas/IntegrationTestResult"
"404":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/integrations/{integrationID}/analytics:
get:
tags: [Integrations]
operationId: getIntegrationAnalytics
summary: Read-only analytics pulled from the integration (Rybbit). The API key never leaves the server.
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/IntegrationID"
- name: site
in: query
required: false
schema:
type: string
description: Rybbit site id override; defaults to the integration's configured site, else first accessible site.
- name: days
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 365
default: 30
responses:
"200":
description: Normalized analytics payload
content:
application/json:
schema:
$ref: "#/components/schemas/IntegrationAnalytics"
"400":
$ref: "#/components/responses/ErrorResponse"
"404":
$ref: "#/components/responses/ErrorResponse"
"502":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/webhooks:
get:
tags: [Webhooks]
operationId: listWebhooks
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
responses:
"200":
description: Outbound webhooks for the project
content:
application/json:
schema:
$ref: "#/components/schemas/WebhookListResponse"
"401":
$ref: "#/components/responses/ErrorResponse"
post:
tags: [Webhooks]
operationId: createWebhook
summary: Deliveries are POSTed as JSON with X-Primora-Event and X-Primora-Signature (sha256=<HMAC-SHA256 hex of the raw body, keyed by the webhook secret>). If no secret is supplied one is generated and returned once.
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateWebhookRequest"
responses:
"201":
description: Webhook created
content:
application/json:
schema:
$ref: "#/components/schemas/WebhookCreateResponse"
"401":
$ref: "#/components/responses/ErrorResponse"
"409":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/webhooks/{webhookID}:
patch:
tags: [Webhooks]
operationId: updateWebhook
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/WebhookID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateWebhookRequest"
responses:
"200":
description: Webhook updated
content:
application/json:
schema:
$ref: "#/components/schemas/WebhookCreateResponse"
"404":
$ref: "#/components/responses/ErrorResponse"
delete:
tags: [Webhooks]
operationId: deleteWebhook
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/WebhookID"
responses:
"204":
description: Webhook deleted
"404":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/webhooks/{webhookID}/deliveries:
get:
tags: [Webhooks]
operationId: listWebhookDeliveries
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/WebhookID"
- name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 200
default: 50
responses:
"200":
description: Recent delivery attempts, newest first
content:
application/json:
schema:
$ref: "#/components/schemas/WebhookDeliveryListResponse"
"404":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/webhooks/{webhookID}/test:
post:
tags: [Webhooks]
operationId: testWebhook
summary: Queues a webhook.test ping delivery.
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/WebhookID"
responses:
"202":
description: Test delivery queued
content:
application/json:
schema:
$ref: "#/components/schemas/WebhookDelivery"
"404":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/deploy-markers:
post:
tags: [Webhooks]
operationId: createDeployMarker
summary: Records a deployment marker in the audit log and fires the deploy.marker webhook event.
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateDeployMarkerRequest"
responses:
"201":
description: Marker recorded
content:
application/json:
schema:
$ref: "#/components/schemas/DeployMarker"
"401":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/jobs:
get:
tags: [Automation]
operationId: listScheduledJobs
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
responses:
"200":
description: Scheduled jobs for the project
content:
application/json:
schema:
$ref: "#/components/schemas/ScheduledJobListResponse"
"401":
$ref: "#/components/responses/ErrorResponse"
post:
tags: [Automation]
operationId: createScheduledJob
summary: Runs a signed POST to the job URL on a cron schedule (standard 5-field cron or @every/@hourly descriptors). Payload is signed X-Primora-Signature like webhook deliveries; an empty secret generates one returned once. HTTPS required for public targets, HTTP allowed for private/self-hosted.
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateScheduledJobRequest"
responses:
"201":
description: Job created
content:
application/json:
schema:
$ref: "#/components/schemas/ScheduledJobCreateResponse"
"400":
$ref: "#/components/responses/ErrorResponse"
"401":
$ref: "#/components/responses/ErrorResponse"
"409":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/jobs/{jobID}:
patch:
tags: [Automation]
operationId: updateScheduledJob
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/JobID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateScheduledJobRequest"
responses:
"200":
description: Job updated
content:
application/json:
schema:
$ref: "#/components/schemas/ScheduledJobCreateResponse"
"404":
$ref: "#/components/responses/ErrorResponse"
delete:
tags: [Automation]
operationId: deleteScheduledJob
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/JobID"
responses:
"204":
description: Job deleted
"404":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/jobs/{jobID}/runs:
get:
tags: [Automation]
operationId: listScheduledJobRuns
summary: Recent executions, newest first. History is capped at 200 runs per job.
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/JobID"
- name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 200
default: 50
responses:
"200":
description: Job run history
content:
application/json:
schema:
$ref: "#/components/schemas/ScheduledJobRunListResponse"
"404":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/jobs/{jobID}/run:
post:
tags: [Automation]
operationId: runScheduledJob
summary: Triggers an out-of-schedule manual run. Returns the run row in "running" state.
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- $ref: "#/components/parameters/JobID"
responses:
"202":
description: Manual run queued
content:
application/json:
schema:
$ref: "#/components/schemas/ScheduledJobRun"
"404":
$ref: "#/components/responses/ErrorResponse"
/projects/{projectID}/realtime/stream:
get:
tags: [Automation]
operationId: streamRealtimeEvents
summary: Server-sent events stream of project domain events — document/object mutations, new issues, deploy markers, job runs. EventSource clients pass `?api_key=` or `?token=` since headers cannot be set.
security:
- bearerAuth: []
- apiKeyAuth: []
parameters:
- $ref: "#/components/parameters/ProjectID"
- name: api_key
in: query
schema:
type: string
- name: token
in: query
schema:
type: string
responses:
"200":
description: text/event-stream of {type, occurred_at, data} messages
"401":
$ref: "#/components/responses/ErrorResponse"
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
apiKeyAuth:
type: apiKey
in: header
name: X-API-Key
parameters:
OrganizationID:
name: organizationID
in: path
required: true
schema:
type: string
format: uuid
ProjectID:
name: projectID
in: path
required: true
schema:
type: string
format: uuid
BucketID:
name: bucketID
in: path
required: true
schema:
type: string
format: uuid
ApiKeyID:
name: apiKeyID
in: path
required: true
schema:
type: string
format: uuid
CollectionID:
name: collectionID
in: path
required: true
schema:
type: string
format: uuid
DocumentID:
name: documentID
in: path
required: true
schema:
type: string
format: uuid
InvitationID:
name: invitationID
in: path
required: true
schema:
type: string
format: uuid
ComponentID:
name: componentID
in: path
required: true
schema:
type: string
format: uuid
UserID:
name: userID
in: path
required: true
schema:
type: string
format: uuid
PaginationLimit:
name: limit
in: query
required: false
schema:
type: integer
format: int32
minimum: 1
maximum: 200
default: 50
PaginationOffset:
name: offset
in: query
required: false
schema:
type: integer
format: int32
minimum: 0
maximum: 100000
default: 0
AuditQuery:
name: q
in: query
required: false
schema:
type: string
AuditAction:
name: action
in: query
required: false
schema:
type: string
ObjectKey:
name: objectKey
in: path
required: true
schema:
type: string
ConnectionID:
name: connectionID
in: path
required: true
schema:
type: string
format: uuid
IntegrationID:
name: integrationID
in: path
required: true
schema:
type: string
format: uuid
WebhookID:
name: webhookID
in: path
required: true
schema:
type: string
format: uuid
JobID:
name: jobID
in: path
required: true
schema:
type: string
format: uuid
DatabaseQuery:
name: database
in: query
required: false
schema:
type: string
SchemaQuery:
name: schema
in: query
required: false
schema:
type: string
TableQuery:
name: table
in: query
required: true
schema:
type: string
responses:
ErrorResponse:
description: Error response
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorEnvelope"
schemas:
HealthStatus:
type: object
properties:
status:
type: string
required: [status]
ReadinessStatus:
type: object
properties:
status:
type: string
checks:
type: object
additionalProperties:
type: string
required: [status, checks]
ErrorEnvelope:
type: object
properties:
status:
type: string
error:
type: object
properties:
code:
type: string
message:
type: string
required: [code, message]
required: [status, error]
BootstrapRequest:
type: object
properties:
organizationName:
type: string
organizationSlug:
type: string
projectName:
type: string
projectSlug:
type: string
description:
type: string
nullable: true
required: [organizationName, organizationSlug, projectName, projectSlug]
BootstrapResponse:
type: object
properties:
organization_id:
type: string
format: uuid
organization_slug:
type: string
organization_name:
type: string
project_id:
type: string
format: uuid
project_slug:
type: string
project_name:
type: string
required:
- organization_id
- organization_slug
- organization_name
- project_id
- project_slug
- project_name
UserSummary:
type: object
properties:
id:
type: string
format: uuid
authSubject:
type: string
email:
type: string
name:
type: string
emailVerified:
type: boolean
required: [id, authSubject, email, name, emailVerified]
ProjectSummary:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
slug:
type: string
description:
type: string
nullable: true
membershipRole:
type: string
nullable: true
required: [id, name, slug]
OrganizationSummary:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
slug:
type: string
membershipRole:
type: string
projects:
type: array
items:
$ref: "#/components/schemas/ProjectSummary"
required: [id, name, slug, membershipRole, projects]
MeResponse:
type: object
properties:
user:
$ref: "#/components/schemas/UserSummary"
organizations:
type: array
items:
$ref: "#/components/schemas/OrganizationSummary"
required: [user, organizations]
OrganizationMembership:
type: object
properties:
id:
type: string
format: uuid
slug:
type: string
name:
type: string
membership_role:
type: string
required: [id, slug, name, membership_role]
CreateOrganizationRequest:
type: object
properties:
name:
type: string
slug:
type: string
required: [name, slug]
UpdateOrganizationRequest:
type: object
properties:
name:
type: string
slug:
type: string
required: [name, slug]
OrganizationMember:
type: object
properties:
user_id:
type: string
format: uuid
email:
type: string
name:
type: string
email_verified:
type: boolean
role:
type: string
enum: [owner, admin, member]
joined_at:
type: string
format: date-time
required: [user_id, email, name, email_verified, role, joined_at]
UpdateOrganizationMemberRoleRequest:
type: object
properties:
role:
type: string
enum: [owner, admin, member]
required: [role]
CreateProjectRequest:
type: object
properties:
name:
type: string
slug:
type: string
description:
type: string
nullable: true
required: [name, slug]
UpdateProjectRequest:
type: object
properties:
name:
type: string
slug:
type: string
description:
type: string
nullable: true
retention_events_days:
type: integer
minimum: 0
maximum: 3650
description: Telemetry event retention; 0 disables the sweep.
retention_audit_days:
type: integer
minimum: 0
maximum: 3650
description: Audit log retention; 0 disables the sweep.
retention_webhook_days:
type: integer
minimum: 0
maximum: 3650
description: Webhook delivery retention; 0 disables the sweep.
required: [name, slug]
Project:
type: object
properties:
id:
type: string
format: uuid
organization_id:
type: string
format: uuid
slug:
type: string
name:
type: string
description:
type: string
nullable: true
membership_role:
type: string
nullable: true
retention_events_days:
type: integer
retention_audit_days:
type: integer
retention_webhook_days:
type: integer
required: [id, organization_id, slug, name]
ProjectOverview:
type: object
properties:
project_id:
type: string
format: uuid
organization_id:
type: string
format: uuid
project_slug:
type: string
project_name:
type: string
member_count:
type: integer
format: int64
active_api_key_count:
type: integer
format: int64
bucket_count:
type: integer
format: int64
object_count:
type: integer
format: int64
object_bytes_total:
type: integer
format: int64
pending_invitation_count:
type: integer
format: int64
audit_events_24h:
type: integer
format: int64
last_audit_at:
type: string
format: date-time
nullable: true
integration_count:
type: integer
format: int64
description: Connectors attached to the project.
webhook_count:
type: integer
format: int64
description: Enabled outbound webhooks.
required:
- project_id
- organization_id
- project_slug
- project_name
- member_count
- active_api_key_count
- bucket_count
- object_count
- object_bytes_total
- pending_invitation_count
- audit_events_24h
- integration_count
- webhook_count
ProjectMember:
type: object
properties:
user_id:
type: string
format: uuid
email:
type: string
name:
type: string
email_verified:
type: boolean
role:
type: string
enum: [admin, developer, viewer]
joined_at:
type: string
format: date-time
required: [user_id, email, name, email_verified, role, joined_at]
UpdateProjectMemberRoleRequest:
type: object
properties:
role:
type: string
enum: [admin, developer, viewer]
required: [role]
CreateInvitationRequest:
type: object
properties:
email:
type: string
format: email
orgRole:
type: string
enum: [owner, admin, member]
projectId:
type: string
format: uuid
nullable: true
projectRole:
type: string
enum: [admin, developer, viewer]
nullable: true
redirectUrl:
type: string
format: uri
nullable: true
required: [email, orgRole]
Invitation:
type: object
properties:
id:
type: string
format: uuid
email:
type: string
format: email
expiresAt:
type: string
format: date-time
required: [id, email, expiresAt]
OrganizationInvitation:
type: object
properties:
id:
type: string
format: uuid
organization_id:
type: string
format: uuid
project_id:
type: string
format: uuid
nullable: true
project_name:
type: string
nullable: true
email:
type: string
format: email
org_role:
type: string
enum: [owner, admin, member]
project_role:
type: string
enum: [admin, developer, viewer]
nullable: true
expires_at:
type: string
format: date-time
accepted_at:
type: string
format: date-time
nullable: true
invited_by_user_id:
type: string
format: uuid
nullable: true
created_at:
type: string
format: date-time
status:
type: string
enum: [pending, accepted, expired]
required:
- id
- organization_id
- email
- org_role
- expires_at
- created_at
- status
AcceptInvitationRequest:
type: object
properties:
token:
type: string
required: [token]
CreateApiKeyRequest:
type: object
properties:
name:
type: string
scopes:
type: array
items:
type: string
enum: [ingest, read, write, admin]
description: >-
Access scopes for the key. admin unlocks everything; write unlocks
read + ingest + non-admin mutations; read and ingest unlock only
themselves. Omitted means ["admin"] (full access, legacy behaviour).
required: [name]
ApiKey:
type: object
properties:
id:
type: string
format: uuid
project_id:
type: string
format: uuid
name:
type: string
prefix:
type: string
scopes:
type: array
items:
type: string
enum: [ingest, read, write, admin]
last_used_at:
type: string
format: date-time
nullable: true
revoked_at:
type: string
format: date-time
nullable: true
required: [id, project_id, name, prefix]
CreatedApiKey:
type: object
properties:
id:
type: string
format: uuid
prefix:
type: string
secret:
type: string
name:
type: string
scopes:
type: array
items:
type: string
enum: [ingest, read, write, admin]
required: [id, prefix, secret, name]
CreateBucketRequest:
type: object
properties:
name:
type: string
slug:
type: string
visibility:
type: string
enum: [private, public]
required: [name, slug, visibility]
UpdateBucketRequest:
type: object
properties:
name:
type: string
slug:
type: string
visibility:
type: string
enum: [private, public]
required: [name, slug, visibility]
Bucket:
type: object
properties:
id:
type: string
format: uuid
project_id:
type: string
format: uuid
slug:
type: string
name:
type: string
visibility:
type: string
required: [id, project_id, slug, name, visibility]
BucketObject:
type: object
properties:
id:
type: string
format: uuid
bucket_id:
type: string
format: uuid
object_key:
type: string
content_type:
type: string
size_bytes:
type: integer
format: int64
checksum_sha256:
type: string
created_at:
type: string
format: date-time
required: [id, bucket_id, object_key, content_type, size_bytes, checksum_sha256, created_at]
UpdateBucketObjectRequest:
type: object
properties:
newObjectKey:
type: string
destinationBucketId:
type: string
format: uuid
nullable: true
required: [newObjectKey]
CopyBucketObjectRequest:
type: object
properties:
objectKey:
type: string
newObjectKey:
type: string
destinationBucketId:
type: string
format: uuid
nullable: true
required: [objectKey, newObjectKey]
PaginationMetadata:
type: object
properties:
total:
type: integer
format: int64
limit:
type: integer
format: int32
offset:
type: integer
format: int32
has_more:
type: boolean
required: [total, limit, offset, has_more]
BucketObjectListResponse:
allOf:
- $ref: "#/components/schemas/PaginationMetadata"
- type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/BucketObject"
required: [items]
AuditLog:
type: object
properties:
id:
type: string
format: uuid
created_at:
type: string
format: date-time
action:
type: string
resource_type:
type: string
resource_id:
type: string
request_id:
type: string
metadata:
type: object
additionalProperties: true
required: [id, created_at, action, resource_type, resource_id, request_id, metadata]
AuditLogListResponse:
allOf:
- $ref: "#/components/schemas/PaginationMetadata"
- type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/AuditLog"
required: [items]
Collection:
type: object
properties:
id:
type: string
format: uuid
project_id:
type: string
format: uuid
slug:
type: string
name:
type: string
description:
type: string
nullable: true
schema:
type: object
description: JSON Schema for the collection
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
required: [id, project_id, slug, name, schema, created_at, updated_at]
CreateCollectionRequest:
type: object
properties:
slug:
type: string
name:
type: string
description:
type: string
nullable: true
schema:
type: object
required: [slug, name]
UpdateCollectionRequest:
type: object
properties:
name:
type: string
description:
type: string
nullable: true
schema:
type: object
Document:
type: object
properties:
id:
type: string
format: uuid
collection_id:
type: string
format: uuid
data:
type: object
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
required: [id, collection_id, data, created_at, updated_at]
CreateDocumentRequest:
type: object
properties:
data:
type: object
required: [data]
UpdateDocumentRequest:
type: object
properties:
data:
type: object
required: [data]
CollectionListResponse:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/Collection"
required: [items]
DocumentListResponse:
allOf:
- $ref: "#/components/schemas/PaginationMetadata"
- type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/Document"
required: [items]
DBXStatus:
type: object
properties:
available:
type: boolean
command:
type: string
reason:
type: string
install:
type: string
required: [available]
DBConnection:
type: object
properties:
id:
type: string
format: uuid
project_id:
type: string
format: uuid
name:
type: string
db_type:
type: string
host:
type: string
port:
type: integer
nullable: true
database:
type: string
username:
type: string
ssl:
type: boolean
nullable: true
is_managed:
type: boolean
has_password:
type: boolean
required: [id, project_id, name, db_type, host, is_managed, has_password]
CreateDBConnectionRequest:
type: object
properties:
name:
type: string
db_type:
type: string
enum: [postgres, mysql, sqlite, redis, mongodb, sqlserver, duckdb, clickhouse, cassandra]
host:
type: string
port:
type: integer
database:
type: string
username:
type: string
password:
type: string
ssl:
type: boolean
driver_profile:
type: string
required: [name, db_type, host]
DBConnectionListResponse:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/DBConnection"
required: [items]
DBConnectionTestResult:
type: object
properties:
ok:
type: boolean
error:
type: string
required: [ok]
DBObject:
type: object
properties:
name:
type: string
kind:
type: string
required: [name, kind]
DBMDTable:
type: object
properties:
columns:
type: array
items:
type: string
rows:
type: array
items:
type: array
items:
type: string
note:
type: string
required: [columns, rows]
DBDatabaseListResponse:
type: object
properties:
databases:
type: array
items:
type: string
raw:
type: string
required: [databases]
DBTableListResponse:
type: object
properties:
tables:
type: array
items:
$ref: "#/components/schemas/DBObject"
table:
$ref: "#/components/schemas/DBMDTable"
raw:
type: string
DBDescribeResponse:
type: object
properties:
table:
$ref: "#/components/schemas/DBMDTable"
raw:
type: string
DBSchemaContextResponse:
type: object
properties:
context:
type: string
required: [context]
DBForeignKeyEdge:
type: object
properties:
schema:
type: string
table:
type: string
column:
type: string
ref_schema:
type: string
ref_table:
type: string
ref_column:
type: string
required: [table, column, ref_table, ref_column]
DBForeignKeysResponse:
type: object
properties:
edges:
type: array
items:
$ref: "#/components/schemas/DBForeignKeyEdge"
raw:
type: string
note:
type: string
required: [edges]
DBQueryRequest:
type: object
properties:
sql:
type: string
database:
type: string
required: [sql]
DBQueryResponse:
type: object
properties:
table:
$ref: "#/components/schemas/DBMDTable"
raw:
type: string
DBRedisRequest:
type: object
properties:
command:
type: string
db:
type: integer
required: [command]
DBRedisResponse:
type: object
properties:
output:
type: string
required: [output]
DBTransferRequest:
type: object
properties:
target_connection_id:
type: string
format: uuid
query:
type: string
description: SELECT run against the source connection.
database:
type: string
target_table:
type: string
description: Destination table for SQL targets (schema-qualified allowed).
key_pattern:
type: string
description: >-
Redis targets: SET key template with {column} placeholders, e.g.
"user:{id}".
value_column:
type: string
description: >-
Redis targets: column whose cell becomes the value. Omitted stores
the whole row as JSON.
ttl_seconds:
type: integer
minimum: 0
description: Optional EX TTL applied to each Redis SET.
limit:
type: integer
minimum: 1
maximum: 1000
default: 1000
required: [target_connection_id, query]
DBTransferResponse:
type: object
properties:
transferred:
type: integer
truncated:
type: boolean
source:
type: string
target:
type: string
required: [transferred, truncated, source, target]
IngestEvent:
type: object
properties:
type:
type: string
enum: [error, metric, log, heartbeat, event]
component:
type: string
description: Auto-registered under the project on first use
kind:
type: string
enum: [frontend, backend, database, android, desktop, web, other]
severity:
type: string
message:
type: string
payload:
type: object
additionalProperties: true
fingerprint:
type: string
description: Error grouping key; derived from message when omitted
ts:
type: string
format: date-time
required: [type]
IngestRequest:
oneOf:
- $ref: "#/components/schemas/IngestEvent"
- type: object
properties:
events:
type: array
items:
$ref: "#/components/schemas/IngestEvent"
maxItems: 500
required: [events]
IngestResponse:
type: object
properties:
accepted:
type: integer
required: [accepted]
TelemetryEvent:
type: object
properties:
id:
type: integer
project_id:
type: string
format: uuid
component_id:
type: string
format: uuid
nullable: true
component_name:
type: string
type:
type: string
severity:
type: string
message:
type: string
payload:
type: object
additionalProperties: true
fingerprint:
type: string
ts:
type: string
format: date-time
required: [id, project_id, type, severity, message, ts]
TelemetryEventListResponse:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/TelemetryEvent"
required: [items]
TelemetryIssue:
type: object
properties:
fingerprint:
type: string
message:
type: string
component_id:
type: string
format: uuid
nullable: true
component_name:
type: string
count:
type: integer
first_seen:
type: string
format: date-time
last_seen:
type: string
format: date-time
severity:
type: string
required: [fingerprint, message, count, first_seen, last_seen, severity]
TelemetryIssueListResponse:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/TelemetryIssue"
required: [items]
TelemetryComponent:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
kind:
type: string
last_seen_at:
type: string
format: date-time
nullable: true
last_status:
type: string
errors_24h:
type: integer
events_24h:
type: integer
meta:
type: object
additionalProperties: true
required: [id, name, kind, errors_24h, events_24h]
TelemetryComponentListResponse:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/TelemetryComponent"
required: [items]
ComponentHealth:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
kind:
type: string
last_seen_at:
type: string
format: date-time
nullable: true
last_status:
type: string
errors_24h:
type: integer
events_24h:
type: integer
meta:
type: object
additionalProperties: true
required: [id, name, kind, errors_24h, events_24h]
EventSeriesBucket:
type: object
properties:
ts:
type: string
format: date-time
counts:
type: object
additionalProperties:
type: integer
required: [ts, counts]
TelemetryStats:
type: object
properties:
window:
type: integer
bucket_sec:
type: integer
series:
type: array
items:
$ref: "#/components/schemas/EventSeriesBucket"
components:
type: array
items:
$ref: "#/components/schemas/ComponentHealth"
errors:
type: integer
events:
type: integer
metrics:
type: integer
metric_names:
type: array
items:
type: string
required: [window, bucket_sec, series, components, errors, events, metrics, metric_names]
MetricPoint:
type: object
properties:
ts:
type: string
format: date-time
avg:
type: number
nullable: true
p50:
type: number
nullable: true
p95:
type: number
nullable: true
max:
type: number
nullable: true
count:
type: integer
required: [ts, count]
MetricSeriesResponse:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/MetricPoint"
required: [items]
Integration:
type: object
properties:
id:
type: string
format: uuid
project_id:
type: string
format: uuid
type:
type: string
enum: [rybbit]
name:
type: string
base_url:
type: string
site_id:
type: string
description: Connector-specific target (Rybbit site id). Optional.
status:
type: string
enum: [unknown, ok, error]
last_health_at:
type: string
format: date-time
nullable: true
has_credentials:
type: boolean
created_at:
type: string
format: date-time
required: [id, project_id, type, name, base_url, status, has_credentials]
CreateIntegrationRequest:
type: object
properties:
name:
type: string
type:
type: string
enum: [rybbit]
base_url:
type: string
description: Root URL of the self-hosted instance, e.g. https://analytics.example.com
api_key:
type: string
description: Credential stored encrypted at rest; never returned by any endpoint.
site_id:
type: string
required: [name, type, base_url]
IntegrationListResponse:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/Integration"
required: [items]
IntegrationTestResult:
type: object
properties:
ok:
type: boolean
status_code:
type: integer
error:
type: string
required: [ok]
RybbitSite:
type: object
properties:
site_id:
type: string
name:
type: string
domain:
type: string
required: [site_id, name]
IntegrationAnalytics:
type: object
properties:
integration_id:
type: string
format: uuid
site:
$ref: "#/components/schemas/RybbitSite"
sites:
type: array
items:
$ref: "#/components/schemas/RybbitSite"
overview:
type: object
properties:
sessions:
type: number
pageviews:
type: number
users:
type: number
pages_per_session:
type: number
bounce_rate:
type: number
session_duration:
type: number
series:
type: array
items:
type: object
properties:
time:
type: string
sessions:
type: number
pageviews:
type: number
users:
type: number
bounce_rate:
type: number
top_pages:
type: array
items:
$ref: "#/components/schemas/RybbitMetricItem"
top_referrers:
type: array
items:
$ref: "#/components/schemas/RybbitMetricItem"
window_days:
type: integer
required: [integration_id, window_days]
RybbitMetricItem:
type: object
properties:
value:
type: string
count:
type: number
percentage:
type: number
required: [value, count]
Webhook:
type: object
properties:
id:
type: string
format: uuid
project_id:
type: string
format: uuid
url:
type: string
events:
type: array
items:
type: string
description: Event filter (issue.created, deploy.marker, webhook.test, job.run, document.*, object.*). Empty means all events.
enabled:
type: boolean
has_secret:
type: boolean
created_at:
type: string
format: date-time
required: [id, project_id, url, events, enabled, has_secret]
CreateWebhookRequest:
type: object
properties:
url:
type: string
format: uri
secret:
type: string
description: HMAC key for X-Primora-Signature. Generated when omitted.
events:
type: array
items:
type: string
enum: [issue.created, deploy.marker, webhook.test, job.run, document.created, document.updated, document.deleted, object.created, object.updated, object.deleted]
enabled:
type: boolean
required: [url]
UpdateWebhookRequest:
type: object
properties:
url:
type: string
format: uri
secret:
type: string
description: Replace the signing secret. Omit to keep the current one.
events:
type: array
items:
type: string
enum: [issue.created, deploy.marker, webhook.test, job.run, document.created, document.updated, document.deleted, object.created, object.updated, object.deleted]
enabled:
type: boolean
WebhookCreateResponse:
allOf:
- $ref: "#/components/schemas/Webhook"
- type: object
properties:
secret:
type: string
description: Plaintext secret — present only when Primora generated it. Store it; it cannot be recovered.
WebhookListResponse:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/Webhook"
required: [items]
WebhookDelivery:
type: object
properties:
id:
type: string
format: uuid
webhook_id:
type: string
format: uuid
event_type:
type: string
payload:
type: object
status:
type: string
enum: [pending, delivered, failed]
attempts:
type: integer
last_status_code:
type: integer
nullable: true
last_error:
type: string
delivered_at:
type: string
format: date-time
nullable: true
next_retry_at:
type: string
format: date-time
nullable: true
created_at:
type: string
format: date-time
required: [id, webhook_id, event_type, status, attempts]
WebhookDeliveryListResponse:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/WebhookDelivery"
required: [items]
CreateDeployMarkerRequest:
type: object
properties:
version:
type: string
ref:
type: string
description: Git SHA, tag or branch being deployed.
environment:
type: string
note:
type: string
DeployMarker:
type: object
properties:
version:
type: string
ref:
type: string
environment:
type: string
note:
type: string
recorded_at:
type: string
format: date-time
required: [recorded_at]
ScheduledJob:
type: object
properties:
id:
type: string
format: uuid
project_id:
type: string
format: uuid
name:
type: string
schedule:
type: string
description: Cron expression (5-field) or descriptor (@hourly, @every 30m).
url:
type: string
payload:
type: object
description: Static JSON payload merged into every delivery's data field.
enabled:
type: boolean
has_secret:
type: boolean
last_run_at:
type: string
format: date-time
nullable: true
last_status:
type: string
enum: [success, failed]
nullable: true
next_run_at:
type: string
format: date-time
nullable: true
created_at:
type: string
format: date-time
required: [id, project_id, name, schedule, url, payload, enabled, has_secret]
CreateScheduledJobRequest:
type: object
properties:
name:
type: string
minLength: 2
schedule:
type: string
description: 'Cron expression, e.g. "*/15 * * * *", or descriptor like "@every 1h".'
url:
type: string
format: uri
secret:
type: string
description: HMAC key for X-Primora-Signature. Generated when omitted.
payload:
type: object
description: Static JSON payload delivered as data on every run.
enabled:
type: boolean
default: true
required: [name, schedule, url]
UpdateScheduledJobRequest:
type: object
properties:
name:
type: string
minLength: 2
schedule:
type: string
url:
type: string
format: uri
secret:
type: string
description: Replace the signing secret. Omit to keep the current one.
payload:
type: object
enabled:
type: boolean
ScheduledJobCreateResponse:
allOf:
- $ref: "#/components/schemas/ScheduledJob"
- type: object
properties:
secret:
type: string
description: Plaintext secret — present only when Primora generated it. Store it; it cannot be recovered.
ScheduledJobListResponse:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/ScheduledJob"
required: [items]
ScheduledJobRun:
type: object
properties:
id:
type: string
format: uuid
job_id:
type: string
format: uuid
status:
type: string
enum: [running, success, failed]
triggered_by:
type: string
enum: [schedule, manual]
status_code:
type: integer
nullable: true
error:
type: string
duration_ms:
type: integer
nullable: true
started_at:
type: string
format: date-time
finished_at:
type: string
format: date-time
nullable: true
required: [id, job_id, status, triggered_by]
ScheduledJobRunListResponse:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/ScheduledJobRun"
required: [items]