# OpenAPI 3.1 specification for StellaOps Notifier WebService (draft) openapi: 3.1.0 info: title: StellaOps Notifier API version: 0.6.0-draft description: | Contract for Notifications Studio (Notifier) covering rules, templates, incidents, and quiet hours. Uses the platform error envelope and tenant header `X-StellaOps-Tenant`. servers: - url: https://api.stellaops.example.com description: Production - url: https://api.dev.stellaops.example.com description: Development security: - oauth2: [notify.viewer] - oauth2: [notify.operator] - oauth2: [notify.admin] paths: /api/v1/notify/rules: get: summary: List notification rules tags: [Rules] parameters: - $ref: '#/components/parameters/Tenant' - $ref: '#/components/parameters/PageSize' - $ref: '#/components/parameters/PageToken' responses: '200': description: Paginated rule list content: application/json: schema: type: object properties: items: type: array items: { $ref: '#/components/schemas/NotifyRule' } nextPageToken: type: string examples: default: value: items: - ruleId: rule-critical tenantId: tenant-dev name: Critical scanner verdicts enabled: true match: eventKinds: [scanner.report.ready] minSeverity: critical actions: - actionId: act-slack-critical channel: chn-slack-soc template: tmpl-critical digest: instant nextPageToken: null default: $ref: '#/components/responses/Error' post: summary: Create a notification rule tags: [Rules] parameters: - $ref: '#/components/parameters/Tenant' requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/NotifyRule' } examples: create-rule: value: ruleId: rule-attest-fail tenantId: tenant-dev name: Attestation failures → SOC enabled: true match: eventKinds: [attestor.verification.failed] actions: - actionId: act-soc channel: chn-webhook-soc template: tmpl-attest-verify-fail responses: '201': description: Rule created content: application/json: schema: { $ref: '#/components/schemas/NotifyRule' } default: $ref: '#/components/responses/Error' /api/v1/notify/rules/{ruleId}: get: summary: Fetch a rule tags: [Rules] parameters: - $ref: '#/components/parameters/Tenant' - $ref: '#/components/parameters/RuleId' responses: '200': description: Rule content: application/json: schema: { $ref: '#/components/schemas/NotifyRule' } default: $ref: '#/components/responses/Error' patch: summary: Update a rule (partial) tags: [Rules] parameters: - $ref: '#/components/parameters/Tenant' - $ref: '#/components/parameters/RuleId' requestBody: required: true content: application/json: schema: type: object description: JSON Merge Patch responses: '200': description: Updated rule content: application/json: schema: { $ref: '#/components/schemas/NotifyRule' } default: $ref: '#/components/responses/Error' /api/v1/notify/templates: get: summary: List templates tags: [Templates] parameters: - $ref: '#/components/parameters/Tenant' - name: key in: query description: Filter by template key schema: { type: string } responses: '200': description: Templates content: application/json: schema: type: array items: { $ref: '#/components/schemas/NotifyTemplate' } default: $ref: '#/components/responses/Error' post: summary: Create a template tags: [Templates] parameters: - $ref: '#/components/parameters/Tenant' requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/NotifyTemplate' } responses: '201': description: Template created content: application/json: schema: { $ref: '#/components/schemas/NotifyTemplate' } default: $ref: '#/components/responses/Error' /api/v1/notify/templates/{templateId}: get: summary: Fetch a template tags: [Templates] parameters: - $ref: '#/components/parameters/Tenant' - $ref: '#/components/parameters/TemplateId' responses: '200': description: Template content: application/json: schema: { $ref: '#/components/schemas/NotifyTemplate' } default: $ref: '#/components/responses/Error' patch: summary: Update a template (partial) tags: [Templates] parameters: - $ref: '#/components/parameters/Tenant' - $ref: '#/components/parameters/TemplateId' requestBody: required: true content: application/json: schema: type: object description: JSON Merge Patch responses: '200': description: Updated template content: application/json: schema: { $ref: '#/components/schemas/NotifyTemplate' } default: $ref: '#/components/responses/Error' /api/v1/notify/incidents: get: summary: List incidents (paged) tags: [Incidents] parameters: - $ref: '#/components/parameters/Tenant' - $ref: '#/components/parameters/PageSize' - $ref: '#/components/parameters/PageToken' responses: '200': description: Incident page content: application/json: schema: type: object properties: items: type: array items: { $ref: '#/components/schemas/Incident' } nextPageToken: { type: string } default: $ref: '#/components/responses/Error' post: summary: Raise an incident (ops/toggle/override) tags: [Incidents] parameters: - $ref: '#/components/parameters/Tenant' requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/Incident' } examples: start-incident: value: incidentId: inc-telemetry-outage kind: outage severity: major startedAt: 2025-11-17T04:02:00Z shortDescription: "Telemetry pipeline degraded; burn-rate breach" metadata: source: slo-evaluator responses: '202': description: Incident accepted default: $ref: '#/components/responses/Error' /api/v1/notify/incidents/{incidentId}/ack: post: summary: Acknowledge an incident notification tags: [Incidents] parameters: - $ref: '#/components/parameters/Tenant' - $ref: '#/components/parameters/IncidentId' requestBody: required: true content: application/json: schema: type: object properties: ackToken: type: string description: DSSE-signed acknowledgement token responses: '204': description: Acknowledged default: $ref: '#/components/responses/Error' /api/v1/notify/quiet-hours: get: summary: Get quiet-hours schedule tags: [QuietHours] parameters: - $ref: '#/components/parameters/Tenant' responses: '200': description: Quiet hours schedule content: application/json: schema: { $ref: '#/components/schemas/QuietHours' } examples: current: value: quietHoursId: qh-default windows: - timezone: UTC days: [Mon, Tue, Wed, Thu, Fri] start: "22:00" end: "06:00" exemptions: - eventKinds: [attestor.verification.failed] reason: "Always alert for attestation failures" default: $ref: '#/components/responses/Error' post: summary: Set quiet-hours schedule tags: [QuietHours] parameters: - $ref: '#/components/parameters/Tenant' requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/QuietHours' } responses: '200': description: Updated quiet hours content: application/json: schema: { $ref: '#/components/schemas/QuietHours' } default: $ref: '#/components/responses/Error' components: securitySchemes: oauth2: type: oauth2 flows: clientCredentials: tokenUrl: https://auth.stellaops.example.com/oauth/token scopes: notify.viewer: Read-only Notifier access notify.operator: Manage rules/templates/incidents within tenant notify.admin: Tenant-scoped administration parameters: Tenant: name: X-StellaOps-Tenant in: header required: true description: Tenant slug schema: { type: string } PageSize: name: pageSize in: query schema: { type: integer, minimum: 1, maximum: 200, default: 50 } PageToken: name: pageToken in: query schema: { type: string } RuleId: name: ruleId in: path required: true schema: { type: string } TemplateId: name: templateId in: path required: true schema: { type: string } IncidentId: name: incidentId in: path required: true schema: { type: string } responses: Error: description: Standard error envelope content: application/json: schema: { $ref: '#/components/schemas/ErrorEnvelope' } examples: validation: value: error: code: validation_failed message: "quietHours.windows[0].start must be HH:mm" traceId: "f62f3c2b9c8e4c53" schemas: ErrorEnvelope: type: object required: [error] properties: error: type: object required: [code, message, traceId] properties: code: { type: string } message: { type: string } traceId: { type: string } NotifyRule: type: object required: [ruleId, tenantId, name, match, actions] properties: ruleId: { type: string } tenantId: { type: string } name: { type: string } description: { type: string } enabled: { type: boolean, default: true } match: { $ref: '#/components/schemas/RuleMatch' } actions: type: array items: { $ref: '#/components/schemas/RuleAction' } labels: type: object additionalProperties: { type: string } metadata: type: object additionalProperties: { type: string } RuleMatch: type: object properties: eventKinds: type: array items: { type: string } minSeverity: { type: string, enum: [info, low, medium, high, critical] } verdicts: type: array items: { type: string } labels: type: array items: { type: string } kevOnly: { type: boolean } RuleAction: type: object required: [actionId, channel] properties: actionId: { type: string } channel: { type: string } template: { type: string } digest: { type: string, description: "Digest window key e.g. instant|5m|15m|1h|1d" } throttle: { type: string, description: "ISO-8601 duration, e.g. PT5M" } locale: { type: string } enabled: { type: boolean, default: true } metadata: type: object additionalProperties: { type: string } NotifyTemplate: type: object required: [templateId, tenantId, key, channelType, locale, body, renderMode, format] properties: templateId: { type: string } tenantId: { type: string } key: { type: string } channelType: { type: string, enum: [slack, teams, email, webhook, custom] } locale: { type: string, description: "BCP-47, lower-case" } renderMode: { type: string, enum: [Markdown, Html, AdaptiveCard, PlainText, Json] } format: { type: string, enum: [slack, teams, email, webhook, json] } description: { type: string } body: { type: string } metadata: type: object additionalProperties: { type: string } Incident: type: object required: [incidentId, kind, severity, startedAt] properties: incidentId: { type: string } kind: { type: string, description: "outage|degradation|security|ops-drill" } severity: { type: string, enum: [minor, major, critical] } startedAt: { type: string, format: date-time } endedAt: { type: string, format: date-time } shortDescription: { type: string } description: { type: string } metadata: type: object additionalProperties: { type: string } QuietHours: type: object required: [quietHoursId, windows] properties: quietHoursId: { type: string } windows: type: array items: { $ref: '#/components/schemas/QuietHoursWindow' } exemptions: type: array description: Event kinds that bypass quiet hours items: type: object properties: eventKinds: type: array items: { type: string } reason: { type: string } QuietHoursWindow: type: object required: [timezone, days, start, end] properties: timezone: { type: string, description: "IANA TZ, e.g., UTC" } days: type: array items: type: string enum: [Mon, Tue, Wed, Thu, Fri, Sat, Sun] start: { type: string, description: "HH:mm" } end: { type: string, description: "HH:mm" }