Developers
The OneLink API
Add tiles, change your page and read your audience and insights from your own code, Zapier, or an assistant. On every plan.
Quickstart
- In your dashboard, open API & assistants, type a name under API keys and click Create a key. Copy it: we only show it once.
- Check it works:
curl https://onelinkin.bio/api/v1/me \ -H "Authorization: Bearer onelink_live_…"
- List your pages. Use a page's id or its handle anywhere a page is asked for.
curl https://onelinkin.bio/api/v1/pages \ -H "Authorization: Bearer onelink_live_…"
- Add a tile. Its picture and headline come from the link.
curl -X POST https://onelinkin.bio/api/v1/pages/yourname/tiles \
-H "Authorization: Bearer onelink_live_…" \
-H "Content-Type: application/json" \
-d '{"url": "https://yournewsletter.com/p/this-week", "section": "Issues"}'Assistants (MCP)
Claude, ChatGPT, Cursor and other assistants connect to https://onelinkin.bio/api/mcp. They sign in with OAuth, so there's no key to paste. Setup for each one is on the connect page. The tools run through the same code as the API, so the two always agree.
Endpoints
Every request is JSON. Send your key as Authorization: Bearer <key>. The full schema is in openapi.json (OpenAPI 3.1).
| Endpoint | What it does | Scope |
|---|---|---|
| GET /api/v1 | Versions and where the MCP server, docs and OpenAPI document are. | none |
| GET /api/openapi.json | This document, as OpenAPI 3.1. | none |
| GET /api/v1/me | Who the key belongs to, its scopes and its name. | any key |
| GET /api/v1/pages | Every page you're on, with your role and the page's plan. | page:read |
| GET /api/v1/pages/{page} | A page's settings, its sections, and its tiles as a tree (folders hold children). | page:read |
| PATCH /api/v1/pages/{page} | Change the name, intro, design, accent, layout, buttons, social links, announcement, send-everyone-to-one-link, language, footer logo size, the link preview's title and description (share_meta, Pro), or the page's own fonts, colours, background, blocks and header (style; each section merges, '' clears a choice, null a section). | page:write |
| GET /api/v1/pages/{page}/tiles | Every tile on the page as a flat list, in page order. | page:read |
| POST /api/v1/pages/{page}/tiles | Add a tile from a link (its picture and headline come with it), a folder, a section button, a form, or a block: text, heading, faq, testimonials, quote, resume, timeline, countdown, marquee, file, image or social_row, with its fields in content. Files and pictures come from a public url; upload from a computer in the dashboard. | page:write |
| POST /api/v1/pages/{page}/tiles/reorder | Put tiles that share a folder (or the top level) in a new order. | page:write |
| PATCH /api/v1/pages/{page}/tiles/{id} | Change a tile: title, link, section, folder, pin, price, badge, schedule, hide, gate; a link tile's animation, goal bar and thumbnail; a block's content. | page:write |
| DELETE /api/v1/pages/{page}/tiles/{id} | Delete a tile. A tile from a link is kept out of sight so feeds don't add it back; a folder's tiles move up a level. | page:write |
| GET /api/v1/pages/{page}/qr-codes | The page's QR codes: what each printed code holds (scan_url), where it goes now, its scans and its look. Free pages have 3; Pro and up as many as they like. | page:read |
| POST /api/v1/pages/{page}/qr-codes | Make a QR code that goes to any address. It can be repointed later without a reprint. | page:write |
| PATCH /api/v1/pages/{page}/qr-codes/{id} | Rename, repoint (target_url) or restyle a QR code. The code itself never changes, so printed copies keep working. | page:write |
| GET /api/v1/pages/{page}/short-links | The page's short links, newest first, with their clicks and campaign tags. Free pages have 10; Pro and up as many as they like. | page:read |
| POST /api/v1/pages/{page}/short-links | Make a short link to any address, with your own ending or a random one, and optional UTM tags. | page:write |
| PATCH /api/v1/pages/{page}/short-links/{id} | Repoint a short link, change its note or its UTM tags. The address stays the same. | page:write |
| DELETE /api/v1/pages/{page}/short-links/{id} | Delete a short link. Anyone who taps it afterwards sees a not found page. | page:write |
| GET /api/v1/pages/{page}/subscribers | The page's email subscribers, newest first. | audience:read |
| GET /api/v1/pages/{page}/forms | The page's forms and gates, with their fields and how many replies each has. | audience:read |
| GET /api/v1/pages/{page}/forms/{id}/responses | One form's replies, newest first. | audience:read |
| GET /api/v1/pages/{page}/messages | Messages sent from the page's message box, newest first. | audience:read |
| GET /api/v1/pages/{page}/products | What the page sells: downloads, tips, tickets, paid bookings and paid links, with prices (in the smallest unit, like cents), tickets sold and whether each is on the page. | page:read |
| GET /api/v1/pages/{page}/orders | Paid, refunded and abandoned orders, newest first, with the buyer, the amount and OneLink's 5% fee. Refunds are made in the dashboard. | audience:read |
| POST /api/v1/pages/{page}/broadcasts | Draft an email to the page's subscribers (Pro): a subject, Markdown before and after, link tiles and a button. It's sent from the dashboard, after a look over. | page:write |
| POST /api/v1/pages/{page}/broadcasts/{id}/test | Send a draft to your own email address, marked as a test. | page:write |
| GET /api/v1/pages/{page}/people | Everyone who got in touch through the page (signed up, wrote, RSVPd, filled in a form, passed a gate, bought or booked), seen most recently first, with their tags and notes. Filter by tag or segment. | audience:read |
| PATCH /api/v1/pages/{page}/people | Set one person's tags (the whole list) and/or notes (Pro). Tags are copied to Mailchimp, and to the CRM on Enterprise, where connected. | page:write |
| GET /api/v1/pages/{page}/segments | Saved segments of the audience list, each with its filter in words and how many subscribers an email to it would reach. | audience:read |
| POST /api/v1/pages/{page}/segments | Save a segment (Pro): a filter by tag, how people got in touch, when they first did, whether they wrote and whether they bought. Send an email to it with create_broadcast_draft's segment_id. | page:write |
| DELETE /api/v1/pages/{page}/segments/{id} | Delete a segment. Nobody is removed from the list. | page:write |
| GET /api/v1/pages/{page}/tests | Running A/B tests on tiles: each version's title and link, how many visitors saw it, taps and tap rate since the test started. | insights:read |
| POST /api/v1/pages/{page}/tiles/{id}/variant | Try a second version of a link tile (Pro): half the visitors see this title and/or link. Sending it again changes version B and starts the count again. | page:write |
| DELETE /api/v1/pages/{page}/tiles/{id}/variant | End a tile's test: keep=a leaves the tile as it is, keep=b makes version B the tile's own. | page:write |
| GET /api/v1/pages/{page}/link-alerts | What the daily link check found broken: link tiles whose page doesn't load (with the status the site answered) and feeds that stopped working. | page:read |
| GET /api/v1/pages/{page}/assist | AI helpers on this page: whether the server has them switched on, whether the plan includes them (Pro), calls used today out of 60, and whether the summary email starts with an AI paragraph. | page:read |
| POST /api/v1/pages/{page}/assist | Ask an AI helper (Pro, owners, admins and editors, 60 calls a page a day): kind bio (three intro options), tiles (tiles from a newsletter issue or article, by text or url), pin (the tile to pin this week, with a reason), caption (a caption made shorter, clearer or a question) or translate (strings into another language). Only the page's own content and added-up numbers are sent; nothing on the page changes. | page:write |
| PATCH /api/v1/pages/{page}/assist | Turn the AI paragraph at the top of the summary email on or off. On needs Pro, and it's written only when the server has AI switched on. | page:write |
| GET /api/v1/pages/{page}/translations | The page's translated copies (Pro): each language's name, intro, captions by tile id and section names, whether it's live at onelinkin.bio/handle/lang, and the page's own words to translate. | page:read |
| PATCH /api/v1/pages/{page}/translations/{lang} | Add a language or change one (Pro; owners, admins and editors). Send only what changes; captions and sections replace their whole list. Empty words show the page's own. live: true shows it with a language switcher and hreflang links. | page:write |
| DELETE /api/v1/pages/{page}/translations/{lang} | Remove a language. Its address then opens the page in its own language. | page:write |
| POST /api/v1/pages/{page}/translations/{lang}/suggest | Translate for me (Pro, when AI is switched on): the page's name, intro, section names and captions in that language, from the AI helper. Nothing is saved; send what you want to keep to saveTranslation. Each 50 strings is one of the page's 60 AI calls a day. | page:write |
| POST /api/v1/pages/{page}/copy | Make a copy of the page (owners and admins): settings, design, tiles with their pictures and files, folders, sections, forms and gates, feeds, events and booking setup. Not subscribers, messages, orders, products, tile tests, alerts, short links or QR codes. The copy belongs to the page's owner and counts toward their plan's pages. | page:write |
| GET /api/v1/pages/{page}/sign-in-links | The page's sign-in links for collaborators (owners and admins): who made each, its note, whether it's open, used, turned off or expired, and who used it. Links are made in the dashboard only; the address is shown once there. | page:read |
| DELETE /api/v1/pages/{page}/sign-in-links/{id} | Turn off a sign-in link that hasn't been used (owners and admins). | page:write |
| GET /api/v1/pages/{page}/domain | The page's own domain (Publisher and above): a root domain like yourpaper.com or a subdomain like links.yourpaper.com, whether it's live, and the DNS records to add. A root domain also gets www records; www visitors go on to the root domain. HTTPS is free and automatic. Set in the dashboard under Design. | page:read |
| GET /api/v1/page-moves | Requests you sent to bring in a page you own on another OneLink account: the page, the email it went to, and whether it's waiting, moved, cancelled, turned down or expired. | page:read |
| POST /api/v1/page-moves | Ask to bring in a page you own on another account (Publisher and above, with room for one more page). If that email owns the page, it gets a link that works once for 7 days; the move happens only when the owner presses Move the page there, signed in. The page keeps its address, tiles, subscribers and settings; the old account stays on its team. Pages that sell through Stripe, or the only page on a paid plan, can't move. | page:write |
| DELETE /api/v1/page-moves/{id} | Cancel a request to bring in a page that's still waiting. | page:write |
| GET /api/v1/directory | Pages listed in the OneLink directory, verified first, by kind of page (the fourteen on onelinkin.bio/for) or by name. Each has its address, name, intro, kind, verified check and a rough size, never exact numbers. Good for finding pages to recommend. | page:read |
| GET /api/v1/pages/{page}/insights | Views, taps, tap rate, sign-ups, a daily series, top tiles and buttons, referrers and devices. | insights:read |
| GET /api/v1/pages/{page}/health | The page's health: a score out of 100 and what to fix (broken links, sample text, a missing photo or intro, untitled or repeated tiles and more), each with the dashboard address that fixes it. Checked at most once a day. | page:read |
| GET /api/v1/pages/{page}/preview | Redirects (302) to the page's preview image, the picture shown when it's shared. | page:read |
| GET /api/v1/white-label | The key owner's white-label settings (Enterprise): whether the OneLink name is off their pages, share cards, emails to visitors and the sign-in page on their own domain, and the sender name, support email and sign-in name. Changed in the dashboard under Pages & team. | page:read |
| GET /api/v1/roadmap | OneLink's public roadmap (shipped, building, planned; only shipped items carry a date) and changelog, newest first. No key needed. | none |
| POST /api/mcp | The MCP server (streamable HTTP, JSON-RPC 2.0) for Claude, ChatGPT, Cursor and other assistants. | any key |
Scopes
page:read: See your pages.page:write: Change your pages.audience:read: See your subscribers, messages and form replies.insights:read: See your insights.
A key acts as you, on every page you're on, within your role: viewers and contributors can read but not change a page, and only owners, admins and editors see subscribers, messages and form replies. A page's plan still applies, so scheduling a tile on a Free page answers plan_required.
Errors
Every error has the same shape:
{ "error": { "code": "not_found", "message": "That tile isn't on this page." } }| validation_error | 400 | Something in the request isn't right. details lists each problem. |
| unauthorized | 401 | No key, a key we don't know, or one that was revoked or expired. |
| plan_required | 402 | The page's plan doesn't include this, like scheduling on Free. |
| forbidden | 403 | The key lacks the scope, or your role on the page doesn't allow it. |
| not_found | 404 | No such page, tile or form among yours. |
| conflict | 409 | The change clashes with the page as it is now. |
| rate_limited | 429 | Too many requests. Wait for Retry-After seconds. |
| server_error | 500 | Our side failed. Try again in a moment. |
Rate limits
120 requests a minute per key, 30 of them changes. Every answer carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset; a 429 also carries Retry-After.
Versions
v1 is current. Changes within v1 are additive: new fields and new endpoints, never a removed or renamed one. We give 180 days notice before retiring anything.
For machines
- /api/openapi.json: the OpenAPI 3.1 document
- /.well-known/mcp/manifest.json: the MCP server and how to sign in
- /llms.txt: OneLink in plain text, for language models
Questions or a bug? Email support@onelinkin.bio.