Changelog
Dates are the platform build that shipped the change.
2026-10-16 (v3.1.947 · API and MCP in one place)
- Account → API and MCP replaces the separate API and MCP tabs: the API keys, then the MCP. A key used through the MCP shows it under Last used, with the assistant's name (v3.1.948; 947 had a separate Access table that repeated the keys).
- An API key used through the MCP is now held to the account's ceiling for assistants (Highest access allowed) as well as its own scopes. Direct API use is unchanged.
- The MCP sends the client's name to the API (
clientInfo.namefrominitialize, else the User-Agent), recorded on the key as its last MCP use.
2026-10-14 (v3.1.941 · No send spacing at the campaign)
- A campaign has no timing of its own: it answers whenever it is called. Timing lives in the flow or the HubSpot workflow (its delay). Campaign send spacing (v3.1.872) is removed.
POST /dispatch/previewand/dispatch/sendnever returntoo_soon; the HubSpot action never answersTOO_SOON.min_gap_daysandmin_gap_hours_priorityare no longer returned byGET /campaigns/{id}and are ignored byPUT /campaigns/{id}.- The Architect's pace (days between sends) goes to the workflow delay or the flow's cadence, never to the campaign.
2026-10-14 (v3.1.940 · API 1.16.0, MCP 1.7.0 · The Architect)
- The Architect (v3.1.931 to v3.1.939) is on the API and the MCP: a campaign planned stage by stage (brief, research, suggestion, templates and blocks, content, Setup HubSpot, HubSpot automation), each stage proposed by the model, confirmed by you, read by the next; the review on confirm; Go builds in mxAURA.
GET/POST /architect/plans,GET/DELETE /architect/plans/{id}(campaigns.*);POST .../chatandPOST .../stages/{stage}/run(ai.write);PUT .../stages/{stage}(campaigns.write; a refused confirm is 422 with the lines);GET .../estimate;POST .../build(ai.writeandcampaigns.write; nothing enabled or published; again fills gaps); the portal buttonsPOST .../setup/apply,.../automation/apply,.../templates/register(campaigns.write);GET /architect/library/{id};GET /architect/tools.- MCP:
architect_plans,architect_plan,architect_stage,architect_estimate,architect_start,architect_chat,architect_run,architect_edit,architect_build,architect_setup_apply,architect_automation_apply,architect_register_library,architect_delete. Plan bodies carry briefs, rows and filters, never message bodies. campaign_plan_items(migration 168) records what a build made: kindsrow,block,article,job;stage;waits_on. The Go-live check names the pieces a message waits on.- HubSpot app:
crm.lists.writeis an optional scope (enrolment lists from Setup HubSpot); one Reconnect per portal that should grant it.
2026-10-13 (v3.1.923 · API 1.15.0, MCP 1.6.0 · Radar on the API and MCP)
- Radar's reads are on the API as data:
GET /radar/toolslists them with their input schemas,POST /radar/read { tool, args }runs one. No model runs and nothing is spent (campaigns.read). POST /radar/ask(ai.write): Radar answers with every number cited to its reads; threads withGET /radar/threads. The week in review (GET /radar/review), findings (GET /radar/findings,POST /radar/findings/run,POST /radar/findings/{id}/dismiss), and for agenciesGET /radar/review/agencyandGET /radar/agency/learning.- MCP:
radar_reads,radar_read,radar_ask,radar_threads,radar_review,radar_findings,radar_run_findings,radar_dismiss_finding,radar_agency_review,radar_agency_learning.radar_askreturns its reads as references;radar_readgets their data. - The
marketread stays in the app (text from other people's websites); Ask on the API and MCP does not use it.
2026-10-13 (v3.1.922 · API 1.14.0, MCP 1.5.0 · Block variants refuse what can never apply)
PUT /campaigns/{id}/pools/{cpId}/variantsanswers 422 with nothing written when a variant can never apply: its filter contradicts the row's filter (an equality on a property the row limits to other values), a variant above it has no filter, or a variant above it has the same filter (compared regardless of value order or case). The message names the variant and the reason. Overlap between variants still saves: the first match wins, so put the specific variant above the broader one. Before v3.1.921 these were only warnings.- How a row picks blocks, stated once: the row's filter decides who gets the step; the variants, in order, decide which blocks they see; a contact matching no variant gets the row's default blocks, and a section a variant leaves out also comes from the default.
- A pool on several rows of one campaign: the first row that admits a contact sends and the pool takes one turn (since v3.1.867). A later row of the same pool whose earlier twin has no filter, or the same filter, never sends; the app now flags exactly that instead of saying rows alternate.
- MCP:
get_row_variantsandset_row_variants(campaigns scopes). The same rules;set_row_variantsis refused the same way.
2026-10-12 (v3.1.903 · API 1.13.0, MCP 1.4.1 · Article states, publishing to hubs, redirects)
- Articles have one state:
draft,liveorpaused, on every article (state) and as a list filter (?state=). A draft cannot be placed in a hub (409). Paused keeps its placements and shows nowhere.POST /hubs/articles/{id}/liveand/pause; the older action names still work. POST /hubs/articles/publishplaces, publishes or schedules several articles in several hubs and adds them to widgets in one call.GET /hubs/articles/publish-targetslists the hubs and widgets.- A deleted article that was live in a hub leaves a 301 from its address to the hub's home page.
content.jsonanswers 301 withmoved_to.reason: deleted.GET /hubs/{id}/redirectslists them;DELETEremoves them.
2026-10-12 (v3.1.901 · API 1.12.0, MCP 1.4.0)
- Version: the API (
X-MXA-Version,/health,GET /v1api_version) and the OpenAPI spec now carry one number, 1.12.0. They had drifted apart (the API said 1.7.0, the spec 1.11.0), which is why older entries here number them differently. MCP server 1.4.0. ai.writenow also coversPOST /identity/competitors/find,POST /identity/market/topics/run(paid searches) andPOST /hubs/evidence/sources/{id}/read(a model call). The rest of the evidence library isarticles.*.- A refusal from the AI allowance is
402withcode: budget_exhaustedanderror.reason(exhausted,would_exceed,disabled,new_account,email_unverified). It was402withbad_requestand no reason. ai.writecalls are limited to 30 a minute per account, shared with the app (429 rate_limited). The v3.1.892 entry said so; until now it applied in the app only.409 has_associationsuses the standard error shape:{ "error": { "code", "message", "associations" } }.- Publishing through the API with a key that lacks
ai.writeno longer starts the edit-suggestion model call. - The spec documents every
ai.writeroute, the evidence library, competitors and Market, the 402 response, contact and terms.GET /v1lists every scope family.
2026-10-12 (v3.1.900 · Company)
- mxAURA is operated by mxAURA, Inc., Quincy, Massachusetts.
2026-10-12 (v3.1.899 · Two-factor policy)
- An account can require two-factor for everyone in it (new accounts start with it on). A session whose person has not turned it on answers
403withcode: mfa_requiredon everything except turning it on. API keys and OAuth grants are not affected. - Security practices are published at mxaura.ai/security.
2026-10-12 (v3.1.894 · Sign-up and support hardening)
- Sign-up needs a Cloudflare Turnstile check and a confirmed email. A new account makes no model calls (
ai.writeroutes answer withreason: email_unverified) until one of its people confirms an address or HubSpot is connected. Accounts that existed before this build are unaffected. - The ops MCP takes its key in the
Authorizationheader only./ops/mcp/k/<key>is retired and answers 410. - Browser origins on
localhostare no longer accepted by the gateway, the HubSpot gateway or the admin API.
2026-10-12 (v3.1.892 · Model spend needs ai.write)
- Every route that calls a model now needs
ai.write. Moved fromidentity.write:/identity/generate,/identity/fix,/identity/rate,/identity/brand-brief,/identity/competitors/compare,/identity/competitors/{id}/read,/identity/market/brief,/identity/targets/draft,/identity/compare/rate,/identity/startand its steps,/identity/suggestions/refresh. Moved fromarticles.writeorhubs.write:/hubs/articles/ai/outline,/hubs/articles/ai/source-brief,/hubs/ai/images,/hubs/articles/{id}/social,/hubs/articles/{id}/faqs/generate,/hubs/authors/{id}/voice/generateand/voice/test,/hubs/brief/suggestion,/hubs/eval. POST /identity/ask(MCPask_help) needsai.write(wasidentity.read), answers questions about mxAURA only, and is metered against the account's allowance.- Model-spend routes are rate limited per account at the edge (429 with
code: rate_limited), and sign-in, sign-up, reset and 2FA posts per address.
2026-10-11 (v3.1.875 · Reference fixes, Create form)
- The reference listed
POST /pools/{id}/messages, retired since v3.1.388 (writes answer 410). Removed. Messages go into a pool withPOST /pools/{id}/sequence. - Documented as the code takes them:
PUT /campaigns/{id}/pools/{cpId}(every field, what is kept and how to clear one, the priority rule),PUT /campaigns/{id}/pools/reorder({ updates: [...] }; this page said POST withorder), andGET/PUT /campaigns/{id}/pools/{cpId}/variants. POST /flows/forms { name }: makes an email-only HubSpot form for a flow, or reuses one of the same name.GET /flows/formsalso returnsportal_id.
2026-10-11 (v3.1.874 · Message review)
POST /advisor/review: the Composer's three critics and nine lines on messages that already exist (message_ids, up to 10 in one pool, read as they would send with their blocks and branding; the messages either side read as context and never scored), or on copy not yet in mxAURA (raw: [{ name, subject, preview, body }]). Writes nothing to the messages; spends model budget (ai.write). Returns per messagepassed,total,fails(line, critic, note, fallacy and quote where named),tells,density,editable,values.GET /advisor/reviews?pool_id=: each message's last review and whether it changed since (identity.read). API 1.7.0.- MCP:
review_messages. The critic's quoted words come back inquoted_tenant_text, fenced, 120 characters at most: the first place the server returns a message's own words. Message text still comes back as character counts. - The Campaigns access level now includes
ai.write. POST /preview/simulate-campaignapplies the campaign's send spacing: a day that is too soon sends nothing.- The go-live check gains
review: messages never reviewed, changed since, or failing a line. A warning only.
2026-10-11 (v3.1.872 · Priority rows and send spacing)
- Priority rows: a limited nurture row with
priorityset goes before alerts, scheduled rows and the rotation, once through. A priority send never moves where the rotation picks up. A recurring row cannot be priority (400). Both the HubSpot dispatch and/dispatch/previewand/dispatch/send; a priority send answerspriority: trueand its row readsmatched; priority. - Send spacing:
min_gap_daysper campaign (andmin_gap_hours_priorityfor priority rows), counted from the contact's last send in the campaign. Too soon: the HubSpot action answers SKIP with reasonTOO_SOON; the API answersstatus: too_soonwithnext_eligible_at. Nothing is written in either case.
2026-10-11 (v3.1.871 · The dispatcher on the API)
POST /dispatch/preview: the production cascade for one contact, answered with the exact message they would get next, every row's decision and the properties read.commit: false(the default) writes nothing anywhere and needscampaigns.read. MCP:preview_next_message.commit: trueandPOST /dispatch/send: a production dispatch with full tracking (progress, rotations, dispatch log withsource, stats,dispatch.sent),write_propertiesto write the HubSpot contact. New scopedispatch.write. MCP:dispatch_next_message.POST /preview/simulate-campaigntakeshs_contact_idas well ascontactId; with either, rows the contact fails are skipped.- Filters:
is_not_any_of(blank passes),is_empty,is_not_empty. API 1.6.0.
2026-10-08 (v3.1.829 · Clean article addresses by default)
embed.js1.11.0: with nodata-modeon the page and none chosen for the gallery, links are clean (/insights/slug/).data-mode="hash"still forces#/links. A hub's stored setting is nowpathunless hash was chosen.- Path mode is still verified on the first visit: the embed asks the site for a made-up address under the mount. A
200that stays under the mount, or any answer from mxAURA's/_site/route (it carriesX-Mxa-Site: 1, including its 404 for an unknown slug), proves it; anything else falls back to#/for that session, so a refresh never 404s. Before this, sites that proxy to/_site/were read as unable to serve clean addresses and shared links previewed as the gallery. - The gallery frame now loads after that check, so the address style it reports is the one the page uses. A
#/sluglink opened on a page that serves clean addresses moves to the clean address.
2026-10-06 (v3.1.801 · Bulk AI Assist)
POST /hubs/ai/jobstakeskind: "bulk"witharticle_ids(up to 300),legs(seo,social,answer) andoverwrite?. One background job that works through the articles and writes only what is empty; one per account at a time (409bulk_running). Its label reports progress and its result lists what was written and what was skipped. MCP:bulk_ai_assist. API 1.11.0.
2026-10-06 (v3.1.799 · Draft links are read)
POST /hubs/articles/ai/draftand/ai/outline: each entry insourcesis now fetched and its article text given to the model as source material. Before this only the address was passed. The response gainssources_readandsources_unread: [{ url, reason }];/ai/outlinenow acceptssources.POST /hubs/articles/sources/checkreportsokwhen a link's text can be read,unreadwith areasonwhen it answered but cannot be,deadfor a missing page.
2026-10-06 (v3.1.798 · mxAURA builds the article page)
https://hubs.mxaura.ai/e/{embed_key}/_site/…: proxy your article addresses here and mxAURA returns your own page with the article's head and HTML in it. 404 for an address that is not an article, 301 for a renamed one. One rewrite line on Netlify, Vercel or nginx; see Public rendering.- Fixed:
content.jsonanswered 500 for live articles from v3.1.796 until this release.
2026-10-06 (v3.1.796 · Article content for your own page)
https://hubs.mxaura.ai/e/{embed_key}/{slug}/content.json: the article as plain HTML (title, byline, lead answer, body, approved FAQs) with its fields and JSON-LD, for a site's server to put in the page at the article's address. 404 for a slug that is not live (never a redirect), 301 withmoved_tofor a renamed one,ETaghonoured.embed.jskeeps HTML placed in the mount element (data-mxa-static) on screen until the gallery has loaded.- v3.1.795: in the gallery, a link to your own site opens in the page itself and a path link (
/services/) goes to your site; the browser tab takes the article's title as the reader moves.
2026-10-05 (v3.1.794 · Social posts read the article body)
POST /hubs/articles/{id}/social(MCP: the social leg of AI Assist) wrote from the article's summary only and refused an article whose summary and title were under 80 characters with "There is not enough written yet to base a post on", whatever the body's length. It reads the body now. Posts generated before this were written from the summary alone; regenerate them.
2026-10-05 (v3.1.792 · Import dates)
POST /hubs/articlesandPUT /hubs/articles/{id}takecreated_atandpublished_at(YYYY-MM-DD or ISO) so an import can carry an article's original dates into the record itself, not only intodisplay_date.created_atis never cleared;published_at: nullclears it; a save that leaves them out never touches them. Withcreated_atand nodisplay_dateon create, the display date follows it. MCPcompose_articleandupdate_articletake the same keys, anddisplay_date. API 1.9.0.
2026-09-06 (v3.1.407 · Blocks)
- Blocks are back as filled-in reusable sections. Mark a template section reusable; compose blocks of that shape; a message picks a block or rotates through them.
/blocks,/block-rotations,/messages/{id}/slots. API 1.7.0.
2026-09-06 (v3.1.405 · Library retired)
- The content Library (blocks, sets) is gone. A field is typed in, is multivalue and rotates, or is filled from Branding.
binding_typeisinlineorclient_default. API 1.6.0; 13 composition MCP tools.
2026-09-06 (v3.1.383 · Composition model)
- Public API 1.5.0:
blocks,block-sets, templateimport/reimport/manifest, poolsequence, messagebindingsandpromote,advisor/rowsandadvisor/variants,preview/url. - 18 MCP tools for the same surface (39 total).
- Legacy
fieldNcolumns on templates and messages remain for existing integrations.
2026-09-04 (v3.1.321 · Outbound webhooks)
webhooksfamily: register endpoints, four events, HMAC-signed deliveries, retries, delivery log.
2026-09-04 (v3.1.320 · MCP)
- Seven tools:
list_hubs,get_hub,get_hub_stats,list_articles,get_article,get_identity,list_brandings(21 total). - Tool results never include user-authored bodies (
*_charsin their place). supportscope profile; it is the default grant.- OAuth server accepts every API scope family.
2026-09-03 (v3.1.319 · API contract)
- Pagination on every list:
?limit(≤200) and?cursor,meta.next_cursor. - Per-key IP allowlist (opt-in; empty = any).
- Per-key rate limit honoured (60/120/300/600 per minute).
Idempotency-Keyon POST, 24-hour memo.- 5xx responses carry a
referenceinstead of internal text.
2026-09-02 (v3.1.283 · Hubs)
- Preview keys retired.
POST /hubs/{id}/previewopens a timed preview window on the live key (publishing.write). - Header fields are single-value; multi-value refused (400).
2026-09-02 (v3.1.274)
- Timed preview graded as
publishing.write, nothubs.write.
2026-09-02 (v3.1.260)
- API keys refused from browser origins (
403 browser_origin). - Request bodies capped at 1 MB by bytes read.
2026-09-02 (v3.1.259)
identity,media,foldersfamilies added.- Hubs scope split into
hubs/articles/publishing/subscribers/ai. - Hub delete and identity delete withheld from the API.