Config
Remote configuration is the core feature of SkyState. Each project has independent configuration per environment. Every change creates a new immutable version identified by a semantic version string (major.minor.patch).
There are three distinct config endpoint groups:
- Public (
/public/...) — anonymous reads, used by SDKs and client apps - Dev (
/dev/...) — SDK writes to the development environment, authenticated with a Dev API Key - Admin (
/admin/...) — full management via JWT Bearer token
Object: ProjectConfig
{
"remoteConfigId": "550e8400-e29b-41d4-a716-446655440000",
"projectId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"environment": "production",
"major": 1,
"minor": 2,
"patch": 3,
"state": "{\"featureEnabled\":true,\"maxUploadMb\":10}",
"comment": "Enable upload feature",
"createdAt": "2025-01-15T10:30:00.000Z",
"stateSizeBytes": 48
}| Field | Type | Description |
|---|---|---|
remoteConfigId | UUID | Unique version ID |
projectId | UUID | Owning project |
environment | string | development, staging, or production |
major | integer | Semantic version major component |
minor | integer | Semantic version minor component |
patch | integer | Semantic version patch component |
state | string | JSON-encoded configuration object |
comment | string or null | Optional description of the change |
createdAt | ISO 8601 datetime | When this version was created |
stateSizeBytes | integer | Byte size of the serialized state |
Public Config Endpoints
Read Latest Config (Anonymous)
The primary SDK endpoint. Returns the latest published configuration for a project environment with no authentication required.
GET /api/public/{accountSlug}/{projectSlug}/config/{envSlug}Auth: None
Path parameters:
| Parameter | Pattern | Description |
|---|---|---|
accountSlug | ^[a-z0-9][a-z0-9-]*[a-z0-9]$ | Account slug |
projectSlug | ^[a-z0-9][a-z0-9-]*[a-z0-9]$ | Project slug |
envSlug | development, staging, or production | Environment name |
Response: 200 OK
{
"version": "1.2.3",
"lastModified": "2025-01-15T10:30:00.000Z",
"config": {
"featureEnabled": true,
"maxUploadMb": 10
}
}The config field is the deserialized JSON object stored in the config version's state field.
Response headers on 200:
| Header | Description |
|---|---|
Cache-Control | public, max-age=<N> — varies by tier and environment (see below) |
X-RateLimit-Limit | Monthly request limit (omitted if unlimited) |
X-RateLimit-Remaining | Remaining requests this month |
X-RateLimit-Reset | Unix timestamp of next monthly reset |
X-RateLimit-Warning | Present if usage is between 100% and 110% of limit |
Cache-Control max-age by tier and environment:
| Tier | development | staging | production |
|---|---|---|---|
free | 10s | — | 900s |
hobby | 10s | 10s | 300s |
pro | 10s | 10s | 60s |
Responses:
| Status | Description |
|---|---|
200 | Config found |
400 | Invalid slug format |
404 | Project, account, or environment not found |
429 | Monthly rate limit exceeded — see Rate Limiting |
Example:
curl https://app.skystate.io/api/public/acme/my-app/config/productionAdmin Config Endpoints
All admin config endpoints require Authorization: Bearer <token>.
Get Config Version by ID
GET /api/admin/config/{remoteConfigId}Path parameters:
| Parameter | Type | Description |
|---|---|---|
remoteConfigId | UUID | Config version ID |
Responses:
| Status | Description |
|---|---|
200 | Returns ProjectConfig object |
404 | Config not found |
Example:
curl https://app.skystate.io/api/admin/config/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer <token>"List Config Versions for an Environment
Returns all versions for the given project and environment, ordered by version descending.
GET /api/admin/{projectId}/config/{envSlug}Path parameters:
| Parameter | Type | Description |
|---|---|---|
projectId | UUID | Project ID |
envSlug | string | development, staging, or production |
Response: 200 OK — array of ProjectConfig objects.
Example:
curl https://app.skystate.io/api/admin/7c9e6679-7425-40de-944b-e07fc1f90ae7/config/production \
-H "Authorization: Bearer <token>"Get Latest Config Version
Returns the most recent version for the given project and environment.
GET /api/admin/{projectId}/config/{envSlug}/latestResponses:
| Status | Description |
|---|---|
200 | Returns ProjectConfig object |
404 | No config exists yet |
Example:
curl https://app.skystate.io/api/admin/7c9e6679-7425-40de-944b-e07fc1f90ae7/config/production/latest \
-H "Authorization: Bearer <token>"Create Config Version (Full Replace)
Creates a new config version with explicitly specified version numbers and state.
PUT /api/admin/{projectId}/config/{envSlug}Request body:
{
"major": 1,
"minor": 2,
"patch": 3,
"state": "{\"featureEnabled\":true}",
"comment": "Enable feature"
}| Field | Type | Required | Description |
|---|---|---|---|
major | integer | Yes | Semantic version major |
minor | integer | Yes | Semantic version minor |
patch | integer | Yes | Semantic version patch |
state | string | Yes | JSON-encoded configuration object |
comment | string | No | Description of this change |
Responses:
| Status | Body | Description |
|---|---|---|
201 | { "remoteConfigId": "<uuid>" } | Config version created |
400 | Error | Validation error |
402 | LimitResponse | Storage limit exceeded for tier |
404 | Error | Project or environment not found |
Example:
curl -X PUT https://app.skystate.io/api/admin/7c9e6679-7425-40de-944b-e07fc1f90ae7/config/production \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"major":1,"minor":2,"patch":3,"state":"{\"featureEnabled\":true}","comment":"Enable feature"}'Patch Config (JSON Patch, optimistic concurrency)
Applies RFC 6902 JSON Patch operations to the latest config version. The If-Match header is required and must contain the current version string. If the version has changed since your last read, the server returns 409 Conflict.
PATCH /api/admin/{projectId}/config/{envSlug}Required header:
If-Match: "1.2.3"The value must be the exact version string from your last read, including the quotes. Wildcards (If-Match: *) are not accepted.
Request body: Array of JSON Patch operations.
[
{ "op": "replace", "path": "/featureEnabled", "value": true },
{ "op": "add", "path": "/newKey", "value": "hello" },
{ "op": "remove", "path": "/oldKey" }
]| Field | Type | Allowed values |
|---|---|---|
op | string | add, remove, replace |
path | string | JSON Pointer (RFC 6901), e.g. /featureEnabled |
value | any | Required for add and replace |
Responses:
| Status | Body | Description |
|---|---|---|
201 | { "remoteConfigId": "<uuid>", "version": "1.2.4" } | Patch applied, new version created |
400 | Error | Missing or invalid If-Match, or invalid patch operations |
402 | LimitResponse | Storage limit exceeded |
404 | Error | Project or environment not found |
409 | ConflictResponse | Version conflict — another write occurred since your read |
Response headers on 201:
| Header | Description |
|---|---|
ETag | New version string, e.g. "1.2.4" |
ConflictResponse (409):
{
"code": "VERSION_CONFLICT",
"message": "The config has been modified since your last read.",
"currentVersion": "1.2.5"
}Use the currentVersion to fetch the latest state and retry your patch.
Example:
curl -X PATCH https://app.skystate.io/api/admin/7c9e6679-7425-40de-944b-e07fc1f90ae7/config/production \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-H 'If-Match: "1.2.3"' \
-d '[{"op":"replace","path":"/featureEnabled","value":true}]'Rollback to a Previous Version
Creates a new config version whose state is a copy of the target historical version. The rollback itself is stored as a new version with an incremented version number.
POST /api/admin/{projectId}/config/{envSlug}/rollback/{targetId}Path parameters:
| Parameter | Type | Description |
|---|---|---|
projectId | UUID | Project ID |
envSlug | string | Environment name |
targetId | UUID | remoteConfigId of the version to restore |
Responses:
| Status | Body | Description |
|---|---|---|
201 | { "remoteConfigId": "<uuid>" } | Rollback created as new version |
402 | LimitResponse | Storage limit exceeded |
404 | Error | Target version not found |
Example:
curl -X POST https://app.skystate.io/api/admin/7c9e6679-7425-40de-944b-e07fc1f90ae7/config/production/rollback/aabb1234-... \
-H "Authorization: Bearer <token>"Dev Config Endpoint
The dev endpoint is used by the SDK during local development. It authenticates with a Dev API Key rather than a Bearer token and is restricted to the development environment.
Patch Config via Dev API Key
PATCH /api/dev/{accountSlug}/{projectSlug}/config/{envSlug}Auth: Authorization: DevKey <key>
The environment must be development. Any other value returns 403 Forbidden.
Required header:
If-Match: "1.2.3"Request body: Same array of JSON Patch operations as the admin PATCH endpoint.
Responses:
| Status | Body | Description |
|---|---|---|
201 | { "remoteConfigId": "<uuid>", "version": "1.2.4" } | Patch applied |
400 | Error | Missing or invalid If-Match, or invalid patch |
402 | LimitResponse | Storage limit exceeded |
403 | Error | Not the development environment, or no dev key claim |
404 | Error | Project or environment not found |
409 | ConflictResponse | Version conflict |
Example:
curl -X PATCH https://app.skystate.io/api/dev/acme/my-app/config/development \
-H "Authorization: DevKey sk_dev_abc123..." \
-H "Content-Type: application/json" \
-H 'If-Match: "1.0.0"' \
-d '[{"op":"replace","path":"/debugMode","value":true}]'Versioning
Config versions use three-component semantic versioning: major.minor.patch.
- The CLI and dashboard increment the appropriate component when pushing via
PUT. PATCHoperations auto-incrementpatchunless a version conflict is detected.- Rollbacks create a new version with a new ID — the historical record is never mutated.
- The
versionfield on the public config response is formatted as"major.minor.patch"(e.g."1.2.3").