Skip to main content

Documentation Index

Fetch the complete documentation index at: https://bavlio.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Bavlio does not yet ship a customer-facing outbound webhook system. You cannot register a URL and have Bavlio POST events to it. Until that ships, poll the endpoints below.

Why “not yet”?

A safe outbound webhook system requires SSRF defense at both registration and dispatch, retry semantics, dead-letter handling, and signing. Shipping it half-built is worse than shipping it later. The full design is parked in the backend roadmap.

Use these polling endpoints instead

MethodPathPurpose
GET/api/v1/campaigns/{campaign_id}/statsComprehensive campaign stats (sends, opens, clicks, replies).
GET/api/v1/campaigns/{campaign_id}/leads/{id}/eventsPer-lead email event timeline.
GET/api/v1/bavimail/emailsList sent emails with status (delivered, opened, bounced).
GET/api/v1/bavimail/inbound-emailsList inbound replies.
GET/api/v1/bavimail/conversationsThreaded inbound + outbound view.

Poll inbound replies

Track which message ids you’ve seen and process new ones. Persist seen ids across restarts in production.
Python
import time, httpx, os

client = httpx.Client(
    base_url="https://api.bavlio.com",
    headers={"Authorization": f"Bearer {os.environ['BAVLIO_API_KEY']}"},
    timeout=30.0,
)

seen_ids = set()
while True:
    response = client.get(
        "/api/v1/bavimail/inbound-emails",
        params={"limit": 100},
    )
    response.raise_for_status()
    for msg in response.json():
        if msg["id"] in seen_ids:
            continue
        seen_ids.add(msg["id"])
        # Handle the new reply
        print(f"Reply from {msg.get('from_email')}: {msg.get('subject')}")
    time.sleep(60)  # poll every minute

Poll campaign completion

Python
import time, httpx, os

client = httpx.Client(
    base_url="https://api.bavlio.com",
    headers={"Authorization": f"Bearer {os.environ['BAVLIO_API_KEY']}"},
    timeout=30.0,
)

campaign_id = "campaign_abc123"
while True:
    stats = client.get(f"/api/v1/campaigns/{campaign_id}/stats").json()
    if stats.get("queued", 0) == 0 and stats.get("in_flight", 0) == 0:
        print("Campaign complete:", stats)
        break
    print("Pending sends:", stats.get("queued", 0))
    time.sleep(120)

Internal webhook receivers (context only)

For visibility: Bavlio operates three inbound webhook receivers — one each for BaviMail, Unipile (LinkedIn), and Stripe. These are server-to-server endpoints between Bavlio and our infrastructure providers, not points you can register against. They are documented internally and surfaced here only so agents understand the data flow.

Roadmap

Once the customer webhook system ships, this page will document: registration endpoint, signing scheme (HMAC-SHA256 with timestamp.body canonical), 5-minute replay window, retry policy with dead-letter queue, and a verification snippet you can drop into any framework.

← Back to Quickstart