Aura Integration Guide
How an external system integrates with Aura. This covers the inbound surface — the MCP server, the tenant B2B2C API, the public agent directory, and webhooks.
Base URLs: prod
https://www.moreaura.ai, devhttps://dev.moreaura.ai. Always usewww.in prod —moreaura.aiissues a 307 that drops theAuthorizationheader.A raw machine-fetchable copy of this guide is served at
/docs/integration/raw(text/markdown).
1. Which surface should I use?
| You want to… | Use | Auth |
|---|---|---|
| Let an AI client / agent discover & read Aura agent cards over MCP | Aura MCP server (POST /api/mcp) | Bearer AURA_MCP_TOKEN |
| Pre-register your end users & send them transactional texts (B2B2C tenant) | Tenant API (/api/tenant/*) | Bearer aura_prov_… provisioning key |
| Browse the public agent directory (no auth) | GET /.well-known/agents | none |
| Have an Aura agent use your MCP server | MCP Servers setting (/api/settings/mcp-servers) | dashboard session |
| Receive/send iMessage, billing, Slack, voice events | Webhooks (/api/webhooks/*) | per-provider signature |
The three families a third-party backend typically integrates with are the Tenant API, the MCP server, and the public directory.
2. Aura as an MCP server
Aura exposes a read-only Model Context Protocol server so MCP-capable clients (Claude, other agents) can discover and read public Aura agent cards.
- Endpoint:
POST https://www.moreaura.ai/api/mcp - Transport: Streamable HTTP, stateless JSON-RPC 2.0 (no SSE, no session id).
GETreturns405. - Auth:
Authorization: Bearer <AURA_MCP_TOKEN>(a secret distinct from any internal secret). - Required header:
MCP-Protocol-Version: 2025-06-18(also accepts2025-03-26). - Gates (in order): server must be enabled (else
404) →Originmust be allowlisted (else403) → protocol version (else400) → bearer token (else401+WWW-Authenticate: Bearer) → IP rate limit (else429).
Methods
initialize, ping, tools/list, tools/call, and notifications/* (acked with 202). serverInfo: { "name": "aura", "version": "0.1.0" }.
Tools (read-only — public directory only)
aura.search_agents
{ "query": "real estate", "capability": "scheduling" }
Returns matching directory-listed agents. capability is optional.
aura.read_agent_card
{ "handle": "nova" }
Returns the agent card with addresses:
{
"email": "nova@moreaura.ai",
"subdomain": "nova.moreaura.ai",
"mcp": "https://www.moreaura.ai/api/mcp"
}
Private and nonexistent handles return an identical "not found" result (enumeration-proof). Only agents that are directory-listed and active are ever returned.
Example
curl -X POST https://www.moreaura.ai/api/mcp \
-H "Authorization: Bearer $AURA_MCP_TOKEN" \
-H "MCP-Protocol-Version: 2025-06-18" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"aura.search_agents","arguments":{"query":"real estate"}}}'
3. Public agent directory (no auth)
A no-auth, A2A-style discovery endpoint — summaries only, no address block.
GET /.well-known/agents— query paramsq,capability,limit(1–100).- Response:
{ "agents": [{ "handle", "name", "description", "capabilities" }], "count" } - Caching:
Cache-Control: public, max-age=60. IP rate-limited.
Also public: GET /api/vcard/{slug} returns a vCard 3.0 (text/vcard) for branded agents (404 otherwise, non-enumerable; 503 if the agent has no phone number).
4. Tenant API (B2B2C partners)
For partner backends that run assistants on Aura. Both endpoints authenticate with a tenant provisioning key and can only act through that tenant's own active assistants — a tenant can never send from another tenant's number.
- Auth:
Authorization: Bearer aura_prov_<base62>. Only the SHA-256 hash of the key is stored server-side; mint/rotate via Aura ops. Missing/invalid key →401 {"error":"Unauthorized"}.
POST /api/tenant/end-users — invisible linking
Pre-register a verified end user so their first text "just works".
{
"phoneNumber": "+15551234567",
"name": "Jane Doe",
"metadata": { "inkdApiKey": "…" }
}
phoneNumberE.164, required.nameoptional (≤200).metadataoptional; secret keys are sealed at rest.201 {"endUserId","created":true}(new) /200 {"endUserId","created":false}(existing — metadata merged).- Consent provenance is stamped automatically (
source: "tenant_provisioning"). - Errors:
400 {"error":"Invalid JSON body"}or first validation issue.
POST /api/tenant/messages — outbound transactional text (e.g. OTP)
Sends from the assistant's own number.
{
"phoneNumber": "+15551234567",
"text": "Your code is 123456",
"assistantSlug": "nova"
}
phoneNumberE.164, required.text1–1600 chars, required.assistantSlugrequired only if the tenant has more than one assistant with a number.200 {"messageId","status"}.- Errors:
400invalid body404 {"error":"assistant_not_found"}409 {"error":"no_sender_number"}/{"error":"ambiguous_assistant","assistantSlugs":[…]}403 {"error":"recipient_opted_out"}— STOP/compliance, applies even to OTPs429 {"error":"rate_limited","retryAfterSeconds":N}+Retry-Afterheader (~1 msg/sec/number)503 {"error":"messaging_not_configured"},502 {"error":"send_failed"}
- The message is recorded into the active conversation thread when one exists. Phone numbers and message bodies are never logged.
5. Letting an Aura agent use YOUR MCP server
This is the reverse direction — configuring an Aura agent as a client of an external MCP server. Managed from the dashboard (Settings → MCP Servers), backed by:
POST /api/settings/mcp-servers(auth: dashboard session)
{
"agentId": "<uuid>",
"name": "My Server",
"serverUrl": "https://…",
"authMethod": "none",
"token": "…"
}
name1–80.serverUrl≤2048, https, SSRF-validated (DNS + private-IP blocklist).authMethod"none"or"bearer";tokenrequired ifbearer.201 {server, runtimeSync}on success.422 "Custom MCP servers are not supported for this agent's runtime"— custom MCP is available only on legacy VM-runtime agents; serverless-orchestrator agents are rejected.502if saved but the hot-push to the running agent failed.- Also:
GET /api/settings/mcp-servers,PUT/DELETE /api/settings/mcp-servers/{id}.
authMethod: "oauth" is recognized but not supported (skipped). Only none and bearer.
6. Webhooks (inbound, signed)
Each webhook verifies a provider-specific signature. Send Content-Type: application/json unless noted.
| Route | Signature | Header(s) |
|---|---|---|
POST /api/webhooks/stripe | Stripe constructEvent | stripe-signature |
POST /api/webhooks/stripe/issuing-authorizations | Stripe constructEvent | stripe-signature |
POST /api/webhooks/slack/events | HMAC-SHA256 v0=, base v0:{ts}:{body} | x-slack-signature + x-slack-request-timestamp |
POST /api/webhooks/composio/triggers | HMAC-SHA256 base64 (Standard-Webhooks/Svix) | webhook-signature, webhook-id, webhook-timestamp |
POST /api/webhooks/twilio/voice · /status · /livekit-sip | HMAC-SHA1 base64 | x-twilio-signature |
POST /api/webhooks/sendblue/inbound/<token> | path token (+ empirical scheme hardening) | — |
Contract quirks worth knowing:
- Sendblue (iMessage) uses a drop-and-ack model — after verification, every branch returns
200; the body signals state ({"ok":true},{"ok":true,"duplicate":true},{"ok":true,"rate_limited":…}). Status callbacks are ignored for inbound routing; the AI reply runs asynchronously. Pre-auth errors:401(bad token/signature). - Slack answers the
url_verificationchallenge (200 {"challenge"}) before signature check. Onlyapp_mentionand IMmessageevents are handled; routed byteam_id. - Stripe issuing-authorizations never returns non-200 for business outcomes — always
{"approved":boolean}with headerStripe-Version: 2025-03-31.basil(real-time card-auth contract). - Twilio voice/status respond with TwiML XML (
text/xml), and return200even on internal error to suppress retries.
7. Authentication reference
Aura uses several separate secrets — do not conflate them:
| Secret / scheme | Header | Used for |
|---|---|---|
AURA_MCP_TOKEN | Authorization: Bearer | the MCP server (/api/mcp) only |
Tenant provisioning key (aura_prov_…) | Authorization: Bearer | tenant API (/api/tenant/*) |
| Dashboard session | cookie | dashboard / settings routes |
| Webhook signing secrets | provider header | inbound webhooks |
Bearer checks are constant-time and fail closed when the corresponding secret is unset.
Questions or need a provisioning key? Contact the Aura team.