> ## Documentation Index
> Fetch the complete documentation index at: https://manifest.build/llm-gateway/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Observability

> Track cost, latency, models, providers, and failures across requests and provider attempts.

<div className="deploy-mode-toggle" role="group" aria-label="Deployment mode">
  <button type="button" data-deploy-mode="cloud">Cloud</button>
  <button type="button" data-deploy-mode="selfhosted">Self-hosted</button>
</div>

Every request through the gateway is recorded: which model served it, what it cost, how long it took, and what failed. The dashboard is built on that record, and you can query the same numbers from your own code.

## Requests and provider attempts

The gateway tracks two things, and the difference matters once fallback is involved:

| | What it is | When you get more than one |
| - | - | - |
| **Request** | One call from your agent to the gateway | Never. One call in, one Request. |
| **Provider attempt** | One call from the gateway to a provider | Every fallback step and every [Autofix](/llm-gateway/docs/llm-gateway/docs/autofix) retry adds another |

A request that succeeds on the first try is one Request with one attempt. A request that fails twice before succeeding is still one Request, with three attempts. A request blocked by the gateway, like a [hard limit](/llm-gateway/docs/llm-gateway/docs/llm-gateway#hard-limits) or a malformed body, is one Request with one attempt that never reached a provider. That attempt is listed under the model you asked for, or **No provider** when the request named none, and carries the error that stopped it.

This is why the request count and the provider call count don't match, and why cost is attributed to attempts: a failed attempt can still burn tokens.

## The dashboard

<CardGroup cols={2}>
  <Card title="Overview" icon="layout-dashboard">
    Spend, tokens, and request volume over time, across all harnesses or one. Includes the provider and model mix.
  </Card>

  <Card title="Requests" icon="list">
    The full log, newest first. Filter it, then open any row for the request body, every provider attempt, and the routing decision.
  </Card>

  <Card title="Providers" icon="layers">
    Per-provider usage, spend, and error rates. Useful for spotting one provider degrading.
  </Card>

  <Card title="Limits" icon="shield-alert">
    Threshold rules per harness, plus email provider setup.
  </Card>
</CardGroup>

<div data-deploy="cloud">
  On the Free plan, the Overview covers up to 7 days of history; the 30-, 90-, and 365-day ranges need Pro.
</div>

### What's on each request

Opening a request in the log shows the whole story: the tier that routed it, the model and provider that served it, input and output tokens, computed cost, latency, the auth type used ([API key, subscription, or local](/llm-gateway/docs/llm-gateway/docs/reference/glossary#auth-type)), and every fallback hop with its own status. Failures carry an error code, so a gateway rejection like [M100](/llm-gateway/docs/llm-gateway/docs/errors/M100) reads differently from a provider's own 500.

That's all metadata. To read the messages themselves, turn on [request logs](/llm-gateway/docs/llm-gateway/docs/request-logs) for the harness. Open a request, pick an attempt, and its **Messages** tab shows the body sent to the provider and the body that came back.

<Tip>
  Local models record `cost = 0` with real token counts and latency, since
  nothing was billed. Custom providers do the same, because the gateway can't
  infer pricing for a model it doesn't know.
</Tip>

## Spend alerts

A limit rule watches one metric for one harness over a rolling period, and acts when the threshold is crossed.

| Field | Options |
| - | - |
| **Metric** | Tokens or cost |
| **Threshold** | The number to watch for |
| **Period** | Hour, day, week, or month |
| **Action** | Every rule emails you. Turn on blocking to also stop requests over the threshold |

Blocking is the gateway half of this and is covered in [hard limits](/llm-gateway/docs/llm-gateway/docs/llm-gateway#hard-limits). The rest of this section is the alerting half.

<Steps>
  <Step title="Open the Limits page">
    Navigate to your harness's **Limits** page in the dashboard.
  </Step>

  <Step title="Create a rule">
    Click **+ Create rule**.
  </Step>

  <Step title="Configure it">
    Pick the metric, threshold, and period. Every rule emails you; turn on **Block requests when exceeded** to also stop requests over the threshold.
  </Step>

  <Step title="Save">
    The rule takes effect immediately.
  </Step>
</Steps>

Alerts are evaluated hourly, so an email can lag the threshold by up to an hour. Blocking is not: it's checked on every request. Each rule emails once per period, so a rule that stays over its threshold won't flood your inbox.

### Email delivery

<div data-deploy="cloud">
  Alerts go to your account email. Check it's current in your profile settings.
</div>

<div data-deploy="selfhosted">
  On the **Limits** page, under **Configure email provider**, pick Resend, Mailgun, or SendGrid. Enter the API key. Mailgun also asks for a sending domain. **Notification email** defaults to your account email; change it to send alerts elsewhere. **Test & Connect** sends a real test email and saves nothing if it fails. The saved provider appears as a card on the same page, where you can edit or remove it.

  Your workspace holds one provider, shared by every harness. Removing it stops alerts for all of them.

  Alerts use the saved provider first, and fall back to the [`EMAIL_*` environment variables](/llm-gateway/docs/llm-gateway/docs/reference/environment-variables) when no provider is saved. Those variables also send verification and password-reset email, which the saved provider never handles.

  Without an email provider from either path, alerts are skipped. Blocking rules still work, since they don't need to send anything.
</div>

## Reading usage from your own code

A harness can query its own numbers with its `mnfst_` key, which is useful for showing a budget in your own UI or stopping work before a limit blocks you.

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl https://app.manifest.build/api/v1/agent/usage \
  -H "Authorization: Bearer mnfst_YOUR_KEY"
```

| Endpoint | Returns |
| - | - |
| `GET /api/v1/agent/usage` | Token usage for the calling harness |
| `GET /api/v1/agent/costs` | Cost data for the calling harness |

<div data-deploy="selfhosted">
  Self-hosted installs swap the base URL for their own host.

  ## Anonymous telemetry

  Separately from your dashboard, each self-hosted install sends a small daily report so the project can see version adoption and which providers deserve attention. It's aggregates only, never prompts or content, and one environment variable turns it off. Full field list and opt-out: [Data and telemetry](/llm-gateway/docs/llm-gateway/docs/reference/telemetry).
</div>

## Related

* [LLM Gateway](/llm-gateway/docs/llm-gateway/docs/llm-gateway) — routing, fallback, and hard limits
* [Request logs](/llm-gateway/docs/llm-gateway/docs/request-logs) — the request and response bodies
* [Autofix](/llm-gateway/docs/llm-gateway/docs/autofix)
* [Error codes](/llm-gateway/docs/llm-gateway/docs/errors)
* [Glossary](/llm-gateway/docs/llm-gateway/docs/reference/glossary)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.