API and CLI
The CLI, authentication, the error shape every endpoint shares, and how requests are rate limited.
Authentication
Two credentials reach /api/v1: your session’s access token (Authorization: Bearer), which is what the composer itself uses and the only credential that can manage tenant membership or API keys, and a tenant API key (X-API-Key), meant for a script, a CI job or the CLI. Neither can issue the other — an API key is API-first access to a single tenant, nothing more.
CLI
A single Rust binary, built with cargo build --release from the cli package in the repo — no runtime to install on a CI image or a laptop. It talks to /api/v1 over the same contract as any other client.
swifttune flows list
swifttune deploy FLOW_ID --version VERSION_ID
swifttune rollback DEPLOYMENT_ID
swifttune evals run --version VERSION_ID --suite flow-structure-v1
swifttune evals list --version VERSION_IDA tenant API key (--api-key or SWIFTTUNE_API_KEY) authenticates every command except deploy, which takes a user access token (--token or SWIFTTUNE_ACCESS_TOKEN) instead: a deployment is attributed to the person who triggered it, and an API key names a tenant, never a person. Add --json to any command for a scriptable response.
Errors
Every error response shares one shape, whatever endpoint produced it, so a client writes one handler instead of one per route.
{
"error": {
"code": "ERR_VALIDATION_FAILED",
"message": "Human-readable message for the user",
"field": "name",
"details": {}
}
}400— the request body failed validation.401— no access token or API key, or it did not verify.403— authenticated, but not a member of the tenant the resource belongs to.404— not found, including a resource that belongs to another tenant.409— the resource is in a state the request conflicts with.422— well-formed but not processable, such as a flow graph with a cycle.429— rate limited; see rate limits below.
Rate limits
A deployed flow’s own endpoint is rate limited per tenant, separately from /api/v1. A limited request answers 429 with X-RateLimit-* and Retry-After headers and a JSON body naming the tier that would raise the ceiling.
{
"error": "rate_limited",
"message": "Too many requests for this deployment",
"upgrade": "https://swifttune.ai/pricing?utm_source=rate_limit"
}Current limits and usage for the management API are on GET /api/v1/quota; the per-tier ceilings are on Pricing.