Add REST API, DB user management, and API documentation
Adds a JSON REST API at /api/v1/ (Bearer token auth via API_KEYS env var) exposing the full pipeline — email processing, log querying, sender profiles, purge rules, whitelist, and analysis — for external consumers like OpenClaw. Adds a /dbusers web UI for generating PostgreSQL roles with read_only, modify, or full permission levels; credentials shown once and never stored. Includes Alembic migration 0005 for the db_api_users tracking table and API.md with full endpoint documentation and integration examples. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ecc6681432
commit
5af3fef37d
13 changed files with 1347 additions and 1 deletions
312
API.md
Normal file
312
API.md
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
# Howl REST API
|
||||
|
||||
Howl exposes a JSON REST API at `/api/v1/` for programmatic access by external services such as OpenClaw. All endpoints require a Bearer token.
|
||||
|
||||
## Authentication
|
||||
|
||||
Set one or more API keys in `.env`:
|
||||
|
||||
```env
|
||||
API_KEYS=your-key-here,another-key
|
||||
```
|
||||
|
||||
Include the key in every request:
|
||||
|
||||
```
|
||||
Authorization: Bearer your-key-here
|
||||
```
|
||||
|
||||
Requests without a valid key return `401 Unauthorized`.
|
||||
|
||||
---
|
||||
|
||||
## Endpoints
|
||||
|
||||
### Email Processing
|
||||
|
||||
#### `POST /api/v1/process`
|
||||
|
||||
Trigger a pipeline poll — fetches unread email from the last 14 days and runs the full classification pipeline.
|
||||
|
||||
**Response**
|
||||
```json
|
||||
{ "processed": 12 }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Email Log
|
||||
|
||||
#### `GET /api/v1/log`
|
||||
|
||||
Query the email processing log.
|
||||
|
||||
**Query parameters**
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|---|---|---|
|
||||
| `status` | string | Filter by status: `pending`, `processing`, `completed`, `failed`, `skipped` |
|
||||
| `sender_type` | string | Filter by sender type: `customer`, `vendor`, `whitelist`, `unknown` |
|
||||
| `classification` | string | Filter by LLM classification (e.g. `vendor_invoice`) |
|
||||
| `q` | string | Search sender address or subject (case-insensitive) |
|
||||
| `limit` | int | Results per page, max 200 (default 50) |
|
||||
| `offset` | int | Pagination offset (default 0) |
|
||||
|
||||
**Response**
|
||||
```json
|
||||
{
|
||||
"total": 847,
|
||||
"items": [
|
||||
{
|
||||
"id": "...",
|
||||
"sender_address": "billing@vendor.com",
|
||||
"subject": "Invoice #1042",
|
||||
"llm_classification": "vendor_invoice",
|
||||
"llm_confidence": 0.97,
|
||||
"final_action": "flag_follow_up",
|
||||
"status": "completed",
|
||||
...
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### `GET /api/v1/log/{entry_id}`
|
||||
|
||||
Retrieve a single log entry by UUID.
|
||||
|
||||
---
|
||||
|
||||
### Sender Profiles
|
||||
|
||||
Sender profiles guide the LLM by providing context about known senders.
|
||||
|
||||
#### `GET /api/v1/senders`
|
||||
|
||||
List all active sender profiles.
|
||||
|
||||
**Response**: `{ "items": [...] }`
|
||||
|
||||
#### `POST /api/v1/senders`
|
||||
|
||||
Create or update a sender profile (upserts by `email_address`).
|
||||
|
||||
**Request body**
|
||||
```json
|
||||
{
|
||||
"email_address": "billing@vendor.com",
|
||||
"display_name": "Vendor Billing",
|
||||
"sender_type": "vendor",
|
||||
"email_types": ["invoice", "statement"],
|
||||
"processing_instructions": "Always flag for follow-up",
|
||||
"notes": null
|
||||
}
|
||||
```
|
||||
|
||||
`sender_type` values: `customer`, `vendor`, `whitelist`, `unknown`
|
||||
|
||||
#### `GET /api/v1/senders/{profile_id}`
|
||||
|
||||
Retrieve a single profile by UUID.
|
||||
|
||||
#### `PUT /api/v1/senders/{profile_id}`
|
||||
|
||||
Replace a profile's fields (same body as POST).
|
||||
|
||||
#### `DELETE /api/v1/senders/{profile_id}`
|
||||
|
||||
Deactivate a profile (soft delete).
|
||||
|
||||
---
|
||||
|
||||
### Purge Rules
|
||||
|
||||
Purge rules define senders whose mail should be deleted after a retention period.
|
||||
|
||||
#### `GET /api/v1/purge-rules`
|
||||
|
||||
List all purge rules (active and inactive).
|
||||
|
||||
#### `POST /api/v1/purge-rules`
|
||||
|
||||
Create or reactivate a purge rule.
|
||||
|
||||
**Request body**
|
||||
```json
|
||||
{
|
||||
"email_address": "newsletter@bulk.com",
|
||||
"display_name": "Bulk Newsletter",
|
||||
"older_than_days": 14,
|
||||
"notes": null
|
||||
}
|
||||
```
|
||||
|
||||
#### `PUT /api/v1/purge-rules/{rule_id}`
|
||||
|
||||
Partially update a rule. All fields are optional.
|
||||
|
||||
```json
|
||||
{ "older_than_days": 7, "is_active": false }
|
||||
```
|
||||
|
||||
#### `DELETE /api/v1/purge-rules/{rule_id}`
|
||||
|
||||
Deactivate a rule (soft delete).
|
||||
|
||||
---
|
||||
|
||||
### Purge Execution
|
||||
|
||||
#### `POST /api/v1/purge/execute`
|
||||
|
||||
Preview or execute a purge run against Microsoft 365.
|
||||
|
||||
**Request body**
|
||||
```json
|
||||
{
|
||||
"mode": "preview",
|
||||
"sender": "newsletter@bulk.com",
|
||||
"days": 30
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Values | Description |
|
||||
|---|---|---|
|
||||
| `mode` | `preview` \| `execute` | `preview` reports what would be deleted without deleting |
|
||||
| `sender` | string or `null` | Specific sender address; `null` uses all active rules |
|
||||
| `days` | int | Retention threshold in days (only applies when `sender` is set) |
|
||||
|
||||
**Response**
|
||||
```json
|
||||
{
|
||||
"mode": "preview",
|
||||
"total": 47,
|
||||
"rows": [
|
||||
{
|
||||
"address": "newsletter@bulk.com",
|
||||
"label": "newsletter@bulk.com (>30d)",
|
||||
"count": 47,
|
||||
"subjects": ["Weekly digest", "Monthly digest", "Special offer"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Analysis
|
||||
|
||||
#### `GET /api/v1/analysis/senders`
|
||||
|
||||
Aggregated sender statistics from the email log (top 200 by volume).
|
||||
|
||||
**Response**
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"sender_address": "billing@vendor.com",
|
||||
"count": 143,
|
||||
"first_seen": "2025-01-03T10:22:00+00:00",
|
||||
"last_seen": "2026-03-28T14:05:00+00:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Whitelist
|
||||
|
||||
#### `GET /api/v1/whitelist`
|
||||
|
||||
List all active whitelist entries.
|
||||
|
||||
#### `POST /api/v1/whitelist`
|
||||
|
||||
Add a whitelist entry. At least one of `email_address` or `domain` is required.
|
||||
|
||||
```json
|
||||
{
|
||||
"email_address": "ceo@partner.com",
|
||||
"domain": null,
|
||||
"description": "Executive contact",
|
||||
"added_by": "openclaw",
|
||||
"expires_at": null
|
||||
}
|
||||
```
|
||||
|
||||
#### `DELETE /api/v1/whitelist/{entry_id}`
|
||||
|
||||
Deactivate a whitelist entry.
|
||||
|
||||
---
|
||||
|
||||
## DB Users
|
||||
|
||||
The `/dbusers` web UI (available in the Howl dashboard sidebar) lets you create PostgreSQL roles for direct database access. This is intended for services that need to query Howl's database directly rather than going through the API.
|
||||
|
||||
### Permission Levels
|
||||
|
||||
| Level | Permissions |
|
||||
|---|---|
|
||||
| **Read Only** | `SELECT` on all tables |
|
||||
| **Modify** | `SELECT` + `INSERT`/`UPDATE` on `customers`, `vendors`, `whitelist`, `sender_profiles`, `purge_rules` |
|
||||
| **Full** | `SELECT` + `INSERT`/`UPDATE`/`DELETE` on all tables |
|
||||
|
||||
### Usage
|
||||
|
||||
1. Navigate to **DB Users** in the sidebar
|
||||
2. Click **+ Create User**
|
||||
3. Enter a username (3–31 chars, lowercase, letters/digits/underscores) — the role will be created as `howl_<username>`
|
||||
4. Select a permission level
|
||||
5. Optionally add a description (e.g. "OpenClaw integration")
|
||||
6. Click **Create User** — credentials are shown **once** and never stored
|
||||
|
||||
To revoke access, click **Revoke** next to the user. This sets the user inactive in Howl and drops the PostgreSQL role.
|
||||
|
||||
### Connection details
|
||||
|
||||
```
|
||||
Host: localhost (or the host running Postgres)
|
||||
Port: 5434
|
||||
Database: howl
|
||||
Username: howl_<username>
|
||||
Password: (shown at creation time)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example: OpenClaw integration
|
||||
|
||||
```python
|
||||
import httpx
|
||||
|
||||
HOWL_BASE = "https://howl.wulfconsulting.cloud"
|
||||
HOWL_KEY = "your-api-key"
|
||||
|
||||
headers = {"Authorization": f"Bearer {HOWL_KEY}"}
|
||||
|
||||
# Trigger a mail fetch
|
||||
httpx.post(f"{HOWL_BASE}/api/v1/process", headers=headers)
|
||||
|
||||
# Pull recent completed entries
|
||||
resp = httpx.get(
|
||||
f"{HOWL_BASE}/api/v1/log",
|
||||
headers=headers,
|
||||
params={"status": "completed", "limit": 100},
|
||||
)
|
||||
entries = resp.json()["items"]
|
||||
|
||||
# Add a sender profile
|
||||
httpx.post(
|
||||
f"{HOWL_BASE}/api/v1/senders",
|
||||
headers=headers,
|
||||
json={
|
||||
"email_address": "alerts@vendor.com",
|
||||
"sender_type": "vendor",
|
||||
"email_types": ["notification"],
|
||||
"processing_instructions": "Route to Infosec if subject contains CVE",
|
||||
},
|
||||
)
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue