Developers

Yappa API

Three things you can wire up: push a lead in, get a signed webhook when Yappa books an appointment or hands a call to your team, and subscribe to bookings as a calendar feed. Everything else about an account is configured in the dashboard.

Base URL https://api.yappa.com.au. All requests and responses are JSON over HTTPS.

Authentication

One bearer token per workspace, issued by the Yappa team from your account page. Tokens start with ws_, are stored only as a hash, and can be revoked at any time. A token identifies the workspace, so you never send an account id.

Header on every request
Authorization: Bearer ws_live_xxxxxxxxxxxxxxxxxxxx

Ask for a token at hello@yappa.com.au. Treat it as a password: it can create leads in your account. If one leaks, tell us and we revoke it on the spot.

Push a lead

POST /v1/leads puts a person into your calling queue. Use it from your CRM, your website forms, or anywhere a new enquiry lands.

Request
POST https://api.yappa.com.au/v1/leads
Authorization: Bearer ws_live_xxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

{
  "phone_e164": "+61412345678",     // required, E.164 only
  "source": "website-form",          // required, how you got them
  "full_name": "Priya Nair",         // optional
  "email": "priya@example.com",      // optional
  "state_au": "VIC",                 // optional, see the note below
  "external_id": "HS-5521",          // optional, your own id
  "custom_fields": {                 // optional, anything you like
    "printer_model": "Brother MFC-L2750DW",
    "quoted_price": "2400"
  }
}
Response 201
{
  "id": "3f6c1b4e-9b1a-4f2c-8d7e-1a2b3c4d5e6f",
  "workspace_id": "0b7c5d6e-1111-2222-3333-444455556666",
  "state": "pending",
  "duplicate": false
}
curl
curl -sX POST https://api.yappa.com.au/v1/leads \
  -H "Authorization: Bearer $YAPPA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"phone_e164":"+61412345678","source":"website-form","full_name":"Priya Nair"}'
Node
const res = await fetch("https://api.yappa.com.au/v1/leads", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.YAPPA_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    phone_e164: "+61412345678",
    source: "website-form",
    full_name: "Priya Nair",
  }),
});
const lead = await res.json();
if (lead.duplicate) console.log("already on the list:", lead.id);
Python
import os, httpx

r = httpx.post(
    "https://api.yappa.com.au/v1/leads",
    headers={"Authorization": f"Bearer {os.environ['YAPPA_TOKEN']}"},
    json={
        "phone_e164": "+61412345678",
        "source": "website-form",
        "full_name": "Priya Nair",
    },
    timeout=10,
)
r.raise_for_status()
lead = r.json()

Things worth knowing

Webhooks

Yappa POSTs to your URL when something happens on a call. Configure the URL, the secret and which events you want in the dashboard under Integrations.

EventFires when
booking.createdThe AI booked an appointment on a call.
lead.transferredThe AI handed a live call to one of your people.
Headers on every delivery
X-Yappa-Event:     booking.created
X-Yappa-Timestamp: 1789700000
X-Yappa-Signature: sha256=<hex digest of the raw body>
Content-Type:      application/json
booking.created body
{
  "booking_id": "8a1f...",
  "lead_id": "3f6c...",
  "call_id": "c0de...",
  "slot_start": "2026-09-22T10:30:00+10:00",
  "duration_minutes": 30,
  "notes_for_rep": "Wants a quote for six panels, home in Frankston."
}
lead.transferred body
{
  "call_id": "c0de...",
  "lead_phone_e164": "+61412345678",
  "lead_external_id": "HS-5521",
  "rep_phone_e164": "+61400111222",
  "reason": "qualified_high_intent",
  "context_summary": "Wants a quote for six panels, free after 3pm.",
  "conference_id": "conf_..."
}

Verify the signature

The signature is an HMAC-SHA256 of the raw request body bytes, keyed with your webhook secret, hex encoded and prefixed with sha256=. Verify before you parse, and compare in constant time.

Python
import hashlib, hmac

def valid(secret: str, raw_body: bytes, header: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode("utf-8"), raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, header or "")
Node
import crypto from "node:crypto";

function valid(secret, rawBody, header) {
  const expected =
    "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(header || "");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Calendar feed

Every workspace has a read-only iCalendar feed of its bookings and scheduled callbacks, at a signed URL. Subscribe to it from Google Calendar, Outlook or Apple Calendar and appointments Yappa makes appear in your diary automatically.

Feed URL
https://api.yappa.com.au/calendar/feed/<signed-token>.ics

Get the URL from the dashboard under Integrations. The token is the only credential, so treat the URL as private: anyone holding it can read your booking times. Ask us to rotate it if it gets out.

Errors

StatusWhat it means
201The lead was created, or already existed (check duplicate).
401Missing, malformed, or revoked bearer token.
422The body did not validate. The most common cause is a phone number that is not E.164.
5xxOur problem. Retry with backoff; the push is idempotent, so a retry is safe.

Errors come back as {"detail": "..."}. Phone numbers must be E.164: a leading plus, country code, no spaces. An Australian mobile looks like +61412345678.

Need something that is not here?

Yappa also connects directly to eleven CRMs, Google Calendar and Outlook without any code, so check whether an integration already exists before you build against this. Email hello@yappa.com.au and tell us what you are trying to do.

Security and data handling