← Back to Getting Started with rtcStats

API and MCP access: querying rtcStats from code and from agents

One Bearer token, two ways in. The REST API for your own services, the MCP server for Claude Code, Cursor and any other agent. What each one returns, and why the agent-facing shape is different.

Last updated Applies tortcstats.com

On this page6 sections

Everything you can do with a session in the dashboard, you can do from code. Send a dump and get the analysis back, list the sessions you have stored, pull one in full, check your remaining credits. The same account token opens both doors: a REST API for your own services, and an MCP server your AI coding assistant connects to directly. API and MCP access starts on the Developer plan.

Get a token first

Create an application token in the dashboard under Settings > Applications, then send it as Authorization: Bearer <token> on every call. The base URL is https://api.rtcstats.com, and the fastest way to confirm the token works is GET https://api.rtcstats.com/v1.0/quota, which verifies auth and returns the credits you have left in one round trip. Tokens are per account rather than per user, so a token committed to a repository or pasted into a shared config is an account-level exposure: treat it the way you treat any other production secret, and rotate it in the dashboard if it leaks. The token also carries the account's settings, which is why two tokens on different plans can send the same dump to the same endpoint and get back payloads that differ in which features are populated. Plan gating is applied when the response is built rather than when the dump is processed, so a field being absent tells you about the plan and not about the call.

What the REST endpoints do

There are eight, and they divide cleanly. POST /v1.0/analyze takes a raw dump as the request body and returns the full analysis; it costs one credit and does not store the session unless you add ?save=true. POST /v1.0/upload stores a dump. POST /v1.0/enrich costs the same credit and returns only the scores and Observations projection, storing nothing. On the read side, GET /v1.0/sessions lists what you have stored, GET /v1.0/sessions/{rtcstatsId} returns one in full, DELETE on the same path removes it, GET /v1.0/quota reports credits, and GET /v1.0/observations/{type} returns the explanation of one Observation type so you can resolve a type key from a payload. The split worth remembering: the three POST ingest endpoints each cost a credit and the reads do not, and only upload and analyze with ?save=true leave anything behind. Dumps above the request-body cap go up as multipart chunks followed by a small assemble request, the same protocol on all three. The complete contract, with request and response schemas, is the API reference.

Connect an agent over MCP

The MCP server lives at https://api.rtcstats.com/v1.0/mcp and speaks streamable HTTP with the same Bearer token. Point Claude Code, Cursor or any MCP-compatible client at it and your assistant gets four tools: get_quota, list_sessions, get_session and get_observation_explanation. They are read-only and they do not consume analysis credits, so an agent exploring your sessions while you debug costs you nothing. The practical effect: you stop context-switching. You are in your editor looking at the code that built the peer connection, and you can ask about the session it produced without leaving the window. Configuration is one block in your MCP config, covered in the integration guide and on the MCP server page. Two limits are worth knowing before you wire it up. The tools read stored sessions, so a session analyzed without ?save=true is not there to be found, and initialize and tools/list are never rate limited while the tool calls themselves count against your read budget. Neither bites in normal use, and both confuse the first time they do.

Why the agent payload looks different

The analysis JSON was originally shaped for the dashboard, which is reasonable to optimize for right up until the consumer is a language model. A UI resolves ambiguity with layout: a column header says milliseconds, so the number underneath does not have to. An agent reading the same JSON has only the key. That is why the aggregated statistics use self-describing keys of the form <metric>_<scope>_<agg>_<unit>, so rtt_out_audio_avg_ms carries its own units and needs no lookup table, and why POST /v1.0/enrich exists as a deliberately trimmed projection rather than as the full payload with fields ignored. Storage and agent consumption are different jobs with different costs, and a shape tuned for one is rarely right for the other. The same reasoning drives smaller choices you will notice in a payload: error codes as stable identifiers with the prose kept separately, and a documented stable subset of fields, with the rest marked subject to change. Write your client against the documented fields and treat the rest as diagnostic.

Reading errors and rate limits correctly

Every error body is { error, errorCode }, and the rule is to branch on errorCode rather than error: the code is the contract and the message is prose that may be reworded. The vocabulary is small. authentication and forbidden mean the token is wrong or the plan does not include what you asked for, insufficient_scope means a read-only token called an endpoint that writes (upload, analyze, enrich or a DELETE), no_credits means exactly that, file_too_large means the dump exceeded the request-body cap and wants the chunked upload path, parsing_issue means the dump was not readable, and rate_limited means you went over the window. Limits run per account over sixty seconds: 30 ingest requests, 120 reads, and 600 multipart chunks. A 429 carries Retry-After in seconds along with the X-RateLimit-* headers, so a client that reads them backs off correctly without guessing. The headers ride on every response emitted after the limiter runs, which means they are absent on 401 and on the plan 403 forbidden (the 403 insufficient_scope does carry them): a client that requires them will misread an auth failure as a missing header rather than as a bad token.

Machine-readable contract

If you are wiring this up with an agent's help, hand it the specification rather than this page. The OpenAPI 3.0 document is served at https://rtcstats.com/api/openapi as JSON, and the same content renders as Markdown at https://rtcstats.com/api-docs.md for clients that do not run JavaScript. Both are generated from the live spec, so they do not drift from the running service. There is also an agent-facing quickstart at https://rtcstats.com/llms.txt, which is the short version of this page written for a grounded model deciding whether rtcStats answers a question it has been asked. Point your assistant at one of those, then ask it to write the client. Prefer the spec over a prose page because a generated document cannot describe an endpoint the service does not have, which is the failure mode when a model writes a client from documentation it memorized months ago. If you are debugging a client that calls something plausible and gets a 404, check the path against the OpenAPI document before checking your code.

NOTE: Can't get this to work? Need help? Contact us

Was this page helpful?