Config Platform - API Contract Specification¶
Overview¶
This document provides concrete API contracts for the Config Platform REST and gRPC APIs. Use this specification to generate client code, integration adapters, and API gateway configurations.
Base URL: /api/v1
API Version: v1 (semantic versioning in x-api-version header)
Authentication: OAuth2/OIDC JWT Bearer tokens with scopes: ecs.read, ecs.write, ecs.admin
REST API Endpoints¶
Config Sets¶
Create Config Set¶
POST /api/v1/config-sets
Authorization: Bearer {token}
Idempotency-Key: {uuid}
Content-Type: application/json
{
"name": "string",
"appId": "string",
"environment": "dev|staging|prod",
"labels": ["string"],
"description": "string"
}
Response: 201 Created
{
"id": "uuid",
"name": "string",
"appId": "string",
"environment": "string",
"labels": ["string"],
"status": "draft|published",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z",
"etag": "string"
}
List Config Sets¶
GET /api/v1/config-sets?cursor={cursor}&limit=50&filter=labels:eq:production&sort=createdAt:desc
Authorization: Bearer {token}
Response: 200 OK
{
"items": [
{
"id": "uuid",
"name": "string",
"appId": "string",
"status": "string",
"etag": "string"
}
],
"nextCursor": "string",
"hasMore": true
}
Get Config Set¶
Response: 200 OK or 304 Not Modified
{
"id": "uuid",
"name": "string",
"appId": "string",
"environment": "string",
"labels": ["string"],
"status": "string",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z",
"etag": "string"
}
Config Items¶
Upsert Config Item¶
PUT /api/v1/config-sets/{setId}/items/{key}
Authorization: Bearer {token}
If-Match: {etag}
Content-Type: application/json
{
"value": "any",
"contentType": "application/json|text/plain|application/yaml",
"isSecret": false,
"labels": ["string"],
"description": "string"
}
Response: 200 OK or 201 Created
{
"key": "string",
"value": "any",
"contentType": "string",
"isSecret": false,
"labels": ["string"],
"version": 1,
"etag": "string",
"updatedAt": "2024-01-01T00:00:00Z"
}
Get Config Item¶
Response: 200 OK or 304 Not Modified
{
"key": "string",
"value": "any",
"contentType": "string",
"isSecret": false,
"version": 1,
"etag": "string"
}
Resolve Configuration¶
GET /api/v1/configs/{path}:resolve?version=latest&env=prod&service={serviceId}&instance={instanceId}
Authorization: Bearer {token}
If-None-Match: {etag}
Response: 200 OK or 304 Not Modified
{
"path": "string",
"value": "any",
"version": "string",
"etag": "string",
"resolvedAt": "2024-01-01T00:00:00Z",
"sources": [
{
"scope": "global|edition|tenant|service|instance",
"version": "string",
"key": "string"
}
]
}
Snapshots and Versions¶
Create Snapshot¶
POST /api/v1/config-sets/{setId}/snapshots
Authorization: Bearer {token}
Content-Type: application/json
{
"note": "string",
"labels": ["string"]
}
Response: 201 Created
{
"id": "uuid",
"configSetId": "uuid",
"version": "string",
"hash": "string",
"createdBy": "string",
"createdAt": "2024-01-01T00:00:00Z",
"note": "string"
}
Get Snapshot Content¶
GET /api/v1/config-sets/{setId}/snapshots/{snapId}/content?format=json|yaml
Authorization: Bearer {token}
Accept: application/json|application/yaml
Response: 200 OK
{
"version": "string",
"items": {
"key1": "value1",
"key2": "value2"
},
"metadata": {
"createdAt": "2024-01-01T00:00:00Z",
"createdBy": "string"
}
}
Compute Diff¶
POST /api/v1/config-sets/{setId}/diff
Authorization: Bearer {token}
Content-Type: application/json
{
"fromVersion": "string",
"toVersion": "string"
}
Response: 200 OK
{
"added": ["key1", "key2"],
"removed": ["key3"],
"modified": [
{
"key": "key4",
"oldValue": "old",
"newValue": "new"
}
]
}
Deployments¶
Deploy Snapshot¶
POST /api/v1/deployments
Authorization: Bearer {token}
Idempotency-Key: {uuid}
Content-Type: application/json
{
"snapshotId": "uuid",
"environment": "dev|staging|prod",
"targetLabels": ["string"]
}
Response: 202 Accepted
{
"id": "uuid",
"snapshotId": "uuid",
"environment": "string",
"status": "pending|in-progress|completed|failed",
"startedAt": "2024-01-01T00:00:00Z"
}
Policies¶
Validate Configuration¶
POST /api/v1/policies/validate
Authorization: Bearer {token}
Content-Type: application/json
{
"configSetId": "uuid",
"draft": {
"key": "value"
},
"context": {
"tenantId": "uuid",
"editionId": "string",
"environment": "string"
}
}
Response: 200 OK
{
"valid": true,
"errors": [
{
"key": "string",
"rule": "string",
"message": "string",
"severity": "error|warning"
}
],
"warnings": []
}
gRPC Services¶
ResolveService¶
Service Definition:
service ResolveService {
rpc Resolve(ConfigResolveRequest) returns (ConfigResolveResponse);
rpc ResolveStream(ConfigResolveRequest) returns (stream ConfigResolveResponse);
}
message ConfigResolveRequest {
string path = 1;
string version = 2;
string environment = 3;
string service_id = 4;
string instance_id = 5;
string etag = 6;
}
message ConfigResolveResponse {
string path = 1;
bytes value = 2;
string version = 3;
string etag = 4;
repeated ConfigSource sources = 5;
google.protobuf.Timestamp resolved_at = 6;
}
message ConfigSource {
string scope = 1;
string version = 2;
string key = 3;
}
RefreshChannel¶
Service Definition:
service RefreshChannel {
rpc Subscribe(SubscriptionRequest) returns (stream RefreshEvent);
}
message SubscriptionRequest {
string tenant_id = 1;
string config_set_id = 2;
repeated string paths = 3;
}
message RefreshEvent {
string event_id = 1;
string config_set_id = 2;
repeated string paths = 3;
string version = 4;
string etag = 5;
google.protobuf.Timestamp timestamp = 6;
}
Error Model¶
All non-2xx responses follow RFC 7807 Problem Details format:
{
"type": "https://api.connectsoft.cloud/problems/config-not-found",
"title": "Config Not Found",
"status": 404,
"detail": "Config set with id 'uuid' was not found",
"instance": "/api/v1/config-sets/uuid",
"traceId": "string",
"tenantId": "uuid",
"errors": [
{
"field": "string",
"message": "string"
}
]
}
Common Error Codes:
400- Bad Request (validation errors)401- Unauthorized (invalid/expired token)403- Forbidden (insufficient scope/tenant)404- Not Found409- Conflict (concurrency conflict, use If-Match)429- Too Many Requests (rate limited, includesRetry-Afterheader)500- Internal Server Error
Authentication and Authorization¶
JWT Token Claims¶
Required claims:
- aud: Audience (ecs.api, ecs.admin)
- sub: Subject (user/service ID)
- tenant_id: Tenant identifier
- scope: Space-separated scopes (ecs.read, ecs.write, ecs.admin)
- exp: Expiration timestamp
Scope Permissions¶
| Scope | Permissions |
|---|---|
ecs.read |
Read config sets, items, snapshots, resolve |
ecs.write |
Create/update/delete config sets and items |
ecs.admin |
All permissions + cross-tenant operations |
Rate Limiting¶
Rate limits are tenant-scoped and edition-aware:
- Free Edition: 100 requests/minute
- Pro Edition: 1000 requests/minute
- Enterprise Edition: 10000 requests/minute
Rate limit headers:
- X-RateLimit-Limit: Request limit per window
- X-RateLimit-Remaining: Remaining requests
- X-RateLimit-Reset: Reset timestamp
- Retry-After: Seconds to wait (on 429)
Idempotency¶
POST endpoints that create resources support idempotency via Idempotency-Key header:
Duplicate requests with the same key return the original response without side effects.
ETags and Conditional Requests¶
Resources include ETag header for optimistic concurrency:
If-None-Match: {etag}- Return 304 if unchangedIf-Match: {etag}- Require current etag for updates
Pagination¶
List endpoints use cursor-based pagination:
Response includes nextCursor and hasMore fields.
Filtering and Sorting¶
Filtering uses query parameters:
filter=labels:eq:production- Equality filterfilter=createdAt:gte:2024-01-01- Range filtersort=createdAt:desc- Sort order
References¶
- Solution Architecture - Detailed API design
- Integration Patterns - SDK usage patterns
- Domain Model Schema - Data model details