Mesh API#
The asya-mesh-api binary serves the /api/v1/mesh/ HTTP API for envelope
lifecycle management. It replaces the legacy mode=mesh gateway deployment
with a dedicated microservice.
Source: src/asya-gateway/cmd/mesh-api/
Architecture#
Two-port HTTP server:
- External port (default 8080): client-facing CRUD + SSE
- Internal port (default 8081): sidecar event publishing + heartbeat
Persistence is delegated to a pg-kv sidecar over Unix socket. The mesh-api binary never connects to PostgreSQL directly.
Route Map#
External (port 8080)#
| Method | Path | Auth | Caller | Description |
|---|---|---|---|---|
POST |
{prefix}/mesh/ |
Network isolation | Protocol adapters, sidecars | Create envelope |
GET |
{prefix}/mesh/ |
Network isolation | Protocol adapters, operators | List envelopes |
GET |
{prefix}/mesh/{id} |
Network isolation | Protocol adapters, operators | Get envelope |
GET |
{prefix}/mesh/{id}/events |
Network isolation | Protocol adapters, SSE clients | SSE event stream |
DELETE |
{prefix}/mesh/{id} |
Network isolation | Protocol adapters | Cancel envelope |
GET |
/health |
Public | K8s probes | Health check |
Internal (port 8081)#
| Method | Path | Auth | Caller | Description |
|---|---|---|---|---|
POST |
{prefix}/mesh/{id}/events |
Network isolation | Sidecar | Publish status/FLY event |
GET |
{prefix}/mesh/{id} |
Network isolation | Sidecar | Heartbeat check |
GET |
/health |
Public | K8s probes | Health check |
Default prefix: /api/v1 (configurable via ASYA_MESH_API_PREFIX).
External API#
POST {prefix}/mesh/?actor={name}#
Create an envelope and dispatch to the actor's queue.
Query parameters:
| Param | Required | Description |
|---|---|---|
actor |
Yes | Target actor queue name |
namespace |
No | Namespace override (defaults to ASYA_NAMESPACE) |
Request application/json:
{
"payload": { "query": "Hello" },
"headers": { "trace_id": "abc" },
"timeout": 300
}
All fields are optional. timeout is in seconds; when set, a deadline_at
timestamp is computed and stored.
Response 201 application/json:
{ "id": "550e8400-e29b-41d4-a716-446655440000" }
The envelope is stamped with x-asya-gateway-url in headers before dispatch.
GET {prefix}/mesh/#
List envelopes with optional filtering and pagination.
Query parameters:
| Param | Default | Description |
|---|---|---|
status |
(all) | Filter by status (pending, running, succeeded, failed, canceled) |
limit |
(none) | Max results |
offset |
0 |
Pagination offset |
Response 200 application/json:
{
"messages": [
{
"id": "...",
"status": "running",
"created_at": "2026-04-17T...",
"updated_at": "2026-04-17T...",
"data": { ... }
}
],
"total": 42
}
Default sort: -created_at (newest first).
GET {prefix}/mesh/{id}#
Get a single envelope.
Response 200 application/json: same shape as list items.
Errors: 404 if not found.
GET {prefix}/mesh/{id}/events#
SSE stream of envelope lifecycle events.
Headers: Content-Type: text/event-stream, Cache-Control: no-cache
Behavior:
- Returns current status as first event (catch-up)
- If already terminal, sends one event and closes
- Otherwise, streams live events until terminal or client disconnect
- Sends
:keepalivecomment every 15 seconds
SSE format:
event: status
data: {"status":"running","actor":"train-model","progress":50.0}
event: fly
data: {"text":"token..."}
event: status
data: {"status":"succeeded"}
DELETE {prefix}/mesh/{id}#
Cancel an envelope. Idempotent — returns 204 even if already terminal.
Response: 204 No Content
Errors: 404 if not found.
Internal API#
POST {prefix}/mesh/{id}/events#
Publish a lifecycle event from a sidecar. This single endpoint replaces the
legacy gateway's separate /mesh/{id}/progress, /mesh/{id}/final, and
/mesh/{id}/fly endpoints.
Request application/json — status event:
{
"type": "status",
"status": "running",
"data": { "actor": "train-model", "progress": 50 }
}
Request application/json — FLY event:
{
"type": "fly",
"data": { "text": "streaming token..." }
}
Response: 204 No Content
Behavior:
- Status events update the store with monotonic ordering enforcement.
A stale update (e.g.
runningaftersucceeded) is silently ignored (204). - FLY events are ephemeral — published to SSE subscribers but never written to the store.
Errors: 404 if envelope not found. 400 for invalid JSON.
GET {prefix}/mesh/{id}#
Same as external GET. Used by sidecars for heartbeat/liveness checks.
Status Model#
Monotonic ordering — once a status is set, only higher-order statuses can overwrite it:
pending (0) → running (1) → paused (2) → succeeded|failed|canceled (3)
Terminal states (succeeded, failed, canceled) have equal order and
cannot overwrite each other.
Breaking Changes from Legacy Gateway Mesh Routes#
This API replaces the mode=mesh deployment of asya-gateway. The old
routes are deprecated. See gateway-api.md § Mesh Routes.
| Old Route | New Route | Notes |
|---|---|---|
POST /mesh |
POST {prefix}/mesh/ |
Path changed; request body differs |
GET /mesh/{id} |
GET {prefix}/mesh/{id} |
Compatible (response shape differs) |
GET /mesh/{id}/stream |
GET {prefix}/mesh/{id}/events |
Renamed; SSE format changed |
GET /mesh/{id}/active |
(removed) | Use GET to check status instead |
POST /mesh/{id}/progress |
POST {prefix}/mesh/{id}/events |
Unified into events POST with type: "status" |
POST /mesh/{id}/final |
POST {prefix}/mesh/{id}/events |
Unified into events POST with terminal status |
POST /mesh/{id}/fly |
POST {prefix}/mesh/{id}/events |
Unified into events POST with type: "fly" |
POST /mesh/config-reload |
(removed) | Config is static in mesh-api |
New endpoints (no legacy equivalent):
| Route | Description |
|---|---|
GET {prefix}/mesh/ |
List envelopes with filtering/pagination |
DELETE {prefix}/mesh/{id} |
Cancel an envelope |
Migration#
To restore backward-compatible routes, set ASYA_MESH_API_PREFIX="" which
produces /mesh/ paths. The SSE endpoint is still renamed (/events not
/stream) and the unified events POST replaces the three separate endpoints.