1. Webhooks in — any system, zero plugins

Every automation platform on earth can POST a webhook: Stripe, Shopify, n8n, Zapier, Make, IFTTT, GitHub Actions, cron + curl, your own backend. Point them all at one endpoint:

POST https://your-callhook.example.com/api/events
Authorization: Bearer <CALLHOOK_INTAKE_TOKEN>

{
  "id": "evt_stripe_8472",          // your idempotency key — replays never double-dial
  "type": "payment.failed",
  "customer_id": "cus_2003",
  "callback_url": "https://your-app.example.com/hooks/callhook",
  "payload": { "amount": "the monthly charge", "reason": "card declined" }
}

Typical wiring: Stripe → failed-payment webhook → callhook payment.failed. Shopify → fulfillment event → delivery.window. Your CRM → overdue job → invoice.due. Calendly-style bookingsappointment.reminder with not_before.

2. Outcome callbacks — the loop closes

When each call finishes, the structured outcome POSTs back to your callback_url:

{
  "event_id":   "evt_stripe_8472",
  "outcome":    { "outcome": "payment_promised", "promise_date": "2026-09-12" },
  "actions":    ["write.mark_promise(...)"],
  "confidence": { "score": 0.93, "label": "high" },
  "transcript":  [ ... ]
}

Your system updates its own records — the conversation's result lands where your business logic lives. Verify authenticity with the shared X-Callhook-Secret header pattern on your side, and dedupe by event_id (we deliver once; redeliveries carry the same id).

3. MCP — AI agents operate the voice channel

Point any MCP client (Claude Code, Cursor, agents) at POST /mcp. Six tools: fire_event, launch_campaign, get_campaign, list_sessions, list_event_types, run_demo.

# Claude Code / any MCP client:
> "Collect 5 payment promises from the overdue list"
→ agent calls launch_campaign → waves fire → early-stop at the goal

4. business.Store — your CRM/billing adapter

The mock store ships for demos; production implements one interface against your real systems — customers, invoices, promises, escalations, contact history. Read tools feed the call context; writes land only from structured outcomes, policy-gated and audit-logged.

type Store interface {
    GetCustomer(id string) (*Customer, error)
    GetOpenInvoice(customerID string) (*Invoice, error)
    ListOverdueCustomers() ([]*Customer, error)   // campaign auto-audiences
    MarkPromise(customerID, invoiceID string, date time.Time) error
    Escalate(customerID, reason string) error
    RecordContact(customerID, channel, outcome string) error
}

5. SSE stream — live in your own tooling

GET /api/stream pushes every session and campaign mutation as Server-Sent Events — wire your own dashboards, alerting, or analytics to the live feed.

Why no per-platform plugins? Every "Stripe integration" is the same POST with different field names. callhook's event schema is the universal adapter — one endpoint, idempotency built in, and every automation tool already speaks it. New platform? It's a curl command, not a codebase.