Notification Service — API Contracts
Status: populated Owner: Platform Engineering Last updated: 2026-04-18
This service has no public REST API and is not routed via Kong. All endpoints are cluster-internal only, accessible by admin-dashboard and health probes.
1. Internal Endpoints (no Kong route)
All on port 3030. Reachable only within the Kubernetes cluster.
Health & Metrics
| Method | Path | Purpose |
|---|---|---|
| GET | /health/live | Liveness probe |
| GET | /health/ready | Readiness (PG + NATS + SendGrid reachable) |
| GET | /metrics | Prometheus metrics |
Notification Log (admin-dashboard)
GET /internal/notifications
Query notification log.
Params: accountId, channel, status, from, to, cursor, limit (max 100).
Response 200:
{
"data": [
{
"notificationId": "uuid",
"channel": "EMAIL",
"category": "BILLING",
"status": "SENT",
"sourceEventType": "billing.invoice.generated.v1",
"recipientAddress": "***@example.com",
"sentAt": "2026-04-01T00:12:00Z",
"attemptCount": 1
}
],
"nextCursor": "opaque"
}
Notification Preferences (admin-dashboard)
GET /internal/preferences?accountId={uuid}
Returns all preferences for an account.
PUT /internal/preferences
Set or update a preference.
{
"accountId": "uuid",
"category": "OPERATOR_ALERT",
"channel": "SMS",
"optedOut": true
}
Response 200: updated preference.
Template Management (admin-dashboard)
GET /internal/templates
Params: type, channel, isActive.
GET /internal/templates/{id}
Full template with bodyHtml, bodyText, variablesSchema.
POST /internal/templates
{
"type": "INVOICE_GENERATED",
"channel": "EMAIL",
"subject": "Your invoice for {{periodStart}} is ready",
"bodyHtml": "<mjml>...</mjml>",
"bodyText": "Your invoice {{invoiceId}} for period {{periodStart}} - {{periodEnd}} is ready.",
"variablesSchema": {
"type": "object",
"required": ["invoiceId", "periodStart", "periodEnd", "subtotalAmount", "currency", "downloadUrl"],
"properties": {
"invoiceId": { "type": "string" },
"periodStart": { "type": "string" },
"periodEnd": { "type": "string" },
"subtotalAmount": { "type": "string" },
"currency": { "type": "string" },
"downloadUrl": { "type": "string", "format": "uri" }
}
}
}
Response 201.
PATCH /internal/templates/{id}
Updates template; increments version; previous version readable via audit log.
POST /internal/templates/{id}/preview
Body: { "variables": { ... } }.
Returns rendered HTML for email preview in admin-dashboard.
Response 200: { "html": "...", "text": "..." }.
2. Error Response Shape
{
"type": "https://errors.ghasi.io/notif/TEMPLATE_NOT_FOUND",
"title": "No active template found",
"status": 404,
"code": "TEMPLATE_NOT_FOUND",
"detail": "No active notification_templates row for type=INVOICE_GENERATED, channel=EMAIL",
"requestId": "req_01H..."
}
3. Caller Authentication (Internal)
Internal endpoints are protected by a shared X-Internal-Token header (Vault-injected into admin-dashboard). Not exposed via Kong; network policy restricts access to cluster-internal pods only.