Skip to main content

HTTP API

Available

Deployed and supported. The fields and commands described here are stable within version v1alpha1.

The StackNGO API is a JSON REST API. The sng CLI and the console use it exclusively: everything they do, you can do with curl or a client generated from the OpenAPI specification.

Address and version​

Base URLhttps://api.dev.stackngo.fr/v1
OpenAPI 3.1 specificationhttps://api.dev.stackngo.fr/v1/openapi.yaml (public, no authentication)
VersionEverything is prefixed with /v1. There is no version header.
HealthGET /healthz (process alive), GET /readyz (dependencies ready), outside /v1 and without authentication

The routes are documented one by one in Endpoints, generated from the specification. Each route states the IAM action it requires (deploy:write, ssm:read, …): this is what a policy must grant for the route to respond with anything other than 403.

Two-step authentication​

  1. Obtain an identity token (OIDC, from https://auth.dev.stackngo.app).
  2. Exchange it for a tenant session with POST /v1/iam/session.
  3. Send the session in Authorization: Bearer <session> on all of the tenant's routes.

Details, with curl examples, are in Authentication. A single token per request; the X-Tenant-Token header is refused (400) on every /v1 route, session opening included: the tenant session is enough.

Request conventions​

  • JSON body: Content-Type: application/json is required on POST, PUT, and PATCH requests that carry a body. Otherwise 415.
  • Unknown fields refused: a field not provided for in the body yields 400. The OpenAPI schemas are therefore exhaustive.
  • Size: a body is limited to 1 MB.
  • Names in the path: resource names ({name}, {tenant}) are lowercase DNS labels. The tenant of a request always comes from the session, never from the path or a header; on the /v1/tenants/{tenant}/… routes, {tenant} must be the session's.

Response conventions​

  • Content-Type: application/json.
  • Lists return an object that wraps the array, named after the resource: {"secrets": […]}, {"apps": […]}, {"items": […]}. There is no pagination: lists are complete.
  • Creations respond 201, deletions 204 without a body, everything else 200.
  • Errors all have the form {"error": "message"}, 415 and 429 included. See Errors.
  • Retry-After accompanies 409 policies_pending responses (tenant just created) and 429s.

Limits and timeouts​

300 requests per minute per IP address on the /v1 routes; server timeouts of 30 s for reading and 60 s for writing. Details and advice in Limits.

Idempotency​

  • PUT /v1/secrets/{name} and PUT /v1/iam/policies/{name} create or replace: replaying the same request gives the same state.
  • POST /v1/apply then POST /v1/apply/complete are designed to be replayed: an identical manifest is marked unchanged.
  • Action POSTs (/scale, /restart, /rotate) are not idempotent.

Generate a client​

curl -fsSL https://api.dev.stackngo.fr/v1/openapi.yaml -o openapi.yaml
npx openapi-typescript openapi.yaml -o stackngo.d.ts # TypeScript
go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest -package stackngo openapi.yaml # Go

The StackNGO console is itself generated from this file.

Complete example​

# 1. Identity (here: a token already obtained by the CLI)
ID_TOKEN=$(yq '.access_token' ~/.config/stackngo/config.yaml)

# 2. Tenant session
SESSION=$(curl -fsS https://api.dev.stackngo.fr/v1/iam/session \
-H "Authorization: Bearer $ID_TOKEN" -H 'Content-Type: application/json' \
-d '{"tenant":"acme"}' | jq -r .access_token)

# 3. A tenant route
curl -fsS https://api.dev.stackngo.fr/v1/secrets -H "Authorization: Bearer $SESSION"
{"secrets":[{"name":"db-password","version_id":"3","version_stages":{"current":"3"},"updated_at":"2026-10-01T09:12:44Z"}]}