# CTRify MCP and REST API Canonical documentation: https://www.ctrify.com/developers OpenAPI 3.0 contract: https://www.ctrify.com/api/ctrify/v1/openapi.json Documentation version: 2026-08-15 CTRify is a hosted SEO action platform. Customers connect an AI agent through MCP or integrate their own software through the REST API. They do not install CTRify, PHP, Python, MySQL or AWS infrastructure locally. ## Canonical entry points - MCP server: `https://www.ctrify.com/mcp` - REST API base: `https://www.ctrify.com/api/ctrify/v1` - OpenAPI: `https://www.ctrify.com/api/ctrify/v1/openapi.json` - OAuth protected-resource metadata: `https://www.ctrify.com/.well-known/oauth-protected-resource/mcp` - OAuth authorization-server metadata: `https://www.ctrify.com/.well-known/oauth-authorization-server` - Dynamic client registration: `https://www.ctrify.com/oauth/register` - Authorization: `https://www.ctrify.com/oauth/authorize` - Token exchange and rotation: `https://www.ctrify.com/oauth/token` - Token revocation: `https://www.ctrify.com/oauth/revoke` The entry-point URLs are not web pages. - `GET https://www.ctrify.com/mcp` correctly returns HTTP 405 with `Standalone SSE is not enabled`. CTRify MCP uses Streamable HTTP with JSON-RPC requests over `POST`. Configure the URL in an MCP client instead of opening it in a browser. - `GET https://www.ctrify.com/api/ctrify/v1` correctly returns HTTP 404 `route_not_found`. The value is a base namespace, not an API resource. Append a documented path or use `/openapi.json`. Do not reinterpret either strict error as a successful connection. ## Choose MCP or REST Use MCP when a person wants Cursor, ChatGPT or another compatible agent to work with CTRify in natural language. Use REST for applications, scheduled integrations, dashboards and deterministic programmatic workflows. Both interfaces use the same OAuth grants, authenticated customer identity, ownership checks, reviewed operation catalog, usage billing, audit trail, idempotency controls and native CTRify behavior. ## MCP connection Required client capabilities: - Remote MCP over Streamable HTTP. - OAuth protected-resource and authorization-server discovery. - Authorization code with PKCE `S256`. - Dynamic public-client registration or an already registered public client. - Bearer authentication. ### Cursor Add this to `.cursor/mcp.json` for one project or to Cursor's global MCP configuration: ```json { "mcpServers": { "ctrify": { "url": "https://www.ctrify.com/mcp" } } } ``` Then connect CTRify from Cursor's MCP settings. Cursor should open the CTRify login and OAuth consent flow automatically. Review the exact permissions before approval. Cursor Agent CLI can use: ```text cursor-agent mcp list cursor-agent mcp login ctrify cursor-agent mcp list-tools ctrify ``` Current Cursor MCP documentation: https://cursor.com/docs/context/mcp ### ChatGPT The current ChatGPT developer-mode flow is: 1. In ChatGPT on the web, open Settings, then Security and login, and enable Developer mode. 2. Open ChatGPT Plugins and select the plus button to create a developer-mode app. 3. Choose a remote MCP connection. 4. Enter `https://www.ctrify.com/mcp` and use OAuth. 5. Complete CTRify login and consent. 6. Review the discovered tools and add CTRify from Developer mode tools in a conversation. Availability depends on the ChatGPT account and workspace policy. OpenAI's interface and eligibility can change. Current official OpenAI documentation: https://developers.openai.com/api/docs/guides/developer-mode ## MCP tools and required workflow CTRify exposes a small stable tool surface backed by 504 allowlisted operations in 25 product modules: - `ctrify_capabilities_search`: bounded search of operations available to the authenticated grant. - `ctrify_capability_get`: exact input contract, permissions, cost behavior, execution mode and side effects for one `operation_id`. - `ctrify_action_execute`: execute only that selected allowlisted operation. - `ctrify_account_snapshot`: account summary. - `ctrify_mcp_usage_get`: activation and external-access usage. - `ctrify_websites_list`: paginated owned website list. - `ctrify_website_get`: one owned website. - `ctrify_seo_opportunities_analyze`: read-only SEO opportunity audit. An agent must follow this sequence for catalog operations: 1. Search for a specific goal with `ctrify_capabilities_search`. 2. Read the exact contract with `ctrify_capability_get`. 3. Inspect permissions, arguments, defaults, cost behavior, side effects and whether execution is immediate or asynchronous. 4. Execute with `ctrify_action_execute` only when arguments match the contract. 5. For every write, job or destructive operation, supply a unique printable `idempotency_key` between 8 and 200 characters. 6. Read the returned state. A successful queue response does not imply the native asynchronous job already finished. Never pass or infer `customer_id`. CTRify derives it from the bearer token. Never infer that a mutation completed from a read response. Never retry changed mutation arguments under the same idempotency key. Native CTRify behavior is authoritative: immediate actions stay immediate, queued workflows stay asynchronous, and existing ownership, state, price, provider and product checks remain active. MCP does not add a synthetic prepare/apply workflow. ## REST API routes Base all paths below on `https://www.ctrify.com/api/ctrify/v1`. | Method | Path | Purpose | | --- | --- | --- | | `GET` | `/openapi.json` | Public OpenAPI 3.0 contract; no token or usage charge | | `GET` | `/account` | Authenticated account snapshot | | `GET` | `/usage` | Activation, included usage and reusable paid points | | `GET` | `/websites` | Paginated list of owned websites | | `GET` | `/websites/{site_id}` | One owned website's status and metrics | | `POST` | `/seo/audits` | Read-only SEO opportunity audit | | `GET` | `/capabilities` | Bounded catalog search; supply `query`, `module` or `kind` | | `GET` | `/capabilities/{operation_id}` | Exact operation contract | | `POST` | `/operations/{operation_id}` | Execute one allowlisted operation | ### List websites ```bash curl -sS \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ 'https://www.ctrify.com/api/ctrify/v1/websites?limit=25' ``` ### Search the catalog and get a contract ```bash curl -sS \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ 'https://www.ctrify.com/api/ctrify/v1/capabilities?query=author&kind=read&limit=10' curl -sS \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ 'https://www.ctrify.com/api/ctrify/v1/capabilities/authors.list' ``` ### Execute a read operation ```bash curl -sS -X POST \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ -H 'Content-Type: application/json' \ --data '{"limit":20,"status":"active"}' \ 'https://www.ctrify.com/api/ctrify/v1/operations/authors.list' ``` ### Execute a mutation ```bash curl -sS -X POST \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: author-create-20260815-0001' \ --data '{"firstname":"Ada","lastname":"Example"}' \ 'https://www.ctrify.com/api/ctrify/v1/operations/authors.create' ``` The JSON body contains only the selected operation's arguments. Do not put `operation_id`, `customer_id` or an idempotency key in the body. The operation ID comes from the path; mutations take the idempotency key from the `Idempotency-Key` header. ## OAuth for REST clients Use a maintained OAuth library where possible. CTRify supports public clients with authorization code plus PKCE `S256`; there is no reusable client secret. Access tokens last one hour. Refresh tokens last up to 30 days and rotate on every successful use. Store the newly returned refresh token before discarding the old one. Reuse of an already rotated refresh token revokes the active grant family. ### Register a public client ```bash curl -sS -X POST \ -H 'Content-Type: application/json' \ --data '{ "client_name":"Your CTRify integration", "redirect_uris":["http://127.0.0.1:8765/callback"], "application_type":"native", "grant_types":["authorization_code","refresh_token"], "response_types":["code"], "token_endpoint_auth_method":"none" }' \ 'https://www.ctrify.com/oauth/register' ``` HTTPS redirect URIs are accepted. HTTP redirect URIs are accepted only for `localhost`, `127.0.0.1` or `::1` loopback clients. ### Open the authorization request Generate a random PKCE verifier of 43 to 128 allowed characters, its SHA-256 base64url challenge, and a random state value. Open: ```text https://www.ctrify.com/oauth/authorize ?response_type=code &client_id=YOUR_CLIENT_ID &redirect_uri=YOUR_URL_ENCODED_REDIRECT_URI &scope=account%3Aread%20websites%3Aread%20assets%3Aread%20seo%3Aanalyze &state=YOUR_RANDOM_STATE &code_challenge=YOUR_BASE64URL_SHA256_CHALLENGE &code_challenge_method=S256 &resource=https%3A%2F%2Fwww.ctrify.com%2Fmcp ``` The CTRify user signs in, reviews the exact permissions and approves or denies access. Validate the returned `state` before using the returned one-time code. ### Exchange the code ```bash curl -sS -X POST \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=authorization_code' \ --data-urlencode 'client_id=YOUR_CLIENT_ID' \ --data-urlencode 'code=THE_RETURNED_CODE' \ --data-urlencode 'redirect_uri=http://127.0.0.1:8765/callback' \ --data-urlencode 'code_verifier=YOUR_ORIGINAL_PKCE_VERIFIER' \ --data-urlencode 'resource=https://www.ctrify.com/mcp' \ 'https://www.ctrify.com/oauth/token' ``` ### Rotate a refresh token ```bash curl -sS -X POST \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=refresh_token' \ --data-urlencode 'client_id=YOUR_CLIENT_ID' \ --data-urlencode 'refresh_token=YOUR_CURRENT_REFRESH_TOKEN' \ --data-urlencode 'resource=https://www.ctrify.com/mcp' \ 'https://www.ctrify.com/oauth/token' ``` ## OAuth scopes When `scope` is omitted, CTRify grants only `account:read websites:read assets:read seo:analyze`. | Scope | Permission | | --- | --- | | `account:read` | Read account state and setup | | `websites:read` | Read owned websites and metrics | | `seo:audit` | Run the dedicated read-only SEO audit | | `assets:read` | Read owned assets, content, campaigns, jobs and reports | | `assets:write` | Edit or publish supported owned assets | | `seo:analyze` | Run analyses and plans without mutations | | `seo:execute` | Run SEO workflows, queues and native credit-using actions | | `connections:manage` | Manage supported connections | | `billing:read` | Read plans, credits and invoices | | `billing:manage` | Run supported billing-management operations | | `domains:manage` | Run registration, DNS and nameserver workflows | | `outreach:send` | Connect delivery providers and send or schedule outreach | | `destructive:execute` | Delete, stop or irreversibly roll back supported assets | Write, execution, connection, billing, domain, outreach and destructive scopes must be requested explicitly and appear on the consent screen. ## Activation and external usage billing MCP and REST access is available to active CTRify customers regardless of subscription type. Subscription plans continue to determine the normal price at which the customer buys CTRify credits. - The first approved external connection charges 100 CTRify credits once per customer and activates both MCP and API access. - Later compatible clients do not create another activation charge for that same account. - Each customer receives 100 included external-access points per UTC day. - After the included allowance, one CTRify credit purchases 1,000 reusable external-access points. - Small indexed reads normally use very few points. Wider lists, live audits, repeated polling and bulk work scale with the requested or returned work. - Handled failed requests consume only anti-abuse overhead. Internal CTRify failures consume no usage points. - Operations with a native CTRify price retain it and receive only external orchestration overhead; the native work is not priced twice. Usage is enforced, not simulated or shadow billed. Every completed result includes usage metadata. Use MCP `ctrify_mcp_usage_get` or REST `GET /usage` to inspect it. ## Security constraints - The authenticated token selects the customer. Clients cannot select or override `customer_id`. - Only reviewed catalog operations can run. - No public route accepts arbitrary PHP method names, SQL, cron callbacks, filesystem paths or internal object-storage keys. - Catalog search is bounded and returns summaries; exact schemas are retrieved one operation at a time. - Native ownership, availability, state, provider and price checks remain active. - Mutations require idempotency protection. - Access and refresh tokens are stored by CTRify only as hashes. - Never put raw tokens in URLs, prompts, source control or logs. - Rate limits, catalog-enumeration controls, usage metering, auditing and grant revocation apply to all plans. ## REST response model Success: ```json { "data": {}, "meta": { "request_id": "...", "api_version": "2026-08-15", "usage": {} } } ``` Error: ```json { "error": { "code": "invalid_arguments", "message": "The request or operation arguments are invalid." }, "request_id": "..." } ``` | Status | Meaning | | --- | --- | | `400` | Malformed request, path or protocol input | | `401` | Missing, expired or invalid bearer token | | `402` | Additional CTRify credits required for external usage | | `403` | Missing scope or inactive access | | `404` | Missing route, resource or owned object | | `405` | Existing route called with an unsupported HTTP method | | `409` | Idempotency key conflicts with an earlier request | | `422` | Query, JSON body or operation arguments violate the contract | | `429` | Request, heavy-operation or enumeration rate limit reached | | `503` | CTRify failed closed because a required metering/runtime dependency was unavailable | The live OpenAPI and OAuth metadata are authoritative for route and authorization discovery.