This is the full developer documentation for Warmup # Build on Warmup > Connect your AI agent over MCP or call the REST API — projects, social networks, publishing and analytics, with the same account you use in the dashboard. ## Two ways to integrate [Section titled “Two ways to integrate”](#two-ways-to-integrate) [MCP server](/docs/mcp)Plug Warmup into Claude, ChatGPT, Cursor or any MCP client. The agent manages projects and reads analytics on your behalf — no code required. [REST API](/docs/api)Call Warmup from your own scripts and services: projects, connections, publishing and analytics over HTTPS with an API token. ## Which one to pick [Section titled “Which one to pick”](#which-one-to-pick) | | MCP server | REST API | | ------------------------ | -------------------------------- | ------------------- | | Who calls it | An AI assistant in a chat or IDE | Your code | | Sign-in | OAuth in the browser, one click | API token (`wmp_…`) | | Projects and connections | Yes | Yes | | Analytics | Yes | Yes | | Publishing posts | Not yet | Yes | Both use the same account and see exactly what you see in the dashboard. ## Where to go next [Section titled “Where to go next”](#where-to-go-next) * [Quickstart](/docs/quickstart) — connect an agent or make your first request in five minutes. * [API reference](/docs/reference) — every endpoint with parameters, schemas and examples. * For AI agents: this documentation is available as plain text at [`/llms.txt`](/llms.txt) and [`/llms-full.txt`](/llms-full.txt). # REST API overview > Base URL, request format and conventions of the Warmup REST API. The Warmup REST API gives your code the same capabilities as the dashboard: projects, social network connections, publishing and analytics. ## Basics [Section titled “Basics”](#basics) | | | | -------------- | ---------------------------------------------------------------------------------- | | Base URL | `https://api.warmup.social` | | Format | JSON in and out; image upload uses `multipart/form-data` | | Authentication | `Authorization: Bearer wmp_…` — see [Authentication](/docs/api/authentication) | | Dates | `YYYY-MM-DD` for periods, ISO 8601 UTC (`2026-10-01T12:00:00.000Z`) for timestamps | | Ids | UUIDs | | Specification | [OpenAPI 3](/docs/reference) | ```bash curl https://api.warmup.social/projects \ -H "Authorization: Bearer wmp_YOUR_TOKEN" ``` ## Resources [Section titled “Resources”](#resources) | Resource | Endpoints | | ---------------- | --------------------------------------------------------------------------------------------------------------------------- | | Projects | `GET /projects`, `POST /projects`, `GET · PATCH · DELETE /projects/{id}` | | Connections | `POST /projects/{id}/connections/{platform}/start`, `DELETE /projects/{id}/connections/{platform}`, Facebook Page selection | | Publications | `POST /projects/{id}/media`, `POST · GET /projects/{id}/publications`, `GET /projects/{id}/publications/{publicationId}` | | Analytics | `GET /analytics/filters · overview · platforms · top-posts · content · duration · activity` | | Tracked accounts | `GET · POST /accounts`, `PATCH · DELETE /accounts/{platform}/{username}` | | API tokens | `GET · POST /api-tokens`, `DELETE /api-tokens/{id}` | ## Limits [Section titled “Limits”](#limits) * Publishing — image upload and creating publications — is limited to **30 requests per minute** per user. Over the limit the API answers `429`. * A project’s networks are limited to Facebook, Instagram and Threads; analytics covers Instagram, TikTok and Facebook. * The number of projects depends on your plan. [Publish a post](/docs/guides/publishing)Upload an image, create a publication and wait for the result. [Read analytics](/docs/guides/analytics)Periods, filters and how the metrics are calculated. # API authentication > Create, use and revoke API tokens for the Warmup REST API. Every request needs an API token (Personal Access Token) in the `Authorization` header. A token acts as you: it sees your projects and analytics and can do what you can do in the dashboard, except managing tokens. ## Create a token [Section titled “Create a token”](#create-a-token) 1. Open the dashboard: [**API tokens**](https://app.warmup.social/en/api-tokens). 2. Click **Create token**, give it a name you’ll recognize later (“Reporting script”, “Zapier”). 3. Copy the token. It starts with `wmp_` and is shown **only once** — Warmup stores only its hash. ## Use it [Section titled “Use it”](#use-it) ```bash curl https://api.warmup.social/projects \ -H "Authorization: Bearer wmp_YOUR_TOKEN" ``` ```js const res = await fetch("https://api.warmup.social/projects", { headers: { Authorization: `Bearer ${process.env.WARMUP_TOKEN}` }, }); const { projects } = await res.json(); ``` The token list in the dashboard shows when each token was last used. ## Revoke a token [Section titled “Revoke a token”](#revoke-a-token) Click **Revoke** next to the token in the dashboard. Requests with a revoked token get `401` immediately. Caution Treat a token like a password: keep it in environment variables or a secret manager, never in client-side code or a repository. Use a separate token for each integration so you can revoke one without breaking the others. ## Errors [Section titled “Errors”](#errors) | Status | Meaning | | ------ | -------------------------------------------------------------------------- | | `401` | The header is missing, the token is wrong, revoked or expired. | | `403` | The action isn’t allowed with an API token (for example, creating tokens). | # Errors > HTTP status codes and error formats of the Warmup REST API. The API uses standard HTTP status codes. Error bodies are JSON in one of three shapes. ## Error shapes [Section titled “Error shapes”](#error-shapes) **Generic error** — status and a message: ```json { "statusCode": 404, "message": "…", "error": "Not Found" } ``` **Business error with a code** — branch on `code`, not on the message: ```json { "code": "connection_missing", "platform": "instagram" } ``` **Validation error** — what is wrong with the request body: ```json { "formErrors": [], "fieldErrors": { "mediaId": ["media_required"] } } ``` Messages are human-readable, may be localized and may change. Branch on the status and `code` — they are stable. ## Status codes [Section titled “Status codes”](#status-codes) | Status | When | | ------------ | --------------------------------------------------------------------------- | | `200`, `201` | Success. | | `202` | Accepted for asynchronous processing (publications). | | `204` | Success without a body (deletions). | | `400` | Invalid parameters or body. | | `401` | Missing or invalid token. | | `403` | Not allowed for this token. | | `404` | Not found. A resource that belongs to someone else also returns 404. | | `409` | Conflict with the current state: plan limit reached, network not connected. | | `429` | Publishing rate limit exceeded — retry after a pause. | | `503` | A dependency (for example Meta) is temporarily unavailable. | ## Common codes [Section titled “Common codes”](#common-codes) | Code | Status | Meaning | | ------------------------------------------------------ | ------ | ------------------------------------------------------------------------- | | `project_limit_reached` | 409 | The plan’s project limit is reached. | | `connection_missing` | 409 | The network isn’t connected to the project. | | `connection_not_ready` | 409 | The connection needs re-authorization. | | `media_not_found` | 400 | The image for `mediaId` was not found. | | `media_aspect_ratio` | 400 | The image doesn’t fit the Instagram feed (4:5 to 1.91:1). | | `text_required`, `media_required`, `media_not_allowed` | 400 | The publication body doesn’t match its `kind`. | | `__unsupported` | 400 | The network doesn’t support this kind, e.g. `instagram_text_unsupported`. | | `_text_too_long` | 400 | The text is over the network’s limit. | | `scheduled_at_past` | 400 | `scheduledAt` is in the past. | | `invalid_timezone` | 400 | `timezone` is not a known IANA zone. | | `publication_dispatched` | 409 | The publication was already sent and can’t be edited. | | `meta_unavailable` | 503 | Meta is temporarily unavailable. | Each endpoint lists its errors in the [API reference](/docs/reference). # Read analytics > Query metrics of your own and competitor accounts — periods, filters and how numbers are calculated. Analytics works on **tracked accounts**: Instagram, TikTok and Facebook profiles you add in the dashboard under Analytics → Accounts, or through `POST /accounts`. Each account is either yours (`own`) or a competitor’s (`competitor`). Note Analytics is independent from projects: connecting a network to a project doesn’t add the account to analytics. ## Start with filters [Section titled “Start with filters”](#start-with-filters) ```bash curl "https://api.warmup.social/analytics/filters?role=own" \ -H "Authorization: Bearer $WARMUP_TOKEN" ``` ```json { "accounts": [ { "id": "3b0e…", "platform": "instagram", "username": "acme", "displayName": "Acme", "avatarUrl": "…" } ], "groups": ["Main brand", "Regional"] } ``` Use the ids in `accountId` and the collection names in `group`. ## Common parameters [Section titled “Common parameters”](#common-parameters) | Parameter | Default | Description | | ----------- | ------------------- | --------------------------------------------------------------- | | `role` | `own` | `own` or `competitor`. | | `from` | 30 days before `to` | Period start, `YYYY-MM-DD`, inclusive. | | `to` | today in `tz` | Period end, `YYYY-MM-DD`, inclusive. | | `tz` | `UTC` | IANA time zone for day boundaries and posting hours. | | `platform` | all | `instagram`, `tiktok`, `facebook`. Comma-separated or repeated. | | `group` | all | Collection names. | | `accountId` | all | Account ids. | Invalid values fall back to defaults instead of failing: an unknown time zone becomes `UTC`, swapped dates are swapped back, and periods longer than 365 days are cut from the start. Check `period` in the response to see what was actually used. ```bash curl "https://api.warmup.social/analytics/overview?from=2026-09-01&to=2026-09-30&tz=Europe/Berlin&platform=instagram,tiktok" \ -H "Authorization: Bearer $WARMUP_TOKEN" ``` ## Reports [Section titled “Reports”](#reports) | Endpoint | Returns | | -------------------------- | ------------------------------------------------------------------------------------ | | `GET /analytics/overview` | KPIs with change, a daily series, data freshness. | | `GET /analytics/platforms` | Totals per network. | | `GET /analytics/top-posts` | Best posts; `sort` = `views` · `er` · `likes` · `comments` · `shares`, `limit` 1–50. | | `GET /analytics/content` | Content types, weekday × hour performance, top 20 hashtags. | | `GET /analytics/duration` | Views by video length bucket and the optimal length. | | `GET /analytics/activity` | Posts per day for the last `days` (7–365, default 180); ignores `from`/`to`. | ## How metrics are calculated [Section titled “How metrics are calculated”](#how-metrics-are-calculated) * **Period metrics** are the current totals of posts **published** in `[from, to]`. Views of an old post gained this month don’t count towards this month. * **Change** compares with the previous period of the same length. To be fair to young posts, the previous period is measured at the same post age (`comparison.mode: "age_matched"`). When `comparison.coverage` is below 0.8, treat the change as approximate. * `change` is in percent; for ER (`er`) it is in percentage points (`changeUnit: "pp"`). `change` is `null` when there is nothing to compare with. * `available: false` means the metric doesn’t exist for the selected networks (for example, saves on Instagram). * **Followers** are the sum of the latest known follower counts at the end of each day. Facebook rounds follower counts, so `followersApproximate` is `true` when Facebook is in scope. * **Freshness**: `freshness.stalePosts` counts posts whose metrics are older than 48 hours. ## Duration buckets [Section titled “Duration buckets”](#duration-buckets) `0-15`, `15-30`, `30-45`, `45-60`, `60-90`, `90-180`, `180+` seconds. The optimal bucket is the one with the best average views among buckets with at least 3 posts. # Connect a social network > Connect Facebook, Instagram or Threads to a project through Meta OAuth. A project publishes to the networks connected to it: Facebook (a Page), Instagram (a professional account) and Threads. Connecting always needs the account owner to approve access in a browser — it can’t be done with API calls alone. ## Flow [Section titled “Flow”](#flow) 1. Start the connection: ```bash curl -X POST https://api.warmup.social/projects/$PROJECT_ID/connections/instagram/start \ -H "Authorization: Bearer $WARMUP_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "timezone": "Europe/Berlin" }' ``` ```json { "authUrl": "https://www.facebook.com/…/dialog/oauth?…" } ``` `timezone` is optional; daily account refreshes are scheduled in it. 2. Open `authUrl` in a browser, sign in to Meta and approve the permissions. 3. Meta returns the browser to Warmup, which redirects to the project page in the dashboard: * `?connect=instagram&result=ok` — connected; * `?connect=instagram&result=error&code=…` — failed, see the codes below; * `?connect=facebook&select=` — the Facebook account has several Pages, pick one (next section). 4. Check the result: `GET /projects/{id}` returns `connections.instagram` with `status: "active"`. ## Choose a Facebook Page [Section titled “Choose a Facebook Page”](#choose-a-facebook-page) When the Facebook account manages several Pages, the user can pick one in the dashboard, or you can do it through the API with the `selectionId` from the URL: ```bash curl https://api.warmup.social/projects/$PROJECT_ID/connections/facebook/pending/$SELECTION_ID \ -H "Authorization: Bearer $WARMUP_TOKEN" curl -X POST https://api.warmup.social/projects/$PROJECT_ID/connections/facebook/select \ -H "Authorization: Bearer $WARMUP_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "selectionId": "'$SELECTION_ID'", "pageId": "1234567890" }' ``` Pages with `enabled: false` can’t be connected; `disabledReason` explains why. The selection expires after a short time — start over if it does. ## Connection status [Section titled “Connection status”](#connection-status) | Status | Meaning | | -------------- | -------------------------------------------------------------------------------------- | | `active` | Ready to publish. | | `needs_reauth` | Access was lost in Meta. Call `…/start` again for the same network and approve access. | | `revoked` | Access was revoked. Reconnect to use the network again. | `missingScopes` lists permissions the user declined; publishing may fail without them. ## Error codes after sign-in [Section titled “Error codes after sign-in”](#error-codes-after-sign-in) | Code | Meaning | | ---------------------------- | ------------------------------------------------------------- | | `oauth_denied` | The user cancelled or declined access. | | `instagram_not_professional` | The Instagram account must be a Business or Creator account. | | `no_facebook_pages` | The Facebook account doesn’t manage any Pages. | | `account_already_connected` | This account is already connected to another project. | | `platform_already_connected` | The project already has a different account for this network. | | `oauth_state_invalid` | The sign-in link expired or was used twice. Start again. | | `meta_unavailable` | Meta is temporarily unavailable. | ## Disconnect [Section titled “Disconnect”](#disconnect) ```bash curl -X DELETE https://api.warmup.social/projects/$PROJECT_ID/connections/facebook \ -H "Authorization: Bearer $WARMUP_TOKEN" ``` Note Facebook access is also revoked in Meta. Instagram and Threads access can only be revoked in the network’s own settings. Analytics history is kept. # Publish a post > Upload an image, publish a post to Facebook, Instagram and Threads and track the result. Publishing is asynchronous: you create a publication, Warmup queues it and posts to each selected network, and you poll for the result. Caution Publications go out to the connected accounts for real. Test on a separate project with test accounts. ## What each network supports [Section titled “What each network supports”](#what-each-network-supports) | Network | `text` | `photo` | `story` | Text limit | | --------- | ------ | ------- | ------- | ---------- | | Facebook | yes | yes | yes | 63,206 | | Instagram | — | yes | yes | 2,200 | | Threads | yes | yes | — | 500 | A single publication can target 1–3 networks. Every network in the list must support the chosen `kind`. ## Flow [Section titled “Flow”](#flow) 1. **Upload the image** (skip for `kind: text`). Up to 15 MB; Warmup converts it to JPEG. ```bash curl -X POST https://api.warmup.social/projects/$PROJECT_ID/media \ -H "Authorization: Bearer $WARMUP_TOKEN" \ -F "file=@photo.jpg" ``` ```json { "id": "6f1c…", "url": "https://…", "width": 1080, "height": 1350 } ``` For the Instagram feed the aspect ratio must be between 4:5 (portrait) and 1.91:1 (landscape). Stories work best at 9:16. 2. **Create the publication.** ```bash curl -X POST https://api.warmup.social/projects/$PROJECT_ID/publications \ -H "Authorization: Bearer $WARMUP_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "kind": "photo", "platforms": ["instagram", "threads"], "text": "New collection is live", "mediaId": "6f1c…" }' ``` The API answers `202 Accepted` with the publication and a target per network in status `queued`. 3. **Poll until every target is final.** ```bash curl https://api.warmup.social/projects/$PROJECT_ID/publications/$PUBLICATION_ID \ -H "Authorization: Bearer $WARMUP_TOKEN" ``` Each target moves `queued` → `publishing` → `published` or `failed`. Poll every few seconds; most posts finish within a minute. ## Polling example [Section titled “Polling example”](#polling-example) ```js const api = "https://api.warmup.social"; const headers = { Authorization: `Bearer ${process.env.WARMUP_TOKEN}` }; async function waitForPublication(projectId, publicationId) { for (let attempt = 0; attempt < 40; attempt++) { const res = await fetch(`${api}/projects/${projectId}/publications/${publicationId}`, { headers }); const publication = await res.json(); if (publication.targets.every((t) => t.status === "published" || t.status === "failed")) { return publication; } await new Promise((resolve) => setTimeout(resolve, 3000)); } throw new Error("Publication is still in progress"); } ``` ## Result [Section titled “Result”](#result) A `published` target has `permalink` (link to the post), `externalPostId` and `publishedAt`. A `failed` target has `errorCode`: | `errorCode` | What to do | | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | | `needs_reauth`, `connection_not_ready` | Reconnect the network ([guide](/docs/guides/connections)). | | `media_rejected` | The network rejected the image — check size and aspect ratio. | | `media_aspect_ratio` | The image doesn’t fit the Instagram feed. | | `rate_limit` | The network’s own posting limit — try later. | | `meta_unavailable` | Meta is temporarily unavailable — try later. | | `published_unconfirmed` | Meta published the post but didn’t return its id. The post most likely went out — check the account before retrying. | ## Schedule for later [Section titled “Schedule for later”](#schedule-for-later) A publication is a plan: `state` is `scheduled` by default, and without `scheduledAt` it goes out right away. Pass a future `scheduledAt` (ISO 8601 with offset) and the publication is sent at that moment, within about half a minute. `timezone` is the IANA zone you entered the time in — Warmup stores it to show the post in the planner at the right local time. ```json { "kind": "photo", "platforms": ["instagram"], "mediaId": "6f1c…", "text": "Friday drop", "scheduledAt": "2026-11-06T18:00:00+02:00", "timezone": "Europe/Kyiv" } ``` * `state: draft` keeps the publication in the planner without sending it. Drafts don’t need connected networks and may have no date at all. * Until a publication is sent (`state` is `draft` or `scheduled`), `PATCH /projects/{id}/publications/{publicationId}` changes any field; `scheduledAt: null` removes the date, `state: scheduled` without a date sends it right away. After sending, `PATCH` answers `409 publication_dispatched`. * `POST /projects/{id}/publications/{publicationId}/publish` sends a draft or a scheduled publication right away. * `DELETE /projects/{id}/publications/{publicationId}` removes it from the planner; a publication that is still `queued` is cancelled. * `GET /projects/{id}/publications?from=…&to=…` returns the planner window plus every draft without a date; `state` summarises the per-network result (`publishing`, `published`, `failed`). ## Rules and limits [Section titled “Rules and limits”](#rules-and-limits) * `text` is required for `kind: text`; `mediaId` is required for `photo` and `story` and not allowed for `text`. * Networks in `platforms` must be connected and `active`, otherwise the API answers `409` with `connection_missing` or `connection_not_ready`. * Upload and publication requests share a limit of 30 per minute per user (`429` above it). * `GET /projects/{id}/publications` without `from`/`to` lists the 50 most recent publications. # MCP server overview > What the Warmup MCP server is, how it works and what an agent can do with it. The Warmup MCP server lets AI assistants work with your Warmup account through the [Model Context Protocol](https://modelcontextprotocol.io). Once connected, an agent can manage projects, connect social networks and answer questions about your analytics. ## Connection details [Section titled “Connection details”](#connection-details) | | | | -------------- | ------------------------------------------------------------------- | | Server URL | `https://mcp.warmup.social/mcp` | | Transport | Streamable HTTP (stateless) | | Authentication | OAuth 2.1 with dynamic client registration; API token as a fallback | | Health check | `GET https://mcp.warmup.social/health` → `{ "ok": true }` | ## What the agent can do [Section titled “What the agent can do”](#what-the-agent-can-do) * **Projects** — list, create, update and delete projects. * **Connections** — start connecting Facebook, Instagram or Threads to a project and finish choosing a Facebook Page. * **Analytics** — key metrics with period-over-period change, network comparison, top posts, best content types and posting times, video length insights and posting regularity — for your own accounts or competitors. See the full list in [Tools](/docs/mcp/tools). ## How it works [Section titled “How it works”](#how-it-works) The server is a thin layer over the [REST API](/docs/api): every tool call becomes an API request made with your access token. The agent sees only your data and can do only what you can do in the dashboard. When the client connects, the server sends short instructions for the model: where to start (`get_analytics_filters` for analytics, `list_projects` for projects), to always mention the period the numbers cover, and to ask you before deleting a project or disconnecting a network. ## Safety [Section titled “Safety”](#safety) Every tool is marked with [MCP tool annotations](https://modelcontextprotocol.io/specification/2025-06-18/server/tools#tool-annotations): * read-only tools (all analytics, listing projects) can run without confirmation; * `delete_project` and `disconnect` are marked destructive, so clients ask you before running them; * `start_connection`, `select_facebook_page` and `disconnect` touch Meta, outside Warmup. Connecting a network always ends in your browser: the agent gives you a link and you approve access yourself. You can see and revoke connected apps in the dashboard under **MCP**. # MCP authentication > How MCP clients sign in to Warmup with OAuth 2.1, and how to use an API token instead. ## OAuth (recommended) [Section titled “OAuth (recommended)”](#oauth-recommended) The Warmup MCP server follows the [MCP authorization specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization). You don’t need to create keys: the client registers itself and you only sign in and approve access. ```text client ── POST /mcp (no token) ─────────▶ 401, WWW-Authenticate: resource_metadata=… client ── GET protected resource metadata ▶ authorization server URL client ── discovery + registration + PKCE ▶ authorization server you ── sign in to Warmup, click Allow ─▶ client receives an access token client ── POST /mcp, Bearer ─────▶ MCP server ──▶ Warmup API ``` * Discovery: `https://mcp.warmup.social/.well-known/oauth-protected-resource/mcp` (RFC 9728). For older clients the server also serves `/.well-known/oauth-authorization-server`. * Access tokens are short-lived. When one expires, the server answers `401` and the client refreshes it with its refresh token. * An OAuth token only works for your data and can’t manage API tokens. To revoke a client’s access, open the dashboard: **MCP → Connected apps → Revoke**. ## API token [Section titled “API token”](#api-token) For clients and scripts without OAuth support, send an API token in the `Authorization` header. 1. Create a token in the dashboard: [**API tokens**](https://app.warmup.social/en/api-tokens). 2. Pass it to the client: ```bash claude mcp add --transport http warmup https://mcp.warmup.social/mcp \ --header "Authorization: Bearer wmp_YOUR_TOKEN" ``` Caution An API token gives full access to your account data. Keep it in a secret store, don’t commit it, and revoke it in the dashboard if it leaks. # Connect a client > Add the Warmup MCP server to Claude Code, Claude.ai, Claude Desktop, ChatGPT, Cursor and other MCP clients. Any client that supports remote MCP servers over Streamable HTTP and OAuth works. Use this URL: ```text https://mcp.warmup.social/mcp ``` After you add the server, the client opens a browser window: sign in to Warmup and click **Allow**. The client then refreshes the access on its own. * Claude Code ```bash claude mcp add --transport http warmup https://mcp.warmup.social/mcp ``` Then run `/mcp`, pick `warmup` and finish the sign-in in the browser. To share the server with your team, add `--scope project`: it goes into `.mcp.json` in the repository, and each teammate signs in with their own account. * Claude.ai / Desktop 1. Open **Settings → Connectors**. 2. Click **Add custom connector**. 3. Name it `Warmup` and paste the server URL. 4. Click **Connect** and allow access. The connector is then available in every chat; enable it from the tools menu. * ChatGPT 1. Turn on developer mode in the connector settings. 2. Create a connector with the server URL and OAuth authentication. 3. Allow access in the window that opens. * Cursor Add the server to `~/.cursor/mcp.json` (or `.cursor/mcp.json` in a project): ```json { "mcpServers": { "warmup": { "url": "https://mcp.warmup.social/mcp" } } } ``` Then find `warmup` in the MCP section of Cursor settings and click **Connect**. * Other clients Point the client at the server URL with the Streamable HTTP transport. Clients that support the [MCP authorization spec](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization) discover the OAuth server and register themselves automatically. If your client can’t do OAuth, use an [API token](/docs/mcp/authentication#api-token) in the `Authorization` header. Tip Check the connection by asking: “List my Warmup projects.” ## Disconnect [Section titled “Disconnect”](#disconnect) Remove the server in the client, and revoke its access in the dashboard under **MCP → Connected apps**. # Example prompts > What to ask an AI agent connected to Warmup, and which tools it uses. These prompts work in any connected client. The agent chooses the tools itself; the lists show what usually happens. ## Set up a project [Section titled “Set up a project”](#set-up-a-project) > Create a project “Autumn launch” and connect Instagram to it. 1. `create_project { name: "Autumn launch" }` 2. `start_connection { id, platform: "instagram" }` 3. The agent replies with a link: open it, sign in to Instagram, approve access. 4. Ask “Is Instagram connected now?” — the agent checks with `get_project`. ## Weekly report [Section titled “Weekly report”](#weekly-report) > How did my accounts do last week compared to the week before? Show the top 5 posts by views. 1. `get_analytics_overview { from, to }` — KPIs with change. 2. `get_top_posts { from, to, sort: "views", limit: 5 }` ## Competitor research [Section titled “Competitor research”](#competitor-research) > Which content type works best for my competitors on TikTok this month, and when do they post? 1. `get_analytics_filters { role: "competitor" }` 2. `get_content_insights { role: "competitor", platforms: ["tiktok"] }` 3. `get_posting_activity { role: "competitor", platforms: ["tiktok"], days: 30 }` ## Video length [Section titled “Video length”](#video-length) > What video length gets the most views on my Instagram? `get_video_duration_insights { platforms: ["instagram"] }` ## Housekeeping [Section titled “Housekeeping”](#housekeeping) > Archive the project “Summer promo” and disconnect its Facebook. 1. `list_projects` to find the id. 2. `update_project { id, status: "archived" }` 3. `disconnect { id, platform: "facebook" }` — the client asks you to confirm. ## Tips [Section titled “Tips”](#tips) * Name the period explicitly (“in September”, “last 90 days”); otherwise the agent uses the last 30 days. * Mention the time zone if posting hours matter: “in Berlin time”. * To narrow analytics to a few accounts, say their usernames — the agent looks up ids with `get_analytics_filters`. # Tools > Every tool of the Warmup MCP server with its parameters and behavior. The server exposes 16 tools. Each one maps to a [REST API](/docs/reference) endpoint and returns its JSON response. API errors come back as a tool error that includes the HTTP status and error code, for example `409 project_limit_reached`. Hints in the tables: **read-only** tools don’t change anything; **destructive** tools ask for confirmation in most clients; **external** tools reach Meta. ## Projects [Section titled “Projects”](#projects) | Tool | What it does | Hints | | ---------------- | ------------------------------------------------------------------------- | ----------- | | `list_projects` | All projects with status, profile, connected networks and the plan limit. | read-only | | `get_project` | One project by `id`. | read-only | | `create_project` | Create a project. | | | `update_project` | Partially update a project. | idempotent | | `delete_project` | Delete a project. | destructive | **Parameters** * `get_project`, `delete_project`: `id` — project UUID. * `create_project`: `name` — 1–80 characters. * `update_project`: `id`, and any of `name`, `status` (`farm` · `active` · `paused` · `archived`), `gender` (`male` · `female`), `language` (BCP 47, e.g. `en-US`), `geo` (ISO country code, e.g. `US`). Pass `null` to clear `gender`, `language` or `geo`. ## Connections [Section titled “Connections”](#connections) | Tool | What it does | Hints | | ----------------------------- | ------------------------------------------------------------------------------------------------------ | --------------------- | | `start_connection` | Start connecting a network; returns `authUrl`. Also reconnects an account that needs re-authorization. | external | | `list_pending_facebook_pages` | Facebook Pages to choose from after sign-in. | read-only | | `select_facebook_page` | Finish connecting Facebook with the chosen Page. | external | | `disconnect` | Disconnect a network from a project. | destructive, external | **Parameters** * `start_connection`: `id`, `platform` (`facebook` · `instagram` · `threads`), optional `timezone` (IANA, e.g. `Europe/Berlin`) for daily refreshes. * `list_pending_facebook_pages`: `id`, `selectionId`. * `select_facebook_page`: `id`, `selectionId`, `pageId`. * `disconnect`: `id`, `platform`. The agent can’t complete OAuth itself: it gives you `authUrl`, you open it and approve access. See [Connect a social network](/docs/guides/connections). ## Analytics [Section titled “Analytics”](#analytics) All analytics tools are read-only and work on **tracked accounts** — your own (`role: own`, default) or competitors (`role: competitor`). | Tool | What it returns | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | `get_analytics_filters` | Tracked accounts (`id`, network, username) and collections. Call it first to get ids for filters. | | `get_analytics_overview` | Views, posts, ER, likes, comments, shares, saves, followers with change against the previous period, plus a daily series. | | `compare_platforms` | Posts, views, likes, comments, average views per post and ER per network. | | `get_top_posts` | Best posts of the period with links, captions and metrics. | | `get_content_insights` | Performance by content type, by weekday and hour, and top hashtags. | | `get_video_duration_insights` | Views by video length bucket and the best-performing length. | | `get_posting_activity` | Posts per day for the last N days and the date of the last post. | **Common filters** (all analytics tools except `get_analytics_filters`, which takes only `role`): | Parameter | Description | | ------------ | ------------------------------------------------------------------------- | | `role` | `own` (default) or `competitor`. | | `from`, `to` | Period, `YYYY-MM-DD`, inclusive. Default: the last 30 days. Max 365 days. | | `tz` | IANA time zone for day boundaries and posting hours. Default `UTC`. | | `platforms` | Only these networks: `instagram`, `tiktok`, `facebook`. | | `groups` | Only accounts from these collections. | | `accountIds` | Only these accounts. | **Extra parameters** * `get_top_posts`: `sort` — `views` (default), `er`, `likes`, `comments`, `shares`; `limit` — 1–50, default 10. * `get_posting_activity`: `days` — 7–365, default 180. It ignores `from` and `to`. How the numbers are calculated: [Analytics guide](/docs/guides/analytics). # Troubleshooting > Fixes for common problems with the Warmup MCP server. ## The client can’t connect or keeps asking to sign in [Section titled “The client can’t connect or keeps asking to sign in”](#the-client-cant-connect-or-keeps-asking-to-sign-in) * Check the URL: `https://mcp.warmup.social/mcp`, including `/mcp` at the end. * Make sure the client supports remote servers over Streamable HTTP. Older clients that only run local (stdio) servers can’t connect directly. * If you revoked the app in **MCP → Connected apps**, remove the server in the client and add it again. ## “401 Unauthorized” in the middle of a session [Section titled ““401 Unauthorized” in the middle of a session”](#401-unauthorized-in-the-middle-of-a-session) The access token expired. Good clients refresh it automatically; if yours doesn’t, reconnect the server (in Claude Code: `/mcp` → `warmup` → re-authenticate). With an API token, a 401 means the token was revoked or expired — create a new one in [API tokens](https://app.warmup.social/en/api-tokens). ## The agent says a network needs re-authorization [Section titled “The agent says a network needs re-authorization”](#the-agent-says-a-network-needs-re-authorization) A connection with status `needs_reauth` lost access in Meta (password change, expired permissions, revoked app). Ask the agent to reconnect it — it calls `start_connection` again and gives you a new link. You can also reconnect on the project page in the dashboard. ## Facebook: “choose a Page” [Section titled “Facebook: “choose a Page””](#facebook-choose-a-page) If your Facebook account manages several Pages, sign-in ends on a page picker in the dashboard. Pick the Page there, or give the agent the `selectionId` from the URL so it can call `list_pending_facebook_pages` and `select_facebook_page`. ## “project_limit_reached” [Section titled ““project_limit_reached””](#project_limit_reached) Your plan allows a limited number of projects. Delete or archive one, or upgrade the plan in the dashboard. ## Analytics is empty [Section titled “Analytics is empty”](#analytics-is-empty) * Analytics covers **tracked accounts**, added in the dashboard under Analytics → Accounts. Connecting a network to a project doesn’t add it to analytics. * Check `role`: competitors are only included with `role: competitor`. * New accounts need some time for the first data collection. # Quickstart > Connect an AI agent to Warmup or make your first REST API request. You need a Warmup account. If you don’t have one yet, [sign up](https://app.warmup.social/en/sign-up) — it takes a minute. ## Option A: connect an AI agent [Section titled “Option A: connect an AI agent”](#option-a-connect-an-ai-agent) 1. Add the Warmup MCP server to your client. The server URL is: ```text https://mcp.warmup.social/mcp ``` * Claude Code ```bash claude mcp add --transport http warmup https://mcp.warmup.social/mcp ``` * Claude.ai / Desktop **Settings → Connectors → Add custom connector**, paste the URL above. * ChatGPT **Settings → Connectors** (developer mode) → create a connector with the URL above. * Cursor Add to `~/.cursor/mcp.json`: ```json { "mcpServers": { "warmup": { "url": "https://mcp.warmup.social/mcp" } } } ``` 2. The client opens a browser window. Sign in to Warmup and click **Allow**. 3. Ask the agent something: > Show my projects and which networks are connected. > How did my Instagram do over the last 30 days? What were the top posts? More clients and details: [Connect a client](/docs/mcp/clients). ## Option B: call the REST API [Section titled “Option B: call the REST API”](#option-b-call-the-rest-api) 1. Create an API token in the dashboard: [**API tokens → Create token**](https://app.warmup.social/en/api-tokens). Copy the `wmp_…` value — it is shown only once. 2. List your projects: ```bash curl https://api.warmup.social/projects \ -H "Authorization: Bearer wmp_YOUR_TOKEN" ``` 3. Get an analytics overview for the last 30 days: ```bash curl "https://api.warmup.social/analytics/overview?role=own" \ -H "Authorization: Bearer wmp_YOUR_TOKEN" ``` Next: [authentication](/docs/api/authentication), the [publishing guide](/docs/guides/publishing) and the [API reference](/docs/reference).