# Analytics
Source: https://snapto.link/docs/api/analytics
Read visit and click analytics for a profile.
## Summary
```bash theme={null}
curl "https://snapto.link/api/v1/profiles/PROFILE_UUID/analytics/summary?days=7" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
```
Requires `analytics:read`. Returns visits, clicks, top links, and top countries for the window.
## The days parameter
| Parameter | Default | Range |
| --------- | ------- | ------------------------ |
| `days` | `7` | 1 to your plan's maximum |
`days` is clamped rather than rejected. Ask for more days than your plan allows and you get your plan's maximum back, not an error. Ask for fewer than 1 and you get 1.
Analytics are collected asynchronously, so the most recent hits can take a short while to appear.
# Elements
Source: https://snapto.link/docs/api/elements
Create, update, delete, and reorder the links on a profile.
An element is one row on a link page. Most are links, but headers and contact rows are elements too.
## Element types
| Type | What it is |
| ------------- | -------------------------------------- |
| `link` | A titled link to a URL |
| `header` | A section heading, with no destination |
| `socialmedia` | A social platform icon link |
| `telephone` | A phone number |
| `email` | An email address |
| `contactcard` | A downloadable contact card |
## List a profile's elements
```bash theme={null}
curl https://snapto.link/api/v1/profiles/PROFILE_UUID/elements \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
```
Requires `elements:read`. Returns elements in display order.
## Create an element
```bash theme={null}
curl -X POST https://snapto.link/api/v1/elements \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"profile_id": "PROFILE_UUID",
"type": "link",
"name": "My new video",
"content": "https://youtube.com/watch?v=dQw4w9WgXcQ",
"enabled_for_display": true,
"enabled_for_download": false
}'
```
Requires `elements:write`.
| Field | Required | Notes |
| ---------------------- | -------- | ------------------------------------------------------------------------- |
| `profile_id` | Yes | The profile the element belongs to. |
| `type` | Yes | One of the types above. |
| `enabled_for_display` | Yes | Whether the element shows on the public page. |
| `enabled_for_download` | Yes | Whether the element is included in the contact card download. |
| `name` | No | The label. Max 255. |
| `content` | No | The destination. Max 255. |
| `description` | No | Optional description. |
| `order` | No | Position within its type. Omit it and the element is appended to the end. |
Creating a link counts against your plan's link limit.
## Update an element
```bash theme={null}
curl -X PUT https://snapto.link/api/v1/elements/ELEMENT_UUID \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"type": "link",
"name": "My new video (updated)",
"content": "https://youtube.com/watch?v=dQw4w9WgXcQ",
"enabled_for_display": true,
"enabled_for_download": false
}'
```
Requires `elements:write`.
`PUT` is a full representation, not a patch. `type`, `enabled_for_display`, and `enabled_for_download` are required on every update. If you omit them, the request fails validation. Fetch the element first and resend its current values for anything you are not changing.
## Reorder elements
```bash theme={null}
curl -X POST https://snapto.link/api/v1/elements/reorder \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"profile_id": "PROFILE_UUID",
"elements": [
{ "id": "ELEMENT_UUID_1" },
{ "id": "ELEMENT_UUID_2" },
{ "id": "ELEMENT_UUID_3" }
]
}'
```
Requires `elements:write`. The array order becomes the display order. Every id must belong to the given profile.
## Delete an element
```bash theme={null}
curl -X DELETE https://snapto.link/api/v1/elements/ELEMENT_UUID \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
```
Requires `elements:write`. This is irreversible.
# Overview
Source: https://snapto.link/docs/api/overview
Base URL, conventions, and the full endpoint list for REST API v1.
## Base URL
```
https://snapto.link/api/v1
```
Every request needs a bearer token and an `Accept: application/json` header. See [Authentication](/docs/authentication).
## Conventions
* **Identifiers are UUIDs.** Profile and element ids are strings, not integers.
* **`PUT` replaces, it does not patch.** Element updates must resend `type`, `enabled_for_display`, and `enabled_for_download` along with whatever you are changing. Send the element's current values for the fields you do not want to touch.
* **Booleans are real booleans.** Send `true`, not `"true"` or `1`.
## Endpoints
| Method | Path | Ability |
| -------- | ---------------------------------- | ---------------- |
| `GET` | `/profiles` | `profiles:read` |
| `POST` | `/profiles` | `profiles:write` |
| `GET` | `/profiles/{id}` | `profiles:read` |
| `PUT` | `/profiles/{id}` | `profiles:write` |
| `GET` | `/profiles/{id}/elements` | `elements:read` |
| `GET` | `/profiles/{id}/analytics/summary` | `analytics:read` |
| `POST` | `/elements` | `elements:write` |
| `POST` | `/elements/reorder` | `elements:write` |
| `PUT` | `/elements/{id}` | `elements:write` |
| `DELETE` | `/elements/{id}` | `elements:write` |
Create, read, and update profiles.
The links on a page: create, update, delete, reorder.
Visits, clicks, and top links.
## Rate limits and errors
60 requests per minute. See [Authentication](/docs/authentication) for the full status code table.
# Profiles
Source: https://snapto.link/docs/api/profiles
List, read, create, and update link-in-bio profiles.
A profile is one link-in-bio page. It has a public handle (`snapto.link/{url}`), a title, a bio, a template, and an ordered list of elements.
## List profiles
```bash theme={null}
curl https://snapto.link/api/v1/profiles \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
```
Requires `profiles:read`. Returns every profile you own.
## Get a profile
```bash theme={null}
curl https://snapto.link/api/v1/profiles/PROFILE_UUID \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
```
Requires `profiles:read`. Returns the profile with its ordered elements and its template.
## Create a profile
```bash theme={null}
curl -X POST https://snapto.link/api/v1/profiles \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"name": "Launch page",
"url": "acme-launch",
"enabled": true,
"title": "Acme",
"bio": "Everything we ship, in one place."
}'
```
Requires `profiles:write`.
| Field | Required | Notes |
| ------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | Yes | Internal name. Max 255 characters. |
| `enabled` | Yes | `true` publishes the page, `false` keeps it unpublished. |
| `url` | Yes | The public handle. 3 to 255 characters, letters, numbers, dots, underscores, and hyphens only. Cannot start with a dot. Must be unique, and some handles are reserved. |
| `title` | No | Public heading. Max 255. |
| `bio` | No | Public bio. Max 255. |
| `description` | No | Internal description. |
| `template_id` | No | A template UUID. Premium templates require a paid plan. |
Creating a profile counts against your plan's profile limit.
## Update a profile
```bash theme={null}
curl -X PUT https://snapto.link/api/v1/profiles/PROFILE_UUID \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"title": "Acme, now with more links",
"enabled": true
}'
```
Requires `profiles:write`.
Set `enabled` to publish or unpublish the public page. Design fields (`buttons_color`, `buttons_text_color`, `text_color`, `buttons_styles`, `hide_logo`, `google_analytics`, and `url_display: subdomain`) require a paid plan and return an error on lower plans.
# Authentication
Source: https://snapto.link/docs/authentication
Tokens, abilities, plan requirements, and rate limits.
The REST API and the MCP server share one credential: a personal API token created in the dashboard under **Settings** then **API**.
## Tokens
Tokens are shown once, at creation. Store the value somewhere safe. You can revoke a token at any time from the same screen, which immediately cuts off both API and MCP access for it.
The REST API takes the token in a header:
```bash theme={null}
curl https://snapto.link/api/v1/profiles \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
```
The MCP server takes it in the URL, because most MCP clients cannot send custom headers:
```
https://snapto.link/mcp/YOUR_TOKEN
```
Because the MCP token sits in the URL, treat the whole URL as a secret. Do not paste it into a shared config file, a screenshot, or a support ticket.
## Abilities
Every token carries a set of abilities. Grant only what the integration needs. A reporting script does not need write access.
| Ability | What it unlocks |
| ---------------- | --------------------------------------------------------------- |
| `profiles:read` | Read profiles, and the runtime schema |
| `profiles:write` | Create and update profiles, publish and unpublish |
| `elements:read` | Read a profile's links |
| `elements:write` | Create, update, delete, and reorder links, and set social links |
| `analytics:read` | Read visit and click analytics |
A request that needs an ability the token lacks returns `403`.
## Plan requirement
API and MCP access requires an active paid subscription, Lite or above. Every plan starts with a 7 day free trial, and the trial includes full access.
Without an active subscription, REST requests return `403` and MCP requests return a JSON-RPC error.
## Rate limits
The REST API allows **60 requests per minute** per user. Over the limit, you get `429`.
The MCP endpoint allows **60 requests per minute** per IP address.
## Errors
The REST API uses standard status codes.
| Status | Meaning |
| ------ | ------------------------------------------------------------------------ |
| `401` | Missing or invalid token, or the resource is not yours |
| `403` | The token lacks the required ability, or there is no active subscription |
| `404` | The resource does not exist |
| `422` | Validation failed. The response body lists the field errors |
| `429` | Rate limit exceeded |
Ownership failures return `401` rather than `404`. A profile that is not yours is treated as an authorisation failure, not a missing resource.
Over MCP, the same conditions come back as tool errors with a readable message rather than HTTP status codes.
# Introduction
Source: https://snapto.link/docs/index
Build on SnapToLink with a REST API and a hosted MCP server.
SnapToLink is a link-in-bio platform. You build a profile page of links, it renders at your own URL, and you get visit and click analytics for it.
Everything you can do in the dashboard, you can also do from code or from an AI agent. There are two ways in.
A JSON API over HTTPS. Use it from your backend, a script, or a scheduled job.
A hosted MCP endpoint. Point Claude, Cursor, or any MCP client at it and manage your page in plain language.
## What you can build
* Keep a link page in sync with your latest content, automatically
* Add, update, and reorder links programmatically
* Set social and contact links from a platform key and a handle
* Pull visit and click analytics into your own dashboards
* Let an agent manage your page for you
Both surfaces run on the same underlying logic, so a link created over the API is identical to one created by an agent or by hand in the dashboard.
## Before you start
You need two things:
1. **An API token.** Create one in the dashboard under **Settings** then **API**.
2. **An active paid plan.** API and MCP access requires a Lite plan or above. Every plan starts with a 7 day free trial, and the trial includes full access.
Create a token and make your first call in about two minutes.
## These docs are agent readable
Every page is available as raw markdown, and the whole site is published in the formats AI tools expect:
* [`llms.txt`](https://snapto.link/docs/llms.txt) lists every page
* [`llms-full.txt`](https://snapto.link/docs/llms-full.txt) is the entire site in one file
Append `.md` to any page URL to get its markdown source.
# Overview
Source: https://snapto.link/docs/mcp/overview
Connect an AI agent to your link-in-bio page over MCP.
SnapToLink hosts an MCP server, so an agent can read and update your page directly. No local process to run, no wrapper to install.
## Endpoint
```
https://snapto.link/mcp/YOUR_TOKEN
```
It speaks Streamable HTTP with JSON-RPC 2.0. Create the token in the dashboard under **Settings** then **API**.
The token is embedded in the URL, because most MCP clients cannot send custom headers. Treat the entire URL as a secret. Revoke the token to cut off access.
An active paid plan is required, Lite or above. The 7 day free trial counts.
## Setup
```bash theme={null}
claude mcp add --transport http snaptolink https://snapto.link/mcp/YOUR_TOKEN
```
Add this to your MCP settings JSON:
```json theme={null}
{
"mcpServers": {
"snaptolink": {
"type": "http",
"url": "https://snapto.link/mcp/YOUR_TOKEN"
}
}
}
```
Go to **Settings** then **MCP** then **Add server**. Choose the HTTP transport and paste the same URL.
Add a custom connector pointing at the URL. This needs a ChatGPT plan that supports connectors.
## Try it
Once connected, ask your agent things like:
* "Add my new video to the top of my SnapToLink page"
* "Which of my links got the most clicks this week?"
* "Hide the old promo link"
* "Set my Instagram to @acme"
## Abilities still apply
The MCP server enforces the same token abilities as the REST API. A read-only token can list and read, but any attempt to write comes back as a tool error. Give an agent a read-only token when you only want reporting.
All 12 tools and the ability each one needs.
## Keep a human in the loop
An agent acts with the full power of the token you hand it. Deleting an element is irreversible. Grant `elements:write` and `profiles:write` only when you actually want the agent changing your page, and review what it changed.
# Tools
Source: https://snapto.link/docs/mcp/tools
The 12 tools exposed by the SnapToLink MCP server.
The server exposes 12 tools. Each one requires an ability on your token, and a tool whose ability is missing returns an error rather than silently doing nothing.
| Tool | Ability | What it does |
| ------------------- | ---------------- | ------------------------------------------------------------------------------------ |
| `profile_list` | `profiles:read` | List all profiles you own |
| `profile_get` | `profiles:read` | One profile with its ordered elements and template |
| `profile_schema` | `profiles:read` | Discover valid element types, field constraints, templates, and social platform keys |
| `profile_create` | `profiles:write` | Create a profile |
| `profile_update` | `profiles:write` | Publish, unpublish, retitle, change template or design |
| `element_list` | `elements:read` | A profile's links in display order |
| `element_create` | `elements:write` | Add a link or header |
| `element_update` | `elements:write` | Update an existing link |
| `element_delete` | `elements:write` | Remove a link. Irreversible |
| `element_reorder` | `elements:write` | Reorder a profile's links |
| `social_link_set` | `elements:write` | Set a social or contact link from a platform key and handle |
| `analytics_summary` | `analytics:read` | Visits, clicks, and top links for a recent window |
## Start with profile\_schema
`profile_schema` exists so an agent does not need these docs in its context. It returns, at runtime:
* the valid element types
* field constraints for profiles and elements
* the templates available to your plan
* the social platform keys and the handle format each one expects
Call it before creating or updating anything.
## Notes on specific tools
### element\_update
`type`, `enabled_for_display`, and `enabled_for_download` are required by the underlying validator. Send the element's current values for any field you are not changing.
### element\_reorder
Pass element ids in the order you want. Positions are assigned from the array order. Ids that do not belong to the profile are rejected, so a typo fails loudly instead of silently reordering nothing.
### social\_link\_set
Pass a platform key and the bare handle. The destination prefix is applied on the server, so you send `acme`, not `https://instagram.com/acme`. Setting the same platform twice updates the existing link rather than adding a second one.
### analytics\_summary
The requested window is clamped to your plan's allowed range and reporting delay. Ask for more days than your plan permits and you get the maximum, not an error.
### element\_delete
Irreversible. The server's own instructions tell agents to confirm with a human first, but that is guidance, not enforcement. A token with `elements:write` can delete.
# Quickstart
Source: https://snapto.link/docs/quickstart
Create a token, make your first API call, and connect an agent.
This takes you from nothing to a working call against your own profile.
## Prerequisites
* A SnapToLink account with an active Lite plan or above. The 7 day free trial counts.
* At least one profile. Create one in the dashboard if you have not yet.
## Create a token
In the dashboard, go to **Settings** then **API**.
Grant only what the integration needs. To read your links and analytics, `profiles:read`, `elements:read`, and `analytics:read` are enough.
See [Authentication](/docs/authentication) for what each ability unlocks.
The token is shown once. Store it somewhere safe. If you lose it, revoke it and create another.
A token acts as you. Never commit one to source control or paste it into a public issue.
## Make your first call
List your profiles:
```bash theme={null}
curl https://snapto.link/api/v1/profiles \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
```
You get back your profiles, each with an `id` you can use in the other endpoints.
Now add a link to one of them. Swap in a profile `id` from the previous response:
```bash theme={null}
curl -X POST https://snapto.link/api/v1/elements \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"profile_id": "PROFILE_UUID",
"type": "link",
"name": "My new video",
"content": "https://youtube.com/watch?v=dQw4w9WgXcQ",
"enabled_for_display": true,
"enabled_for_download": false
}'
```
Load your public page and the link is there. Creating an element needs a token with `elements:write`.
## Connect an agent instead
If you would rather talk to your page than write requests against it, point an MCP client at the hosted server. The same token works.
```bash theme={null}
claude mcp add --transport http snaptolink https://snapto.link/mcp/YOUR_TOKEN
```
Then ask it to add a link, reorder your page, or tell you which link got the most clicks this week.
Setup for Claude Code, Claude Desktop, Cursor, and ChatGPT.
## Get help
Something not working? Email [support@snapto.link](mailto:support@snapto.link).