The REST API
The base URL is https://api.frwrd.to. Every call except creating and
recovering a workspace takes your workspace key as a bearer token:
Authorization: Bearer fw_...
The examples below read the key from $FRWRD_KEY. Bodies are JSON unless
the example says otherwise.
Links
Create a short link:
curl -X POST https://api.frwrd.to/v1/links -H "Authorization: Bearer $FRWRD_KEY" -H "Content-Type: application/json" -d '{"long_url":"https://example.com/a/long/address","title":"Example"}'
The answer has the short link, its hash and the addresses of its QR
code. Only http and https targets are accepted. You can also send
tags, utm and, on a verified workspace, your own hash.
If your workspace has default UTM parameters, they are appended to the
target before it is stored, and long_url in the answer is that stored
target. A utm you send with the link wins over the defaults for the
keys you give, and a utm_ parameter already in the address wins over
both. Links that exist are not changed.
Set the defaults (the keys are source, medium, campaign, term and
content; the new set replaces the old one, and {} clears it):
curl -X PUT https://api.frwrd.to/v1/workspace/utm -H "Authorization: Bearer $FRWRD_KEY" -H "Content-Type: application/json" -d '{"utm":{"source":"newsletter","medium":"email"}}'
List links, newest first (limit up to 200, and offset):
curl "https://api.frwrd.to/v1/links?limit=50" -H "Authorization: Bearer $FRWRD_KEY"
Numbers for one link, by default the last 30 days (since and until take
a date such as 2026-10-01, at most 366 days apart):
curl "https://api.frwrd.to/v1/links/aB3xZ9/stats?since=2026-10-01" -H "Authorization: Bearer $FRWRD_KEY"
The answer gives the total, the split by channel (link for a direct click,
qr for a scan, page for a click on a bio page) and the numbers per day.
For a chart, ask for a range instead: ?range=1d is the last 24 hours in 24
hourly buckets, 7d and 30d the last 7 or 30 UTC days in daily ones. The
answer then adds buckets (each with start and a count per channel, zeros
included, none left out) and all_time, the totals since the first click.
Another value is a 400, and a range does not combine with since or until.
The same works on the page stats below.
The numbers of all your links at once, so you need not open each one:
curl "https://api.frwrd.to/v1/workspace/stats?range=30d" -H "Authorization: Bearer $FRWRD_KEY"
It sums the clicks on every link of the workspace (archived links count, they
were clicked; views of bio pages do not) into the same buckets, with total,
by_channel and all_time, and adds top: the ten links with the most
clicks in the range, each with hash, title, short_url, archived,
total and by_channel. range is 1d, 7d (the default) or 30d.
The answer is cached, so it may be up to 5 minutes old, and all_time is null
when it could not be counted right now (everything else is still there). When
the server is busy it answers 429 with a Retry-After: retry in a few
seconds.
The QR code, as PNG or SVG (size from 128 to 2048):
curl "https://api.frwrd.to/v1/links/aB3xZ9/qr.png?size=512" -H "Authorization: Bearer $FRWRD_KEY" -o code.png
To change a link, send PATCH /v1/links/{hash} with any of long_url,
title, tags and archived. DELETE /v1/links/{hash} archives it: it
stops redirecting, and its numbers stay.
Pages
A page is a Markdown document with a short header. You save the whole
document in one call. The path - is the root page; a page in another
language lives under its language code, and the slash is written %2F, as
in de%2Fhilfe.
curl -X PUT https://api.frwrd.to/v1/pages/hello -H "Authorization: Bearer $FRWRD_KEY" -H "Content-Type: text/markdown" --data-binary @hello.md
Every link in the document becomes a short link of your workspace. To read
a page back as Markdown, send Accept: text/markdown; the answer carries
an ETag. Send it back as If-Match when you save, and the call fails with
412 if someone changed the page meanwhile.
Views of a page and clicks on each of its links:
curl "https://api.frwrd.to/v1/pages/hello/stats" -H "Authorization: Bearer $FRWRD_KEY"
GET /v1/pages lists your pages, GET /v1/pages/{path}/versions shows the
history and DELETE /v1/pages/{path} archives a page.
Bit.ly compatible /v4
Tools that speak Bit.ly's v4 API can point at https://api.frwrd.to/v4 and
use your workspace key as the token. These calls exist, with Bit.ly's
answers, timestamps and error messages:
POST /v4/shortenPOST /v4/expandPATCH /v4/bitlinks/frwrd.to/{hash}GET /v4/bitlinks/frwrd.to/{hash}/clicks/summary
Anything else of Bit.ly's is not served. A spent link quota answers 429
with MONTHLY_LIMIT_EXCEEDED.
Delete the workspace
DELETE /v1/workspace deletes the workspace. Deleting a workspace stops its key and takes its pages
offline at once; after 7 days the pages and settings are deleted. Short links keep working. Proving
the domain (key recovery) within 7 days restores everything; up to 60 days, the links. After 60 days
the domain is free and the links keep working without an owner. Browsers may keep cached copies of a
page, its QR code and images for up to an hour after the delete.
Send the workspace's own domain as confirm; a missing or different value is a 400 and nothing is
deleted. The answer is 204, and the key stops working with it.
curl -X DELETE https://api.frwrd.to/v1/workspace -H "Authorization: Bearer $FRWRD_KEY" -H "Content-Type: application/json" -d '{"confirm":"acme.com"}'
Limits and errors
- Before it checks your key, the API allows 20 requests per second from one address (bursts of 60). After that, 10 per second for each workspace (bursts of 30). Creating or recovering workspaces is limited to 5 per minute per address.
- Over a limit, the answer is
429with the coderate_limited, and aRetry-Afterheader says when to try again. - Errors on
/v1are JSON:{"error":{"code":"...","message":"..."}}. Branch oncode:invalid_body,missing_credentials,invalid_credentials,not_found,conflict,precondition_failed,quota_exceeded,not_verified,rate_limitedorinternal_error.
The full contract is an OpenAPI document that lives with the source code, which is not public yet. Until then, the calls above, the MCP tool descriptions and frwrd.to/llms.txt describe the API.