Tracked links for AI agents

An agent that produces a report has nowhere to put it. Give it an API key or an MCP connector and it can publish, update in place, and report back on who read what.

The slim.to team · · 4 min read

Agents have a delivery problem.

An agent can research a market, write the memo, and format it beautifully — and then it's stuck. The artifact exists inside a run. To get it to a human it gets pasted into a chat message, or written to a file in a sandbox that disappears, or emailed as an attachment nobody can track. The last mile is the weakest part of most agent pipelines.

What an agent actually needs is a place to put things that produces a durable URL, survives the run, and reports back on what happened to it.

Two ways in

MCP, if the agent framework speaks it. Point it at the hosted server at https://slim.to/mcp and the tools appear natively — the agent discovers create_link_from_content, get_link_analytics and the rest without you writing any glue. Setup is covered in the MCP walkthrough.

The REST API, if it doesn't. One header, ordinary HTTPS, works from anything that can make a request:

curl -s -X POST https://slim.to/api/v1/files \
  -H "X-API-Key: $SLIMTO_API_KEY" \
  -F "file=@report.pdf" \
  -F "title=Market memo"

The response carries link.short_url, which is the thing to hand back to the human. Full reference in the API quickstart.

In Python, the shape most agent tools end up wanting:

import os, requests

def publish(path: str, title: str) -> str:
    """Upload a file and return a tracked short link."""
    with open(path, "rb") as fh:
        r = requests.post(
            "https://slim.to/api/v1/files",
            headers={"X-API-Key": os.environ["SLIMTO_API_KEY"]},
            files={"file": fh},
            data={"title": title},
            timeout=60,
        )
    r.raise_for_status()
    return r.json()["link"]["short_url"]

The four habits that matter

Most of what separates a good agent integration from a bad one comes down to four things.

An agent that regenerates a daily report should update one link, not create thirty. replace_link_content (MCP) or a PATCH/re-upload against the existing link keeps the URL, the slug, the domain, the access settings and the whole analytics history. The human bookmarks it once.

Creating a fresh link per run also burns straight through your plan's active-link limit, which is how most people discover this rule.

Give the agent a scoped key, and expect to revoke it

Personal API keys are slim_ plus 40 hex characters, shown once at creation and stored hashed. Give each agent its own, so revoking one doesn't take down the rest. Keys are created and revoked in Settings → API keys, or via the API.

Don't grant deletion casually

delete_link is permanent — it breaks every copy of the URL already shared and discards the analytics. It requires an explicit confirm: true for exactly this reason. If an agent's job is to publish, it does not need to delete. Deactivating a link is reversible; deleting isn't.

Respect the rate limit

120 requests per minute per key. An agent that polls analytics in a tight loop will find this; one that checks on a sensible schedule never will. On 429, back off rather than retrying immediately.

Closing the loop

The part that makes this more than file hosting: the agent can read the analytics back.

curl -s https://slim.to/api/v1/analytics/links/<link_id> \
  -H "X-API-Key: $SLIMTO_API_KEY"

That returns opens, unique viewers, total time spent, device, country and referrer breakdowns, and per-page detail for PDFs and hosted pages. Which means an agent can do things like:

An agent that knows whether its output was read is a meaningfully different thing from one that just produces output.

For push rather than poll, add a webhook in Integrations — slim.to will POST full viewer metadata on every open, which is the better pattern for anything event-driven.

Practical limits

Where to go next

Keep reading