Getting Started
RuleRail exposes a single ingestion endpoint that accepts any inbound email webhook payload and runs it through the full automation pipeline — NLP intent extraction, policy evaluation, and Shopify mutation — returning a structured result in seconds.
Quick integration path
- 1Configure your email provider (Postmark, SendGrid, Mailgun) to forward inbound messages to the analyze endpoint.
- 2Include your Bearer token in the Authorization header.
- 3Read finalStatus from the JSON response and route accordingly in your helpdesk.
Authentication
All requests to the RuleRail API must include a valid API key passed as a Bearer token in the Authorization header. Requests without a valid token receive HTTP 401 Unauthorized.
Authorization: Bearer "YOUR_API_KEY_HERE"
Content-Type: "application/json"Never expose your API key in client-side code or public repositories. Store it in an environment variable and inject it server-side only.
POST /api/tickets/analyze
The primary ingestion endpoint. Accepts any inbound email JSON payload, normalizes it across provider formats, and runs the full RuleRail orchestration pipeline sequentially.
https://rule-rail.vercel.app/api/tickets/analyzecurl -X POST https://rule-rail.vercel.app/api/tickets/analyze \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "bypass-tunnel-reminder: true" \
-d '{
"MessageID": "postmark-inbound-10482",
"From": "jane@example.com",
"TextBody": "Where is my order #1024? It has been 12 days."
}'Payload Schema
The endpoint normalizes incoming JSON across all major provider formats automatically. Field names are resolved in priority order — the first non-empty match wins. At minimum, one body field (TextBody or HtmlBody) must be present.
| Field | Type | Required | Description |
|---|---|---|---|
MessageID | string | Optional | Unique message or delivery ID from your provider. Used as externalTicketId to make submissions idempotent. Falls back to a timestamped UUID if omitted. |
From | string | Optional | Sender email address. Accepts "Display Name <email>" or bare address format. Automatically prepended to the body text so GPT-4o can populate customerEmail. |
TextBody | string | Required | Plain-text email body. Preferred over HtmlBody when both are present. At least one body field must be supplied. |
HtmlBody | string | Optional | Raw HTML email body. Automatically stripped to plain text via regex before NLP extraction. Use when no TextBody is available. |
storeId | string (UUID) | Optional | RuleRail Store UUID. When omitted, the router resolves a store via shopifyDomain, then falls back to the default shadow store. |
shopifyDomain | string | Optional | Shopify shop domain (e.g. "my-brand.myshopify.com"). Used for store lookup when storeId is not provided. |
{
// Provider ID — used as idempotency key
"MessageID": "postmark-inbound-10482",
"From": "Jane Smith <jane@example.com>",
"Subject": "Where is my order?",
"TextBody": "Hi, where is my order #1024? It has been 12 days since dispatch.",
// Optional store routing
"shopifyDomain": "my-brand.myshopify.com",
"storeId": "9a1d7675-9698-47bd-ac29-731ce0672cc7"
}Response Reference
The endpoint always returns HTTP 200 — even on pipeline failures — so that webhook providers never queue re-deliveries. Inspect the finalStatus field in the JSON body to determine how to handle the ticket.
{
"ticketId": "2f0d1d25-6958-4215-9530-752a7aa5b6c7",
"externalTicketId": "postmark-inbound-10482",
"finalStatus": "AUTO_RESOLVED",
"intent": "WISMO",
"shadowMode": true,
"auditSummary": "SHADOW MODE: WISMO DRAFT_REPLY: Your shipment is with UPS..."
}finalStatus values
| finalStatus | Meaning | Recommended action |
|---|---|---|
| AUTO_RESOLVED | The pipeline resolved the ticket autonomously. A draft reply was created, an address was updated, or a refund/reship was executed (or simulated in shadow mode). | Close the ticket in your helpdesk. Optionally log the auditSummary. |
| ESCALATED | The ticket exceeded a policy threshold, the intent was not automatable (GENERAL_FAQ, HUMAN_ESCALATION), or the order could not be found. | Route to a human agent. Inspect the auditSummary for the specific policy gate that triggered escalation. |
| FAILED | An unexpected pipeline error occurred (OpenAI API outage, database write error, malformed input). | Log the error field and retry. The ticket is safe to resubmit — upsert logic prevents duplicate records. |
HTTP status codes
| Code | Meaning |
|---|---|
200 OK | Request processed. Inspect finalStatus in the response body. |
400 Bad Request | No body content found, or invalid JSON. Fix the payload and retry. |
401 Unauthorized | Missing or invalid Bearer token. |
500 Internal Server Error | Unrecoverable server-side error. Retry with exponential back-off. |
Webhook Providers
The adapter resolves the correct field for each semantic role automatically. Configure your provider to POST its inbound payload directly to the analyze endpoint — no transformation layer needed.
| Provider | ID field | Text body | HTML body | Sender |
|---|---|---|---|---|
| Postmark | MessageID | TextBody | HtmlBody | From |
| SendGrid Inbound Parse | headers (Message-ID) | text | html | from |
| Mailgun | Message-Id | body-plain | body-html | sender |
| Generic / Custom | id · uid · messageId | body · plain | — | From · from · ReplyTo |
Ready to integrate?
Point your provider's inbound webhook URL to https://rule-rail.vercel.app/api/tickets/analyze and add the Authorization header via your provider's custom headers configuration. No additional middleware required.