API & webhooks
The Automate Admits REST API lets you push leads from your own web forms and landing pages straight into your inbox, and pull contacts, conversations, and calls into your BI tools. Outbound webhooks fire signed events to your URL so you can wire Automate Admits into your stack without us building anything custom.
The API and webhooks are available on the Growth plan and above. Create keys and register webhook endpoints in the app under Channels & integrations → Developer API & webhooks.
Authentication
Every request authenticates with an API key sent as a bearer token. Create a key in Channels & integrations → Developer API & webhooks → API keys. The full key is shown only once at creation — store it securely. Keys look like aa_<prefix>_<secret>.
Authorization: Bearer aa_live_xxxxxxxxxxxxxxxxxxxxxxxx
Requests without a valid key return 401. Keys on a plan below Growth return 403. Treat keys like passwords: never expose them in client-side code or a browser. POST leads from your server, not from a public web page.
Base URL & format
All endpoints live under:
https://automateadmits.com/api/v1
Requests and responses are JSON (Content-Type: application/json). List endpoints return { "data": [...], "next_cursor": ... }. Single-object endpoints return { "data": {...} }. Errors return { "error": "message" } with an appropriate HTTP status.
Probe a key
Returns the org, plan, API version, and the list of event types you can subscribe to. Useful for verifying a key works.
curl https://automateadmits.com/api/v1/me \
-H "Authorization: Bearer $AA_KEY"
{ "org_id": "org_...", "org_name": "Acme Recovery", "plan": "growth",
"version": "1", "events": ["message_received","lead_created", ...] }
Pagination
List endpoints are cursor-paginated, newest first. Pass limit (default 50, max 100). When more results exist, the response includes a next_cursor — pass it back as ?cursor= to fetch the next page. When next_cursor is null, you've reached the end.
GET /api/v1/contacts?limit=100
GET /api/v1/contacts?limit=100&cursor=1718900000000
Creating leads — the #1 use case
POST a lead from your own form or landing page and it lands in your inbox immediately, ready for a human (this endpoint never triggers an AI auto-reply). It creates a contact and a conversation, and optionally an initial inbound message. This fires the lead_created webhook.
POST /api/v1/contacts)At least one of name, phone, or email is required.
| Field | Type | Notes |
|---|---|---|
name | string | Lead's full name. |
phone | string | Phone number. |
email | string | Email address. |
message | string | Optional first message from the lead (shown as an inbound message). |
source | string | Where the lead came from (e.g. Landing page). Defaults to API. |
insurance | string | Optional. |
location | string | Optional. |
status | string | Optional initial stage. One of new, hot, ready, sched, followup, intake, admitted, cold, closed. Defaults to new. |
curl -X POST https://automateadmits.com/api/v1/leads \
-H "Authorization: Bearer $AA_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Jordan Lee",
"phone": "+15551234567",
"email": "jordan@example.com",
"message": "Saw your ad — do you take Aetna?",
"source": "Google Ads landing page"
}'
HTTP/1.1 201 Created
{ "data": { "contact_id": "ct_...", "conversation_id": "cv_...",
"status": "new", "created_at": 1718900000000 } }
Contacts
List contacts, newest first. Optional q filters by name, phone, or email. Supports limit and cursor.
Fetch a single contact.
Conversations & messages
List conversations, newest activity first. Optional status filter. Supports limit and cursor (on last activity).
Full conversation snapshot (contact, stage, AI summary, and details).
List messages in a conversation, newest first. Supports limit and cursor.
Send an outbound reply on the conversation's channel. Body: { "text": "..." }. Delivery and metering behave exactly like sending from the in-app inbox.
curl -X POST https://automateadmits.com/api/v1/conversations/cv_123/messages \
-H "Authorization: Bearer $AA_KEY" \
-H "Content-Type: application/json" \
-d '{ "text": "Hi Jordan — yes, we accept Aetna. When works for a quick call?" }'
Calls
List calls, newest first. Optional direction = inbound or outbound. Supports limit and cursor. Includes status, duration, numbers, and the linked contact/conversation.
Webhooks
Register a URL under Channels & integrations → Developer API & webhooks → Webhooks and subscribe to the events you care about (subscribe to none to receive all events, including ones we add later). When an event fires, we POST a JSON payload to your URL.
Each delivery carries these headers:
| Header | Value |
|---|---|
X-AA-Event | The event type, e.g. lead_created. |
X-AA-Delivery | A unique delivery id. |
X-AA-Signature | sha256=<hex> — HMAC-SHA256 of the raw request body, keyed by your endpoint's signing secret. |
User-Agent | AutomateAdmits-Webhooks/1 |
Respond with any 2xx status to acknowledge. Non-2xx responses are counted as failures and surfaced in the app. Use the Send test button to POST a signed ping payload and confirm your receiver works.
Event types
| Event | Fires when |
|---|---|
lead_created | A new lead / conversation is created (including via the API). |
lead_hot | A lead moves into the hot stage. |
call_scheduled | An appointment / call is booked. |
call_missed | An inbound call goes unanswered. |
human_handoff | A conversation is handed off from the AI to a human. |
message_received | A new inbound message arrives from a lead. |
stage_changed | A conversation's stage changes. |
lead_assigned | A lead is assigned to a team member. |
Verifying signatures
Always verify the X-AA-Signature before trusting a payload. Compute the HMAC-SHA256 of the raw request body (not a re-serialized copy) using your endpoint's signing secret, then compare it to the hex after sha256= using a constant-time comparison.
// Node.js (Express) example
const crypto = require("crypto");
function verify(req) {
const secret = process.env.AA_WEBHOOK_SECRET; // your endpoint's signing secret
const sig = req.get("X-AA-Signature") || ""; // "sha256=<hex>"
const expected = "sha256=" + crypto
.createHmac("sha256", secret)
.update(req.rawBody) // the exact bytes we sent
.digest("hex");
return sig.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}
If you rotate a secret in the app, older payloads signed with the previous secret will no longer verify — roll the secret when you're ready to update your receiver.