mxAURA™Developer Center
Core ConceptsAuthentication

Authentication

Two credential types, one authorization model.

Credential Prefix Issued by For
API key mxa_live_ App → Account → API Servers, scripts, automation platforms
OAuth access token mxa_oat_ auth.mxaura.ai (OAuth 2.1) MCP clients and browser apps acting for a signed-in user

Both are sent the same way:

text
Authorization: Bearer <credential>

(x-api-key: <credential> is also accepted for API keys.)

Both are graded by the same scopes, the same rate limits, and the same tenant boundary: a credential sees exactly one account's data. That boundary is enforced in the database access layer for every statement, not by the API code checking ids.

API keys

Lifecycle

Action Where Notes
Create Account → API → Create key Shown once. Choose show-once (default) or retrievable (can be revealed again later; audited).
Rotate Account → API → Rotate Issues a new key; the old one keeps working for a grace period and answers with X-MXA-Key-Status: rotated_grace so you can find lingering callers.
Revoke Account → API → Revoke Immediate. The edge cache is flushed the moment you click.
Expire Set at creation A key past expires_at answers 401 key_expired.
Suspend Platform A suspended key answers 401 with the reason.

Keys are stored as a SHA-256 hash. mxAURA cannot show you a show-once key again; rotate it.

Per-key settings (Account → API → Settings)

  • Which addresses may use this key. an optional allowlist of IPv4/IPv6 addresses or CIDRs. Empty means any address, which is the default. With entries, a request from anywhere else gets 403 ip_not_allowed.
  • How many requests per minute. 60, 120 (default), 300 or 600. See rate limits.

Keys and browsers

API keys are refused from browsers: a request carrying an Origin header gets 403 browser_origin. A key in JavaScript is a key in every visitor's hands. Browser apps use OAuth tokens instead.

OAuth 2.1 (MCP clients and browser apps)

https://auth.mxaura.ai is a standards-compliant OAuth 2.1 authorization server:

Endpoint Purpose
/.well-known/oauth-authorization-server Discovery (RFC 8414)
/register Dynamic Client Registration (RFC 7591). Any client may register itself
/authorize Authorization code with PKCE S256 mandatory (plain rejected)
/token authorization_code and refresh_token grants

Consent rides the user's mxAURA session: they sign in to the app (with 2FA if enabled), see the requesting client and the scopes, and approve. The token that results is bound to the account they were signed into.

  • Access tokens live 1 hour; refresh tokens 30 days.
  • Refresh tokens rotate on use; a used refresh token cannot be replayed. To cut off a client, remove the connection in the client itself; its access token expires within the hour and it cannot refresh. (An in-app "connected apps" page for revoking from mxAURA's side is on the roadmap.)
  • Tokens are graded by the public API exactly like keys, with the same scopes, limits and caps.

Most MCP clients handle all of this for you: give them https://mcp.mxaura.ai/mcp and they discover the rest. See the MCP guide.

Scopes

Scopes are family.verb with three verbs:

  • read covers GET.
  • write covers POST, PUT and PATCH — creating and changing things. write implies read.
  • delete covers DELETE, and is held apart because it cannot be undone. delete does not imply write or read.

full (stored as *) grants every read and write scope — and no delete scope. Destruction is a per-family opt-in that an account owner grants to a specific key in the app; an automation never inherits it by having "full access". This is deliberate: an AI agent holding a full key and one bad prompt should not be able to permanently remove a hub.

Deleting a container — something whose dependents cease to exist with it — is additionally traced. DELETE /hubs/{id}, DELETE /templates/{id} and DELETE /blocks/kinds/{id} first consult GET /{resource}/{id}/associations and refuse with 409 has_associations while anything is listed, returning the list in the error so you know exactly what to remove first. There is no force option; the trace is the unlock. Reference deletes (a message in a pool, a pool on a campaign) are not traced — the cascade self-heals — though deleting a pool attached to a running campaign returns a warning.

Family Covers
components messages, headers, summaries, signatures, senders, templates
brandings brandings
pools pools and their composed messages
campaigns campaigns, campaign pools, campaign simulation
flows flows, flow blueprints
enrollments (write only) enrolling and unenrolling contacts in flows. This sends real email
dispatch (read only) the dispatch log and activity feed
hubs hubs, layouts, stats, the hub's own settings
articles articles, authors, content types
publishing placing, publishing, scheduling, featuring articles; opening a preview window
subscribers subscriptions (embed keys), site keys, assignments. Who may embed
identity the messaging identity (frameworks, sources, advisor)
folders folders
media the account's own media library
webhooks outbound event endpoints
ai (write only) anything that calls the model and spends budget: hero images, SEO, drafts, advisor generation

The hubs family is split on purpose: a key for a content team gets articles.write + publishing.write without the ability to mint embed keys (subscribers.write) or spend model budget (ai.write).

The support profile

Every read family, nothing that sends, publishes or spends:

text
components.read brandings.read pools.read campaigns.read flows.read
hubs.read articles.read identity.read dispatch.read

It is the default grant for an OAuth client that does not ask for specific scopes, and a client can request it by name with scope=support. It is what a help agent should hold: enough to answer "why didn't Darren get the email". Never enough to send one, and never enough to spend: since v3.1.892 even ask_help needs ai.write.

Not available over the API (on purpose)

Accounts, users, profiles, billing, HubSpot connections/OAuth, notifications, import/export and platform administration are session-only surfaces in the app. One destructive action is withheld regardless of scope: deleting the messaging identity (everything composes from it) — the identity family has no delete tier at all. Deleting a hub is available, behind hubs.delete and the association trace described under Scopes. Rotating a client's site key is likewise app-only: it revokes every live embed at once.