{
 "slug": "plain",
 "name": "Plain",
 "url": "https://plain.com",
 "domain": "plain.com",
 "category": "customer-support",
 "category_name": "Customer support",
 "tested_at": "2026-10-06",
 "run": "20261006T085856Z",
 "draft": false,
 "reviewed": true,
 "owner_verified": null,
 "origin": "editorial",
 "history": [
  {
   "run": "20261001T225657Z",
   "date": "2026-10-01",
   "level": 1,
   "engine": {
    "runner": "omp",
    "model": null,
    "driver": null,
    "signed": true,
    "inbox": [
     "agentdrives.com"
    ],
    "robots": "start"
   }
  },
  {
   "run": "20261006T085856Z",
   "date": "2026-10-06",
   "level": 1,
   "engine": {
    "runner": "omp",
    "model": "claude-opus-5-5",
    "driver": 2,
    "signed": true,
    "inbox": [
     "agentdrives.com"
    ],
    "robots": "start"
   }
  }
 ],
 "level": 1,
 "level_name": "Needs a person",
 "level_selfhost": null,
 "entry": "closed",
 "door": {
  "passed": 0,
  "tries": 2,
  "self_start": false
 },
 "badges": [],
 "stages": [
  {
   "key": "in",
   "label": "Access",
   "state": "no",
   "text": "Can't get in on its own",
   "at": "signup"
  },
  {
   "key": "work",
   "label": "Use",
   "state": "unreached",
   "text": "Work not measured"
  },
  {
   "key": "pay",
   "label": "Pay",
   "state": "unreached",
   "text": "Payment not reached",
   "value": "unreached",
   "route": "billing_api"
  },
  {
   "key": "leave",
   "label": "Leave",
   "state": "unreached",
   "text": "Leaving not reached",
   "how": "no-account"
  }
 ],
 "outcomes": [
  {
   "key": "find",
   "label": "Find",
   "state": "part",
   "text": "Some docs agents can read: llms.txt and an MCP server",
   "have": [
    "llms_txt",
    "mcp"
   ]
  },
  {
   "key": "access",
   "label": "Access",
   "state": "no",
   "text": "Can't get in on its own",
   "at": "signup",
   "stage": "in"
  },
  {
   "key": "use",
   "label": "Use",
   "state": "unreached",
   "text": "Work not measured",
   "stage": "work"
  },
  {
   "key": "pay",
   "label": "Pay",
   "state": "unreached",
   "text": "Payment not reached",
   "value": "unreached",
   "route": "billing_api",
   "stage": "pay"
  },
  {
   "key": "leave",
   "label": "Leave",
   "state": "unreached",
   "text": "Leaving not reached",
   "how": "no-account",
   "stage": "leave"
  }
 ],
 "access": [
  {
   "key": "person",
   "label": "A person sets it up",
   "routes": [],
   "minutes": null,
   "core": null
  }
 ],
 "minutes": null,
 "next": {
  "to": 2,
  "text": "Next: let an agent sign up on its own"
 },
 "stop": "signup",
 "core": "0/8",
 "scores": {
  "coverage": null,
  "reliability": null,
  "resilience": null,
  "setup": 75,
  "surface_coverage": null,
  "docs_accuracy": null,
  "docs_completeness": null
 },
 "parts": {
  "holds_up": null,
  "docs_match": null,
  "setup": 75,
  "security": null,
  "standards": [
   {
    "standard": "MCP client registration",
    "state": "current",
    "behind": null,
    "value": "cimd"
   }
  ]
 },
 "reliability_method": null,
 "resilience": null,
 "stress": [],
 "surface_audit": null,
 "coverage_core": null,
 "after_wall": null,
 "coverage_source": "computed",
 "driver": {
  "version": 2,
  "model": "claude-opus-5-5",
  "profile": "full",
  "assisted": false,
  "handoff": null,
  "prompt_sha": "f3d0adeeb256",
  "kb_version": "2+overlay-9e43028a2c",
  "identity": null
 },
 "methodology": 15,
 "rules_date": "2026-10-15",
 "engine": {
  "runner": "omp",
  "model": "claude-opus-5-5",
  "driver": 2,
  "signed": true,
  "inbox": [
   "agentdrives.com"
  ],
  "robots": "start"
 },
 "same_level_drives": 2,
 "drives": 2,
 "works_assisted": null,
 "freshness": "fresh",
 "nothing_to_pay": false,
 "core_gated": false,
 "profiles": {},
 "agent_check": {
  "rung": "signup",
  "vendor": "Cloudflare Turnstile (managed challenge)",
  "visible": true,
  "type": "network",
  "human": "",
  "how": "Let verified bots and signed agents past the check on sign-up: in Cloudflare, add a WAF custom rule that skips the bot challenge on your sign-up paths for verified bots and for signed agents (rule field cf.bot_management.signed_agent; since 1 July 2026 signed agents count as verified bots), and render Turnstile only when the request is not from a verified agent.",
  "signed": true
 },
 "agent_pass": null,
 "who_gets_in": {
  "server": {
   "state": "form"
  },
  "signed": {
   "state": "robots",
   "kind": "signup",
   "at": "2026-10-13"
  },
  "browser": {
   "state": "through",
   "measured": false
  },
  "our_key": "pending",
  "robots": "closed",
  "tip": false
 },
 "ladder": {
  "docs": {
   "status": "headless",
   "note": "/docs/llms.txt, .md pages, Accept: text/markdown negotiation and llms-full.txt all fetched headless"
  },
  "signup": {
   "status": "human",
   "note": "Cloudflare managed challenge with visible Turnstile 'Verify you are human' on signin.auth.plain.com/sign-up; sign-in email path answered 'Access blocked, please contact support.'.",
   "via": ""
  },
  "verify": {
   "status": "",
   "note": "Not reached: no account",
   "reached": false
  },
  "credentials": {
   "status": "",
   "note": "API keys only via Settings > Machine Users in the web app; MCP needs OAuth login to a Plain account; no account",
   "via": "",
   "reached": false
  },
  "first_call": {
   "status": "",
   "note": "core-api.uk.plain.com/graphql/v1 returns 401 {\"message\":\"Unauthorized\"} without a key",
   "reached": false
  },
  "first_action": {
   "status": "",
   "note": "Not reached: no credentials",
   "reached": false
  },
  "pay": {
   "status": "",
   "grade": "P3",
   "rails": [
    "Hyperline hosted billing portal (card), plan change by GraphQL changeBillingPlan; from docs, not exercised"
   ],
   "rail_ids": [
    "hosted-checkout"
   ],
   "first_party": false,
   "rail_scope": "none",
   "trial_path": "no-card trial",
   "note": "No 402 on API or paid paths; x402./mpp./agents. subdomains do not resolve; not listed in mpp.dev or x402 Bazaar; no /.well-known/ucp. Docs: 7-day trial without card; changeBillingPlan and createHyperlineBillingPortalSession documented. From docs only: no account to exercise it.",
   "detected_grade": "P3",
   "exercised": false,
   "reached": false
  },
  "cancel": {
   "status": "",
   "note": "Not reached: no plan started (signup blocked by Cloudflare Turnstile, no account). No cancel mutation in the schema; subscription would be managed in the Hyperline billing portal (docs only). from docs, not exercised.",
   "docs_grade": "",
   "reached": false
  },
  "delete": {
   "status": "",
   "note": "No account created. No deleteWorkspace mutation and no workspace-deletion doc; deleteUser fails for the only owner",
   "account": false,
   "reached": false
  }
 },
 "routes": [],
 "checkout": null,
 "docs": null,
 "claims": null,
 "pay_options": {
  "checked": "2026-10-06",
  "source": "drive",
  "options": [
   {
    "id": "hosted-checkout",
    "name": "hosted-checkout",
    "kind": "checkout",
    "first_party": false,
    "lead": false,
    "networks": [],
    "testnet": false
   }
  ],
  "agentic": [],
  "paid": null,
  "exercised": false,
  "detected_grade": "P3",
  "trial": {
   "no_card": true,
   "card_required": null,
   "free_plan": null
  },
  "owner_fixes": [
   {
    "title": "Accept x402 or MPP on your API",
    "how": "Answer an unpaid call with 402 and a payment challenge, so an agent pays per call or buys credits without an account or a card."
   },
   {
    "title": "List your plans on Stripe Projects",
    "how": "Agents buy a plan with `stripe projects add`, paid with a token under a spend cap the owner sets (projects.dev)."
   }
  ]
 },
 "surfaces": {
  "api": true,
  "openapi": false,
  "cli": true,
  "sdk": true,
  "mcp": "official",
  "llms_txt": true,
  "webhooks": true,
  "sandbox": false
 },
 "surface_notes": {
  "api": "GraphQL, 238 queries and 352 mutations in the public schema",
  "openapi": "none; raw GraphQL schema public",
  "mcp": "official remote, OAuth only",
  "cli": "@team-plain/cli 0.4.0 on npm",
  "sdk": "@team-plain/graphql 3.2.0"
 },
 "can_do": [
  "Read all docs as markdown via llms.txt",
  "Download the full GraphQL schema without an account",
  "Discover the MCP server's OAuth metadata (PRM, CIMD, device flow)"
 ],
 "cannot_do": [
  {
   "what": "Create an account",
   "why": "Visible Cloudflare Turnstile on the WorkOS sign-up page; sign-in email path answered 'Access blocked'"
  },
  {
   "what": "Get an API key",
   "why": "Keys are created only in the web app, which needs an account"
  },
  {
   "what": "Drive any capability (threads, replies, assignment, workflows)",
   "why": "No account or credentials"
  },
  {
   "what": "Delete a workspace",
   "why": "No documented route found"
  }
 ],
 "blockers": [
  "Cloudflare Turnstile 'Verify you are human' on signin.auth.plain.com/sign-up",
  "'Access blocked, please contact support.' on the sign-in email path"
 ],
 "tips_for_owner": [
  "Let signed agents through sign-up",
  "Add an agent sign-up route ending in a key",
  "Document how to delete a workspace",
  "Make the 401 say what to send"
 ],
 "tips_for_agents": [
  "Use /docs/llms.txt and .md pages; Accept: text/markdown also works",
  "The full GraphQL schema is public at core-api.uk.plain.com/graphql/v1/schema.graphql: plan calls before you have a key",
  "A human must create the account and a machine-user API key (Settings > Machine Users); then use Authorization: Bearer plainApiKey_…",
  "MCP at mcp.plain.com/mcp uses OAuth; the AS supports CIMD and device flow"
 ],
 "selfhost": null,
 "summary": "Plain has a public GraphQL schema, SDK, CLI, an official OAuth MCP server and markdown docs, but an agent cannot create an account: the WorkOS sign-up page shows a visible Cloudflare Turnstile and the email sign-in path answered 'Access blocked'. No capability could be driven; billing (7-day no-card trial, plan change by API, card in a Hyperline portal) is graded from docs only.",
 "wall": "Cloudflare Turnstile on the sign-up page",
 "plan_scope": "",
 "robots_stop": null,
 "robots": null,
 "plain": {
  "summary": "Plain is a customer-support platform with a public API, documentation, and an official MCP server for AI agents, but an agent trying it alone cannot even create an account. The sign-up page shows a visible \"prove you're human\" check that the agent could not pass, so nothing past reading the docs could be tried.",
  "can_do": [
   "Read all of Plain's documentation and the full list of possible actions without an account",
   "See how Plain's AI login system is set up, without being able to use it"
  ],
  "cannot_do": [
   {
    "what": "Create an account",
    "why": "A visible human-verification check blocks the sign-up page"
   },
   {
    "what": "Get an API key or use any feature (replying to customers, assigning conversations, etc.)",
    "why": "All of these need an account first"
   },
   {
    "what": "Cancel a plan or delete a workspace",
    "why": "No plan or account was ever created to cancel or delete"
   }
  ]
 },
 "plan_gated": [],
 "reply": null,
 "capabilities": [
  {
   "id": "cap-01",
   "group": "core",
   "capability": "Receive and reply to a customer conversation (thread) across channels",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "mutation replyToThread / query threads",
    "mcp": null,
    "cli": null,
    "ui": "Thread view / unified queue"
   },
   "check": "GET thread shows new message in timeline via threads query",
   "source": "https://www.plain.com/docs/product/platform/threads/what-is-a-thread, https://www.plain.com/docs/graphql/messaging/reply-to-thread"
  },
  {
   "id": "cap-02",
   "group": "core",
   "capability": "Create a support thread from an inbound message or manually",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "mutation createThread",
    "mcp": null,
    "cli": null,
    "ui": "New thread button"
   },
   "check": "GET thread by id returns the created thread",
   "source": "https://www.plain.com/docs/graphql/threads/create"
  },
  {
   "id": "cap-03",
   "group": "core",
   "capability": "Let Ari (AI agent) autonomously resolve customer conversations",
   "weight": "core",
   "plan": "paid",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Ari agent assignment / Shadow Mode / Playground"
   },
   "check": "Thread shows assignee=Ari and status changes to resolved without human reply",
   "source": "https://www.plain.com/ari, https://www.plain.com/docs/product/agents/ari.md"
  },
  {
   "id": "cap-04",
   "group": "core",
   "capability": "Ask Sidekick to research, draft, or summarize inside a thread",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Sidekick panel / Slack / keyboard shortcut"
   },
   "check": "Sidekick chat pane shows the answer with cited sources for the query",
   "source": "https://www.plain.com/sidekick, https://www.plain.com/docs/product/agents/sidekick.md"
  },
  {
   "id": "cap-05",
   "group": "core",
   "capability": "Change thread status (e.g. open, needs first response, resolved, snoozed)",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "mutation changeThreadStatus (see status-changes)",
    "mcp": null,
    "cli": null,
    "ui": "Thread status control"
   },
   "check": "GET thread status field reflects new value",
   "source": "https://www.plain.com/docs/graphql/threads/status-changes, https://www.plain.com/docs/product/platform/threads/statuses"
  },
  {
   "id": "cap-06",
   "group": "core",
   "capability": "Assign a thread to a teammate, team, or AI agent",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "mutation assignThread (see assignment)",
    "mcp": null,
    "cli": null,
    "ui": "Thread assignment control"
   },
   "check": "GET thread assignedTo field shows new assignee",
   "source": "https://www.plain.com/docs/graphql/threads/assignment, https://www.plain.com/docs/product/platform/threads/assignment"
  },
  {
   "id": "cap-07",
   "group": "core",
   "capability": "Escalate a thread along a defined escalation path",
   "weight": "core",
   "plan": "paid",
   "surfaces": {
    "api": "mutation escalateThread",
    "mcp": null,
    "cli": null,
    "ui": "Escalate button / escalation paths"
   },
   "check": "GET thread shows escalation event in its activity log",
   "source": "https://www.plain.com/docs/graphql/threads/escalation, https://www.plain.com/docs/product/platform/escalation-paths"
  },
  {
   "id": "cap-08",
   "group": "core",
   "capability": "Automate triage, routing, and follow-ups with workflows (triggers/conditions/actions)",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Workflows builder"
   },
   "check": "Workflow run log shows trigger fired and configured action executed on a matching thread",
   "source": "https://www.plain.com/docs/product/workflows.md, https://www.plain.com/docs/product/workflows/workflows-actions.md"
  },
  {
   "id": "cap-09",
   "group": "secondary",
   "capability": "Create or update a customer record",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "mutation upsertCustomer",
    "mcp": null,
    "cli": null,
    "ui": "Customer profile panel"
   },
   "check": "query customerByEmail returns the upserted fields",
   "source": "https://www.plain.com/docs/graphql/customers/upsert"
  },
  {
   "id": "cap-10",
   "group": "secondary",
   "capability": "Delete a customer record",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "mutation deleteCustomer",
    "mcp": null,
    "cli": null,
    "ui": "Customer profile > delete"
   },
   "check": "query customerByEmail no longer returns the customer",
   "source": "https://www.plain.com/docs/graphql/customers/delete"
  },
  {
   "id": "cap-11",
   "group": "secondary",
   "capability": "Mark a customer as spam",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "mutation markCustomerAsSpam",
    "mcp": null,
    "cli": null,
    "ui": "Thread/customer context menu"
   },
   "check": "query customer shows status=spam",
   "source": "https://www.plain.com/docs/graphql/customers/spam"
  },
  {
   "id": "cap-12",
   "group": "secondary",
   "capability": "Create and manage companies and tenants, and set their tier",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "mutation upsertCompany / upsertTenant / updateCompanyTier",
    "mcp": null,
    "cli": null,
    "ui": "Company/tenant settings"
   },
   "check": "query company shows tier value updated",
   "source": "https://www.plain.com/docs/graphql/companies/upsert, https://www.plain.com/docs/graphql/tiers/update-company-tier"
  },
  {
   "id": "cap-13",
   "group": "secondary",
   "capability": "Apply labels and nested label types to threads",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "mutation addLabels / removeLabels",
    "mcp": null,
    "cli": null,
    "ui": "Thread label picker"
   },
   "check": "GET thread labels array includes the added label",
   "source": "https://www.plain.com/docs/graphql/labels/add, https://www.plain.com/docs/product/platform/labels"
  },
  {
   "id": "cap-14",
   "group": "secondary",
   "capability": "Set and track SLA policies, priorities, and business hours on threads",
   "weight": "secondary",
   "plan": "paid",
   "surfaces": {
    "api": "mutation applySlaPolicy",
    "mcp": null,
    "cli": null,
    "ui": "SLA settings / thread priority control"
   },
   "check": "GET thread shows slaStatus and firstResponseSla values",
   "source": "https://www.plain.com/docs/graphql/sla-policies/apply-to-thread, https://www.plain.com/docs/product/platform/slas"
  },
  {
   "id": "cap-15",
   "group": "secondary",
   "capability": "Create and manage reusable reply snippets",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "mutation createSnippet / updateSnippet / deleteSnippet",
    "mcp": null,
    "cli": null,
    "ui": "Snippets settings"
   },
   "check": "query snippets list includes the created snippet",
   "source": "https://www.plain.com/docs/graphql/snippets/create"
  },
  {
   "id": "cap-16",
   "group": "secondary",
   "capability": "Create and assign internal tasks linked to a thread",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "mutation createTask / updateTask / deleteTask",
    "mcp": null,
    "cli": null,
    "ui": "Thread tasks panel"
   },
   "check": "query tasks for the thread shows the created task",
   "source": "https://www.plain.com/docs/graphql/tasks/create, https://www.plain.com/docs/product/platform/tasks"
  },
  {
   "id": "cap-17",
   "group": "secondary",
   "capability": "Start and send messages in internal discussions (with teammates or agents)",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "mutation createDiscussion / sendDiscussionMessage",
    "mcp": null,
    "cli": null,
    "ui": "Discussion thread"
   },
   "check": "query discussion shows the sent message in its timeline",
   "source": "https://www.plain.com/docs/graphql/discussions/create, https://www.plain.com/docs/graphql/discussions/send-message"
  },
  {
   "id": "cap-18",
   "group": "secondary",
   "capability": "Add internal notes (with @mentions) to a thread",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "mutation createNote (see notes)",
    "mcp": null,
    "cli": null,
    "ui": "Thread notes panel"
   },
   "check": "GET thread notes list includes the created note",
   "source": "https://www.plain.com/docs/graphql/notes"
  },
  {
   "id": "cap-19",
   "group": "secondary",
   "capability": "Generate AI-suggested replies for a thread",
   "weight": "secondary",
   "plan": "paid",
   "surfaces": {
    "api": "query suggestedReplies",
    "mcp": null,
    "cli": null,
    "ui": "Suggested response in composer"
   },
   "check": "query suggestedReplies returns a non-empty drafted reply for the thread",
   "source": "https://www.plain.com/docs/graphql/messaging/suggested-replies, https://www.plain.com/ari/#suggested-responses"
  },
  {
   "id": "cap-20",
   "group": "secondary",
   "capability": "Publish and manage Help Center articles and navigation (knowledge base)",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "mutation createArticle / updateArticle (manage-articles)",
    "mcp": null,
    "cli": null,
    "ui": "Help Center editor"
   },
   "check": "GET help center articles query returns the published article live on the public help center",
   "source": "https://www.plain.com/docs/graphql/help-center/manage-articles, https://www.plain.com/docs/product/help-center.md"
  },
  {
   "id": "cap-21",
   "group": "secondary",
   "capability": "Let customers self-serve with Ask AI on the Help Center",
   "weight": "secondary",
   "plan": "paid",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Help Center Ask AI widget"
   },
   "check": "Public help center Ask AI returns a cited answer to a customer query",
   "source": "https://www.plain.com/docs/product/help-center/help-center-ask-ai.md"
  },
  {
   "id": "cap-22",
   "group": "secondary",
   "capability": "Send a broadcast message to a defined customer audience on a schedule",
   "weight": "secondary",
   "plan": "paid",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Broadcasts composer"
   },
   "check": "Broadcast report shows delivery to the targeted audience at the scheduled time",
   "source": "https://www.plain.com/docs/product/broadcasts.md, https://www.plain.com/docs/product/broadcasts/schedules.md"
  },
  {
   "id": "cap-23",
   "group": "secondary",
   "capability": "Send customer satisfaction (CSAT) surveys and view scores",
   "weight": "secondary",
   "plan": "paid",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "CSAT settings / thread CSAT score"
   },
   "check": "Reporting view shows a CSAT score recorded against the closed thread",
   "source": "https://www.plain.com/docs/product/platform/csat.md, https://www.plain.com/docs/product/platform/csat-scores.md"
  },
  {
   "id": "cap-24",
   "group": "secondary",
   "capability": "View reporting dashboards (volume, heatmaps, SLA compliance, themes/top issues)",
   "weight": "secondary",
   "plan": "paid",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Insights / Reporting tab"
   },
   "check": "Reporting dashboard renders metric values for the selected date range",
   "source": "https://www.plain.com/docs/product/platform/insights.md, https://www.plain.com/docs/product/platform/metrics.md"
  },
  {
   "id": "cap-25",
   "group": "secondary",
   "capability": "Link a thread to an external issue tracker (Linear, Jira, Shortcut) or incident tool",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Thread 'Link issue' action"
   },
   "check": "Thread shows a linked Linear/Jira/Shortcut issue with live status sync",
   "source": "https://www.plain.com/docs/product/integrations/linear.md, https://www.plain.com/docs/product/integrations.md"
  },
  {
   "id": "cap-26",
   "group": "secondary",
   "capability": "Set up a webhook target to receive thread/discussion/task events",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "mutation createWebhookTarget",
    "mcp": null,
    "cli": null,
    "ui": "Webhook settings"
   },
   "check": "Delivery attempts query shows a successful POST to the configured URL after a matching event",
   "source": "https://www.plain.com/docs/graphql/webhook-targets/create, https://www.plain.com/docs/webhooks.md"
  },
  {
   "id": "cap-27",
   "group": "secondary",
   "capability": "Emit custom customer or thread events for use in automation and reporting",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "mutation createCustomerEvent / createThreadEvent",
    "mcp": null,
    "cli": null,
    "ui": null
   },
   "check": "query customer timeline shows the created custom event",
   "source": "https://www.plain.com/docs/graphql/events/create-customer-event, https://www.plain.com/docs/graphql/events/create-thread-event"
  },
  {
   "id": "cap-28",
   "group": "secondary",
   "capability": "Bring a third-party or self-built AI agent into Plain as a workspace participant",
   "weight": "secondary",
   "plan": "paid",
   "surfaces": {
    "api": "docs/agents (tool-calls, suggested-replies)",
    "mcp": "Plain MCP server (per docs/integrations/mcp-server)",
    "cli": null,
    "ui": "Agent setup screen"
   },
   "check": "Thread assignee list includes the custom agent and it posts a reply via the agent API",
   "source": "https://www.plain.com/docs/product/agents/bring-your-own-agent.md, https://www.plain.com/docs/integrations/mcp-server.md"
  },
  {
   "id": "cap-29",
   "group": "secondary",
   "capability": "Define custom thread fields to extend the data model",
   "weight": "secondary",
   "plan": "paid",
   "surfaces": {
    "api": "see threads/thread-fields",
    "mcp": null,
    "cli": null,
    "ui": "Thread fields settings"
   },
   "check": "GET thread shows the custom field with its set value",
   "source": "https://www.plain.com/docs/graphql/threads/thread-fields, https://www.plain.com/docs/product/platform/threads/thread-fields"
  },
  {
   "id": "cap-30",
   "group": "secondary",
   "capability": "Save and share custom filtered views of the thread queue",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Saved views sidebar"
   },
   "check": "Saved view reappears in sidebar and applies its filter on reload",
   "source": "https://www.plain.com/docs/product/platform/views/saved-views.md"
  },
  {
   "id": "cap-31",
   "group": "secondary",
   "capability": "Merge duplicate threads",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Thread 'Merge' action"
   },
   "check": "Source thread shows status merged and redirects to the target thread",
   "source": "https://www.plain.com/docs/product/platform/threads/merging-threads.md"
  },
  {
   "id": "cap-32",
   "group": "secondary",
   "capability": "Import historical tickets from Zendesk, Intercom, Freshdesk, Help Scout, or Front",
   "weight": "secondary",
   "plan": "paid",
   "surfaces": {
    "api": "mutation importThreads (see import)",
    "mcp": null,
    "cli": null,
    "ui": "Import wizard"
   },
   "check": "query threads shows imported tickets with original timestamps preserved",
   "source": "https://www.plain.com/docs/graphql/threads/import, https://www.plain.com/docs/product/integrations/zendesk.md"
  },
  {
   "id": "cap-33",
   "group": "peripheral",
   "capability": "Create and assign custom roles with granular permission scopes",
   "weight": "peripheral",
   "plan": "paid",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Custom Roles settings"
   },
   "check": "A user assigned a restricted custom role cannot access a label/tier outside its scope",
   "source": "https://www.plain.com/overview (Custom Roles), https://www.plain.com/pricing"
  },
  {
   "id": "cap-34",
   "group": "peripheral",
   "capability": "Authenticate workspace users via SAML SSO and keep membership synced with SCIM",
   "weight": "peripheral",
   "plan": "trial",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Workspace security settings"
   },
   "check": "A user provisioned via SCIM appears in the workspace member list automatically",
   "source": "https://www.plain.com/overview (SAML SSO and SCIM), https://www.plain.com/pricing"
  },
  {
   "id": "cap-35",
   "group": "peripheral",
   "capability": "Customize the Slack bot name/avatar and configure Slack digests and discussions",
   "weight": "peripheral",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Slack channel settings"
   },
   "check": "Slack bot posts under the customized name/avatar in the connected channel",
   "source": "https://www.plain.com/docs/product/channels/customize-your-slack-bot.md"
  },
  {
   "id": "cap-36",
   "group": "peripheral",
   "capability": "Set personal status (online/offline/away) and working hours",
   "weight": "peripheral",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "User profile status control"
   },
   "check": "Teammate list shows the user's status updated to away",
   "source": "https://www.plain.com/docs/product/platform/personal-status.md, https://www.plain.com/docs/product/platform/working-hours.md"
  }
 ],
 "attempts": [
  {
   "t": "00:59",
   "cap": "discovery",
   "capability": "robots.txt / aipref",
   "task": "GET https://www.plain.com/robots.txt",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "200 text/plain; User-agent: * Allow: /, explicit Allow for GPTBot, ClaudeBot etc.; no Content-Usage or Content-signal lines; no Content-Usage header",
   "notes": "No aipref preferences published"
  },
  {
   "t": "00:59",
   "cap": "discovery",
   "capability": "llms.txt",
   "task": "GET /llms.txt and /docs/llms.txt",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "Both 200 text/plain; /docs/llms.txt indexes every docs page as .md URL",
   "notes": ""
  },
  {
   "t": "00:59",
   "cap": "discovery",
   "capability": "markdown docs",
   "task": "GET /docs/graphql/authentication with Accept: text/markdown; .md URL",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "Accept: text/markdown -> 200 content-type text/markdown, vary: rsc, accept-encoding, Accept, User-Agent; .md URLs listed in llms.txt return markdown",
   "notes": ""
  },
  {
   "t": "00:59",
   "cap": "discovery",
   "capability": "well-known cards",
   "task": "GET /.well-known/ai-catalog.json, agent-card.json, ucp, oauth-protected-resource, /auth.md on www.plain.com",
   "route": "api",
   "documented": true,
   "result": "failed",
   "verified": true,
   "evidence": "All 404 (text/html)",
   "notes": ""
  },
  {
   "t": "00:59",
   "cap": "discovery",
   "capability": "MCP server/discover",
   "task": "POST server/discover 2026-07-28 to https://mcp.plain.com/mcp",
   "route": "mcp",
   "documented": true,
   "result": "partial",
   "verified": true,
   "evidence": "401, WWW-Authenticate: Bearer resource_metadata=\"https://mcp.plain.com/.well-known/oauth-protected-resource/mcp\", scope=\"openid offline_access\"",
   "notes": "Auth required before discover; PRM present"
  },
  {
   "t": "00:59",
   "cap": "discovery",
   "capability": "MCP auth metadata",
   "task": "GET PRM and AS metadata",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "PRM: resource https://mcp.plain.com/mcp, authorization_servers [https://signin.auth.plain.com]. AS metadata: client_id_metadata_document_supported true, registration_endpoint (DCR), device_authorization_endpoint, grant device_code, S256 PKCE",
   "notes": "WorkOS AuthKit AS; CIMD + DCR + device flow"
  },
  {
   "t": "02:24",
   "cap": "signup",
   "capability": "Sign up",
   "task": "Open app.plain.com/signup -> WorkOS sign-up page in pw browser",
   "route": "browser",
   "documented": true,
   "result": "blocked",
   "verified": true,
   "evidence": "signin.auth.plain.com/sign-up shows Cloudflare managed challenge 'Performing security verification' with visible 'Verify you are human' Turnstile checkbox; did not clear after 12 s (screenshot browser/shots/003.png)",
   "notes": "Visible Cloudflare challenge on WorkOS AuthKit sign-up; not solved by us",
   "quality": {
    "error_legibility": "clear",
    "recoverable": "no"
   }
  },
  {
   "t": "02:24",
   "cap": "signup",
   "capability": "Sign up",
   "task": "Sign-in page 'Continue with email' with address (passwordless path)",
   "route": "browser",
   "documented": true,
   "result": "blocked",
   "verified": true,
   "evidence": "After submitting the agent's inbox the page shows 'Access blocked, please contact support.' (browser/shots/005.png)",
   "notes": "Invisible rejection without a challenge on the WorkOS sign-in email path; not retried"
  },
  {
   "t": "02:24",
   "cap": "signup",
   "capability": "Sign up",
   "task": "Human handoff (own browser) for the Cloudflare Turnstile on sign-up",
   "route": "none",
   "documented": true,
   "result": "blocked",
   "verified": false,
   "evidence": "",
   "notes": "Cloudflare Turnstile 'Verify you are human' on signin.auth.plain.com/sign-up"
  },
  {
   "t": "04:05",
   "cap": "discovery",
   "capability": "MCP initialize fallback",
   "task": "POST initialize offering 2026-07-28; GET /mcp/server-card",
   "route": "mcp",
   "documented": true,
   "result": "blocked",
   "verified": true,
   "evidence": "initialize -> 401 same WWW-Authenticate; /mcp/server-card -> 401",
   "notes": "Protocol version unknown: every method needs an OAuth token from a Plain account"
  },
  {
   "t": "04:05",
   "cap": "discovery",
   "capability": "GraphQL schema",
   "task": "GET https://core-api.uk.plain.com/graphql/v1/schema.graphql (linked from docs/graphql/schema)",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "200 text/plain, 668,649 bytes: 238 queries, 352 mutations; includes replyToThread, createThread, assignThread, createMachineUser, createApiKey, changeBillingPlan, createHyperlineBillingPortalSession, createWorkspace, deleteUser; no deleteWorkspace",
   "notes": "Public schema, no OpenAPI (GraphQL API). SDK @team-plain/graphql 3.2.0 and @team-plain/cli 0.4.0 on npm"
  },
  {
   "t": "04:05",
   "cap": "docs",
   "capability": "Docs",
   "task": "Read llms.txt, auth, MCP, SDK, pricing docs headless",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "/docs/llms.txt + .md pages + llms-full.txt (1,066,305 bytes) all fetched headless",
   "notes": ""
  },
  {
   "t": "04:05",
   "cap": "credentials",
   "capability": "Get API credentials",
   "task": "API key needs Settings > Machine Users in the web app; MCP needs OAuth login",
   "route": "none",
   "documented": true,
   "result": "blocked",
   "verified": false,
   "evidence": "docs/graphql/authentication.md: 'Go to Settings → Machine Users and click + Add Machine User' then 'Add API key'; no account because sign-up is behind Cloudflare Turnstile",
   "notes": "AS offers device flow and CIMD/DCR for MCP OAuth, but each still needs a Plain account"
  },
  {
   "t": "04:05",
   "cap": "first_call",
   "capability": "First API call",
   "task": "POST createThread to core-api.uk.plain.com/graphql/v1 without credentials",
   "route": "api",
   "documented": true,
   "result": "blocked",
   "verified": true,
   "evidence": "401 application/json {\"message\":\"Unauthorized\"}",
   "notes": "No unauthenticated surface besides the schema",
   "quality": {
    "error_legibility": "vague"
   }
  },
  {
   "t": "04:05",
   "cap": "cap-01",
   "capability": "Reply to a thread",
   "task": "Reply to a thread via GraphQL API / MCP",
   "route": "api",
   "documented": true,
   "result": "blocked",
   "verified": false,
   "evidence": "No account or API key: sign-up blocked by Cloudflare Turnstile (see signup); core-api returns 401 Unauthorized",
   "notes": "Not reachable without an account"
  },
  {
   "t": "04:05",
   "cap": "cap-02",
   "capability": "Create a thread",
   "task": "Create a thread via GraphQL API / MCP",
   "route": "api",
   "documented": true,
   "result": "blocked",
   "verified": false,
   "evidence": "No account or API key: sign-up blocked by Cloudflare Turnstile (see signup); core-api returns 401 Unauthorized",
   "notes": "Not reachable without an account"
  },
  {
   "t": "04:05",
   "cap": "cap-05",
   "capability": "Change thread status",
   "task": "Change thread status via GraphQL API / MCP",
   "route": "api",
   "documented": true,
   "result": "blocked",
   "verified": false,
   "evidence": "No account or API key: sign-up blocked by Cloudflare Turnstile (see signup); core-api returns 401 Unauthorized",
   "notes": "Not reachable without an account"
  },
  {
   "t": "04:05",
   "cap": "cap-06",
   "capability": "Assign a thread",
   "task": "Assign a thread via GraphQL API / MCP",
   "route": "api",
   "documented": true,
   "result": "blocked",
   "verified": false,
   "evidence": "No account or API key: sign-up blocked by Cloudflare Turnstile (see signup); core-api returns 401 Unauthorized",
   "notes": "Not reachable without an account"
  },
  {
   "t": "04:05",
   "cap": "cap-07",
   "capability": "Escalate a thread",
   "task": "Escalate a thread via GraphQL API / MCP",
   "route": "api",
   "documented": true,
   "result": "blocked",
   "verified": false,
   "evidence": "No account or API key: sign-up blocked by Cloudflare Turnstile (see signup); core-api returns 401 Unauthorized",
   "notes": "Not reachable without an account"
  },
  {
   "t": "04:05",
   "cap": "cap-03",
   "capability": "Ari resolves conversations",
   "task": "Ari resolves conversations via GraphQL API / MCP",
   "route": "api",
   "documented": true,
   "result": "blocked",
   "verified": false,
   "evidence": "No account or API key: sign-up blocked by Cloudflare Turnstile (see signup); core-api returns 401 Unauthorized",
   "notes": "Not reachable without an account"
  },
  {
   "t": "04:05",
   "cap": "cap-04",
   "capability": "Sidekick in a thread",
   "task": "Sidekick in a thread via GraphQL API / MCP",
   "route": "api",
   "documented": true,
   "result": "blocked",
   "verified": false,
   "evidence": "No account or API key: sign-up blocked by Cloudflare Turnstile (see signup); core-api returns 401 Unauthorized",
   "notes": "Not reachable without an account"
  },
  {
   "t": "04:05",
   "cap": "cap-08",
   "capability": "Workflows",
   "task": "Workflows via GraphQL API / MCP",
   "route": "api",
   "documented": true,
   "result": "blocked",
   "verified": false,
   "evidence": "No account or API key: sign-up blocked by Cloudflare Turnstile (see signup); core-api returns 401 Unauthorized",
   "notes": "Not reachable without an account"
  },
  {
   "t": "04:05",
   "cap": "pay",
   "capability": "Pay step",
   "task": "Probe 402s, well-known, registries, billing docs",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "core-api 401 not 402 on paid paths; x402./mpp./agents.plain.com do not resolve; /.well-known/ucp, /auth.md, /openapi.json 404; not in mpp.dev services or x402 Bazaar; pricing.md: 'Every plan starts with a free 7-day trial, and the trial doesn't need a credit card'; GraphQL documents changeBillingPlan, previewBillingPlanChange, createHyperlineBillingPortalSession ('returns a URL where the user can manage their subscription, invoices, and payment methods')",
   "notes": "No agent payment rail. Plan changes are a documented API call; the card goes in through the hosted Hyperline portal. Not exercised: no account"
  },
  {
   "t": "04:05",
   "cap": "cancel",
   "capability": "Cancel",
   "task": "Find a documented cancel route",
   "route": "api",
   "documented": true,
   "result": "skipped",
   "verified": false,
   "evidence": "No plan started (no account). Docs: changeBillingPlan mutation and Hyperline billing portal; no cancel mutation in schema",
   "notes": "Grade from docs only"
  },
  {
   "t": "04:05",
   "cap": "delete",
   "capability": "Delete account",
   "task": "Find a documented workspace/account delete route",
   "route": "api",
   "documented": true,
   "result": "skipped",
   "verified": false,
   "evidence": "No account created. Schema has deleteUser ('Returns an error if the user is the only owner of the workspace') but no deleteWorkspace; llms-full.txt has no workspace-deletion page",
   "notes": "Nothing to delete"
  }
 ],
 "stale": false,
 "icon": "/logos/plain.png",
 "monitored": false,
 "verdict": "Docs answer our agent on their own: llms.txt, markdown pages, a public GraphQL schema, SDK, CLI and an official OAuth MCP server. Sign-up does not. L1 · Needs a person: our agent gets in on its own nowhere. It stopped at signup, where a visible Cloudflare Turnstile challenge sits on the page. The email sign-in path answered \"Access blocked, please contact support.\" With no human to hand over a workspace, no key, call or action followed. Core-api returned Unauthorized with no credentials. Paying and leaving are graded from docs only: a trial without a card and plan changes by API, since no account ever started.",
 "page": "https://agentdrives.com/tools/plain?via=api"
}