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 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" /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" /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=). 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" 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 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 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 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 required: [name] ApiKey: type: object properties: id: type: string format: uuid project_id: type: string format: uuid name: type: string prefix: type: string 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 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] 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). 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] 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] 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]