Developers
Build with frwd2
Let AI agents create links with the MCP server, call frwd2 from TypeScript with the SDK, or use the REST API from any language.
1. Get an API key
- Sign upand create an organization.
- Open the organization's API keys tab and create a key. Copy it; it's shown once.
- Copy the Organization ID from the Settings tab.
Keys can create and delete your organization's links. Keep them server-side, never in browser code.
To replace a key, press Rotate next to it: the key keeps its name and gets a new secret, shown once. The old secret can stop working straight away (choose this if the key has leaked) or keep working for 1 hour, 24 hours or 7 days while you switch your servers over. Revoke ends a key for good.
2. MCP server
@frwd2/mcpGives Claude, Cursor and any Model Context Protocol client tools to create and manage your organization's links. Runs locally over stdio with npx; nothing to host.
claude mcp add frwd2 \
--env FRWD2_API_KEY=frwd2_ok_... \
--env FRWD2_ORG_ID=your-org-id \
-- npx -y @frwd2/mcpTools
- create_link
- Create a short link. Optional shortId, title, expiresAt, startsAt, password and tags.
- get_link
- Look up a link by short ID.
- list_links
- List links, newest first (limit, offset, tag).
- update_link
- Change targetUrl, title, expiresAt, startsAt, password or tags; isActive=false pauses.
- delete_link
- Delete a link permanently. Marked destructive, so clients ask first.
- generate_short_id
- Suggest a currently unused short ID.
- get_qr_code
- Return a QR code for a link as a PNG image plus SVG.
Environment: FRWD2_API_KEY,FRWD2_ORG_ID, and optionallyFRWD2_API_URL. The same values work as--api-key, --org-id,--api-url flags.
3. TypeScript SDK
@frwd2/sdkTyped client with no dependencies. Works in Node 18+, Bun, Deno and Cloudflare Workers. Dates come back as Date objects.
npm install @frwd2/sdk
# or: pnpm add @frwd2/sdk · bun add @frwd2/sdk4. REST API
Base URL https://api.frwd2.in/api/v1. Authenticate with the X-API-Key header. Request and response bodies are JSON.
| Method | Path | Description |
|---|---|---|
| POST | /orgs/{orgId}/links | Create a link. Body: shortId, targetUrl, title?, expiresAt?, startsAt?, password?, tags? |
| GET | /orgs/{orgId}/links | List links. Query: limit (1–200), offset, tag |
| GET | /orgs/{orgId}/links/tags | List the tags in use |
| GET | /orgs/{orgId}/links/generate | Suggest an unused short ID |
| GET | /orgs/{orgId}/links/{shortId} | Get one link |
| PATCH | /orgs/{orgId}/links/{shortId} | Update targetUrl, title, isActive, expiresAt, startsAt, password (null removes it), tags |
| DELETE | /orgs/{orgId}/links/{shortId} | Delete a link |
| POST | /trial/shorten | Shorten without an account. Body: url. Expires after 3 days. With an X-Device-ID header, repeating a url returns the same link (200 instead of 201) |
curl -X POST https://api.frwd2.in/api/v1/orgs/$FRWD2_ORG_ID/links \
-H "X-API-Key: $FRWD2_API_KEY" \
-H "Content-Type: application/json" \
-d '{"shortId":"spring26","targetUrl":"https://example.com/sale"}'{
"success": true,
"data": {
"shortId": "spring26",
"shortUrl": "https://frwd2.in/spring26",
"targetUrl": "https://example.com/sale",
"title": null,
"isActive": true,
"expiresAt": null,
"startsAt": null,
"hasPassword": false,
"tags": [],
"createdAt": "2026-09-16T10:00:00.000Z"
}
}shortUrl is the address to share. If the organization has connected its own domain (organization settings in the dashboard), it is on that domain, for example https://go.yourbrand.com/spring26. The same link keeps working on frwd2.in, so nothing you have already shared breaks when a domain is added or removed.
5. Errors and rate limits
Errors use standard HTTP status codes and a machine-readable code. Include the requestId when contacting support.
{
"success": false,
"error": {
"code": "CONFLICT",
"message": "Short ID 'spring26' is already in use",
"requestId": "b3c1…"
}
}401 UNAUTHORIZED: missing or revoked API key403 FORBIDDEN: key belongs to another organization404 NOT_FOUND: no such link409 CONFLICT: short ID already taken422 VALIDATION_ERROR: seedetails429 RATE_LIMIT_EXCEEDED: wait forRetry-Afterseconds
Every response includes X-RateLimit-Limit,X-RateLimit-Remaining andX-RateLimit-Reset headers.