API docs

SelfScale API

Call SelfScale from your own code with a personal API key. Today the supported programmatic interface is the MCP endpoint: JSON-RPC 2.0 over HTTPS.

On this page

Overview

SelfScale exposes one programmatic endpoint, https://selfscale.app/api/mcp. It speaks the Model Context Protocol over Streamable HTTP, which is plain JSON-RPC 2.0 sent with an HTTP POST. AI clients such as Claude and Cursor use it for you, and you can call it directly with curl or any HTTP library.

REST API

A REST API is coming. Until then there are no REST endpoints to call: the MCP endpoint is the supported interface, and everything on this page uses it.

Every tool available with a personal API key is read-only. To connect an AI assistant instead of writing code, see the MCP server guide.

Authentication

Create a personal API key in SelfScale under Settings › Developer. Keys start with ss_live_, are shown once, and can be revoked at any time. Send the key on every request in the Authorization header:

Header
Authorization: Bearer ss_live_...

A missing, malformed, revoked or expired key gets 401 Unauthorized with a WWW-Authenticate: Bearer challenge. Keep keys out of source control and client-side code; treat a key like a password.

Base URL and request format

ItemValue
EndpointPOST https://selfscale.app/api/mcp
Content-Typeapplication/json
Acceptapplication/json, text/event-stream (both are required)
BodyOne JSON-RPC 2.0 message per request. Batches (arrays) are refused.
ResponseA JSON-RPC 2.0 response with Content-Type application/json.
Health checkGET https://selfscale.app/api/mcp returns the server name and version, no key needed.

The server is stateless, so you can call tools/list and tools/call directly. Sending an initialize request first is optional; it returns the server's capabilities and protocol version:

curl · initialize
curl -s https://selfscale.app/api/mcp \
  -H "Authorization: Bearer $SELFSCALE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"my-script","version":"1.0.0"}}}'

List tools

tools/list returns every tool your key can call, with its title, description, JSON Schema for its arguments and annotations such as readOnlyHint.

curl · tools/list
curl -s https://selfscale.app/api/mcp \
  -H "Authorization: Bearer $SELFSCALE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Response (trimmed)
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "get_voice_profile",
        "title": "Get my voice profile",
        "description": "Your SelfScale voice profile: the rules your writing follows, your signature phrases, words you avoid, and your tone settings. Use it to write in your voice.",
        "inputSchema": {
          "type": "object",
          "properties": {}
        },
        "annotations": {
          "title": "Get my voice profile",
          "readOnlyHint": true,
          "destructiveHint": false,
          "idempotentHint": true,
          "openWorldHint": false
        }
      },
      {
        "...": "8 more"
      }
    ]
  }
}

Call a tool

tools/call runs one tool. Put the tool name in params.name and its arguments in params.arguments. The tool's result comes back as JSON text inside result.content[0].text.

curl · tools/call get_voice_profile
curl -s https://selfscale.app/api/mcp \
  -H "Authorization: Bearer $SELFSCALE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"get_voice_profile","arguments":{}}}'
Response
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"success\":true,\"hasProfile\":true,\"profile\":{\"name\":\"My voice\",\"active\":true,\"version\":3,\"updatedAt\":\"2026-10-02T12:00:00.000Z\"},\"voice\":{\"learned\":true,\"rules\":[\"Short sentences.\",\"Open with a concrete number.\"],\"signaturePhrases\":[\"Here's the thing\"],\"avoidedWords\":[\"leverage\",\"synergy\"]},\"tone\":{\"...\":\"your tone settings\"},\"toneOmitted\":false}"
      }
    ]
  }
}

Every available tool, its arguments and an example response are listed in the tools reference.

Rate limits

Each key can send up to 60 requests a minute. Each account also has a number of calls per day, set by plan and reset at midnight UTC. Every request counts, including tools/list and initialize.

PlanCalls per day
StandardNot included
Premium25 calls per day
Power25 calls per day
Pro (existing subscribers)5 calls per day

Usage headers

Successful responses carry your daily usage:

HeaderMeaning
X-MCP-LimitCalls allowed today
X-MCP-UsedCalls used today, including this one
X-MCP-RemainingCalls left today

Going over either limit returns 429. Wait for the reset (the response body includes resetAt for the daily limit), then retry. Back off and retry on 503 after the number of seconds in Retry-After.

Errors

HTTP errors

The request was refused before any tool ran. The body is JSON with error and message.

StatusWhenWhat to do
400The body was a JSON-RPC batch (an array of messages).Send one message per request.
401The Authorization header is missing, or the key is wrong, revoked or expired.Check the header reads Bearer followed by your full key, or create a new key.
403Your plan doesn't include MCP, or the request came from a browser origin that isn't allowed.MCP comes with Premium and Power. Browser pages can't call it; call from a server, script or desktop app.
406The Accept header doesn't list both application/json and text/event-stream.Send Accept: application/json, text/event-stream.
413The request body is larger than 256 KB.Send smaller arguments.
429You went over 60 requests a minute, or your plan's calls for the day.Wait for Retry-After or the daily reset (resetAt), then retry.
503SelfScale couldn't check your key, plan or usage just then, or MCP is paused. Nothing was run.Retry after the seconds in Retry-After.

Tool errors

The request was accepted but the tool could not finish. The HTTP status is 200, the JSON-RPC result has isError: true, and content[0].text holds {"error": CODE, "message": "..."}.

CodeMeaning
INVALID_INPUTAn argument is missing, the wrong type, out of range or too long. The message says which. Arguments that don't match the schema come back as "Invalid input" with details.
UNAUTHORIZEDYour key or plan can't use this tool (the analytics tools need Full Analytics), or a connected app rejected SelfScale's stored connection. The message says which; for a connected app, reconnect it on the Integrations page.
NOT_FOUNDThe thing you asked for doesn't exist, or the feature isn't available on your account yet.
RATE_LIMITEDA connected app (or that tool's own limit) asked to slow down. Try again later.
UNAVAILABLEYour data couldn't be read just then. Nothing changed; try again.
Tool error example
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"error\":\"NOT_FOUND\",\"message\":\"Competitors is not available on your account yet.\"}"
      }
    ],
    "isError": true
  }
}

A malformed JSON-RPC message gets a standard JSON-RPC error (for example -32600 invalid request or -32602 invalid params) instead of a result.

Versioning

The endpoint follows the MCP specification. The server negotiates the protocol version in initialize; the version used in these examples is 2025-06-18. Tool names are stable. New tools and new optional arguments can be added at any time, so ignore fields you don't recognize. Breaking changes, such as a renamed tool, are listed on this page.