mxAURA™Developer Center
HelpChangelog

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.name from initialize, 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/preview and /dispatch/send never return too_soon; the HubSpot action never answers TOO_SOON. min_gap_days and min_gap_hours_priority are no longer returned by GET /campaigns/{id} and are ignored by PUT /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 .../chat and POST .../stages/{stage}/run (ai.write); PUT .../stages/{stage} (campaigns.write; a refused confirm is 422 with the lines); GET .../estimate; POST .../build (ai.write and campaigns.write; nothing enabled or published; again fills gaps); the portal buttons POST .../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: kinds row, block, article, job; stage; waits_on. The Go-live check names the pieces a message waits on.
  • HubSpot app: crm.lists.write is 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/tools lists 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 with GET /radar/threads. The week in review (GET /radar/review), findings (GET /radar/findings, POST /radar/findings/run, POST /radar/findings/{id}/dismiss), and for agencies GET /radar/review/agency and GET /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_ask returns its reads as references; radar_read gets their data.
  • The market read 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}/variants answers 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_variants and set_row_variants (campaigns scopes). The same rules; set_row_variants is 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, live or paused, 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}/live and /pause; the older action names still work.
  • POST /hubs/articles/publish places, publishes or schedules several articles in several hubs and adds them to widgets in one call. GET /hubs/articles/publish-targets lists 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.json answers 301 with moved_to.reason: deleted. GET /hubs/{id}/redirects lists them; DELETE removes them.

2026-10-12 (v3.1.901 · API 1.12.0, MCP 1.4.0)

  • Version: the API (X-MXA-Version, /health, GET /v1 api_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.write now also covers POST /identity/competitors/find, POST /identity/market/topics/run (paid searches) and POST /hubs/evidence/sources/{id}/read (a model call). The rest of the evidence library is articles.*.
  • A refusal from the AI allowance is 402 with code: budget_exhausted and error.reason (exhausted, would_exceed, disabled, new_account, email_unverified). It was 402 with bad_request and no reason.
  • ai.write calls 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_associations uses the standard error shape: { "error": { "code", "message", "associations" } }.
  • Publishing through the API with a key that lacks ai.write no longer starts the edit-suggestion model call.
  • The spec documents every ai.write route, the evidence library, competitors and Market, the 402 response, contact and terms. GET /v1 lists 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 403 with code: mfa_required on 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.write routes answer with reason: 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 Authorization header only. /ops/mcp/k/<key> is retired and answers 410.
  • Browser origins on localhost are 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 from identity.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/start and its steps, /identity/suggestions/refresh. Moved from articles.write or hubs.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/generate and /voice/test, /hubs/brief/suggestion, /hubs/eval.
  • POST /identity/ask (MCP ask_help) needs ai.write (was identity.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 with POST /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 with order), and GET/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/forms also returns portal_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 message passed, 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 in quoted_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-campaign applies 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 priority set 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/preview and /dispatch/send; a priority send answers priority: true and its row reads matched; priority.
  • Send spacing: min_gap_days per campaign (and min_gap_hours_priority for priority rows), counted from the contact's last send in the campaign. Too soon: the HubSpot action answers SKIP with reason TOO_SOON; the API answers status: too_soon with next_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 needs campaigns.read. MCP: preview_next_message.
  • commit: true and POST /dispatch/send: a production dispatch with full tracking (progress, rotations, dispatch log with source, stats, dispatch.sent), write_properties to write the HubSpot contact. New scope dispatch.write. MCP: dispatch_next_message.
  • POST /preview/simulate-campaign takes hs_contact_id as well as contactId; 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.js 1.11.0: with no data-mode on 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 now path unless 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 200 that stays under the mount, or any answer from mxAURA's /_site/ route (it carries X-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 #/slug link 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/jobs takes kind: "bulk" with article_ids (up to 300), legs (seo, social, answer) and overwrite?. One background job that works through the articles and writes only what is empty; one per account at a time (409 bulk_running). Its label reports progress and its result lists what was written and what was skipped. MCP: bulk_ai_assist. API 1.11.0.
  • POST /hubs/articles/ai/draft and /ai/outline: each entry in sources is now fetched and its article text given to the model as source material. Before this only the address was passed. The response gains sources_read and sources_unread: [{ url, reason }]; /ai/outline now accepts sources. POST /hubs/articles/sources/check reports ok when a link's text can be read, unread with a reason when it answered but cannot be, dead for 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.json answered 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 with moved_to for a renamed one, ETag honoured. embed.js keeps 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/articles and PUT /hubs/articles/{id} take created_at and published_at (YYYY-MM-DD or ISO) so an import can carry an article's original dates into the record itself, not only into display_date. created_at is never cleared; published_at: null clears it; a save that leaves them out never touches them. With created_at and no display_date on create, the display date follows it. MCP compose_article and update_article take the same keys, and display_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_type is inline or client_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, template import / reimport / manifest, pool sequence, message bindings and promote, advisor/rows and advisor/variants, preview/url.
  • 18 MCP tools for the same surface (39 total).
  • Legacy fieldN columns on templates and messages remain for existing integrations.

2026-09-04 (v3.1.321 · Outbound webhooks)

  • webhooks family: 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 (*_chars in their place).
  • support scope 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-Key on POST, 24-hour memo.
  • 5xx responses carry a reference instead of internal text.

2026-09-02 (v3.1.283 · Hubs)

  • Preview keys retired. POST /hubs/{id}/preview opens 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, not hubs.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, folders families added.
  • Hubs scope split into hubs / articles / publishing / subscribers / ai.
  • Hub delete and identity delete withheld from the API.