FarcasterGateway

Farcaster Observability

Every call already left a record.

The proxy captures as it forwards — status, mode, timing, sizes, upstream status. This surface is the read layer over data the gateway was writing anyway: list it, inspect one, or aggregate it, without standing up anything else to hold it.

shipped Apache-2.0 /v1/invocations

Reading it back

Filter first, then open one.

The list endpoint is tenant-scoped, paginated, and filterable by agent, status, mode, error class, model, settlement, and an RFC 3339 time window. It answers "what went wrong last night" without you fetching everything and grepping.

The failures, last 20

$ curl localhost:8080/v1/invocations\
?agent_id={id}&status=failed&limit=20

← bodies are never returned on the
  list endpoint, at any scope

One record, in full

$ curl localhost:8080/v1/invocations/{id}
{
  "status": "failed",
  "error_class": "upstream_5xx",
  "mode": "streaming",
  "ttft_ms": null,
  "body_captured": false
}

The mechanic

Bodies take two keys, not one.

Request and response bodies are the most sensitive thing the gateway touches, so reading them requires two independent decisions made by two different people — and neither one alone is enough.

Key What it is Held by
Capture An agent-level toggle, off by default — if it was off, there is nothing to read Whoever configures the agent
Scope The invocations:read_body OAuth scope. Metadata reads don't need it Whoever issues the token

body_captured tells you the truth either way. It reflects whether capture was on for that invocation regardless of whether you can read the bodies — so an auditor can tell "nothing was recorded" apart from "something was recorded and you can't see it," which are very different answers. When bodies are returned they're base64-encoded and capped at 1 MiB.

Three fields

The ones that aren't obvious.

Status, latency and sizes are table stakes. These three carry the decisions.

Field What it holds The catch
ttft_ms Time to first byte on the streaming path null for transactional calls, or when no bytes ever streamed
error_class A coarse taxonomy: timeout, upstream_5xx, upstream_4xx, ssrf_blocked, credential_error, cancelled, internal null on success. Coarse on purpose — it's for grouping, not for forensics
model Whatever the caller sent in X-Farcaster-Model Caller-supplied only. Farcaster proxies arbitrary upstreams, not a known LLM wire format, so it will not read your bodies to guess. MCP is the one exception, because its envelope is a published shape

Aggregates

Percentiles, with the guardrails showing.

Group by agent and bucket by hour or day, and get count, error rate, a breakdown by error class, and p50/p95/p99 for both latency and time-to-first-byte. The limits below are deliberate, and the endpoint says so rather than degrading quietly.

$ curl localhost:8080/v1/analytics\
?group_by=agent_id&bucket=day&since=2026-07-01T00:00:00Z
Rule What happens Why
since is required An unbounded query is 400 There is no default window — a query nobody bounded is a query nobody meant
The window caps at 31 days Wider is 400 Percentile aggregation over an unbounded range is how a read endpoint takes down a write path
Its own rate limit 429 here only Tighter than the general /v1 limiter, and separate — being throttled here doesn't mean the rest of the API is
An empty window 200 with an empty groups array Not 404. "Nothing happened" is a valid answer, not a missing resource
In-flight calls Counted, but excluded from percentiles A call that hasn't finished has no latency yet, and pretending otherwise would drag every p50 down

Every query filters by tenant first. An invocation ID belonging to another tenant returns 404, never 403, and the analytics endpoint only ever aggregates your own tenant's calls.

Where the line falls

The capture is free. The dashboard is the product.

Raw invocation and payment capture, readable over the API, is Apache-2.0 — the data is yours and it never leaves your database. What we sell is what a finance team wants done with it.

Capability Tier
Raw invocation and payment capture, readable over the API OSS
Aggregate analytics — counts, error rates, latency and TTFT percentiles OSS
Usage and revenue dashboard, quotas, spend limits, invoicing Commercial

One gap, stated plainly: there is no OTLP / OpenTelemetry export yet. Metrics are read from the gateway's own API today, not pushed to Datadog or Grafana. That's a deliberate phase-two deferral rather than a disagreement about whether it matters — if you're already standardised on OTel, ask us where it is before you build on this.

The full boundary →

Next

You can see every call. Now charge for one.

The last surface is the one that turns a record of what happened into a reason it was allowed to happen at all.