Developers
developer access
A personal access token lets your own scripts and automations use Traceroute without an agent in between: a Shortcut on your phone, a home automation hub, a cron job. It calls the same tools your agent does, at the same address.
The API's address: https://app.traceroutehealth.com/mcp
What a token is for
A token is for software you run yourself. To use Traceroute from Claude or ChatGPT, connect your agent instead: it signs in on its own and needs no token.
You make the token and you hold it. Treat it like a password: anyone who has it can do what its scopes allow on your record. Keep it in a password manager or your automation's secret store, never in a repository or a shared file. It works only at the address above, and every change made with it is recorded as that token's.
Create a token
- In the dashboard, open Account, then Access tokens.
- Give the token a name that says what will hold it, such as "Morning weight shortcut".
- Choose its scopes, below. Grant only what the automation needs.
- Choose an expiry: 30, 90 or 365 days, or no expiry.
- Create it. If you have not signed in within the last ten minutes, you sign in again first.
- Copy the token. It begins with
trt_pat_and is shown this once. If you lose it, revoke it and make another.
Scopes
Every token can read your streams' names and settings, never their values. That is meta:read, and it lets an automation find the stream it writes to. Tools: traceroute_get_context, traceroute_workspace_info, traceroute_get_stream_capabilities, traceroute_list_streams.
- streams:read reads your values: readings, daily series, where a day's value came from, meals, food totals and saved food items. Tools:
traceroute_query_readings,traceroute_query_series,traceroute_explain_value,traceroute_get_food,traceroute_list_food,traceroute_query_food_totals,traceroute_get_food_item,traceroute_list_food_items. - streams:write changes your streams and what is in them: creating, editing and archiving streams, logging readings, correcting, withdrawing and moving them, and logging meals and food items. Tools:
traceroute_create_stream,traceroute_create_derived_stream,traceroute_save_stream,traceroute_save_stream_display,traceroute_archive_stream,traceroute_log_readings,traceroute_correct_reading,traceroute_correct_readings,traceroute_withdraw_reading,traceroute_move_readings,traceroute_save_food,traceroute_save_food_overrides,traceroute_save_food_item. - dashboards:read reads your dashboards. Tools:
traceroute_get_view,traceroute_list_views. - dashboards:write saves dashboards. Tool:
traceroute_save_view. - sharing:read shows whether a dashboard is published and who it is shared with. Tools:
traceroute_get_publication,traceroute_list_access. - sharing:write publishes and unpublishes dashboards, and shares them with people or stops sharing. Tools:
traceroute_publish_view,traceroute_unpublish_view,traceroute_share_view,traceroute_revoke_share. - feedback:write sends feedback to Traceroute. Tool:
traceroute_submit_feedback.
An automation that only logs should take streams:write without streams:read. It can then write to your record and never read a value from it. It can still correct or withdraw readings, and the history keeps what each change replaced.
A token's scopes never change. To grant more, make a new token.
Expiry and revoking
- Expiry. A token with an expiry stops working on that date. One without works until you revoke it.
- Idle expiry. On the same page you can set one rule for all your tokens: a token not used for that many days, from 7 to 365, stops working. It is off until you turn it on. Changing it applies at once in both directions: lengthen it or turn it off, and a token it had stopped works again.
- Revoke. Each token is listed with its scopes, when it was created and last used, and its expiry. Revoke stops it on its next call, for good.
Calling the API
The API is Traceroute's MCP server: JSON-RPC 2.0 over HTTP. Every call is one POST to the address above, with these headers:
Authorization: Bearer <your-token>
Content-Type: application/json
Accept: application/json, text/event-stream
The Accept header must name both types, or the request is refused. The answer is always plain JSON.
Each request stands alone. There is no session to open: no initialize call and no session header are needed before calling a tool. An MCP-Protocol-Version header is optional. Any MCP client library that speaks Streamable HTTP works too: give it the address and the token as a bearer header.
The examples below keep the token in an environment variable, TRACEROUTE_TOKEN.
List your tools
The tools a token can call are the ones its scopes grant. tools/list returns exactly those, each with its description and input schema.
curl https://app.traceroutehealth.com/mcp \
-H "Authorization: Bearer $TRACEROUTE_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Find a stream
Every reading goes to a stream, by its ID. List your streams once to find the ID and the unit of the one your automation writes to. Any token can make this call.
curl https://app.traceroutehealth.com/mcp \
-H "Authorization: Bearer $TRACEROUTE_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call",
"params":{"name":"traceroute_list_streams","arguments":{}}}'
A tool's answer is in result.structuredContent, and the same JSON as text in result.content:
{"jsonrpc":"2.0","id":2,"result":{
"content":[{"type":"text","text":"…"}],
"structuredContent":{
"streams":[{"id":"<stream-id>",
"display_name":"Body weight",
"definition":{"unit":"lb", …},
"revision":1}, …],
"next_cursor":""}}}
It returns up to 100 streams. When next_cursor is not empty, pass it as "after" for the next page. Your agent can also tell you a stream's ID if you ask it.
Log a reading
curl https://app.traceroutehealth.com/mcp \
-H "Authorization: Bearer $TRACEROUTE_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call",
"params":{"name":"traceroute_log_readings",
"arguments":{
"submission_id":"<new-uuid>",
"readings":[{
"stream_id":"<stream-id>",
"observed_on":"<yyyy-mm-dd>",
"value":"182.4","unit":"lb","method":"measured"}]}}}'
- submission_id is a new UUID for each submission, in lowercase.
uuidgen | tr A-Z a-zmakes one. If the response is lost, send the same request again with the same ID: it is recorded once. The same ID with different content is refused. - readings holds 1 to 25 readings. If one is invalid, none is recorded.
- observed_on is the calendar date the reading belongs to, as
YYYY-MM-DD. - value is always a string, read by the stream's value type:
"182.4"for a number,"true"or"false"for a yes-or-no stream, or text. - unit must be the stream's own unit,
definition.unit. Nothing is converted. - method is
measured,self_reportedorestimated. - note is optional, up to 500 characters, on each reading.
The answer names what was recorded:
{"jsonrpc":"2.0","id":3,"result":{
"content":[{"type":"text","text":"…"}],
"structuredContent":{
"submission_id":"<new-uuid>",
"reading_ids":["<reading-id>"]}}}
To change a reading later, use traceroute_correct_reading or traceroute_withdraw_reading. Logging again adds a second reading.
iOS Shortcuts
This shortcut logs one number to one stream. Find the stream's ID and unit first, as above.
- Add Ask for Input with input type Number. To log a value from Health instead, use Find Health Samples for the latest sample of a type, then take its value.
- Add Format Date on the current date, with the custom format
yyyy-MM-dd. This is the reading's date. - Make the submission ID. Add Format Date on the current date with the custom format
yyyyMMdd-HHmm-ss00-0000-, then Random Number from 100000000000 to 999999999999, then a Text action that joins the two. Any lowercase UUID works; this one is new on every run. - Add Get Contents of URL with the URL
https://app.traceroutehealth.com/mcp. Under it, set Method to POST. - Under Headers, add
AuthorizationwithBearer, a space and your token;Content-Typewithapplication/json; andAcceptwithapplication/json, text/event-stream. - Set Request Body to JSON and add these fields, each of type Text unless it says otherwise:
jsonrpc2.0;id1;methodtools/call; andparams, a Dictionary. - In
params, addnametraceroute_log_readings andarguments, a Dictionary. Inarguments, addsubmission_idwith the Text from step 3, andreadings, an Array with one Dictionary item. - In that item, add
stream_idwith the stream's ID;observed_onwith the date from step 2;valuewith the number from step 1;unitwith the stream's unit; andmethodwith self_reported, or measured for a value a device took. Keepvaluea Text field even though it holds a number. - While you set it up, add Show Result after the request. A reading was recorded when the answer has
reading_ids; otherwise the answer says what was wrong.
The token is stored in the shortcut. Sharing the shortcut shares the token, so remove it first.
Any tool that sends a POST with headers you set and a JSON body you write works the same way, Home Assistant's RESTful command for one: the address, the three headers, and the body above. A tool that only sends its own fixed JSON format needs something in between to turn it into that body.
Errors and limits
- HTTP 401. The token is unknown, revoked or expired, with
WWW-Authenticate: Bearer error="invalid_token". An expired token's answer says so and why: it reached its expiry date, or it went unused for longer than your idle expiry, which you can lengthen to bring it back. Otherwise check the token on the Access tokens page, or make a new one. - A tool outside the token's scopes. It is missing from
tools/list, and calling it returns an error that names the scope it needs. Nothing is written. - A tool that refuses its input, a number sent where a string belongs included. The answer is HTTP 200 with
"isError": truein the result and the reason in its text. Nothing is written. - A malformed call. An unknown tool name returns a JSON-RPC
error. HTTP 400 means theAcceptheader lacks a type or the body is not a JSON-RPC request; 415 means theContent-Typeis notapplication/json; 413 means the body is over 16 KB. - HTTP 429. A token may make 60 requests a minute. Over that, wait the seconds the
Retry-Afterheader gives, then try again. - Limits. An account holds at most 25 tokens that are not revoked and have not reached their expiry date.
For anything else, write to support@traceroutehealth.com or use the contact form.
Traceroute is for adults 18 and older in the United States. It is not medical advice, diagnosis or treatment.