# Everylink > Everylink is an agent-first link-in-bio platform. The HTTP API is the single > source of capability: every action a human can take in the dashboard, an agent > can take through the same API. A profile is an identity (name, bio, image, slug) > plus an ordered grid of blocks (links, text, images, social embeds, cross-promo) > that is published to a fast static viewer. ## Getting started - Base URL: https://api.everyl.ink - Auth: send your key in the `x-api-key` request header on every call. Create a key in the dashboard under Settings -> Developers -> API keys. Keys are scoped to your account; treat them like passwords. - OpenAPI: the full, always-current request/response contract is served live at https://api.everyl.ink/openapi — treat it as the source of truth for exact shapes. ## MCP - Endpoint: https://api.everyl.ink/mcp (MCP Streamable HTTP, stateless; POST JSON-RPC). Same `x-api-key` header, same permissions, same error codes as REST. - Tools: profiles.list, profiles.delegated (client profiles shared with your agency), profiles.get, profiles.update, blocks.types, blocks.add, blocks.update, blocks.delete, blocks.setLayout. Call blocks.types first for each block type's `data` JSON Schema. - Writes require `expectedVersion` (the profile's current `version`). A failed call returns an MCP tool error (`isError: true`) whose text is the REST envelope, e.g. `{ "error": { "code": "VERSION_CONFLICT", "message": "..." } }` — re-read with profiles.get and retry. - Client config (Claude Code `.mcp.json`, Cursor, and other clients that take a URL plus headers): { "mcpServers": { "everylink": { "type": "http", "url": "https://api.everyl.ink/mcp", "headers": { "x-api-key": "YOUR_KEY" } } } } Claude Code CLI: claude mcp add --transport http everylink https://api.everyl.ink/mcp --header "x-api-key: YOUR_KEY" ## Conventions - JSON request and response bodies; errors use `{ "error": { "code", "message" } }`. - Edits are version-checked: send the resource's current `version` on writes; a stale version returns a 409 conflict (optimistic locking). ## Capabilities ### Profiles - List your profiles, create a profile, fetch one by id or by slug. - Import from hoo.be at creation: `POST /profiles` with `{ slug, import: { url: "https://hoo.be/", include: "content" | "content+theme" } }` creates a NEW profile from that public page (images rehosted; native blocks; theme mapped onto the theme fields below when included). The response adds `importReport` ({ importedBlocks, issues: [{ item, reason }] }) listing skipped/approximated items. It never imports into an existing profile. A failed import creates nothing (no profile, seat or media). - Update identity (name, bio, image, slug); check slug availability; delete. - Brand logo + theme ride the same `PATCH /profiles/:id` (version-CAS): `logo` = http(s) image URL (null clears, omit = unchanged). `theme` = the whole theme object (replaces the stored one): `preset` (light | dark | cream | mono | ocean | grape | sand | custom — a named preset renders its bundle, `custom` or absent renders the fields below; retain those fields when changing preset to restore Custom later), `mode` (light | dark), `color` (page bg hex), `background` ({ url: http(s) URL, fit: cover | tile } — full-viewport image; tile = Fit width, repeat downwards, upload with media kind `page_bg`), `text`, `accent` (hex), `font` (sans | serif | Inter | Poppins | Montserrat | DM Sans | Space Grotesk | Outfit | Nunito | Roboto | Work Sans | Manrope | Playfair Display | Lora | Fraunces | EB Garamond), `corners` (sharp | soft | rounded), `card` ({ background?, border?: boolean, borderColor?, shadow?: boolean — false = flat cards, no drop shadow }), `avatar` ({ ring? }), `icons` (brand | accent), `layout` (split — default, identity left + grid on desktop | centered — one phone-width column with a centered header and the 2-col mobile grid at every size; kept when a preset is set). Hex = #rgb–#rrggbbaa. - Showcase opt-in: set `showcase: true` on the profile update to feature the page on the everyl.ink homepage; `GET /showcase` (public, no auth) lists opted-in, published profiles (slug, name, bio, image, background). - billed_to / who-pays: read and set which account is billed for a profile. - Ownership transfer: offer a profile to another account; the recipient accepts, declines, or the sender cancels (see incoming/outgoing transfer lists). ### Blocks - List, add, update, and delete a profile's blocks. `data` is an opaque per-type JSON payload (link, text, image, instagram, facebook, youtube, cross_promo, hot_bar, spotify, shop_carousel, ...). Discover each type's exact schema from the block catalog. Highlights: - link: `layout` "classic" (default) | "fill" | "top" | "left" — the image layouts use `background` as the card image; optional `button` (CTA pill label), `badge` (small round corner image URL) or `badgePlatform` (one of the 14 social brands → its glyph as the badge) and `imagePosition` ({ x, y } percent 0–100, the image focal point; default center). - hot_bar and shop_carousel accept `backgroundColor` only; `background` image input is rejected. - hot_bar: `items` = [{ platform, url }] (1–12; platform = one of the 14 social brands) — a row of round social icons. - spotify: `url` = an open.spotify.com track/album/playlist/artist/episode/ show URL → the official embed (compact at grid h1, full when taller). - youtube_video: optional `more` = [{ url }] (up to 19) → a carousel. - shop_carousel: `products` = [{ image, title, url, price? }] (1–20), optional `title`, `button` + `buttonUrl`. - text: optional `align` (left|center|right) and `size` (s|m|l); a `heading: true` text is a bare full-width section title. - New http(s) URL fields (badge, hot bar/product links + images) reject non-http schemes. - Instagram blocks take `url`: "@username" (a handle or any profile link is reduced to it) or a single post/reel link. Its feed is fetched in the background after the save and refreshed every 24h. - Preview an Instagram source before saving: `POST /instagram/preview` with `{ "source": "@username" }` (or a post/reel link) returns its handle, followers, author and recent posts. Authenticated (session or API key); 10 requests/min per user. - Reorder blocks and set the responsive grid layout ({x,y,w,h} per block). - Per-block visibility rules (schedule / geo / device targeting). ### Media - Presign an upload then attach media (e.g. profile image, image blocks); files are stored on object storage and edge-served. ### Delegation / grants - Delegate a profile to an agency account (by account id, or by the agency's account email via `POST /profiles/:id/grants/by-email`), list a profile's grants, change a grant's scope (`PATCH`), list delegated profiles, revoke a grant. Scopes: `edit` (content only) vs `manage` (content + settings). - Accepting delegated access requires the $30/mo agency add-on on the account. ### Custom domains - Add a custom hostname to a profile, list domains, trigger verification, remove. ### Analytics - Per-profile stats (timeseries by grain), breakdown by dimension, and the social mentions overlay. ### Billing - Read entitlement (is the profile allowed to publish). Start a checkout session or open the Stripe customer portal. Preview a seat change before adding a profile ($9/mo per profile). Enable or disable the agency add-on.