Skip to main content

Operator Management Service — API Contracts

Status: populated Owner: Platform Engineering Last updated: 2026-04-18 Companion: APPLICATION_LOGIC · SECURITY_MODEL

1. Admin REST API (via Kong)

Base path: /v1/admin/operators Auth: Kong jwt plugin — requires scope ops:admin in JWT claims. Headers injected by Kong: X-Request-Id, traceparent, X-Admin-Id.

1.1 POST /v1/admin/operators

Create a new operator.

Request body:

{
"name": "Carrier Alpha UK",
"host": "smpp.carrier-alpha.co.uk",
"port": 2775,
"systemId": "ghasi_prod",
"systemType": "",
"bindType": "TRANSCEIVER",
"password": "s3cr3t!",
"tpsLimit": { "maxTps": 500, "burstMultiplier": 1.5, "enforcementMode": "HARD_REJECT" }
}

Note: password is write-only — never returned in responses.

Response 201:

{
"operatorId": "018f1a2b-...",
"name": "Carrier Alpha UK",
"host": "smpp.carrier-alpha.co.uk",
"port": 2775,
"systemId": "ghasi_prod",
"bindType": "TRANSCEIVER",
"tpsLimit": { "maxTps": 500, "burstMultiplier": 1.5, "enforcementMode": "HARD_REJECT" },
"status": "INACTIVE",
"healthState": "UNKNOWN",
"createdAt": "2026-04-18T10:00:00.000Z"
}

Errors:

HTTPCodeMeaning
400INVALID_PAYLOADZod schema failure
409DUPLICATE_OPERATORSame (host, port, systemId) exists
503VAULT_UNAVAILABLEVault write failed

1.2 GET /v1/admin/operators

List operators. Supports ?status=ACTIVE&page=1&limit=50.

Response 200:

{
"data": [ { "operatorId": "...", "name": "...", "status": "ACTIVE", "healthState": "HEALTHY", ... } ],
"meta": { "total": 12, "page": 1, "limit": 50 }
}

1.3 GET /v1/admin/operators/:id

Fetch single operator. Returns 404 for soft-deleted.

1.4 PATCH /v1/admin/operators/:id

Partial update. Accepts any subset of operator fields. To rotate password, include "password": "<new>".

Response 200: updated operator object (no password field).

Errors: 404, 409 (duplicate check on host/port/systemId), 503 (Vault on password rotation).

1.5 DELETE /v1/admin/operators/:id

Soft-delete. Sets deleted_at = now(), status = INACTIVE. Publishes operator.config.deleted.v1.

Response 204.

1.6 GET /v1/admin/operators/:id/routing-rules

List routing rules for operator.

1.7 POST /v1/admin/operators/:id/routing-rules

{ "prefix": "+44", "mcc": "234", "mnc": "30", "priority": 10, "weight": 100, "costPerSegment": "0.006500", "active": true }

Returns 201 with created rule. 409 on prefix overlap.

1.8 PATCH /v1/admin/operators/:id/routing-rules/:ruleId

Update rule fields.

1.9 DELETE /v1/admin/operators/:id/routing-rules/:ruleId

Hard-delete routing rule (no audit concern; operator is the aggregate boundary).

1.10 GET /v1/admin/operators/:id/health

Returns current health state + last 24h log entries.

1.11 GET /health/live, GET /health/ready, GET /metrics

Operational; not exposed via Kong.


2. Internal REST API (mTLS, no Kong route)

Base path: http://operator-management-service.svc.cluster.local:3020 Auth: mutual TLS — caller certificate must be in cluster CA bundle. No public exposure. Not in Kong config.

2.1 GET /v1/internal/operators/:id/credentials

Returns Vault-backed credentials for smpp-connector to bind.

Response 200:

{
"operatorId": "018f1a2b-...",
"host": "smpp.carrier-alpha.co.uk",
"port": 2775,
"systemId": "ghasi_prod",
"password": "s3cr3t!",
"bindType": "TRANSCEIVER",
"tpsLimit": { "maxTps": 500, "burstMultiplier": 1.5, "enforcementMode": "HARD_REJECT" }
}

Errors: 404 (operator unknown), 503 (Vault unavailable — smpp-connector falls back to in-memory cache).

2.2 GET /v1/internal/operators

Returns all active operators (without passwords) for routing-engine bootstrap.

2.3 GET /v1/internal/operators/:id/routing-rules

Returns routing rules for a single operator — used by routing-engine on cache miss.


3. Error Response Shape

{
"type": "https://errors.ghasi.io/ops/DUPLICATE_OPERATOR",
"title": "Operator already exists",
"status": 409,
"code": "DUPLICATE_OPERATOR",
"detail": "An operator with host=smpp.carrier-alpha.co.uk, port=2775, systemId=ghasi_prod already exists",
"instance": "/v1/admin/operators",
"requestId": "req_01H..."
}

4. OpenAPI

Generated from NestJS decorators into openapi.json. Admin API committed and linted in CI against Kong route config.