Developer docs
Alfred API.
POST a command from any HTTP client. Slack, Zapier, n8n, your backend.
Get an API key
Open your portal → Settings → Integrations → API keys. Click New key, name it (e.g. slack-bot), and copy the token. The full secret is shown once — store it in your secret manager immediately.
Tokens look like ak_a1b2c3... and are scoped to a single business. Revoke at any time from the same screen.
The POST contract
curl -X POST https://alfred-intelligence.com/api/embedded/alfred/command \
-H "Authorization: Bearer ak_YOUR_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{
"command": "Book 20 botox consultations this month",
"channel": "embedded"
}'Required: command (string, ≤ 2000 chars).
Optional: channel — embedded (default) or in_app; any other value is recorded as embedded. Sets where the command came from for the audit log; doesn't affect routing.
{
"command_id": "0a4f...",
"job_id": "f792...",
"status": "queued",
"confirmation": "Started \"Book consultations\" for this month. Targeting 20 contacts. You'll get 3 updates during the run.",
"estimated_result": "~20 consults booked"
}Response status codes
queued— Skill resolved. Job is running. Contacts being enrolled now.needs_clarification— Ambiguous command. Response includes a clarifying_question + candidates. Send a follow-up command picking one.no_match— No Skill matched. Response confirmation explains why. Try a more specific command.error— Internal error. Job was logged but not started. Retry later.
Examples
JavaScript / Node
const res = await fetch('https://alfred-intelligence.com/api/embedded/alfred/command', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ALFRED_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
command: 'Win back lapsed patients',
channel: 'embedded',
}),
})
const data = await res.json()
console.log(data.confirmation)Slack outgoing webhook
# In Slack: Apps → Outgoing Webhooks
# Trigger word: alfred
# URL: https://your-relay-service/slack-to-alfred
# In your relay:
const text = req.body.text.replace(/^alfred\s*/i, '')
const res = await fetch('https://alfred-intelligence.com/api/embedded/alfred/command', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ALFRED_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ command: text, channel: 'embedded' }),
})
const data = await res.json()
return { text: data.confirmation }n8n / Zapier
# n8n HTTP Request node configuration:
# Method: POST
# URL: https://alfred-intelligence.com/api/embedded/alfred/command
# Headers:
# Authorization: Bearer {{ $env.ALFRED_API_KEY }}
# Content-Type: application/json
# Body (JSON):
{
"command": "{{ $json.user_message }}",
"channel": "embedded"
}Auth errors
401 missing_authorization— no Bearer header.401 invalid_or_revoked_key— token doesn't match a row or was revoked.403 insufficient_scope— key doesn't includealfred.command. Mint a new one.429 rate_limited— too many calls per business. Back off ~1 minute.410 business_gone— the business that owns this key was deleted.
Rate limits + CORS
Per-business AI bucket. Same budget shared between in-app and embedded API calls. Headers on every response indicate remaining capacity for the current window.
CORS is wide open (Access-Control-Allow-Origin: *). Preflight (OPTIONS) is handled. You can call this endpoint directly from browser JavaScript if you're comfortable shipping the key — but for any user-facing app, proxy through your backend.
Not in v1 (yet)
- Webhooks for job state changes (planned)
- List recent commands via the API (use the in-app contact timeline for now)
- Stream Alfred's thinking (planned)
- Multi-step conversations within a single API call (planned)
Ready to ship?
Mint your first key in the portal.
