Examples
All examples assume MXA_API_KEY in the environment. Base URL
https://api.mxaura.ai/v1.
A minimal client
Node
const BASE = 'https://api.mxaura.ai/v1';
async function mxa(method, path, body, headers = {}) {
const r = await fetch(BASE + path, { method, headers: { 'Authorization': `Bearer ${process.env.MXA_API_KEY}`, 'Content-Type': 'application/json', ...headers }, body: body ? JSON.stringify(body) : undefined });
const j = await r.json();
if (!r.ok) { const e = new Error(`${j.error?.code}: ${j.error?.message}`); e.status = r.status; e.retryAfter = Number(r.headers.get('Retry-After') || 0); throw e; }
return j;
}Python
import os, requests
BASE = 'https://api.mxaura.ai/v1'
S = requests.Session(); S.headers['Authorization'] = f"Bearer {os.environ['MXA_API_KEY']}"
def mxa(method, path, json=None, **headers):
r = S.request(method, BASE + path, json=json, headers=headers)
body = r.json()
if not r.ok: raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (retry-after {r.headers.get('Retry-After')})")
return bodyWalk every page
async function* all(path) {
let cursor = null;
do {
const j = await mxa('GET', `${path}${path.includes('?') ? '&' : '?'}limit=200${cursor ? '&cursor=' + cursor : ''}`);
for (const row of j.data) yield row;
cursor = j.meta?.next_cursor;
} while (cursor);
}
for await (const a of all('/hubs/articles?status=published')) console.log(a.title);Back off on 429
async function withBackoff(fn, tries = 5) {
for (let i = 0; ; i++) {
try { return await fn(); }
catch (e) { if (e.status !== 429 || i >= tries) throw e; await new Promise(r => setTimeout(r, (e.retryAfter || 2 ** i) * 1000)); }
}
}Compose a message into a pool, idempotently
curl -X POST "$BASE/pools/$POOL/messages" \
-H "Authorization: Bearer $MXA_API_KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: compose-welcome-2-$(date +%Y%m%d)" \
-d '{ "message_id": "…", "template_id": "…", "header_id": "…", "summary_id": "…", "signature_id": "…", "sender_id": "…" }'Run it twice: the second response is identical and carries Idempotent-Replayed: true.
See what a contact would receive
steps = mxa('POST', '/preview/simulate-campaign', {'campaignId': CAMPAIGN, 'contactId': '124303957916', 'maxSteps': 5})['data']
for s in steps: print(s['position'], s['pool_name'], '→', s['message_name'], s.get('reason', ''))Enroll a contact (this sends email)
mxa('POST', f'/flows/{FLOW}/enroll', {'hs_contact_id': '124303957916'}, **{'Idempotency-Key': f'enroll-{FLOW}-124303957916'})Needs enrollments.write. Counts toward the hourly cap; on 429 enrollment_cap wait Retry-After.
Find out why a send was blocked
curl "$BASE/activity/dispatches?dispatch_status=blocked&days=7&limit=50" -H "Authorization: Bearer $MXA_API_KEY"Each row carries a reason_code (no_sender, no_branding,
reauth_required, campaign_disabled) plus the campaign and contact. Or register a webhook for
dispatch.blocked and stop asking.
Publish an article to a hub
# place it
curl -X POST "$BASE/hubs/$HUB/entries" -H "Authorization: Bearer $MXA_API_KEY" -H "Content-Type: application/json" -d '{ "article_id": "'$ART'" }'
# publish it
curl -X POST "$BASE/hubs/$HUB/entries/$ART/publish" -H "Authorization: Bearer $MXA_API_KEY"
# or schedule it
curl -X POST "$BASE/hubs/$HUB/entries/$ART/schedule" -H "Authorization: Bearer $MXA_API_KEY" -H "Content-Type: application/json" -d '{ "publish_at": "2026-09-10T13:00:00Z" }'Needs publishing.write. The article.published webhook fires when it goes live.
Import an article with its original dates
# Create it with the dates it had on the old site. created_at and published_at are the record's
# own stamps (the library's Created column, the editor); display_date is what readers see.
curl -X POST "$BASE/hubs/articles" -H "Authorization: Bearer $MXA_API_KEY" -H "Content-Type: application/json" \
-d '{ "content_type_id": "'$TYPE'", "slug": "sell-assets-defer-the-taxes",
"data": { "title": "Sell Assets, Defer the Taxes", "body": "<p>...</p>" },
"created_at": "2020-03-01", "published_at": "2020-03-01", "display_date": "2020-03-01" }'
# Already imported? Back-date it in place. Only the keys you send change.
curl -X PUT "$BASE/hubs/articles/$ARTICLE" -H "Authorization: Bearer $MXA_API_KEY" -H "Content-Type: application/json" \
-d '{ "created_at": "2020-03-01", "published_at": "2020-03-01" }'Dates are YYYY-MM-DD (stored as noon UTC) or an ISO time. created_at is never cleared; published_at: null clears it. With created_at and no display_date on create, the display date follows created_at. None of these keys publishes anything: placing the article in a hub does. Needs articles.write. Over MCP the same keys are on compose_article and update_article.
Put the article text on your own page (for search and answer engines)
// In the function or worker that serves /insights/<slug>/ on your site.
const r = await fetch(`https://hubs.mxaura.ai/e/${EMBED_KEY}/${slug}/content.json`, { redirect: "manual" });
if (r.status === 404) return new Response("Not found", { status: 404 }); // not the gallery with a 200
if (r.status === 301) return Response.redirect((await r.json()).moved_to.url, 301); // the slug was renamed
if (!r.ok) return lastGoodCopy(slug) ?? new Response("Try again shortly", { status: 503, headers: { "Retry-After": "120" } });
const a = await r.json();
// 1. head: <title>${a.title}</title>, description, canonical ${a.url},
// <script type="application/ld+json">${JSON.stringify(a.jsonld)}</script>
// 2. body: put a.html INSIDE the mount element, before embed.js runs:
// <div data-mxa-hub="EMBED_KEY" data-mode="path" data-path="/insights/">${a.html}</div>embed.js shows that HTML until the gallery is up, then hides it. If the gallery never loads the article stays on screen. No credential: the address is public, like the gallery. Details under Public rendering.
Let a reviewer see drafts on the live page for an hour
curl -X POST "$BASE/hubs/$HUB/preview" -H "Authorization: Bearer $MXA_API_KEY" -H "Content-Type: application/json" -d '{ "minutes": 60 }'The live embed shows drafts, noindex, uncached, for 60 minutes; { "minutes": 0 } closes it early. Needs publishing.write.
Register a webhook and test it
curl -X POST "$BASE/webhooks" -H "Authorization: Bearer $MXA_API_KEY" -H "Content-Type: application/json" \
-d '{ "url": "https://hooks.example.com/mxaura", "events": ["dispatch.sent", "dispatch.blocked"] }'
# → { "data": { "id": "…", "secret": "whsec_…", … } } store the secret now; it is not shown again
curl -X POST "$BASE/webhooks/$ID/test" -H "Authorization: Bearer $MXA_API_KEY"Make / Zapier / n8n
Use an HTTP module with Authorization: Bearer <key>; the JSON envelope maps
directly. For events, the platform's "catch webhook" URL is the endpoint you
register. mxAURA's own Make connector, when installed, wraps the same API.