REST API
The NornWeave REST API provides full control over inboxes, threads, and messages.
Authentication
All requests require an API key in the Authorization header:
Authorization: Bearer YOUR_API_KEYBase URL
http://localhost:8000/v1Inboxes
Create an Inbox
Create a new virtual inbox for your AI agent.
POST /v1/inboxesRequest Body:
{
"name": "Support Agent",
"email_username": "support"
}| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name for the inbox |
email_username | string | Yes | Local part of the email address |
Response:
{
"id": "ibx_abc123",
"name": "Support Agent",
"email_address": "support@mail.yourdomain.com",
"created_at": "2025-01-31T12:00:00Z"
}Example:
curl -X POST http://localhost:8000/v1/inboxes \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Support Agent", "email_username": "support"}'If using Mailgun or SendGrid with auto-route setup enabled, NornWeave will automatically create the routing rule in your provider.
Get an Inbox
GET /v1/inboxes/{inbox_id}Response:
{
"id": "ibx_abc123",
"name": "Support Agent",
"email_address": "support@mail.yourdomain.com",
"created_at": "2025-01-31T12:00:00Z"
}Delete an Inbox
DELETE /v1/inboxes/{inbox_id}Response: 204 No Content
Threads
Threads are the core unit for LLM context. They group related messages into a conversation format.
Get a Thread
GET /v1/threads/{thread_id}Response:
{
"id": "th_123",
"inbox_id": "ibx_abc123",
"subject": "Re: Pricing Question",
"last_message_at": "2025-01-31T10:05:00Z",
"messages": [
{
"id": "msg_001",
"role": "user",
"author": "bob@gmail.com",
"content": "Hi, how much does your service cost?",
"timestamp": "2025-01-31T10:00:00Z"
},
{
"id": "msg_002",
"role": "assistant",
"author": "support@mail.yourdomain.com",
"content": "Thanks for reaching out! Our pricing starts at $20/month.",
"timestamp": "2025-01-31T10:05:00Z"
}
]
}| Field | Description |
|---|---|
role | user for inbound messages, assistant for outbound |
content | Clean Markdown content (HTML converted, cruft removed) |
The
role field maps directly to LLM chat formats, making it easy to use thread content as conversation history.Messages
Send a Message
Send a new email or reply to an existing thread.
POST /v1/messagesRequest Body:
{
"inbox_id": "ibx_abc123",
"to": ["client@gmail.com"],
"subject": "Hello from NornWeave",
"body": "This is **Markdown** content that will be converted to HTML.",
"reply_to_thread_id": "th_123"
}| Field | Type | Required | Description |
|---|---|---|---|
inbox_id | string | Yes | Inbox to send from |
to | array | Yes | Recipient email addresses |
subject | string | Yes | Email subject |
body | string | Yes | Markdown content |
reply_to_thread_id | string | No | Thread ID for replies |
Response:
{
"id": "msg_003",
"thread_id": "th_123",
"inbox_id": "ibx_abc123",
"direction": "OUTBOUND",
"to": ["client@gmail.com"],
"subject": "Hello from NornWeave",
"content_clean": "This is **Markdown** content that will be converted to HTML.",
"created_at": "2025-01-31T12:00:00Z"
}When reply_to_thread_id is provided, NornWeave automatically:
- Sets proper
In-Reply-ToandReferencesheaders - Adds the message to the existing thread
- Maintains conversation threading in email clients
Get a Message
GET /v1/messages/{message_id}Response:
{
"id": "msg_001",
"thread_id": "th_123",
"inbox_id": "ibx_abc123",
"direction": "INBOUND",
"from": "bob@gmail.com",
"to": ["support@mail.yourdomain.com"],
"subject": "Pricing Question",
"content_raw": "<html>...",
"content_clean": "Hi, how much does your service cost?",
"metadata": {
"message_id": "<abc123@mail.gmail.com>",
"headers": {}
},
"created_at": "2025-01-31T10:00:00Z"
}Search
Search for messages across your inboxes.
POST /v1/searchRequest Body:
{
"query": "pricing",
"inbox_id": "ibx_abc123",
"limit": 10
}| Field | Type | Required | Description |
|---|---|---|---|
query | string | Yes | Search query |
inbox_id | string | No | Limit to specific inbox |
limit | number | No | Max results (default: 10) |
Response:
{
"results": [
{
"message_id": "msg_001",
"thread_id": "th_123",
"subject": "Pricing Question",
"snippet": "Hi, how much does your service cost?",
"score": 0.95
}
],
"total": 1
}Phase 1: Search uses SQL
Phase 3: Search will use vector embeddings for semantic search.
ILIKE for simple text matching.Phase 3: Search will use vector embeddings for semantic search.
Webhooks
These endpoints receive inbound email from your provider. Configure them in your provider’s dashboard.
Mailgun
POST /webhooks/mailgunSendGrid
POST /webhooks/sendgridAWS SES
POST /webhooks/sesSee Provider Guides for setup instructions.
Error Responses
All errors follow a consistent format:
{
"error": {
"code": "not_found",
"message": "Thread not found",
"details": {}
}
}| Status Code | Description |
|---|---|
400 | Bad request (invalid parameters) |
401 | Unauthorized (missing/invalid API key) |
404 | Resource not found |
429 | Rate limited |
500 | Internal server error |