Matrix logo

API Server

The HTTP API server exposes REST endpoints and JSON-RPC 2.0 on a single listener. It is the primary transport for agent integration when the daemon runs as a service.

Source file: pkg/api/server.go

The HTTP API server exposes REST endpoints and JSON-RPC on a single listener. It is the primary transport for agent integration when the daemon runs as a service.


Design decisions

Single listener, dual protocol

REST and JSON-RPC share the same HTTP server. REST endpoints are at /v1/*; JSON-RPC is at /rpc. This reduces port usage and simplifies deployment.

Structured JSON everywhere

Every response is JSON. Success:

{ "ok": true, "data": { ... } }

Failure:

{ "ok": false, "error": { "code": "...", "message": "...", "retry": false } }

HTTP status codes are secondary: 200 for success, 400 for malformed requests, 401 for auth failures, 422 for semantic failures (compile error, test failure, revert). The envelope is the primary contract.

Bearer token auth

When server.auth_token (or TACHYON_AUTH_TOKEN) is configured, every request except GET /healthz and GET / requires Authorization: Bearer <token>. The comparison uses subtle.ConstantTimeCompare to prevent timing attacks.

When auth is disabled, the server logs a warning: "no auth_token set, all callers on this address can compile/deploy/sign; bind to loopback or set server.auth_token".

Route table

MethodPathHandler
GET/healthzHealth check (version, forge version, available chains, project root)
GET/Service info ({service, version, health, rpc})
POST/rpcJSON-RPC 2.0 passthrough
POST/v1/compileCompile Solidity contracts
POST/v1/testRun forge tests
POST/v1/simulateDry-run eth_call
POST/v1/deployDeploy contract (idempotent)
POST/v1/callContract call (simulate or broadcast)
GET/v1/chainsList chain profiles
POST/v1/chainsRegister custom chain
POST/v1/chains/useSet active chain
GET/v1/artifacts/{name}Get cached artifact by name
GET/v1/registry/deploymentsLookup deployment by idempotency key

Request decoding

All POST handlers use a shared decode helper:

func decode(w http.ResponseWriter, r *http.Request, v any) bool
  • Closes body via defer
  • Returns false on JSON decode error, writing a 400 envelope
  • Ignores EOF (empty body is valid for some endpoints)

Forge version probing

The server probes forge --version at startup and caches the result. This is included in the health check response so agents know the forge version available.


Server lifecycle

srv := api.New(eng, logger)
err := srv.ListenAndServe(cfg.APIAddr)  // blocks
// ... later ...
err := srv.Shutdown(ctx)  // graceful with 10s timeout

Modifying the API server

What to changeWhere
Add endpointpkg/api/server.go - register handler in New()
Change authpkg/api/server.go - authMiddleware
Add middlewarepkg/api/server.go - wrap mux in ListenAndServe
Change response formatpkg/types/types.go - Envelope[T]