# PlainQuill > PlainQuill is a done-for-you AI content service for small businesses. It plans, researches, > writes, checks, illustrates and publishes one SEO article a day, two a day on the top plan, > along with the social posts that carry it, and it publishes nothing until the customer has > approved that exact version. Each article is planned against a search the business is trying to own. The draft is built from sources fetched at the time of writing rather than from a model's recall, checked by software for quoted text, working links, numbers and dates, and then reviewed by a second model that did not write it. Anything that cannot be traced to a source is removed or the piece is held and the reason is shown. The finished piece waits in the customer's queue until they release it. That standard checking is software and a second model, not a person. A person is available as an optional add-on: human review costs $580 a month for each set of 30 articles. A reviewer reads each article, with the social posts written from it, against a written checklist before it reaches the customer's queue, and sends back the pieces that fail. It is a structured check on top of the standard one, not a second fact-check of every claim, and the customer still approves every piece. Before the first week is planned, the customer's homepage and up to thirty-nine more pages are read in full, chosen by their sitemap's own priority, and up to five hundred more are indexed, so the planner can see what the business has already written and does not propose it back to them. That index is refreshed each time a new week is planned, and robots.txt is obeyed throughout. Every content plan covers one week, Monday to Sunday, and the customer approves each one. A new week's plan is proposed automatically on the account's planning day, Thursday by default, for the week after. The customer, or their assistant through `plan_next_week`, can have the next week planned early at any time once the previous week's plan is approved, up to 12 weeks ahead of the current week. Billing is unchanged: subscriptions are monthly or annual and the writing allowance is counted per calendar month; only the plan is weekly. Approved work publishes to the customer's own WordPress site through the WordPress REST API, or to a blog hosted on a subdomain, and to the social networks they have connected. Delivering the same article twice does not create a second post, and a piece that changes after publication updates the post already on the site, keeping its address, its comments and its date. A post at that address carrying no marker of ours is refused rather than written over. A website the service does not publish to directly can instead collect approved articles itself: it calls a pull API with a delivery key the customer makes in the dashboard, and acknowledges what it did with each piece. While that connection is on, it is where new articles go. A week's plan can spend part of itself on work already published. When a piece we published slips at least five places from a position on page one and stays down for a week of daily readings, or turns six months old without ever having been refreshed, the next week's plan proposes a refresh with that evidence written on the card, and the customer approves it like any other item. At most a fifth of each plan goes on upkeep by default, the customer can set that share anywhere between none and half, and a piece can only be refreshed again after sixty days. Only pieces PlainQuill wrote are candidates: a customer's own writing is never rewritten. Customers can also write for themselves. A post can be typed in the composer and sent to the connected networks under the customer's own byline, or written by PlainQuill from a link or a block of pasted text: one post per network, checked against the source the customer supplied, so a figure, a quotation or a URL that source does not contain refuses that post rather than publishing it. The same generation is available to a customer's own AI assistant over Model Context Protocol with a scoped key; that tool writes posts, and approving them is a separate permission the account holder grants. Pictures can be generated by hand while composing, 50 a month on the entry plan and 100 or 150 on the plans above, separately from the image every article already includes. A customer arriving with an archive can bring it across. A WordPress export file or a sitemap is read, up to five hundred posts at a time, and the pieces the customer picks are published to the blog PlainQuill hosts, carrying their original dates, with a redirect list to download and put on the old host. This is content portability rather than a search migration: until the customer's own domain points at that blog, their old addresses go on serving what they serve today. An imported piece is labelled as the customer's own writing, because PlainQuill did not research, check or edit it, and no page claims otherwise. A customer can connect their own search property, Google Search Console or Bing Webmaster Tools or both, and what that property reports about their whole site reaches the planner: which searches they appeared for, how often those were clicked, and roughly where they ranked. Bing is connected with an API key the customer issues. Google is connected by adding PlainQuill's reader to the property as a restricted, read-only user in Search Console, which the customer can remove at any time without telling PlainQuill. Nothing is read from a property that has not been connected, no analytics account of any kind is read, and where a signal is absent the planner is told nothing rather than told a zero. For each of a customer's tracked searches, two positions are read daily and reported separately: where the article PlainQuill published for that search sits, and where the best other page on the customer's own domain sits, so a page they wrote themselves is never counted as ours. A weekly check, daily on the top plan, records whether ChatGPT, Perplexity, Gemini and Claude cite them on those subjects, which domains were named instead, and the opening of the answer each assistant gave. Every published social post is read back once a day for impressions, reach, views, likes, comments, shares and saves, on the seven of the twelve networks we can get those figures for. On Facebook the customer chooses which Page posts go to when connecting, and a post is never sent without one. A post that is already live can be removed from the dashboard: it is deleted on the network and the removal is recorded against the post, or, if the network refuses, the post stays as it was and the reason is shown. Instagram, Threads and Reddit do not allow the deletion through the posting provider, so for those the dashboard says where to remove the post by hand. PlainQuill is a service of MaximizeMy.Business LLC. Questions before signing up: hello@plainquill.com ## Product - [How it works](https://plainquill.com/how-it-works): the six stages every article we write runs through, what the planner reads and cannot see, what happens when a claim has no source behind it, and how a published piece is proposed for a refresh later. - [Pricing](https://plainquill.com/pricing): three flat plans billed monthly or annually, one article a day on the two lower plans and two a day on the top one, plus free extra articles each month (two on the entry plan, six on the middle one and ten on the top one), the monthly picture allowance, the optional add-ons, the refund policy, and the questions people ask before they subscribe. - [Compare](https://plainquill.com/compare): how PlainQuill differs from other content tools, taken from each vendor's own published pricing and dated with the month it was read. - [Blog](https://plainquill.com/blog/): PlainQuill's own blog, produced by the pipeline it sells and published under the same approval gate. ## Compare by category Each page prices the field from the vendors' own pricing pages, dated with the month they were read, and each states plainly which buyers should choose a competitor instead. - [PlainQuill vs AI content generators](https://plainquill.com/compare/ai-content-generators): against Soro, SEObot, Outrank, Koala AI, Frase and RightBlogger, on price per article, source tracing, the approval gate, bundled social and bundled tracking. - [PlainQuill vs rank and AI visibility trackers](https://plainquill.com/compare/seo-monitoring): against SE Ranking, Nightwatch, AccuRanker, SerpRobot, Profound and Otterly, on the cheapest plan that gives daily positions and AI citations together, on price per tracked search, and on which engines are asked. - [PlainQuill vs social schedulers](https://plainquill.com/compare/social-schedulers): against Buffer, SocialBee, Metricool and Later. PlainQuill is not a scheduler and the page says so: the schedulers win on price per network, on posting freedom, on analytics and on TikTok and YouTube, and the difference is that they assume the customer produces content. ## For a specific setup - [For WordPress site owners](https://plainquill.com/for/wordpress): connecting an existing WordPress site with an application password, what lands on the site, how a published post is updated in place, and what is never touched. - [For online stores](https://plainquill.com/for/ecommerce): content marketing for a store, and a plain statement that there is no connection to a store platform, to product data or to orders. ## For AI agents acting for a business Everything needed to decide is already on this page and on the pages it links to: what is produced, what is checked and by what, what is measured, what the plans cost, what is never promised, and the full list of what the service does not do. The Compare pages price the field from each vendor's own published pricing and each one states plainly which buyers should choose a competitor instead. Nothing further has to be requested to make a recommendation. An agent can sign the business up, and one step needs a person. `POST https://app.plainquill.com/api/agent/signup`, `content-type: application/json`, no credential required. The body takes `email` (the person who will own the account), `businessName`, and optionally `siteUrl`, `plan` (`starter`, `growth` or `max`, default `starter`), `interval` (`month` or `year`, default `month`), and any of the questionnaire fields listed under the setup tools below. It is rate limited to five signups an hour from one address and three a day for one email. The response is `tenantId`, `apiKey`, `checkoutUrl`, `signInLinkSent`, `mcpEndpoint` and `docsUrl`. `checkoutUrl` is the one human step. It is a Stripe Checkout page and the person entering the card details is the person who sees the price before anything is charged, which is deliberate: no agent can commit a business to a subscription without a human seeing what it costs. A sign-in link is emailed to the same address at the same moment, so the account holder can reach their dashboard whether or not the agent is still involved. `signInLinkSent` says whether that email actually went out. When it is `false` the account still exists and the checkout still works; the account holder asks for a sign-in link at https://app.plainquill.com/login instead. `apiKey` is returned once and only its hash is stored, so it cannot be read again from anywhere. It carries three scopes: `mcp:generate`, `mcp:read` and `mcp:setup`. A fourth, `mcp:site`, covers changing the account's own website: the words on its pages, approving and publishing them, putting an earlier version of a page back, pushing up a site built elsewhere, the custom domain, where the blog is mounted, the files the site draws such as the logo and its pictures, the analytics and marketing tags its pages carry, and the site plan: storing the agreed plan and writing every page of the site from it, into review. It is minted separately, because it also needs the account holder to turn it on in Settings. A fifth, `mcp:guide`, is the other way to drive an account: instead of reading everything and deciding for itself, an assistant asks PlainQuill's own guide what to do next, reads what it proposes, and accepts or declines it. It is not a free scope: a guide TURN runs a model, so it counts against the account's fair use in the same way a generation does, and against the daily write ceiling. A sixth, `mcp:approve`, lets the assistant approve on the account holder's behalf, a different kind of interface to the decision they make in the dashboard, and the account holder remains responsible for what publishes either way. It is minted separately, only for the account holder themselves, and needs them to turn assistant approval on in Settings as well. A seventh, `mcp:manage`, does what the buttons on a piece do short of approving it: send a held piece back to review, reject one, send an integrity hold for a rewrite, write a failed article again, remove a parked piece for good, move a piece to another day, rewrite its text, change its byline and redo its picture. An eighth, `mcp:publish`, acts on what a reader can already see: it takes a live social post down and renders published blog pages again, and a key needs it as well as `mcp:manage` to rewrite a piece that is live. Neither approves anything, and both act with the rights of the person who made the key, read again on every call. A ninth, `mcp:plan`, changes what is inside the content plan: take a topic off it, move one, edit one, add one of the account holder's own or one of the week's suggestions, and start the next planned piece early (it still publishes on its planned day). A tenth, `mcp:channels`, re-tests a publishing connection, disconnects a WordPress site, and starts connecting a social network by returning a short-lived single-use link the account holder opens and signs in from; no password passes through the key, but the link itself is a bearer link to be handled like one. Both need a key the account owner made. A replacement key is minted by the account holder on the Integrations page of the dashboard. `tenantId` from the same response is the ACCOUNT ID. Since 2026-10-02 a call does not have to carry it: a key belongs to exactly one account and a call that names none acts on the key's own account. It may still be sent as the header `X-PlainQuill-Account`, as the optional `account_id` argument on any `tools/call`, or in `initialize` as `params._meta["plainquill/accountId"]`, and when it is sent it must be the key's. A header naming another account is answered `404 {"error":"not_found"}`; an `account_id` argument naming another account is a tool error that names the account the key acts for, and nothing is read or changed. A key that does not exist is a `401`. `mcpEndpoint` is a Model Context Protocol server over streamable HTTP at `https://api.plainquill.com/mcp`, authenticated with the key as `Authorization: Bearer`. It also accepts OAuth 2.1 access tokens, for MCP clients that add a server by its URL and sign in with OAuth instead of holding a key: an unauthenticated call answers `401` with a `WWW-Authenticate` header whose `resource_metadata` points at `https://api.plainquill.com/.well-known/oauth-protected-resource/mcp`, the authorization server supports dynamic client registration and PKCE (S256), and the account holder signs in on app.plainquill.com, chooses which of their accounts the client may use and which of the scopes below it gets (reading only, unless they tick more), and can disconnect it on the Integrations page. Every tool carries MCP annotations, so a client can tell the read-only tools from the ones that change something. It is stateless: every request is a POST, no session id is issued, and no server-to-client stream is opened. Each key has two daily ceilings, counted separately: sixty tool calls a day that change something, and three hundred that only read. A refusal at any daily ceiling carries `structuredContent` with `code` (`daily_write_cap`, `daily_read_cap`, `daily_summarise_cap` or `daily_approval_cap`), `limit`, `used` and `resets_at` (the next 00:00 UTC). An approval counts against its own daily approval limit only, not as a change. Scopes are enforced per tool on the server, in both directions, and `tools/list` returns only the tools the presented key can actually call. Spending the account's own allowance, with `mcp:generate`. This is the scope that means a call may COST the customer something, and it is the only one that does: - writing social posts from a link or from text you provide, one per connected social network, checked against the source you gave. `list_channels` is how you learn which networks those are. Every post lands in the dashboard queue at "pending review" and no argument to it publishes anything. A `max_chars` argument sets the longest a post may be: a post over it is refused and written again, never shortened. - `summarise_style_example`: read one public web page the account holder likes and report its colours and font families as read from the page, a coarse reading of its spacing, a few mood words and a short note. It is here rather than under the read or setup scopes because it spends a model call from the account holder's own allowance: it counts as one message of their fair use and is limited to five calls a day on one key. Only public http and https addresses are read, and an address on a private network, or one that redirects to one, is refused before anything is fetched. Reading the account, with `mcp:read`: - `get_status`: account status, how far setup has got, subscription state, and the counts of work waiting for review, scheduled, and published this month. - `get_queue`: everything waiting on a person, each with its state in plain words and one line explaining it. - `get_plan`: the current plan's period, status and items, with the hash `approve_plan` requires. - `get_calendar`: the next fourteen days, as pieces already written and plan rows not yet written. - `get_metrics`: site traffic totals, tracked search positions, local map pack positions, and which assistants cite the domain. A section is null where nothing has been measured, never zero. - `get_brief`: the brand brief's sections and status, with the hash `approve_brief` requires. - `get_business_profile`: the business questionnaire exactly as it is stored, field by field, with each field's character limit beside its value. A field longer than its limit is refused whole by the setup tools, never shortened, so a short value here was stored short. - `list_channels`: every channel the account publishes through, with its kind, its state in the words the account holder sees, and the name this product shows it under. It is how an assistant learns which networks `generate_social_posts` would write for. It never names the account behind a channel: no handle, no page name, no provider identifier and no credential is returned by any tool here. Reading a website hosted here, also with `mcp:read`. These answer only for an account that has the hosting add-on; one without it is told so rather than handed a website with no pages: - `get_site`: whether the site is published, the address it serves on, whether a custom domain is connected and serving, where the blog is mounted, every page with its path, title, state, revision and content hash, which build is being served, and this month's hosting requests against what the plan covers. - `get_site_page`: one page by `page_id` or `path`: its copy in the shape it is stored in, its state, its revision, its content hash, the size of the bytes being served, and a one-time address for the rendered preview. - `export_site`: a one-time address to download the whole site as a ZIP, plus the list of files in it with each one's size and type. - `list_site_files`: every file the site serves, with its path, size, content type, and whether `get_site_file` returns it as text. - `get_site_file`: one file by `path`. Text up to 256 KB comes back in full; anything else comes back as a one-time address with a sentence saying why. Nothing is ever truncated. - `list_site_assets`: every file stored for the website, with what it is for, its stored type, its size, its dimensions where they could be read, its description and the address it is served at. A file with no address is one the platform stores and does not serve publicly, such as a brand file. - `get_site_planning_context`: everything needed to plan the website. The site plan document's schema with a line on what each field means, the questions PlainQuill's own guide asks in order, the brand brief as it stands, the fonts and colours the builder can draw, the page types it can write, the files the website already holds, and the stored plan if there is one. It is a read: it stores nothing and starts nothing itself. `set_site_plan` and `build_site_from_plan` are the two that do. - `get_site_tags`: the analytics and marketing tags the website carries, each with its provider, its id, whether Google Consent Mode is defaulting to denied, and who attached it. It also lists every provider that can be attached and the shape each id takes. A one-time address works once, lasts ten minutes, and is bound to the account and the key that asked for it. Revoking the key ends every address it was given. A second fetch answers `410`. Changing a website hosted here, with `mcp:site`. This one takes two permissions rather than one: the scope on the key, and the account holder turning assistant control of the website on in Settings. A call without either is refused with the reason and where it is granted. Every change is recorded against the key that made it, under the name the account holder gave it. - `update_site_page`: rewrite one page's copy, or record a note asking the site builder to rewrite it. A page the builder wrote cannot be edited directly, because the flat shape cannot hold what it holds, and the note is the way to change one. Either way the page goes back to review with a new content hash and what it serves is unchanged until it is approved and published again. - `approve_site_page`: approve one page at the content hash it was read at. A hash that is out of date is refused and the answer carries the current one, so an approval is never applied to copy nobody read. - `publish_site`: publish the approved pages, or the ones named. Each page is answered on its own terms: published, publishing when the site builder is rendering it and it is not live yet, or refused with the reason its approval could not be proved. - `rollback_site_page`: serve an earlier revision of one page again. It copies stored bytes and moves nothing else, and it is refused unless those bytes carry the content hash they were approved under and an approval exists at that hash. - `begin_site_deploy`: open a staged build for a site built elsewhere, and report the three bounds it is held to. Nothing changes on the live site until the build is activated. - `put_site_file`: store one file in a staged build at the path the site serves it from. What it is served as is decided from the path and never from a type the call declares, and a path that leaves the site is refused rather than repaired. - `activate_site_deploy`: make a staged build the live site, only when the files staged hash to the manifest the call names. A build with no index is refused, and the build that was live becomes superseded in the same write. - `set_site_domain`: connect a domain the account owns, and report the DNS record to add. It is not serving when this answers: a certificate follows the record resolving, and `get_site` is what reports whether it is serving yet. - `remove_site_domain`: disconnect the custom domain, after which the site serves on its PlainQuill address. Nothing about the domain's own registration or DNS is touched. - `set_site_blog_path`: move the blog to another section of the site. The path it leaves keeps resolving as a redirect, so inbound links and search positions survive the rename. - `upload_site_asset`: store a logo, a favicon, a picture or a brand file for the website. What the file IS is read from its bytes, never from its name or from any type the call declares, and an SVG carrying a script or a reference to another site is refused rather than edited. Each upload gets its own id and address and nothing is overwritten; a logo and a favicon are drawn on every page the next time one is published or re-rendered. - `delete_site_asset`: remove one stored file by its id. Refused while any page, including a draft, or the theme still uses it, and refused for the logo or the favicon the pages currently draw until a replacement has been uploaded. - `set_site_plan`: store the agreed plan the website is built from: what the site is for, who it is for, the pages with what each must hold, the style, and the files it should draw. The whole document replaces any plan already stored, and it is refused rather than trimmed if it does not fit the rules, with the field that was wrong named. Storing a plan is not the account holder agreeing to it: any agreement already recorded is cleared, because the stored document is now a different one. - `build_site_from_plan`: write every page of the website from the stored plan. Refused when no usable plan is stored, because a build with nothing to build from writes the builder's defaults over the pages that are there. Every page is rewritten and left at pending review, and a page already published keeps serving the copy it published until the account holder approves and publishes the new one. It publishes nothing and approves nothing. - `set_site_tag`: attach one analytics or marketing tag to every page. You give a provider and its id and PlainQuill renders that provider's own snippet; there is no field for a script, a URL to load or a snippet to paste, so tracking from anywhere outside the supported list cannot be attached at all. Google Analytics 4, Google Tag Manager, Plausible, Fathom, Umami, Matomo and Meta Pixel are the providers. Google's two render with Consent Mode defaults denied until the account holder says their site asks visitors for consent. Tags are added as each page is served and are not part of any page's approved copy, so this changes no page, no approval and no content hash, and publishes nothing. - `remove_site_tag`: remove the website's tag for one provider. A provider with nothing attached is refused rather than reported as a removal that happened. Reading a finished piece, with `mcp:read`. These two write nothing and are offered to a read-only key. `get_piece` is how an assistant reads what was written before it says anything about it to the account holder, and the content hash it returns is what any later decision about that piece has to name. - `get_piece`: one article or social post in full: the body as stored, the id and content hash of the revision those bytes belong to, what the editor verified and how much of the piece it covered, the sources cited, what each check found, and the state in the same words the account holder sees. It reports the day the piece is planned for and the exact instant it is scheduled to be sent, with the account's own timezone named. A social post written from a source you provided has no plan day, so the scheduled instant is the only answer to when it goes out. For a social post it also reports `link`: the link the post carries and its `placement`, which is `text`, `first_comment` or `field` (on Facebook, the link field that shows a preview card; the address is not added to the text, and an address already typed into the post is left there). It also reports `publish_warnings`: empty unless something went wrong short of failing when the piece was last sent, each entry a `kind` (`link_dropped` when the post went out without its link because the link would have taken it past its length limit, `provider_warning` when the network reported a problem) and PlainQuill's own `message`. It also reports `published_url`: where the piece is live (for a social post, the network's own address for it, from the send or from the provider's upload history once confirmed live), or null until there is one. - `list_approvable`: only the pieces that are inside the approval bound right now, each with its id, the id and content hash of the revision waiting, its title, its channel, its publish date and the exact instant it is scheduled to be sent, with the account's own timezone named. The two dates are different facts, exactly as they are on `get_piece`. A piece whose day has passed is included with `past_due` true and `would_schedule_for`, the slot approving it would use. It is not the review queue: anything held, flagged, more than 30 days past its planned day or waiting for the account holder in person is absent from it, and `get_queue` is where the whole queue is reported. An empty list means nothing is inside the bound, never that nothing is waiting. - `list_scheduled`: every piece that is approved and waiting for its publish time, soonest first: when it goes out, its channel, the revision id and content hash that would be sent, the approval those bytes are scheduled on, whether it has already been handed to the account's own website or its network (`handed_off`), and whether its network needs a person to approve a new version. Deciding about a piece, with `mcp:approve`. This is the account holder approving through an assistant they chose, a different kind of interface to the same decision, and the account holder remains responsible for what publishes either way. It takes two permissions rather than one, the way `mcp:site` does: the scope on the key, and the account holder turning assistant approval on in Settings. Both are off until the account holder turns them on, both are re-read on every call, and a call missing either is refused with the reason and a link to where it is granted. Only a key the account holder made themselves can approve; a colleague's key is refused. A piece can be approved only when every check passed, it is not held or flagged, it is no more than 30 days past the day its plan gave it, and the content hash presented matches the version that is waiting, so an assistant cannot approve what it has not read. A piece whose planned day has passed is never published at once: approving it schedules it for the next open slot, at most one extra piece per article set per day on top of the plan, so a backlog goes out spread over the following days. There is a daily limit of a day's worth of PIECES plus two, and never fewer than 40, counting each planned article and every post derived from it, and the refusal names that number. Every approval records the key on the piece's history and lists it in the account holder's daily or weekly mail, whichever their mail preference is. - `approve_piece`: approve one piece, bound to the `revision_id` and `content_hash` returned by `get_piece` or `list_approvable`. It publishes on the date the plan gave it, or on the next open slot when that date has passed. An optional `publish_on` (YYYY-MM-DD) asks for a later day: today or after, within 60 days, never earlier than the plan's day. No argument brings a piece earlier or publishes it at once. The result reports `scheduled_for`, and `moved_from` when the piece was moved. - `request_changes`: send one piece back to be rewritten, with a note saying what to fix. The note is what the writer is given. A scheduled piece can be sent back too; the approval it was scheduled on is withdrawn first. - Pieces an assistant released from a hold, or an article an assistant rewrote with `edit_piece`, are refused with `assisted_approval_off` unless the account owner turned on "Let your assistant approve pieces it edited or released" (Settings, Assistants; off by default). With it on they are approved like any other piece, bound to the exact version, and the approval records that it was made under the owner's setting. It never covers LinkedIn or Pinterest posts, a piece held by the integrity checks, a flagged piece, or an edit of a piece the editor last held. - `approve_reverse_link`: approve one link from an older post to a newer article that was held back when that article was approved. It needs both approval grants and a key the account owner made. The link is added once the newer article is live. Managing pieces, with `mcp:manage`, each the same as a control on the piece in the dashboard and checked the same way: the owner can act on any piece and a member only on their own byline's, and a key whose maker has left the account changes nothing. Releases, rejections, rewrites, removals, moves, edits and takedowns are recorded against the key in the piece history; a byline change, a retry, a re-render and posts written from an article are recorded as the dashboard records them, which is by what they produce rather than by who asked. None of these tools approves a piece, and each result says so in `approval_written`. - `release_piece`: send a held piece (the publish check could not prove its approval) back to the review queue. A piece an assistant released can then be approved only by a person, unless the account owner allowed assistants to approve pieces they edited or released. It does not release a piece held by the integrity checks (`integrity_hold_needs_person`): moving one to the review queue would hide the warning a person reads before approving it, so `rework_piece`, or a person on the piece's card, is the path for those. - `reject_piece`: reject a piece that is waiting for review, held, or scheduled, so it is never published. A scheduled piece's approval is withdrawn first. - `unschedule_piece`: take a scheduled piece off the schedule and back to the review queue. The approval it was scheduled on is withdrawn and recorded in the piece history; it publishes only after a fresh approval of its exact version. A piece already handed to the account's own website or to its network, or being published, is refused with `handed_to_provider`. A piece whose words the integrity checks held and a person published anyway is refused with `integrity_hold_needs_person`. An approved piece is scheduled at the next hourly publishing check and can be taken off from then. - `rework_piece`: send a piece held by the integrity checks back through the writer; it returns to the review queue. - `retry_piece`: write a FAILED article again from its plan row, as Try again does. It costs nothing, runs one article at a time, and needs a key the account owner made. - `remove_piece`: remove a piece parked in the library for good. Its credit is not returned, so `confirm: true` is required. - `reschedule_piece`: move a planned or approved piece LATER, up to 60 days ahead in the account's own time zone. An earlier day, or a day whose publishing time has passed, is refused. An approved piece keeps its approval; only the day moves, and the move is recorded against the key. Instead of `date`, `publish_at` sets the exact publish time (ISO UTC on the hour, e.g. `2026-10-02T15:00:00Z`, at least 10 minutes ahead) on a piece waiting for a person, LinkedIn and Pinterest posts included, or on an approved one (later only). It approves nothing: a person's later approval publishes at that time, and if the time has passed by then the approval asks for a new one. A social post can be timed apart from its article this way. - `edit_piece`: replace a piece's text with your own markdown, naming the `revision_id` and `content_hash` you read. The checks run again and the piece returns to the review queue as a new version that needs a fresh approval. A scheduled piece can be edited too: the approval it was scheduled on is withdrawn and the new version needs its own. A live article can be edited too, with `mcp:publish` as well; its page keeps serving the approved version until the new one is approved. - `change_piece_author`: credit a piece to another active byline. Needs a key the account owner made. - `redo_piece_image`: make a new picture for a piece from a short description, inside the piece's redo allowance. - `adapt_piece_to_social` (`mcp:generate`): write one social post per connected network from a finished article; each post waits for review. - `set_reverse_link`: check or uncheck one proposed link from an older post to an article that waits for a decision (`item_id`, `link_id`, `selected`). Checked links are approved with the article and added once it is live; unchecked ones are held back. `get_piece` lists them as `reverseLinks`. Live pieces, with `mcp:publish`, and only on a key the account owner made: - `unpublish_piece`: take a live social post down. The network is asked to delete it by the post id it gave when it went out, a post the network no longer has is reported as already gone, and a send the network has accepted but not yet posted is cancelled there. A post still scheduled in PlainQuill is refused with `not_live`; `unschedule_piece` or `reject_piece` stops it. The piece becomes withdrawn only once the network confirms. A live article on the hosted blog is taken down too (its page and its sitemap entry, then the piece is withdrawn), only when the account owner turned on "Let your assistant take articles down"; otherwise the refusal is `article_takedown_off`. Articles on the customer's own WordPress are taken down there, and the posts written from an article are not taken down with it. - `refresh_published`: render the pages already published on the hosted blog again, one or all, from the version each was approved at and through the same publish check. Nothing new is published. The plan's topics, with `mcp:plan`, on a key the account owner made. `plan_id` and `topic_id` are the ids `get_plan` reports. Each change is recorded against the key; none approves a piece. - `skip_plan_topic`: take one topic off the plan, so it is not written. A topic already being written cannot be taken off. - `reschedule_plan_topic`: move one topic to another day inside the plan's period. - `edit_plan_topic`: change a topic's subject, angle, target search, notes, format or byline. A field left out keeps its value; an empty string clears it. - `add_plan_topic`: add a topic of the account holder's own to a plan not yet approved, on a given day or the next free one. - `add_plan_suggestion`: add one of this week's suggested topics to a plan not yet approved. - `generate_next_piece`: start writing the next planned piece now. It still publishes on its planned day, after an approval. One-off articles, on top of the plan's own pieces: - `get_article_allowance` (`mcp:read`): how many one-off articles the account can still order this month (Starter 2, Growth 6, Max 10, plus any bought), the default publish date, whether an approved plan exists, and topic suggestions from the account's own research, each with a `cluster_id`. - `order_article` (`mcp:plan`, a key the account owner made): order one article on a topic, with optional notes or angle (`angle`), `cluster_id`, byline (`persona_id`) and publish date (tomorrow or later; by default the day after everything planned). It spends one of the month's one-off articles and never bills. It is written now, goes through the same checks as any piece, and waits for an approval of its exact version. Refusals name the reason: `allowance_used`, `date_taken` (with `next_free_date`; an order never lands on top of a planned piece), `in_flight`, `no_approved_plan`, `plan_not_active`, `bad_date`, `topic_too_short`, `unknown_cluster`, `already_covered`, `bad_byline`. - `retire_article` (`mcp:publish`, a key the account owner made, and the owner's "Let your assistant take articles down" setting): take a live hosted-blog article down and send its address to another live article (`redirect_to_item_id`) with a permanent redirect, so nothing is left at a not-found page. The other article is checked first; nothing comes down if it is not live on the hosted blog. - `track_search` (`mcp:setup`, a key the account owner made), and `untrack_search` on the same terms: change the searches whose rank is checked daily, inside the plan's limit. `get_metrics` reports them, and `webmaster_search` there carries the last 28 days from the account's own Google Search Console and Bing Webmaster properties. - `add_plan_topic` also takes `angle`, `target_query` and `notes`, set on the new topic in the same call. - `edit_piece` (`mcp:manage`) also takes `title` and `meta_description`; they are part of the new version and publish only after that exact version is approved. The published Sources panel is the piece's own source list, so an edit whose numbered sources or `[n]` markers do not match it is refused: cite a new page inline as a link. `get_plan` returns each topic's `notes`; a skipped topic no longer holds its day for `add_plan_topic`, and moving it keeps it skipped. - `get_blog_settings` (`mcp:read`): the hosted blog's address, custom domain and status, name, tagline and appearance choices. The custom CSS and head markup are reported as set or not, never their content. Channels, with `mcp:channels`, on a key the account owner made: - `retest_channel`: check a WordPress or hosted-blog connection again. It never lifts a pause. - `disconnect_channel`: disconnect a WordPress site; new articles go to the hosted blog, and pieces already written for the site do not publish until it is connected again. - `connect_social_channel`: start connecting a network whose sign-in is its own page (x, linkedin, facebook, instagram, threads, pinterest, reddit, gbp). The answer is `handoffUrl`, a short-lived, single-use BEARER link: whoever opens it first, within 15 minutes, can attach an account to this PlainQuill account, and any open (a link preview counts) uses it up. Give it only to the account holder and treat it like a password. Mastodon, Discord and Telegram are connected on the Channels page with typed details and are refused here. The plan's network limit is checked again when the connection completes. - `get_channel_profile` (`mcp:read`, so any key that can read the account can call it): what the profile on a connected Bluesky, Mastodon, Telegram or Discord channel is missing (profile picture, cover image, display name, bio, website link, pinned post), what only the account holder can set on the network itself, and the setup draft. It never returns a handle, an account id or a credential. On the other networks the profile is set on the network itself; PlainQuill cannot read or change it there. - `set_channel_profile`: save a channel's profile values as a draft for the account owner, with the owner's key only. It changes the profile on the network only with `apply: true` and only when the owner has switched on "Let assistants change this profile" for that channel; otherwise it is refused with `profile_consent_off` and nothing is sent. The content library, with `mcp:read` to look and `mcp:setup` to move things in and out. The library is where a piece the account has ALREADY PAID FOR is parked instead of sent. A saved piece carries no approval of its own, sits on no schedule, and reaches no reader while it is there. - `list_library`: everything parked in the library: each saved article and each saved post group with its networks, the posts inside it, when it was last touched, and whether a live approval still binds its current version. - `save_piece`: park one piece in the library instead of sending it. A saved piece keeps what it cost: publishing it later uses no allowance. A piece waiting for the account holder's own sign-off cannot be parked by any key. Saving an article saves the posts written from it as one group, in one move. It records the parking in the piece's history as a row the publish gate can never read, and removes no approval, so nothing the piece had already earned is lost. Parking a piece that is itself already approved or scheduled disarms a live approval, so it needs the same two permissions that bringing one back does. Parking an article that is still waiting for review needs only `mcp:setup`, and it parks every post written from it that has not gone out, including posts that were already approved; the result lists the id of every post that moved, in `also_moved`. - `create_post` (`mcp:generate`): write a social post in the account holder's own words and park it in the library. One call writes one post per network named, sharing one group key, with optional per-network variations. Each network's length limit and the account's hashtag rules are checked before anything is written, and a post that breaks one refuses the whole call with nothing written. It is saved, never sent: no approval, no slot, and there is no argument here that schedules it. - `unsave_piece`: take one saved piece back out. Where it goes is decided by what is already true of it: a piece whose current version still carries a live approval goes back to approved and to its publishing slot (the next open slot when its planned day has passed, never at once; an optional `publish_on` asks for a day instead), and anything else goes back into the review queue for a person. A piece parked before it was approved always comes back to where it was, never to approved. Because the first of those puts a piece back on the path to a reader, it additionally needs `mcp:approve`, the account holder's assistant-approval setting and a key the account holder made themselves; without all three, an un-save that would land on approved is refused and the piece stays where it is. The one exception is the reverse of a save: a key that parked an article may take it back out, and the posts parked with it come back where they were, approved ones approved. A post that was parked on its own before its article still needs both permissions to come back approved. A post written from an article still in the library cannot be taken out on its own. Running setup, with `mcp:setup`: - `update_business_profile`: the business questionnaire, through the same validation the customer's own form uses. - `answer_interview`: the same fields, and finishing the questionnaire, which starts the brand brief being written. - `connect_hosted_blog`: check a subdomain or claim it, which connects the hosted blog as the publishing channel. The address cannot be changed once anything has published on it. - `approve_brief`: approve the brand brief, or record a note asking for changes. Approving starts the demand research the weekly plans are built from. - `approve_plan`: approve the week's plan. Approving the first one starts the first article. - `plan_next_week`: ask for the next week's content plan to be drawn up now rather than on the planning day. Refused, with the reason, while an earlier week's plan is still waiting for approval, or when that week would be more than 12 weeks ahead of the current week. The plan arrives for approval like any other; nothing is written from it until it is approved. - `get_business_facts` (`mcp:read`, beside the setup call that changes them): the owner-reviewed address, phone numbers, opening hours, names, categories and listing ids, each leaf carrying who set it and when. A field that was never answered is absent rather than empty. - `update_business_facts`: merge those details leaf by leaf, validated as a whole record. Phone numbers and profile links are replaced whole rather than appended to; a value longer than a field allows is refused by name and never truncated. A change re-renders the pages that publish these details. - `get_listing_findings` (`mcp:read`): what Google, Yelp, Apple Maps, the customer's own website and the site PlainQuill publishes say about the business, and which of those disagree with the record. A source reads as checked-and-consistent, disagreeing, not checked, or not connected; those are four different facts and "not checked" is never reported as "everything matches". Some providers do not permit their values to be stored, so a finding from one of those says that a field disagrees without quoting what they show. PlainQuill never changes anybody else's listing. - `get_ai_label_settings` (`mcp:read`): how AI-written social posts are labelled: the account setting and, for each connected network, whether it has its own AI label, whether its rules keep the label on, and the channel's override. Only AI-written posts are labelled; a post the customer typed never is. - `set_ai_label_settings`: change the account's AI label or one channel's override, with the account owner's key only. A network's own AI label is on by default where it can be set; no text is added unless the owner turns on a short "AI-assisted" line. On a network whose rules require AI disclosure, a piece nobody approved by hand keeps the network's label, and turning it off there is refused with `ai_label_locked_strict_network`. - `update_author`: set the by-line published articles carry: a name, a one-line bio and a public link. It is the business's own identity and never a person invented for the purpose. Only the fields you pass are changed, nothing is shortened to fit, and `get_business_profile` reads it back. Both approvals require the hash returned by the matching read tool. If the document changed since it was read, the approval is refused rather than applied to something nobody read. Webhooks, with `mcp:read` to look and `mcp:setup` to add or remove. A webhook is an https address PlainQuill POSTs a signed JSON event to when something happens on the account: a piece ready for review, approved, published (only once the live copy is verified), failed or needing attention, a channel paused or resumed, a plan or a brand brief ready for approval. Each request carries a `PlainQuill-Signature` header, an HMAC-SHA256 of the timestamp and the body under the endpoint's own secret. Adding and removing endpoints needs a key the account holder made themselves. - `list_webhooks`: the endpoints, their events and whether each is on, with each address masked to its origin and last four characters. - `create_webhook`: add an endpoint for all events or a chosen list; at most five per account. The address must be public https; private and local addresses are refused and redirects are not followed. The signing secret is returned once and cannot be read again. - `delete_webhook`: remove an endpoint and its delivery log. Working with the guide, with `mcp:guide`. This is the second of the two ways to use the server and it is a different shape of key rather than a different mode: an assistant holding it asks what to do next instead of deciding for itself. A key may carry both sets. - `guide_next`: the ordered list of what this account should do next, each step as one sentence with a link into the dashboard and, where it is about a specific piece, its item id, revision id and content hash. No model is called, so the same account gives the same answer however often it is asked. It carries a hash over the whole list. - `guide_turn`: one message to the guide, and its answer. The answer may carry a proposal, in words, with a hash. It does not apply anything. Messages are refused above 1500 characters rather than shortened. It answers for the whole account, or for a hosted website and its plan. It runs a model, so each turn counts against the account's fair use and the daily write ceiling. - `guide_accept`: apply a proposal by the hash that came back with it, through the same code the account holder's own screen applies it with. If anything moved since the proposal was made the call is refused rather than applied to something nobody read, and accepting the same hash twice reports that it is already applied. It saves setup changes and the website plan, and it never starts a website build: rebuilding a site rewrites every page and sends the whole site back for review, so the account holder starts that in the dashboard. A website plan also needs the account holder to have turned on assistant control of the website in Settings, the same second permission `mcp:site` takes. The guide area on the key stands in for the scope half of that and never for the setting half. Accepting a proposal is subject to the same rule the dashboard keeps for the change underneath it: changing an account's setup is the account holder's decision, so a key made by somebody who is not an owner of the account can ask the guide and cannot accept. The boundary is the product, not a limitation of the interface. An agent can configure the whole account and approve the brand brief and each week's plan, because those are the business's instructions about how it wants to be written for. Every ARTICLE and every SOCIAL POST waits for an approval before it publishes, and the publish gate matches that approval to the exact version of the exact piece, so an approval of a brief or a plan cannot satisfy it. Who may give that approval is the account holder's decision: themselves, a colleague, or an assistant approving on their behalf through a key they have granted the two separate permissions described above. A key approving is the account holder approving through a tool they chose, and they remain responsible for what publishes either way. As the site puts it to the account holder: nothing publishes without an approval of that exact version, given by you, a teammate you invite, or an assistant you have authorised to approve for you. ## About and legal - [About](https://plainquill.com/about): who operates the service, how to reach it, and what it answers for: the approval of each exact version, sourced claims, flat prices and the refund policy. Also in Spanish: [Acerca de](https://plainquill.com/es/about). - [Partners](https://plainquill.com/partners): the referral program, its commission, its attribution window and how a partner is paid. - [Terms](https://plainquill.com/legal/terms): the agreement, including payment, the refund policy, ownership of published content, and what is not promised. - [Privacy](https://plainquill.com/legal/privacy): what is collected, how measurement works, and every third party a page contacts. - [Data deletion](https://plainquill.com/data-deletion): how to ask for data to be deleted, what disconnecting a network deletes, and how long each network's comments and reviews are kept. Also in Spanish: [Eliminación de datos](https://plainquill.com/es/data-deletion). - [Support](https://plainquill.com/support): how to reach support, how to ask for a refund, where requests about personal data go, and how to disconnect a connected assistant such as Claude or ChatGPT. Also in Spanish: [Soporte](https://plainquill.com/es/support). ## What PlainQuill does not do - It does not promise rankings, traffic figures or a position in any search engine. A position is measured and reported, never guaranteed. - It does not build backlinks and does not run outreach. - It does not publish anything without a recorded approval of the exact version being published. A post the customer typed themselves is approved by the act of writing it; everything a model wrote waits in the queue. - It does not connect to a store platform, to product data or to order data. What it works from is the customer's public website, what they describe about their business, and any link or text they hand it directly. - It does not put a link on an X post. X charges for link posts and this product does not buy that add-on, so the posting provider removes the address from the post and from its first comment; an X post promotes the piece in its own words and cannot carry a reader to it. On Facebook a post without a picture sends the link as Facebook's own link field, so Facebook shows a preview card and the address is not added to the post text (an address already typed into the post is left there, and the link field is still sent); a Facebook post with a picture has the link added to the end of the text, because a Facebook photo post has no link field. On Reddit a post without a picture sends the link as Reddit's own link field, as a Reddit link post, and a Reddit post with a picture has the link added to the end of the text. On Pinterest the link is sent as Pinterest's own link field, the page a reader reaches by tapping the Pin, and the description is left as written. On Bluesky the link is sent as Bluesky's own link field, a link card with the article's picture as its thumbnail when one is available, and the address is not added to the post text. On Instagram, LinkedIn and Threads the link goes in the first comment under the post (on Instagram the address is text to copy, because Instagram makes no address clickable). On every other network the link is added to the end of the post at publish time, unless it would push that post past the network's character limit, in which case the link is dropped rather than the approved copy trimmed. - It does not report clicks on a social post, and five of the twelve networks report nothing at all, because nothing measures them for us. - It does not serve a hosted blog at the apex of the customer's own domain. A blog we host is served on a PlainQuill subdomain, and a subdomain of the customer's own domain, such as blog.theirdomain.com, can be connected to it. A hosted website can take a custom domain including the apex. Either connection is made from the dashboard and serves once the customer's DNS record is in place and the certificate is active. - It does not claim any check over writing a customer imported or typed themselves. No gate report, no editor verdict and no source count is shown for those, because none was run. - Connecting requires nothing installed on a customer's site: access is an application password they issue and can revoke. An optional WordPress plugin that shortens issuing that password to two clicks is prepared for submission to the plugin directory; the service never requires it.