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

  1. Sign upand create an organization.
  2. Open the organization's API keys tab and create a key. Copy it; it's shown once.
  3. 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/mcp

Gives 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/mcp

Tools

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/sdk

Typed 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/sdk

4. REST API

Base URL https://api.frwd2.in/api/v1. Authenticate with the X-API-Key header. Request and response bodies are JSON.

MethodPathDescription
POST/orgs/{orgId}/linksCreate a link. Body: shortId, targetUrl, title?, expiresAt?, startsAt?, password?, tags?
GET/orgs/{orgId}/linksList links. Query: limit (1–200), offset, tag
GET/orgs/{orgId}/links/tagsList the tags in use
GET/orgs/{orgId}/links/generateSuggest 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/shortenShorten 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 key
  • 403 FORBIDDEN: key belongs to another organization
  • 404 NOT_FOUND: no such link
  • 409 CONFLICT: short ID already taken
  • 422 VALIDATION_ERROR: see details
  • 429 RATE_LIMIT_EXCEEDED: wait for Retry-After seconds

Every response includes X-RateLimit-Limit,X-RateLimit-Remaining andX-RateLimit-Reset headers.