# Ruellia Communications Platform > Modern, multi-channel communications (Email, SMS, Webhooks/Notifications) with Model Context Protocol (MCP) support and real-time usage-based billing. > Status: Currently in Private Beta for applications in the cntnus incubator (@cntn.us, @cntnus.com). Non-incubator signups are queued on the waiting list. ## Core Services & Endpoints - Marketing Site: https://ruellia.cntnus.app - Developer Console: https://app.ruellia.cntnus.app - API Base URL: https://api.ruellia.cntnus.app - MCP Endpoint: https://api.ruellia.cntnus.app/v1/mcp - OpenAPI Spec: https://api.ruellia.cntnus.app/openapi.json ## Quick Start for AI Agents To enable an AI agent to send messages, manage sender domains, or check usage: 1. Generate an Agent Token in the console or pass an existing token via \`Authorization: Bearer \`. 2. Connect your agent to the MCP endpoint: - Server URL: \`https://api.ruellia.cntnus.app/v1/mcp\` (dev: \`https://api.dev.ruellia.cntnus.app/v1/mcp\`, stage: \`https://api.stage.ruellia.cntnus.app/v1/mcp\` — stay in one environment end to end) - Method: \`POST\` (JSON-RPC 2.0, protocol 2024-11-05; handshake: \`initialize\` → \`tools/list\` → \`tools/call\`) - Headers: \`Content-Type: application/json\`, \`Accept: application/json, text/event-stream\`, \`Authorization: Bearer \` 3. FIRST verify registration: call \`tools/list\` and confirm Ruellia tools are present — that listing is authoritative, this file is a snapshot. If zero Ruellia tools are registered, fix your client config, do not attempt calls. In that state feedback is still reachable over plain HTTP (\`POST /v1/feedback\`, same JSON body, Bearer token). ## REST Send Contract \`POST /v1/messages/send\` requires \`channel\` plus the matching nested payload; flat \`{to, subject, body}\` bodies are rejected with 400: - Email: \`{"channel":"email","email":{"to":"a@b.com","subject":"Hi","body":"..."}}\` (or \`{"to","templateId","templateData"}\`) - SMS: \`{"channel":"sms","sms":{"to":"+14155552671","body":"..."}}\` - Webhook: \`{"channel":"notification","notification":{"targetUrl":"https://...","event":"...","data":{}}}\` - Status: \`GET /v1/messages/{id}\` · Usage: \`GET /v1/usage\` (\`?period=YYYY-MM\`) · Full spec: \`GET /openapi.json\` ## Bootstrapping Without a Token (Device-Style Consent Flow) If you have no token yet, use the pollable consent flow instead of manual copy/paste: 1. POST https://api.ruellia.cntnus.app/v1/auth/requests Body: { "agentName": "...", "scopes": ["messages:send","messages:read",...], "ttlSeconds": 3600, "callbackUrl": "https://... (optional)" } 2. Present the returned "authorizationUrl" to the user for approval in the Console. 3. Poll GET https://api.ruellia.cntnus.app/v1/auth/requests/{requestId} until status "approved"; the first approved response returns "token" and "mcpEndpoint" exactly once. 4. Use the token to mint long-term least-privilege keys via POST /v1/auth/tokens. If expired, create a new request. ## App Integration: Builder Token vs. App Key An integration agent gets a full-access **builder token** (\`agent:full\`) so it can provision domains/templates AND mint keys via \`create_api_key\`. The application itself gets its own least-privilege **app key** (e.g. \`["messages:send","messages:read"]\`) — never embed the builder token in app code, config, client bundles, or git. Rate limit: 120 req/min per token (429 + \`Retry-After\`: back off, don't file feedback). ## Tools Exposed via MCP Snapshot — `tools/list` on the live endpoint is authoritative; reconcile against it. - \`send_email(to, subject, body, from?, replyTo?)\`: Dispatches transactional and conversational emails. - \`send_templated_email(to, templateId, templateData, from?)\`: Sends via a stored SES template (\`tpl_...\`, mustache \`{{variables}}\`). - \`create_template(name, subject, htmlPart, textPart?, description?)\`: Creates a reusable SES template. - \`list_templates()\`: Lists existing templates. - \`send_sms(to, body, from?)\`: Sends SMS text messages (E.164, 160 chars per segment). - \`send_notification(targetUrl, event, data)\`: Fires webhook push events. - \`send_batch_messages(messages)\`: Dispatches up to 100 messages atomically. - \`get_inbound_messages(status?, to?, subject?, since?, limit?)\`: Queries inbound received emails (default limit 20, max 100; 30-day S3/DynamoDB TTL). - \`configure_inbound(action, webhookUrl?, webhookSecret?, enabled?)\`: Inspects instant \`+@\` receiving address/MX status (\`action: "get"\`) or configures real-time \`email.received\` webhooks (\`action: "update"\`). - \`manage_inbound_message(id, action)\`: Inspects, marks read/unread, archives, or deletes an inbound email. - \`reply_to_inbound(inboundId, body, html?, subject?, from?)\`: Replies to an inbound email preserving thread headers. - \`test_inbound_email(to?, from?, subject?, body?)\`: Simulates an inbound email to test parsing and webhooks. - \`check_suppression_list()\`: Lists bounced/complained recipients (sending to them returns 400). - \`get_usage(period?)\`: Queries real-time usage breakdown (requests, storageBytes, messages, cost). - \`get_message_status(messageId)\`: Checks delivery state. - \`list_domains()\`: Lists verified and pending sender domains. - \`register_domain(domainName)\`: Initiates custom domain registration and returns DKIM/SPF DNS records. Verify via \`POST /v1/domains/{id}/verify\`, then poll \`GET /v1/domains\` until \`verified:true\`. - \`get_authorization_link(scopes?, agentName?, description?, tab?, ttlSeconds?)\`: Generates an authorization deep link with a 1-hour TTL for the user to grant consent in the Ruellia Developer Console. - \`check_authorization_status(requestId)\`: Checks the status of an authorization request; returns the short-lived 1-hour integration setup token when approved, or reminds agent to refresh deep link when expired. - \`create_api_key(name, scopes?, tokenType?)\`: Mints a least-privilege app key (requires an \`agent:full\` builder token; secret returned once). - \`list_api_keys()\` / \`revoke_api_key(tokenId)\`: Key rotation lifecycle (require \`agent:full\`). - \`submit_feedback(title, description, type?, severity?, tags?, context?, attachments?)\`: Reports an error, bug, or feature request back to Ruellia. **Call this whenever another tool fails or returns something unexpected.** - \`list_feedback(status?, type?, severity?, limit?)\`: Lists your organization's previously submitted feedback and triage status. - \`get_feedback(feedbackId)\`: Checks the triage status of a single submission. ## Reporting Feedback If any endpoint or tool misbehaves, report it instead of retrying indefinitely or guessing: - HTTP: \`POST https://api.ruellia.cntnus.app/v1/feedback\` with your Bearer token. - MCP: the \`submit_feedback\` tool (same JSON contract). \`type\`: bug | error | feature_request | documentation | question | other. \`severity\`: low | medium | high | critical. Screenshots and log excerpts are supported inline as base64: \`"attachments": [{ "filename": "error.png", "contentType": "image/png", "data": "" }]\` Limits: 5 attachments, 4 MB each, 6 MB total. For larger artifacts, pass a \`"url"\` instead. Credentials are automatically redacted from every field before storage, so pasting a failing request is safe. Each submission returns an \`id\`; poll \`get_feedback\` to track resolution. Requires the \`feedback:submit\` scope, granted on all agent tokens by default. ## Usage-Based Pricing (Pay-As-You-Go, ~2x AWS cost) - Base Minimum Cost: $0.00 / month - API Requests: $0.01 / 1,000 requests - Storage: $0.50 / GB-month - Email: $0.0002 / email ($0.20 / 1k) - SMS: $0.015 / segment - Webhook: $0.0001 / dispatch