The TinyTo REST API: create short links, read their stats and manage them from your
own code.
v1REST · JSONBase URL: https://tinyto.me/apiAdvanced planOpen as Markdown ↗
Overview
Every request is JSON over HTTPS. Responses always use the same envelope: on success
data holds the payload and error
is null; on failure data is
null and the HTTP status plus
error.code tell you what happened.
The API is scoped to the account that owns the key. You cannot read or modify links
from another account, and there is no endpoint that returns data across accounts.
Availability: the API is included in the Advanced plan. If the account
drops to a lower plan, existing keys stop working immediately with
403 forbidden.
Quickstart
Create a key. Open
Dashboard → API, give it a name and
copy it. It is shown once; we store only a hash.
Check it works.GET /v1/me is the
cheapest call and returns your plan and link usage.
Create your first link and keep the id:
every other endpoint keys off it.
res = requests.get(
"https://tinyto.me/api/v1/links",
params={"limit": 20},
headers={"Authorization": f"Bearer {os.environ['TINYTO_KEY']}"},
timeout=10,
)
for link in res.json()["data"]["items"]:
print(link["short_url"], link["clicks"])
The same account is reachable over the Model Context Protocol, so Claude
and ChatGPT can create and read links as a tool rather than through raw HTTP. The endpoint
is https://tinyto.me/mcp.
Authentication is OAuth 2.1 with PKCE. The client registers itself, sends the user through
a consent screen and receives a bearer token — there is no API key to paste. Unlike the REST
API, the MCP server is available on every plan; link limits follow the plan.
Tool
Scope
What it does
list_links
links:read
List links with click counts, newest first
get_link
links:read
One link with its destination and clicks
get_link_stats
links:read
Clicks, countries and the weekday/hour heatmap
account_info
links:read
Plan, active links and remaining allowance
create_link
links:create
Shorten a URL, optionally with a slug or expiry
No tool deletes or edits an existing link: the assistant can create and read, nothing else.
create_link is the only write operation and is marked
non-destructive, so clients show it without extra warnings.
Connecting a client
Every client takes the same URL and walks the OAuth flow from there: Claude,
Claude Code, ChatGPT, OpenCode, Cursor, VS Code, Codex CLI, Gemini CLI, Windsurf, Zed,
Cline and Antigravity. Step-by-step instructions, including the exact config for each
one, live on their own page:
Clients discover everything from these, so no manual configuration is needed:
URL
Purpose
/.well-known/oauth-protected-resource
RFC 9728 metadata: which authorization server protects /mcp
/.well-known/oauth-authorization-server
RFC 8414 metadata: authorize, token, registration and JWKS URLs
/.well-known/jwks.json
Public keys to verify access tokens
Access tokens are RS256 JWTs with the audience set to
https://tinyto.me/mcp, valid for one hour, refreshed
with a rotating refresh token. Users disconnect an app from
Dashboard → API, which invalidates its
tokens immediately; clients can also call POST /oauth/revoke
(RFC 7009).
Errors
Failures never throw a different shape. Treat error.code
as the stable contract and the HTTP status as a hint.
{
"data": null,
"error": {
"code": "invalid_request",
"message": "slug must be 3-50 alphanumeric characters."
}
}
Status
Code
When
400
invalid_request
A required field is missing, has the wrong type, or the slug/expiry is invalid.
401
unauthorized
No key, or the key is invalid, expired or revoked.
402
plan_limit_reached
The account has no active links left on its plan.
403
forbidden
Read-only key used for a write call, or the plan does not include API access.
404
not_found
The link does not exist, or it belongs to another account.
429
rate_limited
More than 120 requests in a minute for this key.
500
server_error
Unexpected failure on our side. Safe to retry with backoff.
Rate limits
120 requests per minute per key, counted in a rolling window. Exceeding it returns
429 with Retry-After
and the X-RateLimit-* headers.
HTTP/1.1 429 Too Many Requests
Retry-After: 17
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1793352680
Back off on Retry-After rather than retrying
immediately, and batch reads where you can.
Changelog
Date
Change
2026-10-30
v1 published: links, per-link stats and account endpoints.
Machine-readable contract: /openapi.json, generated from the
same list this page renders. Breaking changes will ship under /v2; v1 keeps working
for at least 6 months after a successor is announced.