Conventions
Base URL and versioning
https://api.mxaura.ai/v1
The version is in the path. Breaking changes ship as /v2 with /v1 kept
alive; additive changes (new fields, new endpoints, new event types) ship
into /v1 without notice. Treat unknown fields as ignorable.
Envelope
Every response is JSON.
Success
{ "data": <object | array>, "meta": { … } }
Error
{ "error": { "code": "forbidden_scope", "message": "This key lacks pools.write.", "reference": "a1b2c3d4" } }
code is stable and machine-readable; message is for humans and may
change; reference appears on 5xx and is the id to quote when you ask us
about it.
Pagination
Every list endpoint answers two query parameters:
| Param | Meaning |
|---|---|
limit |
Page size. Default 50, maximum 200. |
cursor |
Opaque; take it from the previous page's meta.next_cursor. |
"meta": { "limit": 50, "returned": 50, "total": 137, "next_cursor": "NTA=" }
next_cursor is null on the last page. Do not construct cursors.
curl "https://api.mxaura.ai/v1/hubs/articles?limit=100&cursor=MTAw" -H "Authorization: Bearer …"
Rate limits
Three limits apply to every request, in this order:
| Limit | Scope | Default |
|---|---|---|
| Burst | per credential | 25 requests / 10 s |
| Per minute | per credential | 120 / min — configurable per key to 60, 300 or 600 |
| Account ceiling | across all credentials on the account | 600 / min |
A limited request answers 429 rate_limited with Retry-After (seconds).
Every response carries X-RateLimit-Limit (your per-minute limit) and
X-RateLimit-Account-Limit.
Enrollment cap. Enrolling contacts causes real email. It is capped per
account per hour (default 500). Beyond it: 429 enrollment_cap with
Retry-After. This cap is separate from the request limits above.
Back off on 429; do not retry immediately.
Idempotency
Any POST may carry an Idempotency-Key header (any string up to 128
characters, unique per intended operation — a UUID is ideal). A retried
request with the same key and the same credential returns the first
response, status included, for 24 hours, with Idempotent-Replayed: true.
Use it on every create you might retry.
curl -X POST https://api.mxaura.ai/v1/pools/…/messages \
-H "Authorization: Bearer …" -H "Idempotency-Key: 6f1c…" -d '…'
IP allowlist
Per key, optional, off by default. See Authentication.
Request bodies
JSON, Content-Type: application/json. Bodies are capped at 1 MB; larger
requests get 413. Media uploads go through the media endpoints, not JSON.
Headers you will see
| Header | Meaning |
|---|---|
X-RateLimit-Limit |
This credential's per-minute limit |
X-RateLimit-Account-Limit |
The account ceiling |
Retry-After |
On 429/503: seconds to wait |
X-MXA-Key-Status: rotated_grace |
You are using a key that has been rotated; switch to the new one |
Idempotent-Replayed: true |
This response was served from the idempotency memo |
X-Response-Time |
Server time for the request |
Ids and times
Ids are UUIDs (36 characters, lowercase). HubSpot contact ids are strings of
digits. Times are ISO 8601 in UTC (2026-09-04T03:25:13.490Z) on the way out;
on the way in, ISO 8601 with or without a zone (no zone means UTC).
Errors
| Status | code |
Meaning |
|---|---|---|
| 400 | bad_request |
Validation failed; message says what |
| 401 | unauthorized |
Missing, malformed, expired or revoked credential |
| 403 | forbidden_scope |
Credential lacks the scope for this route, or the route is app-only |
| 403 | browser_origin |
API key used from a browser |
| 403 | ip_not_allowed |
Key used from outside its allowlist |
| 404 | not_found |
No such object in your account |
| 409 | conflict |
State does not allow this (e.g. rotating a revoked key) |
| 429 | rate_limited |
A request limit; see Retry-After |
| 429 | enrollment_cap |
Hourly enrollment cap; see Retry-After |
| 5xx | upstream_error |
Our side; quote reference |
Full list with remedies in Troubleshooting.