SMLL Docs

API Overview

The SMLL REST API - base URL, authentication, resource hierarchy, errors and rate limits.

Everything the dashboard and the CLI do, they do by calling the SMLL REST API. The same API is available to you, so anything you can click you can also script.

The base URL is:

https://api.smll.io

All authenticated endpoints live under /api/v1.

Quick start

Create an API key from Settings > API Keys (or smll api-keys create), then:

export SMLL_API_KEY=sk-...
AUTH="Authorization: Bearer $SMLL_API_KEY"

# Who am I?
curl -s -H "$AUTH" https://api.smll.io/api/v1/me

# What can I reach?
curl -s -H "$AUTH" https://api.smll.io/api/v1/workspaces

Resource hierarchy

Almost every endpoint is addressed by where the resource lives, not by ID alone. Resources nest three levels deep:

workspace                                  billing, quotas, members, API keys
└── VPC                                     an isolated network + namespace
    ├── services                            containers you deploy
    ├── databases                           PostgreSQL and MySQL
    ├── caches                              Redis-compatible
    ├── queues                              NATS
    ├── buckets                             S3-compatible object storage
    ├── secrets                             shared config
    └── registry                            private container images

That shape shows up directly in the paths:

/api/v1/workspaces/{workspaceID}/vpcs/{vpcID}/services/{serviceID}

So most calls need a workspace ID and a VPC ID before the resource ID. You can list your way down from /api/v1/workspaces, or read the IDs out of the dashboard URL. The CLI stores them for you after smll context set.

A VPC is scoped to one region. There is no cross-region endpoint: to work in two regions, create a VPC in each.

Authentication

Every request under /api/v1 needs a bearer token:

Authorization: Bearer <token>

Three kinds of token are accepted, and they are interchangeable at the endpoint level:

TokenLooks likeUsed by
API keysk- + 64 hex charsScripts, CI, integrations
CLI session tokenhex stringsmll login
Supabase JWTthree dot-separated partsThe dashboard

For anything automated, use an API key. See Authentication for creating, scoping, and revoking them.

Permissions

Requests are authorised against your role in the workspace that owns the resource:

RoleReadCreate, update, delete
OwnerYesYes
AdminYesYes
DeveloperYesNo
ViewerYesNo

Read endpoints accept any member of the workspace. Most write endpoints require Owner or Admin, and return 403 insufficient workspace permissions otherwise. The per-endpoint tables in this section mark the ones that need it.

An API key carries the role of the user who created it, so a key made by a Developer cannot deploy.

Requesting a VPC that belongs to a different workspace returns 403, even if you are a member of both. The VPC ID and the workspace ID in the path have to agree.

Requests

Send JSON, and say so:

Content-Type: application/json

Request bodies are capped at 1 MB. Uploads that exceed that (source archives, objects) go through their own endpoints, which hand back a presigned URL you upload to directly.

Unknown fields in a body are ignored rather than rejected.

Responses

Successful responses are JSON. List endpoints return a bare array:

[
  { "id": "3f9c...", "name": "api", "status": "running" },
  { "id": "7a21...", "name": "worker", "status": "running" }
]

Single resources return an object. Deletes usually return {"status":"deleted"} or 204.

Most list endpoints return the whole collection, because these collections are naturally small (the resources in one VPC). The few that can grow without bound - logs, builds, deployments, transactions, slow queries - accept a limit query parameter.

Timestamps are RFC 3339 in UTC (2026-08-20T18:57:21Z). IDs are UUIDs. Money is GBP, as a decimal number.

Errors

Errors carry a non-2xx status and a JSON body with one key:

{ "error": "insufficient workspace permissions" }
StatusMeaning
400Malformed body, or a missing or invalid field
401Missing, invalid, expired or revoked token
403Authenticated, but not allowed - wrong role, or resource in another workspace
404No such resource, or it is soft-deleted
409Name already in use in this VPC
429Rate limited
503The underlying infrastructure is unavailable

503 infrastructure is unavailable means the platform could not reach Kubernetes. Creates fail closed on purpose: no record is written for a resource that could not be built, so a retry is safe and will not leave a duplicate behind.

Rate limits

The general limit on /api/v1 is 100 requests per minute, applied per client IP, with a burst of 100. Some endpoints are tighter: the public blog API allows 30 per minute, and webhooks 30 per minute.

Exceeding it returns 429 with a Retry-After header giving the seconds to wait.

There is no rate limit header on successful responses, so treat 429 plus Retry-After as the signal and back off from there.

Versioning

The version lives in the path (/api/v1). Fields are added to responses over time, so parse leniently and ignore what you do not recognise. Removals and behaviour changes get a new version.

Next steps

On this page