Customer-facing reference for the two integration surfaces:
| Surface | Base URL | Auth | Status |
|---|---|---|---|
| MCP server | https://api.composedchaos.net/stl-mcp/ |
Authorization: Bearer stl_… |
Live |
| REST API | https://api.composedchaos.net/stl-api/v1 |
X-API-Key: stl_… header |
Live |
Both are served over IPv4 and IPv6, TLS only. All timestamps are ISO-8601;
send timezone-aware values (2026-07-14T09:00:00-05:00).
Keys are issued from the admin console (shown once — store them). Format
stl_…. Two scopes:
api — Developer plan key. Valid only on the metered micro-APIs:
POST /parse-lead, POST /drivetime/route, POST /drivetime/feasibility.
Not valid on MCP or tenant-data endpoints.client — full integration key for one tenant: the micro-APIs plus that
tenant's leads, knowledgebase, conversations, availability, appointments,
webhooks, metrics — and the MCP server.A scoped key never sees another tenant's data; cross-tenant objects return
404 exactly as if they didn't exist.
Errors are JSON: {"detail": "<reason>"}.
| Code | Meaning |
|---|---|
| 401 | missing/invalid key |
| 403 | key scope not authorized for this endpoint |
| 404 | not found (or belongs to another tenant) |
| 409 | booking conflict (slot no longer available) |
| 422 | validation error (bad input, malformed email) |
| 429 | rate limited — honor the Retry-After header |
| 503 | dependency temporarily unavailable — retry with backoff |
Per-client per-minute limits (defaults): parse 10, drive-time 60, availability 20, writes (leads/appointments) 30, reads 120, webhook registration 10.
GET /metrics returns your current billing-period usage against allowances.api or client scope)POST /parse-lead — marketplace notification email in, structured lead out
(Angi, Thumbtack, Google Local Services, …). Send either raw_email (full
RFC-822 source) or text (+ optional subject, from_addr).
curl -s https://api.composedchaos.net/stl-api/v1/parse-lead \
-H "X-API-Key: $STL_KEY" -H 'Content-Type: application/json' \
-d '{"text": "New lead! John D, (913) 555-0142, water heater leaking, Olathe KS", "from_addr": "leads@thumbtack.com"}'
Response: {"source": "thumbtack", "lead": {"name", "phone", "email",
"address", "job_desc", "urgency": "normal|urgent|unknown", "lead_ok": bool},
"usage": {"input", "output", "cost_usd"}}. lead_ok: false means the email
was a receipt/digest/marketing, not a new lead. 422 = unparseable input,
503 = parsing temporarily unavailable (safe to retry).
POST /drivetime/route — drive time between two points.
Body {"origin": {"lat", "lon"}, "destination": {"lat", "lon"}} →
{"seconds", "meters", "source": "valhalla"|"haversine"} (haversine =
estimate while the routing engine is unreachable).
POST /drivetime/feasibility — which appointment slots are actually
reachable given a day's existing jobs. Body:
{"job": {"lat": 38.88, "lon": -94.81},
"window_start": "2026-07-14T08:00:00-05:00",
"window_end": "2026-07-14T18:00:00-05:00",
"duration_minutes": 90,
"appointments": [{"start": "…", "end": "…", "lat": 39.0, "lon": -94.6}],
"home_base": {"lat": 38.9, "lon": -94.7},
"buffer_minutes": 15, "granularity_minutes": 30}
→ {"feasible_slots": [{"start", "end", "drive_in_seconds",
"drive_out_seconds", "drive_source"}], "count"}.
client scope — implicitly your tenant)| Endpoint | Notes |
|---|---|
GET /clients/{slug} |
your client record (billing/calendar credentials redacted) |
GET /clients/{slug}/kb/{tier} |
knowledgebase docs; tier general, negative, or escalation |
PUT /clients/{slug}/kb/{tier} |
{"path", "content_md"} — creates a new version, history kept |
GET /leads?disposition=&limit= |
dispositions: qualified, escalated, info-only, spam, booked |
POST /leads |
inject a lead: {"client", "job_desc", name?, phone?, email?, address?, source?, urgency?, notify_client?} → 201 {"id", "client"}. Fires lead.created and (by default) notifies the business owner |
GET /availability?client=&days=&address= |
proposable slots: {"mode", "slots": [{"start", "end", …}]}; pass address for drive-time-aware results on Field-tier clients |
POST /appointments |
{"client", "start", "job_desc", name?, phone?, address?} → 201 {"appointment_id", "lead_id", "start", "end", "status", "lead_created"}; 409 if the slot was taken |
GET /appointments?client= |
upcoming appointments |
GET /conversations/{id} |
channel, disposition, summary, full transcript |
GET /metrics |
current-period usage vs. allowances |
GET /calendar-url |
your read-only ICS feed URL (subscribe from Google/Outlook/Apple; token-guarded, rotatable) |
client scope)POST /webhooks with {"url": "https://…", "events": ["lead.created",
"appointment.booked"]} → the hook row including the once-shown
whsec_… secret. GET /webhooks lists, DELETE /webhooks/{id} removes.
Deliveries are POST with JSON body and headers:
X-STL-Event — event nameX-STL-Delivery — unique delivery id (deduplicate on this)X-STL-Signature — sha256= + HMAC-SHA256 of the raw request body
keyed with your whsec_ secretimport hmac, hashlib
def verify(secret: str, body: bytes, header: str) -> bool:
digest = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(header, "sha256=" + digest)
Respond 2xx quickly; anything else is retried a bounded number of times.
https://api.composedchaos.net/stl-mcp/ — streamable-HTTP transport,
authenticated with Authorization: Bearer <client-scope key> (api-scope
keys are rejected). Every tool is automatically scoped to your tenant and
metered on the same billing meters as the REST API.
Claude Code:
claude mcp add --transport http speed-to-lead \
https://api.composedchaos.net/stl-mcp/ \
--header "Authorization: Bearer stl_…"
Any other MCP-capable client:
{"mcpServers": {"speed-to-lead": {
"url": "https://api.composedchaos.net/stl-mcp/",
"headers": {"Authorization": "Bearer stl_…"}}}}
| Tool | What it does |
|---|---|
list_clients |
the client record(s) your key can see |
list_leads |
recent leads, filterable by disposition |
create_lead |
inject a lead (fires webhooks + owner notification) |
get_conversation |
transcript + summary for one conversation |
get_knowledgebase |
KB docs for a tier |
drive_time |
point-to-point drive time |
feasible_slots |
drive-time-aware open slots for a job |
check_availability |
proposable appointment slots |
book_appointment |
book a slot (409-safe on conflicts) |
parse_lead_email |
marketplace email → structured lead |