# FunnelKit Shortener: full documentation > Generated from https://shortener-staging.funnelkit.com. API base URL: https://linkapp-staging.funnelkit.com/api. MCP endpoint: https://linkapp-staging.funnelkit.com/mcp. Short link domain: link-staging.funnelkit.com. --- # Documentation FunnelKit Shortener creates branded short links and tells you who clicked them. Everything you can do in the dashboard you can also do from the REST API, the `fks` CLI or an AI agent over MCP. ## Start here - [Quickstart](/docs/quickstart/): create an API key and your first short link in five minutes. - [REST API](/docs/api/): authentication, endpoints, errors and rate limits. - [CLI](/docs/cli/): the `fks` command, its JSON output and exit codes. - [MCP server](/docs/mcp/): connect Claude Code, Claude Desktop or Cursor to your workspace. - [Custom domains](/docs/domains/): serve links from `go.yourbrand.com`. ## Hosts | What | Address | |---|---| | Dashboard | `https://linkapp-staging.funnelkit.com` | | REST API base URL | `https://linkapp-staging.funnelkit.com/api` | | OpenAPI 3.1 spec | `https://linkapp-staging.funnelkit.com/api/openapi.json` | | MCP endpoint | `https://linkapp-staging.funnelkit.com/mcp` | | Short links | `https://link-staging.funnelkit.com` | ## Concepts - **Workspace:** links, domains, members, API keys and the plan all belong to a workspace. You can belong to several. - **Link:** a destination URL plus a slug on a domain. `link-staging.funnelkit.com/spring` is the slug `spring` on the domain `link-staging.funnelkit.com`. Slugs are unique per domain. - **API key:** a secret starting with `fks_` that acts on one workspace. Create keys under Settings, API keys. Treat them like passwords. - **Soft limits:** going over a plan limit never breaks a redirect. Over the click allowance, analytics are sampled; over the new-link allowance, creating links pauses. See [Pricing](/pricing/). ## For agents This documentation is also available as [llms.txt](/llms.txt) (an index) and [llms-full.txt](/llms-full.txt) (every page in one Markdown file). Point your agent at either one. > FunnelKit Shortener is in a private beta and signup is invite-only. [Request early access](https://linkapp-staging.funnelkit.com/signup). --- # Quickstart Create your first short link from the command line in about five minutes. ## 1. Get access Signup is invite-only during the private beta. [Request early access](https://linkapp-staging.funnelkit.com/signup), then sign up with the invite code you receive. A workspace on the Free plan is created for you. ## 2. Create an API key In the dashboard, open **Settings, API keys** and create a key. It starts with `fks_` and is shown once, so copy it now. Keep it in an environment variable: ```shell export FKS_API_KEY="fks_YOUR_KEY" ``` ## 3. Create a link With curl: ```shell curl -X POST https://linkapp-staging.funnelkit.com/api/links \ -H "Authorization: Bearer $FKS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com/spring-launch","slug":"spring"}' ``` The response is the new link. Its `shortUrl` is ready to share: ```json { "id": "lnk_...", "domain": "link-staging.funnelkit.com", "slug": "spring", "shortUrl": "https://link-staging.funnelkit.com/spring", "url": "https://example.com/spring-launch", "tags": [], "redirectType": 302, "createdAt": "2026-10-06T09:00:00.000Z" } ``` Or with the CLI (see [installation](/docs/cli/#install)): ```shell fks links create https://example.com/spring-launch --slug spring ``` ## 4. Follow it ```shell curl -sI https://link-staging.funnelkit.com/spring ``` You get a `302` with a `location` header pointing at your destination. ## 5. See the clicks ```shell curl https://linkapp-staging.funnelkit.com/api/links/LINK_ID/stats -H "Authorization: Bearer $FKS_API_KEY" ``` Clicks usually appear within a minute. The dashboard shows the same data as charts. ## Next steps - Let an agent do it: [connect the MCP server](/docs/mcp/). - Use your own domain: [custom domains](/docs/domains/). - Read the [API reference](/docs/api/) for every endpoint. --- # REST API A JSON API over HTTPS for links, analytics, QR codes, domains and workspaces. The full machine-readable reference is the OpenAPI 3.1 spec at [https://linkapp-staging.funnelkit.com/api/openapi.json](https://linkapp-staging.funnelkit.com/api/openapi.json). ## Base URL ```text https://linkapp-staging.funnelkit.com/api ``` ## Authentication Send a workspace API key as a Bearer token on every request. Keys start with `fks_` and are created in the dashboard under Settings, API keys. ```http Authorization: Bearer fks_YOUR_KEY ``` A key acts on the workspace it was created in. A missing or invalid key returns `401`. ## Create a link `POST /links` ```shell curl -X POST https://linkapp-staging.funnelkit.com/api/links \ -H "Authorization: Bearer $FKS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/pricing", "slug": "pricing", "tags": ["web"], "utm": { "source": "newsletter", "medium": "email" } }' ``` Returns `201` with the link. Only `url` is required. | Field | Type | Notes | |---|---|---| | `url` | string | Destination, `http` or `https`. Scanned before the link is created. | | `slug` | string | 1 to 64 letters, digits, `-` or `_`. Random 7 characters if omitted. | | `domain` | string | A verified custom domain. Defaults to `link-staging.funnelkit.com`. | | `title` | string | Up to 200 characters. | | `tags` | string[] | Up to 20 tags. | | `utm` | object | `source`, `medium`, `campaign`, `term`, `content`. | | `password` | string | Pro and up. | | `expiresAt`, `expiredUrl` | string | ISO 8601 time and a fallback destination. Pro and up. | | `geo` | object | Country code to URL, for example `{"DE":"https://example.de"}`. Pro and up. | | `iosUrl`, `androidUrl` | string | Mobile deep links. Team and up. | | `redirectType` | number | `302` (default) or `301`. | To create many links at once, `POST /links/bulk` with `{"links":[...]}` (up to 50 per request; the CLI splits larger files automatically). The response lists the result for each item. ## List links `GET /links` ```shell curl "https://linkapp-staging.funnelkit.com/api/links?limit=25&tag=web" \ -H "Authorization: Bearer $FKS_API_KEY" ``` Query parameters: `q` (search), `tag`, `domain`, `archived`, `limit` (1 to 100, default 25) and `cursor`. The response is `{"links":[...],"nextCursor":"..."}`; pass `nextCursor` back as `cursor` to get the next page. It is `null` on the last page. Archiving a link only hides it from lists: it keeps redirecting. To stop a link but keep its analytics, set `expiresAt`. ## Get and update a link `GET /links/{id}` returns one link. `PATCH /links/{id}` changes any field except `domain`. Edits are unlimited on every plan. ```shell curl -X PATCH https://linkapp-staging.funnelkit.com/api/links/LINK_ID \ -H "Authorization: Bearer $FKS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com/pricing-2027"}' ``` ## Link stats `GET /links/{id}/stats` ```shell curl "https://linkapp-staging.funnelkit.com/api/links/LINK_ID/stats?from=2026-09-01T00:00:00Z&interval=day" \ -H "Authorization: Bearer $FKS_API_KEY" ``` Returns `totals`, a `timeseries` and a `breakdown` by country, device, OS, browser, referrer and trigger. `from` and `to` are ISO 8601 times (default: the last 30 days) and `interval` is `hour` or `day`. The window is limited to your plan's analytics retention. `GET /stats` returns the same for the whole workspace plus the top links. ## Delete a link `DELETE /links/{id}` ```shell curl -X DELETE https://linkapp-staging.funnelkit.com/api/links/LINK_ID \ -H "Authorization: Bearer $FKS_API_KEY" ``` Returns `{"ok":true}`. The short URL stops redirecting within about a minute. ## Other endpoints | Endpoint | What it does | |---|---| | `GET /links/{id}/qr` | SVG QR code. `size`, `ecc`, and on Pro and up `fg`/`bg` colours. | | `GET /tags` | Tags with link counts. | | `GET /stats/export` | Click data as CSV. Team and up. | | `GET /domains`, `POST /domains` | List or add custom domains. | | `POST /domains/{id}/verify` | Re-check DNS and the certificate. | | `GET /workspace` | The current workspace, plan and usage. | ## Errors Every error has the same shape: ```json { "error": { "code": "validation_failed", "message": "Use 1-64 letters, digits, \"-\" or \"_\"", "details": { "field": "slug" } } } ``` `code` is stable and safe to branch on; `message` is for people; `details` is optional. | Status | Codes | Meaning | |---|---|---| | `401` | `unauthorized` | Missing or invalid API key. | | `402` | `plan_limit_reached`, `feature_not_in_plan` | The new-link allowance is used up, or the feature needs a higher plan. Existing links keep working. | | `403` | `forbidden` | Your role cannot do this, or the workspace is suspended. | | `404` | `not_found` | No such link or domain in this workspace. | | `409` | `slug_taken`, `conflict` | The slug is already used on that domain. | | `422` | `validation_failed`, `unsafe_url` | The body is invalid, or the destination failed the safety scan. | | `429` | `rate_limited` | Too many requests. Wait and retry. | ## Rate limits Requests per minute, per workspace: 60 on Free, 600 on Pro, 3,000 on Team and 10,000 on Scale. Over the limit you get `429`; back off and retry. --- # CLI `fks` manages your short links from a terminal, a script or an AI agent. Every command accepts `--json` and exits with a documented code, so output is safe to parse. ## Install > The npm package is coming soon. Until it is published, `npx fks` will not work for you, and you can run the CLI from source as below. Once the package is on npm: ```shell npx fks --help # or install it globally npm install -g fks ``` From source today (Node 22 or later), inside a checkout of the FunnelKit Shortener repository: ```shell pnpm install pnpm --filter fks build node packages/cli/dist/fks.js --help ``` Add an alias to save typing: `alias fks="node $PWD/packages/cli/dist/fks.js"`. ## Log in Create an API key in the dashboard (Settings, API keys), then: ```shell fks login --api-key fks_YOUR_KEY ``` The key is saved in your user config directory. In CI or for agents, set the `FKS_API_KEY` environment variable instead; it takes precedence over the saved key. `fks logout` removes the saved key. ## Commands | Command | What it does | |---|---| | `fks login`, `fks logout` | Save or remove your API key. | | `fks links create ` | Create a link. Options include `--slug`, `--domain`, `--title` and `--tag` (repeatable). | | `fks links list` | List links, newest first. Filter with `--tag`, `--domain`, `--search`; page with `--limit` and `--cursor`. | | `fks links get ` | Show one link. | | `fks links update ` | Change the destination or other fields, for example `--url`. | | `fks links delete ` | Delete a link. | | `fks links bulk ` | Create links from a JSON or CSV file (sent in batches of 50). | | `fks stats [id]` | Clicks for one link, or the whole workspace without an id. Supports `--from`, `--to`. | | `fks qr ` | Write the link's QR code as SVG to a file or stdout. | | `fks domains list`, `add`, `verify`, `remove` | Manage custom domains. | | `fks keys list`, `create`, `revoke` | Manage API keys. | | `fks workspace` | Show the current workspace, plan and usage. | Run `fks --help` for every option. ## JSON output for agents Add `--json` to any command to get machine-readable output on stdout. Errors go to stderr in the same shape as the API: ```shell $ fks links create https://example.com --slug taken --json {"error":{"code":"slug_taken","message":"That slug is already used on link-staging.funnelkit.com"}} $ echo $? 6 ``` Human-readable output (the default) may change between versions; JSON output and exit codes will not. ## Exit codes | Code | Meaning | |---|---| | `0` | Success. | | `1` | Unexpected error. | | `2` | Usage error: unknown command or bad flags. | | `3` | Authentication failed: missing or invalid API key. | | `4` | Not found. | | `5` | Plan limit reached, or the feature needs a higher plan. | | `6` | Validation error or conflict, such as an unsafe URL or a taken slug. | | `7` | Rate limited. Wait and retry. | | `8` | Network or server error. Retrying may help. | ## Examples Create a link and keep only the short URL: ```shell fks links create https://example.com/launch --slug launch --json | jq -r .shortUrl ``` Point an existing link somewhere new: ```shell fks links update lnk_123 --url https://example.com/launch-v2 ``` Clicks for the last week: ```shell fks stats lnk_123 --from 2026-09-29 --json ``` --- # MCP server FunnelKit Shortener runs a remote [Model Context Protocol](https://modelcontextprotocol.io) server, so AI assistants can create links, read analytics and manage domains in your workspace. ## Endpoint ```text https://linkapp-staging.funnelkit.com/mcp ``` It uses the Streamable HTTP transport. There are two ways to authenticate: - **Sign in with your browser (OAuth).** Add the server without a key; your MCP client opens a FunnelKit consent page where you pick the workspace. Tokens last an hour and refresh automatically. This is the easiest option for people. - **A workspace API key** in the `Authorization` header. This is best for scripts, CI and headless agents. The assistant can do anything the key's workspace can, so create a dedicated key for each assistant and revoke it when you stop using it. ## Claude Code Sign in with your browser: ```shell claude mcp add --transport http funnelkit https://linkapp-staging.funnelkit.com/mcp ``` Then run `/mcp` inside Claude Code, choose **funnelkit** and **Authenticate**. Or use an API key: ```shell claude mcp add --transport http funnelkit https://linkapp-staging.funnelkit.com/mcp \ --header "Authorization: Bearer fks_YOUR_KEY" ``` ## Claude Desktop Claude Desktop connects to remote servers through the `mcp-remote` bridge. Add this to `claude_desktop_config.json` (Settings, Developer, Edit config) and restart the app: ```json { "mcpServers": { "funnelkit": { "command": "npx", "args": [ "-y", "mcp-remote", "https://linkapp-staging.funnelkit.com/mcp", "--header", "Authorization: Bearer ${FKS_API_KEY}" ], "env": { "FKS_API_KEY": "fks_YOUR_KEY" } } } } ``` ## Cursor Add this to `~/.cursor/mcp.json`, or `.cursor/mcp.json` in a project: ```json { "mcpServers": { "funnelkit": { "url": "https://linkapp-staging.funnelkit.com/mcp", "headers": { "Authorization": "Bearer fks_YOUR_KEY" } } } } ``` Other clients that support remote HTTP servers with custom headers work the same way. ## Tools | Tool | What it does | |---|---| | `create_link` | Create a short link. Takes `url` and optionally `slug`, `domain`, `title`, `tags`. | | `bulk_create_links` | Create up to 50 links in one call. | | `update_link` | Change a link's destination, slug, title or tags. | | `delete_link` | Delete a link. | | `list_links` | Search and page through links. | | `get_link` | Get one link by id. | | `get_link_stats` | Clicks, time series and breakdowns for one link. | | `get_workspace_stats` | Clicks across the workspace and the top links. | | `create_qr` | Get a QR code (SVG) for a link. | | `list_domains` | List the workspace's domains and their status. | | `add_domain` | Add a custom domain and get the CNAME record to create. | | `verify_domain` | Check DNS and certificate status for a domain. | Tool errors use the same `code` values as the [REST API](/docs/api/#errors), so an assistant can tell a taken slug from a plan limit. ## Example prompts - "Shorten https://example.com/webinar as `webinar` and tag it events." - "Create links for each URL in this list, with slugs from the page titles." - "Which of my links got the most clicks last week, and from which countries?" - "Point the `pricing` link at https://example.com/pricing-2027." - "Add go.example.com as a custom domain and tell me the DNS record to create." - "Make a QR code for the `spring` link." --- # Custom domains Use your own domain, such as `go.yourbrand.com`, for short links. Branded links are easier to recognise and keep your reputation separate from everyone else's. Pro includes 3 domains, Team 25 and Scale 100. ## 1. Choose a subdomain Use a subdomain you are not using for anything else, such as `go.`, `link.` or `l.`. A dedicated short domain you own also works. ## 2. Add it In the dashboard, open **Domains** and add the hostname. Or from the CLI: ```shell fks domains add go.yourbrand.com ``` Or the API: ```shell curl -X POST https://linkapp-staging.funnelkit.com/api/domains \ -H "Authorization: Bearer $FKS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"hostname":"go.yourbrand.com"}' ``` ## 3. Create the DNS records At your DNS provider, create two records. The values are shown in the dashboard, in the API response and by `fks domains add`: | Type | Name | Value | Why | |---|---|---|---| | `CNAME` | `go.yourbrand.com` | `link-staging.funnelkit.com` | sends visitors to us | | `TXT` | `_fks-verify.go.yourbrand.com` | the token shown for your domain | proves you own the domain | Many providers want only the `go` (or `_fks-verify.go`) part in the name field. If someone else claimed your domain without verifying it, you can claim it after 72 hours. ## 4. Verify We check DNS automatically. To check now, click **Verify** in the dashboard, or run: ```shell fks domains verify ``` The status moves from `pending` to `active`, usually within a few minutes but sometimes up to a day while DNS changes spread. ## Certificates You do not need to do anything for HTTPS. Once the CNAME resolves, a certificate for your hostname is issued and renewed automatically. ## Using the domain Pass `domain` when you create a link, or pick the domain in the dashboard: ```shell fks links create https://yourbrand.com/spring --domain go.yourbrand.com --slug spring ``` Slugs are unique per domain, so `go.yourbrand.com/spring` and `link-staging.funnelkit.com/spring` can point to different places. ## Removing a domain Delete it in the dashboard, with `fks domains remove`, or `DELETE /domains/{id}`. Links on that domain stop working, so move or delete them first. --- # Pricing Annual billing gives 2 months free. All limits are soft: over the click allowance, links keep redirecting and analytics are sampled; over the new-link allowance, creating links pauses and existing links keep working. There are no overage charges. | | Free $0/mo | Pro $12/mo | Team $39/mo | Scale $129/mo | |---|---|---|---|---| | New links / month | 50 | 1,000 | 10,000 | 100,000 | | Tracked clicks / month | 10k | 100k | 1M | 10M | | Custom domains | 0 | 3 | 25 | 100 | | Analytics retention | 30 days | 1 year | 3 years | 5 years | | Members | 1 | 3 | Unlimited | Unlimited | | API requests / min | 60 | 600 | 3,000 | 10,000 | | Billed annually | – | $120/yr | $390/yr | $1,290/yr | | Unlimited link edits | yes | yes | yes | yes | | REST API, CLI and MCP server | yes | yes | yes | yes | | Every destination scanned | yes | yes | yes | yes | | QR codes | yes | yes | yes | yes | | Password protection and expiry | – | yes | yes | yes | | Routing by country and device | – | yes | yes | yes | | Styled QR codes | – | yes | yes | yes | | Mobile deep links | – | – | yes | yes | | Roles and permissions | – | – | yes | yes | | Analytics export (CSV) | – | – | yes | yes | | A/B testing | – | – | coming soon | coming soon | | Retargeting pixels | – | – | coming soon | coming soon | | Webhooks | – | – | coming soon | coming soon | | SSO (SAML) | – | – | – | coming soon | | Audit logs | – | – | – | coming soon |