API and agents
API overview
The Mesh API is a versioned REST/JSON API for CI pipelines, scripts, and AI agents. Everything the console does with projects, services, deployments, domains, volumes, logs, usage, and billing, the API does too.
Base URL
The API lives at the same origin as the console: add /v1 paths to the
address you sign in to. The console shows it on the API tokens page.
This guide uses https://mesh.example.com.
export MESH_API=https://mesh.example.com
export MESH_TOKEN=wgm_...
curl $MESH_API/v1/token -H "Authorization: Bearer $MESH_TOKEN"Every path starts with /v1. The API reference lists
every endpoint, and GET /v1/openapi.json returns the OpenAPI 3.1 document
with every request and response schema.
Authentication
Send an API token as a bearer token. The token acts as the person who created it: workspace roles apply on every call, exactly as in the console, and its scope narrows what it may touch.
Requests and responses
Bodies are JSON with snake_case field names. 64-bit integers, such as
size_bytes, are strings. Enum values are their full names, such as
DEPLOYMENT_STATE_ACTIVE.
curl -X POST $MESH_API/v1/projects \
-H "Authorization: Bearer $MESH_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "storefront"}'Staged changes
Creating or updating a service, or creating a volume, changes the service's draft. Nothing runs until you release the environment:
curl -X POST $MESH_API/v1/environments/$ENVIRONMENT_ID/releases \
-H "Authorization: Bearer $MESH_TOKEN"Service.pending_changes and unapplied_changes report what waits. See
Deployments and releases.
Updating a service replaces its whole draft and needs the current
expected_spec_revision, so two clients cannot overwrite each other's
changes. Read the service, change the spec, and send it back.
Deletes
Deletes are restorable during the grace period with POST …/restore.
Workspaces, projects, production environments, and volumes need
confirmation_name set to the resource's name. GET …/deletion-preview shows
what a delete would take with it. See Deleting and restoring.
Errors
Every error has the same shape, and every response carries an
X-Request-Id header. Quote it when you ask for help.
{
"error": {
"code": "not_found",
"message": "service not found",
"request_id": "6f1c2b0e-…"
}
}| Code | HTTP status | Meaning |
|---|---|---|
invalid_argument | 400 | The request is malformed or a value is out of range. |
unauthenticated | 401 | The token is missing, expired, or revoked. |
permission_denied | 403 | The token's scope, access, or your role does not allow this. |
not_found | 404 | The resource does not exist, or you cannot see it. |
conflict, failed_precondition | 409 | The resource changed, or its state does not allow this now. |
rate_limited | 429 | Slow down; see Retry-After. |
unavailable | 503 | Try again shortly. |
deadline_exceeded | 504 | The operation took too long. |
internal | 500 | Something failed on our side. |
A resource in another workspace looks the same as a missing one.
Retries
Reads are always safe to retry. Retry a write only when no response arrived.
Deployment actions accept an idempotency_key, so repeating the same request
never runs the action twice.
Rate limits
Each token may make 10,000 requests per hour, with bursts of up to 50 per
second. Responses carry X-RateLimit-Limit, X-RateLimit-Remaining, and
X-RateLimit-Reset; a 429 adds Retry-After. Your operator can change the
limits.
Versioning
/v1 is a stable contract. New endpoints and new optional fields arrive in
v1; a breaking change would get a new version prefix.