openapi: 3.1.0 info: title: Notifier Pack Approvals Ingestion (fragment) version: 0.1.0-draft description: > Contract for ingesting pack approval/policy decisions emitted by Task Runner and Policy Engine. Served under Notifier WebService. paths: /api/v1/notify/pack-approvals: post: summary: Ingest pack approval decision operationId: ingestPackApproval tags: [PackApprovals] security: - oauth2: [notify.operator] - hmac: [] parameters: - name: X-StellaOps-Tenant in: header required: true schema: { type: string } - name: Idempotency-Key in: header required: true description: Stable UUID to dedupe retries. schema: { type: string, format: uuid } requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/PackApprovalEvent' } examples: approval-granted: value: eventId: "20e4e5fe-3d4a-4f57-9f9b-b1a1c1111111" issuedAt: "2025-11-17T16:00:00Z" kind: "pack.approval.granted" packId: "offline-kit-2025-11" policy: id: "policy-123" version: "v5" decision: "approved" actor: "task-runner" resumeToken: "rt-abc123" summary: "All required attestations verified." labels: environment: "prod" approver: "ops" responses: '202': description: Accepted; durable write queued for processing. headers: X-Resume-After: description: Resume token echo or replacement schema: { type: string } default: $ref: '#/components/responses/Error' components: securitySchemes: oauth2: type: oauth2 flows: clientCredentials: tokenUrl: https://auth.stellaops.example.com/oauth/token scopes: notify.operator: Ingest approval events hmac: type: http scheme: bearer description: Pre-shared HMAC token (air-gap friendly) referenced by secretRef. schemas: PackApprovalEvent: type: object required: - eventId - issuedAt - kind - packId - decision - actor properties: eventId: { type: string, format: uuid } issuedAt: { type: string, format: date-time } kind: type: string enum: [pack.approval.granted, pack.approval.denied, pack.policy.override] packId: { type: string } policy: type: object properties: id: { type: string } version: { type: string } decision: type: string enum: [approved, denied, overridden] actor: { type: string } resumeToken: type: string description: Opaque token for at-least-once resume. summary: { type: string } labels: type: object additionalProperties: { type: string } responses: Error: description: Error envelope content: application/json: schema: type: object required: [error] properties: error: type: object required: [code, message, traceId] properties: code: { type: string } message: { type: string } traceId: { type: string }