# Agent Chat
Source: https://bavlio.mintlify.app/api-reference/agent/agent-chat
https://api.bavlio.com/openapi.json post /api/v1/agent/chat
SSE streaming endpoint for the unified Bavi agent.
Write path:
1. Write user message to conversation_messages BEFORE streaming
2. Stream agent response via SSE
3. Write assistant response to conversation_messages on finish
# Archive Conversation
Source: https://bavlio.mintlify.app/api-reference/agent/archive-conversation
https://api.bavlio.com/openapi.json delete /api/v1/agent/conversations/{thread_id}
Archive (soft-delete) a conversation.
# Create Conversation
Source: https://bavlio.mintlify.app/api-reference/agent/create-conversation
https://api.bavlio.com/openapi.json post /api/v1/agent/conversations
Create a new conversation.
# Get Conversation
Source: https://bavlio.mintlify.app/api-reference/agent/get-conversation
https://api.bavlio.com/openapi.json get /api/v1/agent/conversations/{thread_id}
Get a conversation with its messages.
# Get Pending Interrupt
Source: https://bavlio.mintlify.app/api-reference/agent/get-pending-interrupt
https://api.bavlio.com/openapi.json get /api/v1/agent/conversations/{thread_id}/interrupt
Check if a conversation has a pending interrupt (for browser reopen).
# List Conversations
Source: https://bavlio.mintlify.app/api-reference/agent/list-conversations
https://api.bavlio.com/openapi.json get /api/v1/agent/conversations
List user's non-archived conversations, newest first.
# Create Api Key
Source: https://bavlio.mintlify.app/api-reference/api-keys/create-api-key
https://api.bavlio.com/openapi.json post /api/v1/api-keys
Create a new API key. Returns the raw key exactly once.
Requires JWT authentication (not API key). This prevents a leaked
API key from being used to mint replacement keys.
# List Api Keys
Source: https://bavlio.mintlify.app/api-reference/api-keys/list-api-keys
https://api.bavlio.com/openapi.json get /api/v1/api-keys
List all active API keys for the authenticated user.
Returns key prefixes (not raw keys) and metadata.
# Revoke Api Key
Source: https://bavlio.mintlify.app/api-reference/api-keys/revoke-api-key
https://api.bavlio.com/openapi.json delete /api/v1/api-keys/{key_id}
Revoke an API key. The key is soft-deleted and immediately invalidated.
Requires JWT authentication. Ownership is verified server-side.
# Get Current User
Source: https://bavlio.mintlify.app/api-reference/authentication/get-current-user
https://api.bavlio.com/openapi.json get /api/v1/auth/me
Get current user information.
Alias for /verify endpoint for better API consistency.
Args:
user_info: Authenticated user information from JWT
Returns:
Dictionary containing user information
# Send Welcome Email
Source: https://bavlio.mintlify.app/api-reference/authentication/send-welcome-email
https://api.bavlio.com/openapi.json post /api/v1/auth/welcome-email
Send a welcome email to a newly signed-up user.
Idempotent: subsequent calls return {"status": "already_sent"}.
Fail-open on Redis unavailability (worst case: duplicate email).
# Verify Token
Source: https://bavlio.mintlify.app/api-reference/authentication/verify-token
https://api.bavlio.com/openapi.json get /api/v1/auth/verify
Verify JWT token and return user information.
This endpoint validates the JWT token in the Authorization header
and returns the user information extracted from the token.
Args:
user_info: Authenticated user information from JWT
Returns:
Dictionary containing user information:
- user_id: User's unique identifier from Supabase
- email: User's email address
- role: User's role (default: "user")
- authenticated: Always True for valid tokens
- app_metadata: Application-specific metadata
- user_metadata: User-specific metadata
# Add Domain
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/add-domain
https://api.bavlio.com/openapi.json post /api/v1/bavimail/domains
# Cancel Email
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/cancel-email
https://api.bavlio.com/openapi.json post /api/v1/bavimail/emails/{email_id}/cancel
# Check Dns Status
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/check-dns-status
https://api.bavlio.com/openapi.json get /api/v1/bavimail/domains/{domain_id}/dns-status
# Create Alias
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/create-alias
https://api.bavlio.com/openapi.json post /api/v1/bavimail/aliases
# Delete Alias
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/delete-alias
https://api.bavlio.com/openapi.json delete /api/v1/bavimail/aliases/{alias_id}
# Delete Domain
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/delete-domain
https://api.bavlio.com/openapi.json delete /api/v1/bavimail/domains/{domain_id}
# Delete Inbound Email
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/delete-inbound-email
https://api.bavlio.com/openapi.json delete /api/v1/bavimail/inbound-emails/{email_id}
# Download Inbound Attachment
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/download-inbound-attachment
https://api.bavlio.com/openapi.json get /api/v1/bavimail/inbound-emails/{email_id}/attachments/{index}
# Get Alias
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/get-alias
https://api.bavlio.com/openapi.json get /api/v1/bavimail/aliases/{alias_id}
# Get Conversation
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/get-conversation
https://api.bavlio.com/openapi.json get /api/v1/bavimail/conversations/{conversation_id}
# Get Domain
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/get-domain
https://api.bavlio.com/openapi.json get /api/v1/bavimail/domains/{domain_id}
# Get Domain Setup
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/get-domain-setup
https://api.bavlio.com/openapi.json get /api/v1/bavimail/domains/{domain_id}/setup
# Get Email
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/get-email
https://api.bavlio.com/openapi.json get /api/v1/bavimail/emails/{email_id}
# Get Email Clicks
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/get-email-clicks
https://api.bavlio.com/openapi.json get /api/v1/bavimail/emails/{email_id}/clicks
# Get Email Links
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/get-email-links
https://api.bavlio.com/openapi.json get /api/v1/bavimail/emails/{email_id}/links
# Get Inbound Email
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/get-inbound-email
https://api.bavlio.com/openapi.json get /api/v1/bavimail/inbound-emails/{email_id}
# Get Inbound Email Raw
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/get-inbound-email-raw
https://api.bavlio.com/openapi.json get /api/v1/bavimail/inbound-emails/{email_id}/raw
# List Aliases
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/list-aliases
https://api.bavlio.com/openapi.json get /api/v1/bavimail/aliases
# List Conversations
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/list-conversations
https://api.bavlio.com/openapi.json get /api/v1/bavimail/conversations
# List Domains
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/list-domains
https://api.bavlio.com/openapi.json get /api/v1/bavimail/domains
# List Emails
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/list-emails
https://api.bavlio.com/openapi.json get /api/v1/bavimail/emails
# List Inbound Emails
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/list-inbound-emails
https://api.bavlio.com/openapi.json get /api/v1/bavimail/inbound-emails
# Send Email
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/send-email
https://api.bavlio.com/openapi.json post /api/v1/bavimail/emails
# Update Alias
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/update-alias
https://api.bavlio.com/openapi.json put /api/v1/bavimail/aliases/{alias_id}
# Update Domain
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/update-domain
https://api.bavlio.com/openapi.json put /api/v1/bavimail/domains/{domain_id}
# Verify Domain
Source: https://bavlio.mintlify.app/api-reference/bavimail-proxy/verify-domain
https://api.bavlio.com/openapi.json post /api/v1/bavimail/domains/{domain_id}/verify
# Re-register BaviMail webhook for the calling tenant
Source: https://bavlio.mintlify.app/api-reference/bavimail-self-service/re-register-bavimail-webhook-for-the-calling-tenant
https://api.bavlio.com/openapi.json post /api/v1/bavimail/webhooks/re-register
Force a fresh `ensure_webhook` round-trip for the calling user. Idempotent: if BaviMail already has an active+verified webhook, returns it as `already_active` without recreating. If a previously registered webhook is dead (consecutive_failures>=5, disabled_at set, or is_active=false), it is deleted and recreated. The endpoint is scoped strictly to `current_user.id`; operators with admin support tooling use a separate path. Rate-limited to 10 requests/minute per authenticated user (JWT `sub` claim, with credential/IP fallback for unparsable or unauthenticated callers).
# Personalize Campaign Email
Source: https://bavlio.mintlify.app/api-reference/campaign-personalization/personalize-campaign-email
https://api.bavlio.com/openapi.json post /api/v1/campaigns/{campaign_id}/personalize
Generate personalized email content for a campaign lead.
This endpoint is called by the Worker Lambda (via internal API key) or
directly by authenticated users (via JWT).
# Preview Template Substitution
Source: https://bavlio.mintlify.app/api-reference/campaign-personalization/preview-template-substitution
https://api.bavlio.com/openapi.json post /api/v1/campaigns/{campaign_id}/template-preview
Preview template variable substitution without personalization.
This endpoint renders a template with actual lead data but WITHOUT
AI personalization. Useful for previewing what {{variable}} substitutions
will look like before launching a campaign.
Args:
campaign_id: Campaign ID
step_index: Step index to preview
variant_label: Variant label to preview
lead_row_index: Row index of lead in dataset to use for preview
current_user: Authenticated user
campaign_service: Campaign service instance
Returns:
Preview of subject and body with variables substituted
# Create Campaign
Source: https://bavlio.mintlify.app/api-reference/campaigns/create-campaign
https://api.bavlio.com/openapi.json post /api/v1/campaigns/
Create a new email campaign.
Creates a campaign in DRAFT status. Use the launch endpoint to start
sending emails.
Args:
request: Campaign creation request with steps configuration
current_user: Authenticated user information
service: Campaign service instance
Returns:
Created campaign response
# Delete Campaign
Source: https://bavlio.mintlify.app/api-reference/campaigns/delete-campaign
https://api.bavlio.com/openapi.json delete /api/v1/campaigns/{campaign_id}
Delete a campaign.
Deletes the campaign and all associated leads and jobs (cascade delete).
Args:
campaign_id: Campaign ID
current_user: Authenticated user information
service: Campaign service instance
# Get Aggregate Stats
Source: https://bavlio.mintlify.app/api-reference/campaigns/get-aggregate-stats
https://api.bavlio.com/openapi.json get /api/v1/campaigns/aggregate-stats
Get aggregate stats across all user campaigns.
# Get Campaign
Source: https://bavlio.mintlify.app/api-reference/campaigns/get-campaign
https://api.bavlio.com/openapi.json get /api/v1/campaigns/{campaign_id}
Get a specific campaign by ID.
Args:
campaign_id: Campaign ID
current_user: Authenticated user information
service: Campaign service instance
Returns:
Campaign response with total leads count
# Get Campaign Click Stats
Source: https://bavlio.mintlify.app/api-reference/campaigns/get-campaign-click-stats
https://api.bavlio.com/openapi.json get /api/v1/campaigns/{campaign_id}/click-stats
Get click tracking stats for a campaign.
# Get Campaign Stats
Source: https://bavlio.mintlify.app/api-reference/campaigns/get-campaign-stats
https://api.bavlio.com/openapi.json get /api/v1/campaigns/{campaign_id}/stats
Get comprehensive stats for a single campaign.
# Get Launch Warnings
Source: https://bavlio.mintlify.app/api-reference/campaigns/get-launch-warnings
https://api.bavlio.com/openapi.json get /api/v1/campaigns/{campaign_id}/launch-warnings
Retrieve persisted launch warnings for a campaign.
# Get Lead Events
Source: https://bavlio.mintlify.app/api-reference/campaigns/get-lead-events
https://api.bavlio.com/openapi.json get /api/v1/campaigns/{campaign_id}/leads/{campaign_lead_id}/events
Get email event timeline for a specific campaign lead.
# Get Step Performance
Source: https://bavlio.mintlify.app/api-reference/campaigns/get-step-performance
https://api.bavlio.com/openapi.json get /api/v1/campaigns/{campaign_id}/stats/step-performance
Get per-step performance breakdown for a campaign.
# Launch Campaign
Source: https://bavlio.mintlify.app/api-reference/campaigns/launch-campaign
https://api.bavlio.com/openapi.json post /api/v1/campaigns/{campaign_id}/launch
Launch a campaign.
Returns campaign data with any warnings and a summary of launch results.
# Launch Preflight
Source: https://bavlio.mintlify.app/api-reference/campaigns/launch-preflight
https://api.bavlio.com/openapi.json post /api/v1/campaigns/{campaign_id}/launch-preflight
Check launch readiness without side effects.
Returns warnings and summary so the user can review before confirming launch.
# List Campaign Leads
Source: https://bavlio.mintlify.app/api-reference/campaigns/list-campaign-leads
https://api.bavlio.com/openapi.json get /api/v1/campaigns/{campaign_id}/leads
List leads for a campaign with their current status.
Includes lead data from the dataset for display purposes.
Args:
campaign_id: Campaign ID
current_user: Authenticated user information
service: Campaign service instance
status_filter: Optional status filter
page: Page number (1-indexed)
page_size: Items per page (max 200)
Returns:
Paginated list of campaign leads with lead data
# List Campaigns
Source: https://bavlio.mintlify.app/api-reference/campaigns/list-campaigns
https://api.bavlio.com/openapi.json get /api/v1/campaigns/
List all campaigns for the authenticated user.
Args:
current_user: Authenticated user information
service: Campaign service instance
status_filter: Optional status filter
search: Optional search term for campaign name
page: Page number (1-indexed)
page_size: Items per page (max 100)
Returns:
Paginated list of campaigns
# Pause Campaign
Source: https://bavlio.mintlify.app/api-reference/campaigns/pause-campaign
https://api.bavlio.com/openapi.json post /api/v1/campaigns/{campaign_id}/pause
Pause an active campaign.
Paused campaigns will not send any more emails until resumed.
The dispatcher will skip leads from paused campaigns.
Args:
campaign_id: Campaign ID
current_user: Authenticated user information
service: Campaign service instance
Returns:
Updated campaign response
# Resume Campaign
Source: https://bavlio.mintlify.app/api-reference/campaigns/resume-campaign
https://api.bavlio.com/openapi.json post /api/v1/campaigns/{campaign_id}/resume
Resume a paused campaign.
Args:
campaign_id: Campaign ID
current_user: Authenticated user information
service: Campaign service instance
Returns:
Updated campaign response
# Update Campaign
Source: https://bavlio.mintlify.app/api-reference/campaigns/update-campaign
https://api.bavlio.com/openapi.json patch /api/v1/campaigns/{campaign_id}
Update a campaign.
Only certain fields can be updated, and some fields cannot be changed
after the campaign is launched.
Args:
campaign_id: Campaign ID
request: Update request
current_user: Authenticated user information
service: Campaign service instance
Returns:
Updated campaign response
# Get Capabilities
Source: https://bavlio.mintlify.app/api-reference/capabilities/get-capabilities
https://api.bavlio.com/openapi.json get /api/v1/capabilities
Return current capability flags. Called on frontend boot + SPA refocus.
# Check Connect Status
Source: https://bavlio.mintlify.app/api-reference/connected-accounts/check-connect-status
https://api.bavlio.com/openapi.json get /api/v1/connected-accounts/connect-status/{checkpoint_token}
Poll whether an IN_APP_VALIDATION account is ready.
Used by the frontend when the checkpoint type is IN_APP_VALIDATION
(user approves in the LinkedIn mobile app, no code to enter).
# Claim Connected Account
Source: https://bavlio.mintlify.app/api-reference/connected-accounts/claim-connected-account
https://api.bavlio.com/openapi.json post /api/v1/connected-accounts/claim
Free a LinkedIn slug previously connected by another user.
The frontend calls this after receiving a 409 ``account_owned_by_another_user``
from /connect or /connect-cookie. That earlier 409 carries a signed
``claim_token`` AND deletes the requesting user's freshly minted
Unipile account upstream so no orphan accumulates if the user never
follows through. Presenting the token here:
1. Verifies HMAC + expiry + requesting-user binding (fail-closed).
2. Enforces single-use jti via INSERT into ``consumed_claim_tokens``;
a replay returns 410 Gone.
3. Runs the DB function ``claim_connected_account`` which (inside one
transaction) disconnects the previous owner's row, pauses their
campaigns, and queues a user_alert.
4. Best-effort: deletes the previous owner's Unipile account upstream.
The function does NOT INSERT a new row for the requesting user.
Response carries ``next_action="reconnect"``; the frontend redirects
the user back to /connect (or /connect-cookie) to register their own
Unipile session, which now succeeds because the slug is no longer
held by any connected row.
# Connect Account
Source: https://bavlio.mintlify.app/api-reference/connected-accounts/connect-account
https://api.bavlio.com/openapi.json post /api/v1/connected-accounts/connect
Connect a LinkedIn account via username/password.
P0: Password is never logged — only username is referenced in logs.
# Connect Account Cookie
Source: https://bavlio.mintlify.app/api-reference/connected-accounts/connect-account-cookie
https://api.bavlio.com/openapi.json post /api/v1/connected-accounts/connect-cookie
Connect a LinkedIn account via browser cookie (li_at).
SECURITY: li_at cookie is never logged or stored. It is sent directly
to Unipile and discarded.
# Create Auth Link
Source: https://bavlio.mintlify.app/api-reference/connected-accounts/create-auth-link
https://api.bavlio.com/openapi.json post /api/v1/connected-accounts/auth-link
Generate a hosted auth URL to connect a LinkedIn account.
# Disable Connected Account
Source: https://bavlio.mintlify.app/api-reference/connected-accounts/disable-connected-account
https://api.bavlio.com/openapi.json post /api/v1/connected-accounts/{account_id}/disable
Soft-disable a connected account (sets status to 'disconnected').
# Get Account Health
Source: https://bavlio.mintlify.app/api-reference/connected-accounts/get-account-health
https://api.bavlio.com/openapi.json get /api/v1/connected-accounts/{account_id}/health
Get health indicators for a connected LinkedIn account.
# Get Connected Account
Source: https://bavlio.mintlify.app/api-reference/connected-accounts/get-connected-account
https://api.bavlio.com/openapi.json get /api/v1/connected-accounts/{account_id}
Get a single connected account by ID.
# List Connected Accounts
Source: https://bavlio.mintlify.app/api-reference/connected-accounts/list-connected-accounts
https://api.bavlio.com/openapi.json get /api/v1/connected-accounts
List all connected accounts for the current user.
# Resume Rate Limited Account
Source: https://bavlio.mintlify.app/api-reference/connected-accounts/resume-rate-limited-account
https://api.bavlio.com/openapi.json post /api/v1/connected-accounts/{account_id}/resume
Resume a rate-limited LinkedIn account. Reactivates frozen leads.
Step-aware: step 1 leads → active, step 2+ leads → connected.
# Solve Checkpoint Endpoint
Source: https://bavlio.mintlify.app/api-reference/connected-accounts/solve-checkpoint-endpoint
https://api.bavlio.com/openapi.json post /api/v1/connected-accounts/checkpoint
Solve a 2FA/OTP checkpoint to complete account connection.
# Update Account Limits
Source: https://bavlio.mintlify.app/api-reference/connected-accounts/update-account-limits
https://api.bavlio.com/openapi.json patch /api/v1/connected-accounts/{account_id}/limits
Update daily limits for a connected account.
# Estimate Credits
Source: https://bavlio.mintlify.app/api-reference/credits/estimate-credits
https://api.bavlio.com/openapi.json post /api/v1/credits/estimate
Estimate credit cost for an operation without consuming credits.
Provides cost estimation based on:
- Operation type
- Operation count
- User's current tier (for discounts)
- Current pricing configuration
Args:
request: Credit estimation request with operation details
current_user: Authenticated user
supabase_service: Supabase service instance
Returns:
CreditEstimateResponse with cost breakdown
# Get Credit Balance
Source: https://bavlio.mintlify.app/api-reference/credits/get-credit-balance
https://api.bavlio.com/openapi.json get /api/v1/credits/balance
Get current user's credit balance and package information.
Returns comprehensive credit information including:
- Total credits available
- Credits used
- Current active package
- List of all active credit packages
Args:
current_user: Authenticated user from JWT
supabase_service: Supabase service instance
Returns:
CreditBalanceResponse with complete credit information
Raises:
HTTPException: If unable to retrieve credit balance
# Get Credit Transactions
Source: https://bavlio.mintlify.app/api-reference/credits/get-credit-transactions
https://api.bavlio.com/openapi.json get /api/v1/credits/transactions
Get credit transaction history for the current user.
Returns detailed transaction log including:
- Credit consumption events
- Credit refunds
- Package purchases
- Balance adjustments
Args:
limit: Maximum transactions to return
offset: Pagination offset
operation_type: Optional filter by operation type
current_user: Authenticated user
supabase_service: Supabase service instance
Returns:
JSON response with transaction list
# Archive a dataset
Source: https://bavlio.mintlify.app/api-reference/datasets/archive-a-dataset
https://api.bavlio.com/openapi.json post /api/v1/datasets/{dataset_id}/archive
Soft-delete a dataset by setting archived_at timestamp
# Download dataset in specified format
Source: https://bavlio.mintlify.app/api-reference/datasets/download-dataset-in-specified-format
https://api.bavlio.com/openapi.json get /api/v1/datasets/{dataset_id}/download
Download dataset rows in CSV, Excel, or JSON format with download tracking
# List datasets with pagination
Source: https://bavlio.mintlify.app/api-reference/datasets/list-datasets-with-pagination
https://api.bavlio.com/openapi.json get /api/v1/datasets/list
Server-side paginated dataset listing with optional pipeline type filter and search
# Restore an archived dataset
Source: https://bavlio.mintlify.app/api-reference/datasets/restore-an-archived-dataset
https://api.bavlio.com/openapi.json post /api/v1/datasets/{dataset_id}/restore
Un-archive a dataset by clearing archived_at timestamp
# Update dataset metadata
Source: https://bavlio.mintlify.app/api-reference/datasets/update-dataset-metadata
https://api.bavlio.com/openapi.json patch /api/v1/datasets/{dataset_id}
Update dataset fields like dataset_name
# Bulk Search
Source: https://bavlio.mintlify.app/api-reference/email-finder/bulk-search
https://api.bavlio.com/openapi.json post /api/v1/email-finder/bulk
Bulk find: 3 credits/row, full SMTP+BaviMail verification.
Equivalent to running /find for each row in parallel via ARQ workers. Rows
must have `name` and either `domain` or `company`. Company-only rows are
resolved via _resolve_company_domain before charging; unresolved rows are
skipped with no charge and reported in `skipped_unresolved`.
# Find Email
Source: https://bavlio.mintlify.app/api-reference/email-finder/find-email
https://api.bavlio.com/openapi.json post /api/v1/email-finder/find
Find someone's email by trying patterns via sequential SMTP verification.
Generates 8 email pattern candidates, tries each via SMTP RCPT TO in
probability order (stop on first valid), then verifies the winner via BaviMail.
Costs 3 credits. Async — returns job_id for polling.
Free tier users get 403.
# Get Bulk Status
Source: https://bavlio.mintlify.app/api-reference/email-finder/get-bulk-status
https://api.bavlio.com/openapi.json get /api/v1/email-finder/bulk/{job_id}/status
Aggregated bulk status. `?include_rows=false` returns counts only.
# Get Company
Source: https://bavlio.mintlify.app/api-reference/email-finder/get-company
https://api.bavlio.com/openapi.json get /api/v1/email-finder/company/{domain}
Get company profile + email patterns by domain.
# Get Stats
Source: https://bavlio.mintlify.app/api-reference/email-finder/get-stats
https://api.bavlio.com/openapi.json get /api/v1/email-finder/stats
Get email finder database statistics.
# Get Verification Status
Source: https://bavlio.mintlify.app/api-reference/email-finder/get-verification-status
https://api.bavlio.com/openapi.json get /api/v1/email-finder/verify/{job_id}
Poll for find or verify job status.
# Health Check
Source: https://bavlio.mintlify.app/api-reference/email-finder/health-check
https://api.bavlio.com/openapi.json get /api/v1/email-finder/health
Email finder health check — verifies database connectivity.
# Search Person
Source: https://bavlio.mintlify.app/api-reference/email-finder/search-person
https://api.bavlio.com/openapi.json post /api/v1/email-finder/search
Search for a B2B contact by name + company/domain.
Returns a profile from the database if found, or predicted email patterns
with confidence scores if not found. Costs 0 credits (monthly lookup limit only).
# Verify Email
Source: https://bavlio.mintlify.app/api-reference/email-finder/verify-email
https://api.bavlio.com/openapi.json post /api/v1/email-finder/verify
Verify an email address via SMTP + BaviMail.
Checks cache first (free). If not cached, consumes 1 credit and
enqueues a verification job. Poll /verify/{job_id} for results.
Free tier users get 403 — verification requires a paid plan.
# Prune Dataset By Risk
Source: https://bavlio.mintlify.app/api-reference/email-verification/prune-dataset-by-risk
https://api.bavlio.com/openapi.json post /api/v1/email-verification/dataset/{dataset_id}/prune
Delete rows above a risk threshold and re-index remaining rows.
# Validate Email
Source: https://bavlio.mintlify.app/api-reference/email-verification/validate-email
https://api.bavlio.com/openapi.json post /api/v1/email-verification/validate
Validate a single email address and return risk assessment.
# Verify Dataset Emails
Source: https://bavlio.mintlify.app/api-reference/email-verification/verify-dataset-emails
https://api.bavlio.com/openapi.json post /api/v1/email-verification/dataset/{dataset_id}
Verify all emails in a dataset and return per-row risk results.
# Get Enrichment Status
Source: https://bavlio.mintlify.app/api-reference/enrichment-chat/get-enrichment-status
https://api.bavlio.com/openapi.json get /api/v1/enrichment-chat/session/{session_id}/status
Get the current status of enrichment processing.
This can handle both chat session IDs and processing session IDs.
Args:
session_id: The session ID (chat or processing)
Returns:
Status information including processing state and results
# Get Session File Data
Source: https://bavlio.mintlify.app/api-reference/enrichment-chat/get-session-file-data
https://api.bavlio.com/openapi.json get /api/v1/enrichment-chat/session/{session_id}/file-data
Get file data from a session for enrichment.
This endpoint retrieves the actual lead data that was uploaded
so the agent can process it with harvest tools.
Args:
session_id: The session ID
Returns:
File data including leads and metadata
# Notify File Uploaded
Source: https://bavlio.mintlify.app/api-reference/enrichment-chat/notify-file-uploaded
https://api.bavlio.com/openapi.json post /api/v1/enrichment-chat/file-uploaded/{session_id}
Notify the chat session that a file has been uploaded.
This endpoint is called when a file is uploaded through the chat interface.
It stores the file information in the chat context.
Args:
session_id: The chat session ID (not the processing session ID)
file_info: Information about the uploaded file
Returns:
Confirmation message
# Send Enrichment Message
Source: https://bavlio.mintlify.app/api-reference/enrichment-chat/send-enrichment-message
https://api.bavlio.com/openapi.json post /api/v1/enrichment-chat/message
Send a message in the enrichment chat session with enhanced processing.
Enhanced version with comprehensive validation, monitoring, and optimized
resource management for enrichment chat interactions.
Features:
- Input validation and sanitization
- Rate limiting and credit estimation
- Performance monitoring and logging
- Comprehensive error handling
- Processing session integration
Args:
request: Validated chat request with session ID and user message
current_user: Authenticated user information
enrichment_chat_service: Service for managing chat sessions
Returns:
EnrichmentChatResponse: Enhanced response with timing and status information
Raises:
HTTPException: For validation errors, rate limits, or processing failures
# Start Enrichment Chat
Source: https://bavlio.mintlify.app/api-reference/enrichment-chat/start-enrichment-chat
https://api.bavlio.com/openapi.json post /api/v1/enrichment-chat/start
Start a new enrichment chat interface with enhanced initialization.
Enhanced version with performance monitoring, better error handling,
and optimized welcome message generation.
Features:
- Performance monitoring and timing
- Enhanced error handling and logging
- Optimized agent integration
- Response time tracking
Returns:
EnrichmentChatResponse: Initial chat message with timing information
Raises:
HTTPException: If authentication fails or system error occurs
# Get Enrichment Job Status
Source: https://bavlio.mintlify.app/api-reference/enrichment-processing/get-enrichment-job-status
https://api.bavlio.com/openapi.json get /api/v1/enrichment/job/{job_id}/status
Get the comprehensive status of an enrichment job.
Provides detailed information about job progress, timing, resource usage,
and results. Includes error information for failed jobs and progress
estimates for running jobs.
Args:
job_id: The job ID to check (must be valid UUID format)
current_user: Authenticated user
supabase_service: Supabase service instance for job tracking
Returns:
EnrichmentJobStatus with comprehensive job information
Raises:
HTTPException: If job not found, access denied, or system error
# Process File Enrichment
Source: https://bavlio.mintlify.app/api-reference/enrichment-processing/process-file-enrichment
https://api.bavlio.com/openapi.json post /api/v1/enrichment/process-file
Process file enrichment request from the agent.
This endpoint is called by the agent's process_file_enrichment tool
to trigger background processing of LinkedIn URLs with comprehensive
validation and error handling.
Features:
- Input validation for LinkedIn URLs and session parameters
- Credit checking and quota verification
- Optimized Arq job enqueueing with proper resource management
- Comprehensive error handling and status reporting
- Job priority and duration estimation
Args:
request: File processing request details with validation
current_user: Authenticated user with credit information
redis_cache: Redis cache instance for session management
supabase_service: Supabase service instance for job tracking
Returns:
ProcessFileResponse with comprehensive job details
Raises:
HTTPException: For validation errors, insufficient credits, or processing failures
# Submit Feedback
Source: https://bavlio.mintlify.app/api-reference/feedback/submit-feedback
https://api.bavlio.com/openapi.json post /api/v1/feedback
Submit user feedback with optional screenshot and attachments.
# Preview CSV or Excel file before upload
Source: https://bavlio.mintlify.app/api-reference/file-upload-csvexcel/preview-csv-or-excel-file-before-upload
https://api.bavlio.com/openapi.json post /api/v1/upload/preview
Upload a CSV or Excel file to preview its structure, columns, and sample data
# Preview Excel file sheets
Source: https://bavlio.mintlify.app/api-reference/file-upload-csvexcel/preview-excel-file-sheets
https://api.bavlio.com/openapi.json post /api/v1/upload/excel/preview
Upload an Excel file to preview all sheets with metadata and sample data
# Upload CSV with sender profile support
Source: https://bavlio.mintlify.app/api-reference/file-upload-csvexcel/upload-csv-with-sender-profile-support
https://api.bavlio.com/openapi.json post /api/v1/sessions/{session_id}/upload/csv
Upload CSV file with option to use saved sender profiles or create new ones
# Upload Excel with multi-sheet and sender profile support
Source: https://bavlio.mintlify.app/api-reference/file-upload-csvexcel/upload-excel-with-multi-sheet-and-sender-profile-support
https://api.bavlio.com/openapi.json post /api/v1/sessions/{session_id}/upload/excel
Upload Excel file with option to process multiple sheets, use saved sender profiles, or create new ones
# Get Google Access Token
Source: https://bavlio.mintlify.app/api-reference/google-oauth/get-google-access-token
https://api.bavlio.com/openapi.json get /api/v1/auth/google/access-token
Get the current Google OAuth access token for the user.
This endpoint retrieves the user's Google OAuth access token,
refreshing it if necessary. The token can be used for Google Picker API.
Returns:
Dictionary with access token and token type
# Get Picker Config
Source: https://bavlio.mintlify.app/api-reference/google-oauth/get-picker-config
https://api.bavlio.com/openapi.json get /api/v1/auth/google/picker-config
Get Google Picker API configuration for frontend.
Returns the necessary configuration for initializing Google Picker
in the frontend, including API key and client ID.
Returns:
Dictionary with picker configuration
# Google Oauth Callback
Source: https://bavlio.mintlify.app/api-reference/google-oauth/google-oauth-callback
https://api.bavlio.com/openapi.json get /api/v1/auth/google/callback
Handle Google OAuth callback.
This endpoint is called by Google after the user completes authentication.
It exchanges the authorization code for access/refresh tokens and stores them.
Args:
code: Authorization code from Google
state: State parameter for validation
Returns:
Redirect to frontend with success/error status
# Google Oauth Login
Source: https://bavlio.mintlify.app/api-reference/google-oauth/google-oauth-login
https://api.bavlio.com/openapi.json post /api/v1/auth/google/login
Initiate Google OAuth flow.
This endpoint generates a Google OAuth authorization URL for the user
to authenticate and grant access to their Google Sheets.
Returns:
Dictionary with authorization URL and instructions
# Google Oauth Logout
Source: https://bavlio.mintlify.app/api-reference/google-oauth/google-oauth-logout
https://api.bavlio.com/openapi.json post /api/v1/auth/google/logout
Revoke Google OAuth credentials.
This endpoint revokes the user's Google OAuth tokens and marks them
as inactive in the database.
Returns:
Success message
# Google Oauth Status
Source: https://bavlio.mintlify.app/api-reference/google-oauth/google-oauth-status
https://api.bavlio.com/openapi.json get /api/v1/auth/google/status
Get Google OAuth authentication status.
This endpoint checks if the user has valid Google OAuth credentials
and returns their status including expiration and granted scopes.
Returns:
Authentication status information
# Get Sheet Info
Source: https://bavlio.mintlify.app/api-reference/google-sheets-oauth/get-sheet-info
https://api.bavlio.com/openapi.json get /api/v1/sheets/{sheet_id}/info
Get metadata about a Google Sheet.
Returns information about the sheet including available tabs and dimensions.
Args:
sheet_id: Google Sheets ID
Returns:
Sheet metadata including tabs and dimensions
# Grant Sheet Access
Source: https://bavlio.mintlify.app/api-reference/google-sheets-oauth/grant-sheet-access
https://api.bavlio.com/openapi.json post /api/v1/sheets/grant-access
Grant and record access to a Google Sheet selected via Google Picker.
This endpoint is called after a user selects a sheet through the Google Picker.
Returns success without database recording (permissions verified via Google API).
Returns:
Dictionary with success status and sheet details
# Import Google Sheets As Extraction
Source: https://bavlio.mintlify.app/api-reference/google-sheets-oauth/import-google-sheets-as-extraction
https://api.bavlio.com/openapi.json post /api/v1/sheets/import-as-extraction
Import Google Sheets data as an extraction for processing.
This endpoint imports data from a Google Sheet and creates an extraction
record that can be processed through the standard extraction pipeline
(sheet selection → column mapping → review/process).
Returns:
Dictionary with extraction_id and metadata
# Verify Sheet Access
Source: https://bavlio.mintlify.app/api-reference/google-sheets-oauth/verify-sheet-access
https://api.bavlio.com/openapi.json post /api/v1/sheets/verify-access
Verify user has access to a Google Sheet.
Verifies access via Google API (source of truth for permissions).
Returns:
Dictionary with access status and sheet metadata
# Health Check
Source: https://bavlio.mintlify.app/api-reference/health/health-check
https://api.bavlio.com/openapi.json get /api/v1/health
Basic health check endpoint.
This endpoint always returns 200 OK to indicate the service is running.
It's used by load balancers for basic liveness checks.
Returns:
dict: Simple health status with timestamp
# Readiness Check
Source: https://bavlio.mintlify.app/api-reference/health/readiness-check
https://api.bavlio.com/openapi.json get /api/v1/ready
Readiness check endpoint for container orchestration.
This endpoint checks if the service is ready to accept traffic.
Unlike the liveness check (/health), this verifies that all
required services are properly initialized.
Returns:
dict: Readiness status with service details
# System Status
Source: https://bavlio.mintlify.app/api-reference/health/system-status
https://api.bavlio.com/openapi.json get /api/v1/api/v1/status
Comprehensive system status check.
Checks the status of all critical system components including
the workflow engine and Redis cache. Returns appropriate HTTP
status codes based on service health.
HTTP Status Codes:
- 200: All services healthy or degraded (but operational)
- 503: Critical services unavailable
Returns:
dict: Detailed system status information
# API Reference
Source: https://bavlio.mintlify.app/api-reference/introduction
Full OpenAPI 3.1 specification for the Bavlio API. 190+ endpoints across campaigns, leads, sender profiles, personalization, BaviMail proxy, and more.
The Bavlio API is described by an OpenAPI 3.1 specification. The endpoint pages in this section are auto-generated from the live spec at [`api.bavlio.com/openapi.json`](https://api.bavlio.com/openapi.json) — they're always in sync with what's deployed.
Looking for a quick-start? Start with [Quickstart](/quickstart) — auth, first call, and error handling in 5 minutes. This reference is the comprehensive map; the quickstart is the ramp.
## Spec sources
`api.bavlio.com/openapi.json` — always-fresh production contract. Point your code generator at this.
Use the sidebar in this section to browse every endpoint. Try-It console included for authenticated calls.
## Endpoint groups
The API surface clusters into thirteen domains. Click any path family below to jump to the relevant endpoint pages.
`/api/v1/auth/*`, `/api/v1/api-keys/*` — Verify your token, fetch your user profile, manage API keys.
**Note:** API key creation requires a Supabase JWT, not an API key (prevents key-from-key minting).
`/api/v1/campaigns/*` — Create, list, launch, pause, resume campaigns. Per-campaign stats, leads, events, playground drafts. \~25 endpoints.
`/api/v1/email-finder/*`, `/api/v1/email-verification/*` — Search by name+company, verify deliverability, bulk verification.
**Note:** `find` and `verify` endpoints are async — they return `job_id`; poll for results.
`/api/v1/lead-finder/*` — Batch resolve names → LinkedIn profile URLs. Async with status polling.
`/api/v1/sender-profiles/*` — Manage up to 5 sender profiles per user. Named prompts (per-profile saved instructions) for AI personalization.
`/api/v1/templates/*` — Reusable email templates with variable substitution.
`/api/v1/suppression/*` — Do-not-contact list management.
`/api/v1/datasets/*`, `/api/v1/user-extractions/*` — Stored data sources from CSV, Excel, Google Sheets, and Chrome extension extractions.
`/api/v1/personalize/*` — Submit single or bulk personalization jobs. Async via ARQ — poll job status. Generation history endpoints expose run-level audit trail.
`/api/v1/agent/*` — Conversational interface to Bavlio capabilities. SSE streaming + interrupt resume. Conversation history persistence.
`/api/v1/connected-accounts/*` — Connect LinkedIn accounts via hosted-auth, credentials, or cookie. Check health, set send/invite limits, resume disabled accounts.
`/api/v1/bavimail/*` — Send transactional emails, manage sending domains and aliases, list inbound replies, browse conversations. Backed by BaviMail.
`/api/v1/credits/*`, `/api/v1/stripe/*` — Check credit balance, transaction history, estimate cost. Stripe checkout / portal / subscription status (JWT only).
`/api/x402/v1/*` — Wallet-paid endpoints (no API key). USDC on Base mainnet via x402 protocol. 5 endpoints. See [x402 API guide](https://bavlio.com/developers/x402) for details.
## Honest about state
These reference pages reflect what's live today. If you spot a discrepancy with actual behavior, the live spec at [`api.bavlio.com/openapi.json`](https://api.bavlio.com/openapi.json) is the source of truth. Roadmap items (Idempotency-Key middleware, customer webhooks, restricted API keys, MCP server) are flagged on their respective concept pages — not silently shown as if they exist.
First call in 5 minutes.
Key format, rotation, scoping.
Three envelopes documented honestly.
# Get Batch Status
Source: https://bavlio.mintlify.app/api-reference/lead-finder/get-batch-status
https://api.bavlio.com/openapi.json get /api/v1/lead-finder/batch/{session_id}/status
Poll batch lead finder progress. Ownership-guarded (L4).
Reads directly from Supabase (not SessionService Redis cache) because
worker updates counters via direct Supabase writes that don't invalidate cache.
# Submit Batch
Source: https://bavlio.mintlify.app/api-reference/lead-finder/submit-batch
https://api.bavlio.com/openapi.json post /api/v1/lead-finder/batch
Submit a batch of names to find LinkedIn URLs.
Creates a processing session + dataset, reserves credits (3 per name),
dispatches ARQ jobs for each name.
# Cancel Post
Source: https://bavlio.mintlify.app/api-reference/linkedin-content/cancel-post
https://api.bavlio.com/openapi.json delete /api/v1/linkedin/posts/{post_id}
# Create Post
Source: https://bavlio.mintlify.app/api-reference/linkedin-content/create-post
https://api.bavlio.com/openapi.json post /api/v1/linkedin/posts/
# Get Rate Limit
Source: https://bavlio.mintlify.app/api-reference/linkedin-content/get-rate-limit
https://api.bavlio.com/openapi.json get /api/v1/linkedin/posts/rate-limit
# List Posts
Source: https://bavlio.mintlify.app/api-reference/linkedin-content/list-posts
https://api.bavlio.com/openapi.json get /api/v1/linkedin/posts/
# Schedule Post
Source: https://bavlio.mintlify.app/api-reference/linkedin-content/schedule-post
https://api.bavlio.com/openapi.json post /api/v1/linkedin/posts/schedule
# Sync Posts
Source: https://bavlio.mintlify.app/api-reference/linkedin-content/sync-posts
https://api.bavlio.com/openapi.json post /api/v1/linkedin/posts/sync
# Get Profile
Source: https://bavlio.mintlify.app/api-reference/linkedin-playground/get-profile
https://api.bavlio.com/openapi.json post /api/v1/linkedin/profile
# List Actions
Source: https://bavlio.mintlify.app/api-reference/linkedin-playground/list-actions
https://api.bavlio.com/openapi.json get /api/v1/linkedin/actions
Return persistent action history and today's usage counts.
# List Chat Messages
Source: https://bavlio.mintlify.app/api-reference/linkedin-playground/list-chat-messages
https://api.bavlio.com/openapi.json get /api/v1/linkedin/chats/{chat_id}/messages
# List Chats
Source: https://bavlio.mintlify.app/api-reference/linkedin-playground/list-chats
https://api.bavlio.com/openapi.json get /api/v1/linkedin/chats
# Save Search Results
Source: https://bavlio.mintlify.app/api-reference/linkedin-playground/save-search-results
https://api.bavlio.com/openapi.json post /api/v1/linkedin/search/save
Save LinkedIn search results as a lead dataset.
# Search Linkedin
Source: https://bavlio.mintlify.app/api-reference/linkedin-playground/search-linkedin
https://api.bavlio.com/openapi.json post /api/v1/linkedin/search
# Send Invite
Source: https://bavlio.mintlify.app/api-reference/linkedin-playground/send-invite
https://api.bavlio.com/openapi.json post /api/v1/linkedin/invite
# Send Message
Source: https://bavlio.mintlify.app/api-reference/linkedin-playground/send-message
https://api.bavlio.com/openapi.json post /api/v1/linkedin/message
# Get Alerts
Source: https://bavlio.mintlify.app/api-reference/notifications/get-alerts
https://api.bavlio.com/openapi.json get /api/v1/notifications/alerts
Get user alerts. Default: unread only.
# Get Preferences
Source: https://bavlio.mintlify.app/api-reference/notifications/get-preferences
https://api.bavlio.com/openapi.json get /api/v1/notifications/preferences
Get notification preferences for the current user.
# Mark Alert Read
Source: https://bavlio.mintlify.app/api-reference/notifications/mark-alert-read
https://api.bavlio.com/openapi.json patch /api/v1/notifications/alerts/{alert_id}/read
Mark an alert as read.
# Send Test Notification
Source: https://bavlio.mintlify.app/api-reference/notifications/send-test-notification
https://api.bavlio.com/openapi.json post /api/v1/notifications/test
Send a test notification to verify delivery.
# Update Preferences
Source: https://bavlio.mintlify.app/api-reference/notifications/update-preferences
https://api.bavlio.com/openapi.json put /api/v1/notifications/preferences
Upsert notification preferences for the current user.
# Batch preview (SSE) — up to 25 leads, streams results as they complete
Source: https://bavlio.mintlify.app/api-reference/personalization/batch-preview-sse-—-up-to-25-leads-streams-results-as-they-complete
https://api.bavlio.com/openapi.json post /api/v1/personalize/preview/batch
Serial backend processing (no gather) to keep per-lead cache behavior predictable and budget-flat. Streams one SSE `lead_result` event per lead and a final `done` event. Echoes `client_run_id` as `batch_id` on every event so frontends can discard stale events from prior runs.
# Check personalization job status
Source: https://bavlio.mintlify.app/api-reference/personalization/check-personalization-job-status
https://api.bavlio.com/openapi.json get /api/v1/personalize/status/{job_id}
Get comprehensive status information for a personalization job
# Fetch the default personalization prompt
Source: https://bavlio.mintlify.app/api-reference/personalization/fetch-the-default-personalization-prompt
https://api.bavlio.com/openapi.json get /api/v1/personalize/default-prompt
Returns the current default system prompt for email generation so the UI can show it as a starting point for user edits.
# Get a single run + its first 500 per-lead generations
Source: https://bavlio.mintlify.app/api-reference/personalization/get-a-single-run-+-its-first-500-per-lead-generations
https://api.bavlio.com/openapi.json get /api/v1/personalize/generations/runs/{run_id}
# Get personalization job result
Source: https://bavlio.mintlify.app/api-reference/personalization/get-personalization-job-result
https://api.bavlio.com/openapi.json get /api/v1/personalize/result/{job_id}
Retrieve the result of a completed personalization job
# List recent generation runs for a given prompt
Source: https://bavlio.mintlify.app/api-reference/personalization/list-recent-generation-runs-for-a-given-prompt
https://api.bavlio.com/openapi.json get /api/v1/personalize/generations
# List user's datasets for the inline data-source picker
Source: https://bavlio.mintlify.app/api-reference/personalization/list-users-datasets-for-the-inline-data-source-picker
https://api.bavlio.com/openapi.json get /api/v1/personalize/datasets
# Paginated leads list for a single run (for >500-lead runs)
Source: https://bavlio.mintlify.app/api-reference/personalization/paginated-leads-list-for-a-single-run-for->500-lead-runs
https://api.bavlio.com/openapi.json get /api/v1/personalize/generations/runs/{run_id}/leads
# Queue bulk personalization requests
Source: https://bavlio.mintlify.app/api-reference/personalization/queue-bulk-personalization-requests
https://api.bavlio.com/openapi.json post /api/v1/personalize/bulk
Queue multiple lead-sender pairs for background personalization with enhanced validation
# Queue personalization request
Source: https://bavlio.mintlify.app/api-reference/personalization/queue-personalization-request
https://api.bavlio.com/openapi.json post /api/v1/personalize
Queue a personalization request for background processing with enhanced validation and monitoring
# Resolve the prompt the playground should boot into
Source: https://bavlio.mintlify.app/api-reference/personalization/resolve-the-prompt-the-playground-should-boot-into
https://api.bavlio.com/openapi.json get /api/v1/personalize/effective-prompt
Runs resolve_effective_prompt server-side with default_load_mode=True, returning the user's most-recently-saved named prompt if one exists, else the transitional custom_prompt, else the stock default. Single source of truth for playground boot (plan §4.7).
# Save a custom prompt onto a sender profile
Source: https://bavlio.mintlify.app/api-reference/personalization/save-a-custom-prompt-onto-a-sender-profile
https://api.bavlio.com/openapi.json post /api/v1/personalize/save-prompt
Upserts the given prompt into `sender_data.prompts[]` (named slot, default 'saved') AND mirrors it to `sender_data.custom_prompt` atomically. Used from the preview playground when a user wants future campaigns to use their iterated prompt.
# Sync preview of a personalized email for a single lead
Source: https://bavlio.mintlify.app/api-reference/personalization/sync-preview-of-a-personalized-email-for-a-single-lead
https://api.bavlio.com/openapi.json post /api/v1/personalize/preview
Blocking endpoint. Runs find_commonalities + generate_email inline against the provided lead + sender profile. Returns subject, body, commonality, and the prompt source used. Does not create a campaign, does not queue a job.
# Approve Lead Email
Source: https://bavlio.mintlify.app/api-reference/playground/approve-lead-email
https://api.bavlio.com/openapi.json post /api/v1/campaigns/{campaign_id}/leads/{campaign_lead_id}/approve
Freeze a per-step approved email on this campaign_lead.
Writes into `campaign_leads.metadata.approved_emails[step_index]`. The
send-time short-circuit (PR A2) reads this exact blob and skips LangGraph.
# Playground Cancel
Source: https://bavlio.mintlify.app/api-reference/playground/playground-cancel
https://api.bavlio.com/openapi.json post /api/v1/campaigns/{campaign_id}/playground/cancel
DB-authoritative cancel — flip generation_job.status to 'cancelled'.
# Playground Drafts
Source: https://bavlio.mintlify.app/api-reference/playground/playground-drafts
https://api.bavlio.com/openapi.json get /api/v1/campaigns/{campaign_id}/playground/drafts
Return full draft subject+body for every lead in the batch.
Tenant-scope enforced via ``service.get_batch_drafts`` which calls
``_load_campaign_owned(campaign_id, user_id)`` before any row read.
A user who passes another user's batch_id gets a 404 because the
``campaign_id`` is ownership-checked first — the batch filter is only
applied WITHIN an authorized campaign scope.
Intended usage from the UI: fetched once when the batch reaches
terminal-all (overall pending+running == 0), and on explicit "refresh
drafts" actions. NOT called on the 2s poll loop — the status endpoint
returns ``has_draft`` + ``subject_preview`` for that surface.
# Playground Generate
Source: https://bavlio.mintlify.app/api-reference/playground/playground-generate
https://api.bavlio.com/openapi.json post /api/v1/campaigns/{campaign_id}/playground/generate
Enqueue an ARQ ``playground_generation`` task per target lead.
# Playground Status
Source: https://bavlio.mintlify.app/api-reference/playground/playground-status
https://api.bavlio.com/openapi.json get /api/v1/campaigns/{campaign_id}/playground/status
Aggregate generation_job state per lead for the optional batch_id.
# Reset Lead Approvals
Source: https://bavlio.mintlify.app/api-reference/playground/reset-lead-approvals
https://api.bavlio.com/openapi.json post /api/v1/campaigns/{campaign_id}/leads/{campaign_lead_id}/reset
Reset approvals for this lead. Omitting step_indices clears every step.
# Unapprove Lead Email
Source: https://bavlio.mintlify.app/api-reference/playground/unapprove-lead-email
https://api.bavlio.com/openapi.json post /api/v1/campaigns/{campaign_id}/leads/{campaign_lead_id}/unapprove
Clear the approved blob for one step on this lead.
# Apply Referral Code
Source: https://bavlio.mintlify.app/api-reference/referral/apply-referral-code
https://api.bavlio.com/openapi.json post /api/v1/referral/apply
Apply a referral code to the current user.
# Get Referral Code
Source: https://bavlio.mintlify.app/api-reference/referral/get-referral-code
https://api.bavlio.com/openapi.json get /api/v1/referral/code
Get or generate the user's referral code.
# Get Referral Stats
Source: https://bavlio.mintlify.app/api-reference/referral/get-referral-stats
https://api.bavlio.com/openapi.json get /api/v1/referral/stats
Get referral statistics for the current user.
# Root Health Check
Source: https://bavlio.mintlify.app/api-reference/root-health-check
https://api.bavlio.com/openapi.json get /health
Simple health check endpoint for Docker.
# Cancel Chat Session
Source: https://bavlio.mintlify.app/api-reference/sender-profile-chat/cancel-chat-session
https://api.bavlio.com/openapi.json delete /api/v1/sender-profile-chat/session/{session_id}
Cancel a chat session.
Deletes the session without creating a profile.
Args:
session_id: The chat session ID to cancel
Returns:
Confirmation message
# Get Chat History
Source: https://bavlio.mintlify.app/api-reference/sender-profile-chat/get-chat-history
https://api.bavlio.com/openapi.json get /api/v1/sender-profile-chat/session/{session_id}/history
Get the chat history for a session.
Returns all messages in the conversation so far.
Args:
session_id: The chat session ID
Returns:
List of chat messages
# Send Chat Message
Source: https://bavlio.mintlify.app/api-reference/sender-profile-chat/send-chat-message
https://api.bavlio.com/openapi.json post /api/v1/sender-profile-chat/message
Send a message in the chat session.
Processes user input and returns the next question or completes
the profile creation process.
Args:
request: Chat request with session ID and user message
Returns:
Chat response with bot's reply
# Start Chat Session
Source: https://bavlio.mintlify.app/api-reference/sender-profile-chat/start-chat-session
https://api.bavlio.com/openapi.json post /api/v1/sender-profile-chat/start
Start a new chat session for creating a sender profile.
Initiates a conversational interface that guides users through
creating a comprehensive sender profile.
Returns:
Initial chat message with session ID
# Create Named Prompt
Source: https://bavlio.mintlify.app/api-reference/sender-profiles/create-named-prompt
https://api.bavlio.com/openapi.json post /api/v1/sender-profiles/{profile_id}/prompts
# Create Sender Profile
Source: https://bavlio.mintlify.app/api-reference/sender-profiles/create-sender-profile
https://api.bavlio.com/openapi.json post /api/v1/sender-profiles/
Create a new sender profile.
Creates a new sender profile for the authenticated user. The profile
will be scoped to the user and can only be accessed by them.
Maximum of 5 profiles allowed per user.
The sender_data can contain ANY fields - there is no predefined schema.
Common fields might include full_name, company, role, etc., but you can
include any fields your use case requires.
Args:
profile_data: The sender profile data
current_user: Authenticated user information
settings: Application settings
Returns:
The created sender profile with generated ID
Raises:
HTTPException: If profile creation fails or limit exceeded
# Delete Named Prompt
Source: https://bavlio.mintlify.app/api-reference/sender-profiles/delete-named-prompt
https://api.bavlio.com/openapi.json delete /api/v1/sender-profiles/{profile_id}/prompts/{name}
# Delete Sender Profile
Source: https://bavlio.mintlify.app/api-reference/sender-profiles/delete-sender-profile
https://api.bavlio.com/openapi.json delete /api/v1/sender-profiles/{profile_id}
Delete a sender profile.
Deletes a sender profile if the authenticated user has access.
Args:
profile_id: The ID of the profile to delete
current_user: Authenticated user information
settings: Application settings
Returns:
None (204 No Content on success)
Raises:
HTTPException: If profile not found or access denied
# Get Default Sender Profile
Source: https://bavlio.mintlify.app/api-reference/sender-profiles/get-default-sender-profile
https://api.bavlio.com/openapi.json get /api/v1/sender-profiles/default/
Get the default sender profile for the authenticated user.
Retrieves the user's default profile if one exists.
Args:
current_user: Authenticated user information
settings: Application settings
Returns:
The default sender profile or None if no default set
# Get Sender Profile
Source: https://bavlio.mintlify.app/api-reference/sender-profiles/get-sender-profile
https://api.bavlio.com/openapi.json get /api/v1/sender-profiles/{profile_id}
Retrieve a specific sender profile.
Retrieves a sender profile by ID if the authenticated user has access.
Args:
profile_id: The ID of the profile to retrieve
current_user: Authenticated user information
settings: Application settings
Returns:
The requested sender profile
Raises:
HTTPException: If profile not found or access denied
# List Named Prompts
Source: https://bavlio.mintlify.app/api-reference/sender-profiles/list-named-prompts
https://api.bavlio.com/openapi.json get /api/v1/sender-profiles/{profile_id}/prompts
# List Sender Profiles
Source: https://bavlio.mintlify.app/api-reference/sender-profiles/list-sender-profiles
https://api.bavlio.com/openapi.json get /api/v1/sender-profiles/
List all sender profiles for the authenticated user.
Retrieves all sender profiles owned by the authenticated user with
optional pagination. Profiles are sorted by creation date (newest first).
Maximum of 5 profiles per user.
Args:
current_user: Authenticated user information
settings: Application settings
limit: Maximum number of profiles to return (default: 100)
offset: Number of profiles to skip (default: 0)
Returns:
List of sender profiles for the user
# Search Sender Profiles
Source: https://bavlio.mintlify.app/api-reference/sender-profiles/search-sender-profiles
https://api.bavlio.com/openapi.json get /api/v1/sender-profiles/search/
Search sender profiles by name.
Searches through the authenticated user's profiles for those matching
the search query. Search is case-insensitive and matches partial names.
Args:
query: Search query string
current_user: Authenticated user information
settings: Application settings
limit: Maximum number of profiles to return (default: 20)
Returns:
List of matching sender profiles
# Update Named Prompt
Source: https://bavlio.mintlify.app/api-reference/sender-profiles/update-named-prompt
https://api.bavlio.com/openapi.json patch /api/v1/sender-profiles/{profile_id}/prompts/{name}
# Update Sender Profile
Source: https://bavlio.mintlify.app/api-reference/sender-profiles/update-sender-profile
https://api.bavlio.com/openapi.json put /api/v1/sender-profiles/{profile_id}
Update an existing sender profile.
Updates a sender profile if the authenticated user has access.
Only provided fields will be updated - omitted fields remain unchanged.
Args:
profile_id: The ID of the profile to update
updates: The fields to update
current_user: Authenticated user information
settings: Application settings
Returns:
The updated sender profile
Raises:
HTTPException: If profile not found or access denied
# Add leads to session
Source: https://bavlio.mintlify.app/api-reference/session-management/add-leads-to-session
https://api.bavlio.com/openapi.json post /api/v1/sessions/{session_id}/leads
Queue leads for processing in an existing session
# Bulk update sender data
Source: https://bavlio.mintlify.app/api-reference/session-management/bulk-update-sender-data
https://api.bavlio.com/openapi.json post /api/v1/sessions/{session_id}/sender-data/bulk
Update sender data from multiple sources (JSON objects)
# Create processing session
Source: https://bavlio.mintlify.app/api-reference/session-management/create-processing-session
https://api.bavlio.com/openapi.json post /api/v1/sessions/create
Create a new processing session with initial sender data
# Create session from existing dataset
Source: https://bavlio.mintlify.app/api-reference/session-management/create-session-from-existing-dataset
https://api.bavlio.com/openapi.json post /api/v1/sessions/datasets/{dataset_id}/new-session
Create a new session linked to an existing dataset for re-enrichment
# Delete session
Source: https://bavlio.mintlify.app/api-reference/session-management/delete-session
https://api.bavlio.com/openapi.json delete /api/v1/sessions/{session_id}
Clean up session data and remove all associated resources
# Get job status
Source: https://bavlio.mintlify.app/api-reference/session-management/get-job-status
https://api.bavlio.com/openapi.json get /api/v1/sessions/{session_id}/jobs/{job_id}/status
Check the status of a background job associated with a session
# Get session results
Source: https://bavlio.mintlify.app/api-reference/session-management/get-session-results
https://api.bavlio.com/openapi.json get /api/v1/sessions/{session_id}/results
Retrieve processing results for a completed or in-progress session
# Get session status
Source: https://bavlio.mintlify.app/api-reference/session-management/get-session-status
https://api.bavlio.com/openapi.json get /api/v1/sessions/{session_id}/status
Retrieve current status and progress information for a session
# Update sender data
Source: https://bavlio.mintlify.app/api-reference/session-management/update-sender-data
https://api.bavlio.com/openapi.json post /api/v1/sessions/{session_id}/sender-data
Add or update sender data for an existing session
# Start session processing
Source: https://bavlio.mintlify.app/api-reference/session-processing/start-session-processing
https://api.bavlio.com/openapi.json post /api/v1/sessions/{session_id}/process
Start background processing of all queued leads in a session
# Create Checkout Session
Source: https://bavlio.mintlify.app/api-reference/stripe/create-checkout-session
https://api.bavlio.com/openapi.json post /api/v1/stripe/create-checkout-session
Create a Stripe Checkout session for the requested tier.
# Create Portal Session
Source: https://bavlio.mintlify.app/api-reference/stripe/create-portal-session
https://api.bavlio.com/openapi.json post /api/v1/stripe/create-portal-session
Create a Stripe Billing Portal session for subscription management.
# Get Subscription Status
Source: https://bavlio.mintlify.app/api-reference/stripe/get-subscription-status
https://api.bavlio.com/openapi.json get /api/v1/stripe/subscription-status
Return current subscription info for the authenticated user.
# Purchase Credits
Source: https://bavlio.mintlify.app/api-reference/stripe/purchase-credits
https://api.bavlio.com/openapi.json post /api/v1/stripe/purchase-credits
Create a Stripe Checkout session for a one-time credit top-up purchase.
# Add Suppression
Source: https://bavlio.mintlify.app/api-reference/suppression/add-suppression
https://api.bavlio.com/openapi.json post /api/v1/suppression/
Add an email to the suppression list.
# Delete Suppression
Source: https://bavlio.mintlify.app/api-reference/suppression/delete-suppression
https://api.bavlio.com/openapi.json delete /api/v1/suppression/{entry_id}
Remove an email from the suppression list.
# List Suppression
Source: https://bavlio.mintlify.app/api-reference/suppression/list-suppression
https://api.bavlio.com/openapi.json get /api/v1/suppression/
List suppression entries for the current user.
# Create Template
Source: https://bavlio.mintlify.app/api-reference/templates/create-template
https://api.bavlio.com/openapi.json post /api/v1/templates/
Create a new email template.
Templates can be used across multiple campaigns for sending template-based
emails. Variables in the template (e.g., {{first_name}}) will be replaced
with lead data at send time.
Args:
request: Template creation request with name and content
current_user: Authenticated user information
service: Campaign service instance
Returns:
Created template response
# Delete Template
Source: https://bavlio.mintlify.app/api-reference/templates/delete-template
https://api.bavlio.com/openapi.json delete /api/v1/templates/{template_id}
Delete a template.
Note: Deleting a template that is in use by a campaign will set the
template_id to NULL in the campaign's step configuration.
Args:
template_id: Template ID
current_user: Authenticated user information
service: Campaign service instance
# Get Template
Source: https://bavlio.mintlify.app/api-reference/templates/get-template
https://api.bavlio.com/openapi.json get /api/v1/templates/{template_id}
Get a specific template by ID.
Args:
template_id: Template ID
current_user: Authenticated user information
service: Campaign service instance
Returns:
Template response
# List Templates
Source: https://bavlio.mintlify.app/api-reference/templates/list-templates
https://api.bavlio.com/openapi.json get /api/v1/templates/
List all templates for the authenticated user.
Args:
current_user: Authenticated user information
service: Campaign service instance
page: Page number (1-indexed)
page_size: Items per page (max 100)
Returns:
Paginated list of templates
# Update Template
Source: https://bavlio.mintlify.app/api-reference/templates/update-template
https://api.bavlio.com/openapi.json patch /api/v1/templates/{template_id}
Update a template.
Args:
template_id: Template ID
request: Update request
current_user: Authenticated user information
service: Campaign service instance
Returns:
Updated template response
# Bulk Delete Extractions
Source: https://bavlio.mintlify.app/api-reference/user-extractions/bulk-delete-extractions
https://api.bavlio.com/openapi.json post /api/v1/user-extractions/bulk-delete
Delete multiple extractions in bulk.
Args:
request: Request containing list of extraction IDs to delete
current_user: Authenticated user information
settings: Application settings
Returns:
BulkDeleteResponse with deletion results
Raises:
HTTPException: If authentication fails
# Create Session From Extraction
Source: https://bavlio.mintlify.app/api-reference/user-extractions/create-session-from-extraction
https://api.bavlio.com/openapi.json post /api/v1/user-extractions/{extraction_id}/create-session
Create an enrichment session from a saved extraction.
This endpoint converts an extraction (stored as JSON in Supabase storage)
into a new enrichment session with associated dataset and dataset_rows.
Flow:
1. Fetch user_extractions record (validate ownership)
2. Download JSON from extraction-files bucket using storage_path
3. Parse JSON array of lead objects
4. Create processing_sessions record (pipeline_type="enrichment")
5. Create datasets record (source_type="extraction")
6. Create dataset_rows records (one per lead)
7. Update user_extractions.session_id to link them
8. Return session details
Args:
extraction_id: The ID of the extraction to convert
current_user: Authenticated user information
cache: Redis cache instance
settings: Application settings
Returns:
CreateSessionResponse with session_id and metadata
Raises:
HTTPException: If extraction not found, access denied, or processing fails
# Delete Extraction
Source: https://bavlio.mintlify.app/api-reference/user-extractions/delete-extraction
https://api.bavlio.com/openapi.json delete /api/v1/user-extractions/{extraction_id}
Delete a single extraction.
Args:
extraction_id: The ID of the extraction to delete
current_user: Authenticated user information
settings: Application settings
Returns:
Success response with deletion confirmation
Raises:
HTTPException: If extraction not found or access denied
# Download Extraction
Source: https://bavlio.mintlify.app/api-reference/user-extractions/download-extraction
https://api.bavlio.com/openapi.json get /api/v1/user-extractions/{extraction_id}/download
Download an extraction in the specified format.
This endpoint:
1. Fetches user_extractions record (validates ownership)
2. Downloads JSON from extraction-files bucket using storage_path
3. Parses JSON array of lead objects
4. Filters columnValues.* fields and strips prefix
5. Converts to requested format (CSV/Excel/JSON)
6. Returns as streaming response
Args:
extraction_id: The ID of the extraction to download
format: Download format (csv, excel, or json)
current_user: Authenticated user information
settings: Application settings
Returns:
File as a streaming response in the requested format
Raises:
HTTPException: If extraction not found or access denied
# Get Extraction Info
Source: https://bavlio.mintlify.app/api-reference/user-extractions/get-extraction-info
https://api.bavlio.com/openapi.json get /api/v1/user-extractions/{extraction_id}/info
Get detailed information about a specific extraction.
Args:
extraction_id: The ID of the extraction to retrieve
current_user: Authenticated user information
settings: Application settings
Returns:
Detailed extraction information
Raises:
HTTPException: If extraction not found or access denied
# List User Extractions
Source: https://bavlio.mintlify.app/api-reference/user-extractions/list-user-extractions
https://api.bavlio.com/openapi.json get /api/v1/user-extractions/
List all available extractions for the authenticated user.
Returns all extractions from the Chrome extension (PitchBook, LinkedIn, etc.).
Args:
current_user: Authenticated user information
settings: Application settings
limit: Maximum number of extractions to return (default: 50)
offset: Number of extractions to skip (default: 0)
source: Optional filter by extraction source (e.g., 'PitchBook')
Returns:
List of available extractions with metadata
# Process Extraction To Session
Source: https://bavlio.mintlify.app/api-reference/user-extractions/process-extraction-to-session
https://api.bavlio.com/openapi.json post /api/v1/user-extractions/{extraction_id}/process
Process an extraction into a session for lead personalization.
This endpoint converts the stored extraction data (ZIP) to Excel format
and processes it through the standard session-based pipeline.
Args:
extraction_id: The ID of the extraction to process
request: Processing configuration including session ID
current_user: Authenticated user information
settings: Application settings
Returns:
Processing status and results
Raises:
HTTPException: If extraction not found, access denied, or processing fails
# Rename Extraction
Source: https://bavlio.mintlify.app/api-reference/user-extractions/rename-extraction
https://api.bavlio.com/openapi.json patch /api/v1/user-extractions/{extraction_id}/rename
Rename an extraction (update its title in metadata).
Args:
extraction_id: The ID of the extraction to rename
rename_request: Request body containing the new title
current_user: Authenticated user information
settings: Application settings
Returns:
Success response with updated extraction info
Raises:
HTTPException: If extraction not found or access denied
# Rename Extraction Options
Source: https://bavlio.mintlify.app/api-reference/user-extractions/rename-extraction-options
https://api.bavlio.com/openapi.json options /api/v1/user-extractions/{extraction_id}/rename
Handle CORS preflight for rename endpoint.
# Get Quota Status
Source: https://bavlio.mintlify.app/api-reference/users/get-quota-status
https://api.bavlio.com/openapi.json get /api/v1/users/quota-status
Get detailed quota status and recommendations.
This endpoint provides:
- Current quota usage and limits
- Warning levels and enforcement status
- Upgrade recommendations based on usage
Args:
user_info: Authenticated user information from JWT
quota_service: Global quota service instance
Returns:
Dictionary containing quota status and recommendations
# Get Usage Dashboard
Source: https://bavlio.mintlify.app/api-reference/users/get-usage-dashboard
https://api.bavlio.com/openapi.json get /api/v1/users/usage
Get user's current usage statistics and quota information.
This endpoint returns comprehensive usage data including:
- Current month's usage and remaining quota
- Subscription tier and limits
- Recent processing history
- Storage usage metrics
Args:
user_info: Authenticated user information from JWT
usage_service: Usage tracking service instance
limit: Maximum number of history records to return (1-100)
offset: Number of history records to skip for pagination
Returns:
Dictionary containing:
- summary: Current usage summary with quotas and limits
- history: List of recent processing jobs
- stats: Additional statistics for charts
# Handle Unipile Webhook
Source: https://bavlio.mintlify.app/api-reference/webhooks/handle-unipile-webhook
https://api.bavlio.com/openapi.json post /api/v1/webhooks/unipile
Receive and process Unipile webhook events.
# Health Check
Source: https://bavlio.mintlify.app/api-reference/webhooks/health-check
https://api.bavlio.com/openapi.json get /api/v1/webhooks/bavimail
# Stripe Webhook
Source: https://bavlio.mintlify.app/api-reference/webhooks/stripe-webhook
https://api.bavlio.com/openapi.json post /api/v1/webhooks/stripe
Stripe webhook endpoint — signature-verified, idempotent via event dedup.
# Webhook Handler
Source: https://bavlio.mintlify.app/api-reference/webhooks/webhook-handler
https://api.bavlio.com/openapi.json post /api/v1/webhooks/bavimail
# DNS-only email deliverability check (x402-paid, $0.003 USDC)
Source: https://bavlio.mintlify.app/api-reference/x402/dns-only-email-deliverability-check-x402-paid-$0003-usdc
https://api.bavlio.com/openapi.json post /api/x402/v1/email/validate
DNS-only inline validate. No ARQ. No user context. Idempotent.
~500ms median latency (one MX lookup). Falls back to a stable
``risk_level == "invalid"`` payload on syntax/MX failure rather than
raising — invalid-but-well-shaped emails should return paid content,
not an error, because the question the agent asked was answered.
# Find LinkedIn profile URL via public search engines (x402-paid, $0.008 USDC)
Source: https://bavlio.mintlify.app/api-reference/x402/find-linkedin-profile-url-via-public-search-engines-x402-paid-$0008-usdc
https://api.bavlio.com/openapi.json post /api/x402/v1/linkedin/find-url
SYNC inline search. No ARQ. No user context. Idempotent per query.
# Find working email via sequential SMTP pattern probing (x402-paid, $0.010 USDC)
Source: https://bavlio.mintlify.app/api-reference/x402/find-working-email-via-sequential-smtp-pattern-probing-x402-paid-$0010-usdc
https://api.bavlio.com/openapi.json post /api/x402/v1/email/find
SYNC inline SMTP find. No ARQ. No user context. Idempotent per candidate list.
Caller either pre-computes candidates or passes first/last/domain and we
generate them. Returns the first pattern that SMTP-validates, or
``found=false`` if none did.
# Search prospect pool by tag overlap (x402-paid, $0.012 USDC)
Source: https://bavlio.mintlify.app/api-reference/x402/search-prospect-pool-by-tag-overlap-x402-paid-$0012-usdc
https://api.bavlio.com/openapi.json post /api/x402/v1/prospects/search
SYNC inline Supabase read. No ARQ. No user context. Idempotent.
# Verify deliverability via SMTP RCPT probe (x402-paid, $0.005 USDC)
Source: https://bavlio.mintlify.app/api-reference/x402/verify-deliverability-via-smtp-rcpt-probe-x402-paid-$0005-usdc
https://api.bavlio.com/openapi.json post /api/x402/v1/email/verify
SYNC inline SMTP verify. No ARQ. No user context. Idempotent.
The x402 payment middleware runs BEFORE this handler (PaymentMiddlewareASGI
intercepts on path match). Settlement happens AFTER handler return iff
``status < 400``. An adapter timeout / upstream error returns 4xx/5xx and
skips settlement per the lib invariant.
# Authentication
Source: https://bavlio.mintlify.app/authentication
bav_live_ API keys, Bearer tokens, key rotation, x402 wallet auth as alternative.
Bavlio's SaaS API uses workspace-scoped API keys. Pass the key as a Bearer token in the `Authorization` header. Every request needs it.
## Key format
Bavlio API keys start with `bav_live_` followed by 43 URL-safe characters. The prefix lets you spot Bavlio keys in your secrets scanner. Treat the entire string as the secret.
```text Example theme={null}
bav_live_a1b2c3d4e5f6g7h8i9j0kLmNoPqRsTuVwXyZ
```
## Creating a key
Use the Google or email account on your workspace. [bavlio.com/login](https://bavlio.com/login).
Free-tier accounts cannot create keys; upgrade to a paid plan if you see a 403 on creation.
Name describes the use (`production-agent`, `staging-worker`). The full value is shown **only once** on creation.
Set as `BAVLIO_API_KEY` environment variable. Never commit it to source.
**By design:** API keys cannot mint API keys. The endpoint that creates keys requires a logged-in dashboard session — this prevents a leaked key from cloning itself, and means agent provisioning always involves a human-in-the-loop initial setup.
## Sending the key
Pass the key as a Bearer token. Both the SaaS API and the BaviMail proxy under `/api/v1/bavimail/*` accept the same header.
```bash cURL theme={null}
curl -X GET https://api.bavlio.com/api/v1/auth/me \
-H "Authorization: Bearer bav_live_REPLACE_WITH_YOUR_KEY"
```
```python Python theme={null}
import os, httpx
client = httpx.Client(
base_url="https://api.bavlio.com",
headers={"Authorization": f"Bearer {os.environ['BAVLIO_API_KEY']}"},
)
me = client.get("/api/v1/auth/me").json()
```
```javascript Node theme={null}
const response = await fetch("https://api.bavlio.com/api/v1/auth/me", {
headers: { Authorization: `Bearer ${process.env.BAVLIO_API_KEY}` },
});
const me = await response.json();
```
## Rotating a key
Both old and new keys are valid in parallel — no downtime.
Update the secret in your environment, restart workers.
Look at the dashboard **Last Used** column for both keys.
Revoked keys return HTTP 401 on every subsequent request. There is no undo — create a new key if needed.
## Scopes & permissions
Today, all API keys grant **full workspace access** — there is no per-key scoping. Restricted (Stripe-style `rk_`) keys are on the roadmap. Until then, treat each key as workspace-admin and rotate aggressively if leaked.
## x402 wallet auth (alternative)
AI agents without a Bavlio account can hit a subset of Bavlio's data — email verification, email finder, LinkedIn URL discovery, prospect search — without an account, paying per call in USDC on Base mainnet via the x402 protocol. No signup, no API key, no subscription.
Full guide to wallet-paid endpoints. 5 endpoints at 0.003-0.012 USDC each.
For agents using a regular `bav_live_` API key.
# Errors & Idempotency
Source: https://bavlio.mintlify.app/errors
Three error envelopes coexist today. Status code reference, retry rules, and current idempotency state with workaround.
Bavlio is honest about its current state. Three error envelope shapes coexist today (a unification migration is parked as a follow-up). Idempotency-Key middleware is not yet implemented. Here's how to deal with both.
## Error envelope shapes
Match on HTTP status code first; treat the body as supplementary detail. Newer endpoints conform to ADR-010 (flat shape with stable code); older endpoints still emit FastAPI defaults; validation failures emit a Pydantic-shaped envelope.
### EpicHTTPError (flat)
Used by newer endpoints. The `detail` field is a stable machine-readable code; `message` is a human-readable explanation.
```json Example theme={null}
{
"detail": "VALIDATION_ERROR",
"message": "Email is required"
}
```
Seen on: `/api/v1/personalize`, `/api/v1/personalize/preview`, `/api/v1/email-finder/*` (most routes).
### Legacy HTTPException
Older FastAPI default. The `detail` field is a human-readable string; no separate code field. Treat `detail` as opaque text — match on status code and endpoint, not on `detail` content.
```json Example theme={null}
{
"detail": "Email is required"
}
```
Seen on: older endpoints that have not yet migrated to EpicHTTPError.
### Pydantic request validation
Returned automatically when request bodies fail Pydantic validation. The `details` array contains structured per-field errors; `path` is the request path; `message` is constant.
```json Example theme={null}
{
"error": "Request Validation Error",
"details": [
{
"loc": ["body", "email"],
"msg": "field required",
"type": "value_error.missing"
}
],
"path": "/api/v1/email-finder/search",
"message": "The request failed validation"
}
```
Seen on: any endpoint with a Pydantic request body.
## Status codes & retry rules
| Status | Meaning | Retry? |
| ------ | --------------------------------------- | ------------------------- |
| 200 | OK | n/a |
| 201 | Created | n/a |
| 202 | Accepted (async work queued) | n/a |
| 400 | Bad request — fix the body / params | no |
| 401 | Authentication failed | no (re-auth) |
| 403 | Authenticated but not allowed | no |
| 404 | Not found | no |
| 409 | Conflict (duplicate, state change race) | maybe (after read) |
| 422 | Validation failed | no |
| 429 | Rate limited | yes (after `Retry-After`) |
| 500 | Server error | yes (exponential backoff) |
| 502 | Bad gateway | yes |
| 503 | Service unavailable | yes |
| 504 | Gateway timeout | yes |
A safe default agent: retry 429 honoring `Retry-After`, retry 5xx with exponential backoff (max 5 attempts), surface everything else immediately.
## Retry pattern
Drop-in helper that respects `Retry-After` and backs off exponentially.
```python Python theme={null}
import time
import httpx
def call_with_backoff(client, method, path, *, max_retries=5, **kwargs):
"""Retry on 429 and 5xx with exponential backoff. Stop on 4xx others."""
for attempt in range(max_retries):
response = client.request(method, path, **kwargs)
if response.status_code < 400:
return response
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", "1"))
time.sleep(retry_after)
continue
if 500 <= response.status_code < 600:
time.sleep(2 ** attempt)
continue
response.raise_for_status()
response.raise_for_status()
```
## Idempotency
The `Idempotency-Key` header is **not yet honored** by Bavlio. Sending it has no effect server-side. A retried POST after a network failure will create a duplicate.
**Workaround until the middleware ships:** after a failed mutation, follow up with a read before retrying. For example, after a failed `POST /api/v1/campaigns/`, call `GET /api/v1/campaigns/?name=` to check whether your campaign was already created. Match on a stable client-side correlation field (campaign name, lead-set hash, etc.).
**Roadmap:** a FastAPI middleware that accepts `Idempotency-Key` on POST/PUT/PATCH/DELETE, hashes the request, stores the response in Redis for 24 hours, and returns the cached response on retry.
## FAQ
Retry on 429 (after waiting `Retry-After` seconds) and on 5xx server errors with exponential backoff. Do NOT retry on 4xx (other than 429) — fix the request and try once. Check `error.detail` or `error.message` for the specific cause.
Three envelopes coexist today. Newer endpoints use a flat shape: `{ detail: , message: }` per ADR-010 (EpicHTTPError). Older endpoints use the FastAPI default: `{ detail: }`. Pydantic validation failures return `{ error, details, path, message }`. Match on status code first.
401 means the API key is missing, malformed, or revoked. Re-authenticate. 403 means the key is valid but lacks permission for the operation — for example, attempting to mint a new API key with an API key (only Supabase JWTs can mint keys).
# MCP (Model Context Protocol)
Source: https://bavlio.mintlify.app/integrations/mcp
Two MCP surfaces — a docs MCP server live today (queries the documentation), and a planned API-action MCP server (drives the live API).
Bavlio exposes two distinct MCP surfaces:
Lets agents query the Bavlio documentation by tool calls (search, fetch page). Auto-generated from this site.
Lets agents take actions against the live Bavlio API (create campaigns, send email, search leads). Planned.
## Docs MCP — live
Auto-published by the docs platform at:
```text theme={null}
https://bavlio.mintlify.app/mcp
```
Use cases: any agent that needs to *consult* Bavlio's documentation (e.g., a Cursor session writing integration code, a Claude Desktop session debugging a 401, an autonomous agent learning the API surface). The MCP server exposes search and page-fetch tools that read this site directly.
### Quick install (Cursor)
Add to your Cursor MCP config:
```json theme={null}
{
"mcpServers": {
"bavlio-docs": {
"url": "https://bavlio.mintlify.app/mcp"
}
}
}
```
### Quick install (Claude Desktop)
Open Claude Desktop's MCP config and add:
```json theme={null}
{
"mcpServers": {
"bavlio-docs": {
"transport": { "type": "http", "url": "https://bavlio.mintlify.app/mcp" }
}
}
}
```
### What this covers vs. doesn't
**Covers:** every page on this site — Quickstart, Authentication, Errors, Pagination, Rate Limits, Webhooks, the full API Reference (190 endpoints with request/response schemas), and the OpenAPI spec.
**Doesn't cover:** taking actions against the API. Agents using only the docs MCP can read docs but can't, for example, create a campaign or send an email. For that you need the API-action MCP below — or just call the REST API directly with a `bav_live_` key.
***
## API-action MCP — roadmap
**Status: not yet available.** The endpoint, package, and tool surface below are previews — the API-action MCP is not yet shipped. Do not paste the install command yet; it will fail.
A separate MCP server that wraps the Bavlio REST API as agent-callable tools. Lets an agent create campaigns, send emails, search leads, etc. without writing HTTP plumbing.
### Planned install path
```text theme={null}
npx add-mcp https://mcp.bavlio.com/mcp
```
Transport: Streamable HTTP. Auth: Bearer token using your existing `bav_live_` API key.
### Planned tool surface
Initial tool set targets the most common agent workflows: campaign lifecycle, lead management, send + reply, plus the two stateless email primitives.
| Tool | Read-only | Destructive | Idempotent | Description |
| ----------------------- | --------- | ----------- | ---------- | -------------------------------------------------------------- |
| `list_campaigns` | yes | no | yes | List campaigns with optional status filter. |
| `create_campaign` | no | no | no | Create a new campaign in DRAFT state. |
| `launch_campaign` | no | no | yes | Launch a DRAFT campaign after preflight checks pass. |
| `pause_campaign` | no | no | yes | Pause an active campaign. |
| `search_leads` | yes | no | yes | Search leads in a campaign by name, company, or status. |
| `add_leads_to_campaign` | no | no | no | Append leads to a campaign from a CSV/JSON payload. |
| `send_email` | no | no | no | Send a transactional email via the BaviMail proxy. |
| `list_replies` | yes | no | yes | List recent inbound replies (untrusted-content envelope). |
| `get_campaign_stats` | yes | no | yes | Aggregate campaign metrics (sent, delivered, opened, replied). |
| `verify_email` | yes | no | yes | SMTP-probe an email address; returns valid/invalid/risky. |
### Design notes
* **Untrusted-content envelope.** Tools that surface third-party content (inbound replies) wrap responses in `{ __untrusted_third_party_content: true, content: ... }`. The fence is a machine-readable signal that a trust boundary was crossed. Same pattern as `@bavimail/mcp-server`.
* **No client-side caching of API keys.** The server reads the API key on every call; key rotation takes effect without restart.
* **Tool annotations.** Every tool ships with `readOnlyHint`, `destructiveHint`, and `idempotentHint` per the MCP spec.
### Until then
Use the REST API directly. The [Quickstart](/quickstart) covers everything an agent needs. The API-action MCP is a convenience layer on top — the underlying capability is already available today via REST.
# Bavlio API
Source: https://bavlio.mintlify.app/introduction
Agent-first sales outreach infrastructure. Authenticate with one API key, invoke any capability, no human-in-the-loop required.
Bavlio is a sales outreach platform built so AI agents can drive every workflow — from finding leads to personalizing emails to running multi-step campaigns — through a single REST API.
These docs are the canonical reference. Every public capability behind your `bav_live_` API key is documented here, with copy-paste examples in cURL, Python, and Node, an interactive [API reference](/api-reference/introduction), and machine-readable specs at [/openapi.json](https://api.bavlio.com/openapi.json) for tooling.
## Get going in 5 minutes
Authenticate, make your first call, handle errors, and build a real outreach loop.
Every endpoint with live request examples and response schemas, generated from the OpenAPI spec.
`bav_live_` API key format, Bearer header, key rotation, x402 wallet auth.
Wire Bavlio into Claude Desktop, Cursor, and any MCP-compatible agent. Docs MCP live now; API-action MCP on the roadmap.
## Core capabilities
Create, launch, pause, and resume multi-step outbound campaigns. Per-campaign stats, leads, events, and AI-personalized drafts.
SMTP-probe candidate emails, verify deliverability, batch-resolve full datasets.
Resolve names + companies to LinkedIn profile URLs. Batch async with status polling.
Send transactional email, manage sending domains and aliases, browse inbound replies.
Connect LinkedIn accounts, send invites and messages, sync content, manage send limits.
USDC-on-Base micropayments for unauthenticated agent calls. No account required.
## Built for agents
The full API is described by an [OpenAPI 3.1 spec](https://api.bavlio.com/openapi.json) (190+ endpoints). An [`/llms.txt`](/llms.txt) index and [`/llms-full.txt`](/llms-full.txt) full-content dump are auto-generated for AI ingestion. A [docs MCP server](/integrations/mcp) is live at `bavlio.mintlify.app/mcp` for any agent that needs to query these docs as native tools (Claude Desktop, Cursor, etc.).
These docs document what exists *today*. Where a feature is on the roadmap (`Idempotency-Key` middleware, customer-registered webhooks, restricted API keys), the page says so plainly and gives a working alternative until it ships. No aspirational claims.
Once you have an API key, every public capability — campaigns, leads, sender profiles, templates, sends, replies — is invocable from documentation alone. The first key still needs a dashboard login (deliberate: prevents key-from-key minting); after that, agents drive everything.
## Need help?
API uptime, incident history, scheduled maintenance.
Contact the team for setup, billing, or scoping questions.
What's new, deprecations, breaking changes.
# Pagination
Source: https://bavlio.mintlify.app/pagination
Bavlio's pagination is endpoint-specific — three patterns coexist. The OpenAPI spec is the source of truth for any endpoint's request and response shape.
Bavlio does not yet enforce a unified pagination contract. Three patterns coexist. Check [`/openapi.json`](https://api.bavlio.com/openapi.json) for any endpoint's definitive request and response shape.
## Three patterns in use
### offset + limit
Most list endpoints accept `?offset=0&limit=100`. Default `limit` varies per endpoint (commonly 50 or 100). Continue until response contains fewer rows than `limit`.
```text Example theme={null}
GET /api/v1/campaigns/?offset=0&limit=100
```
### has\_more flag
Some endpoints return `{ items: [...], has_more: bool }`. Continue until `has_more` is false. Use the last item id as the next page anchor where applicable.
```text Example theme={null}
GET /api/v1/personalize/history?after_id=
```
### no pagination
Some endpoints return the full collection in one response (sender profiles, templates). Safe to call once.
```text Example theme={null}
GET /api/v1/sender-profiles/
```
## Drain-all helper
Handles both offset+limit and has\_more shapes. Falls back cleanly when the response is a flat list (no pagination).
```python Python theme={null}
def drain_all(client, path, *, page_size=100, **params):
"""Drain a list endpoint that uses offset+limit pagination."""
offset = 0
while True:
response = client.get(path, params={**params, "offset": offset, "limit": page_size})
response.raise_for_status()
items = response.json()
if not isinstance(items, list):
payload = items
items = payload.get("items", [])
yield from items
if not payload.get("has_more"):
return
else:
yield from items
if len(items) < page_size:
return
offset += page_size
```
## Common gotchas
* **Default limits vary.** Some endpoints default to 50, some to 100, some to no pagination at all. Always pass an explicit `limit` to make behavior predictable.
* **Order is not stable across pages** for some endpoints under heavy concurrent writes. If you need a consistent snapshot, paginate by a stable id range rather than offset, or freeze the list and resume on failure.
* **Some endpoints have no pagination at all.** Sender profiles and templates return the full collection. Calling them once is correct.
## Roadmap
A unified cursor-based pagination contract (`?cursor=&limit=` with `next_cursor` + `has_more` envelope) is on the roadmap. Until then, treat each endpoint as having its own contract and check the OpenAPI spec.
# Quickstart
Source: https://bavlio.mintlify.app/quickstart
Authenticate, make your first call, handle errors, paginate, and retry safely. Five minutes from key to first response.
Built for AI agents. Skip the UI screenshots. This page covers everything an agent needs: auth, base URL, first call, errors, idempotency, pagination, polling, rate limits.
All examples use the live production API at `https://api.bavlio.com`. Replace `bav_live_REPLACE_WITH_YOUR_KEY` with your real key before running.
## 1. Get an API key
Open [bavlio.com/login](https://bavlio.com/login). Free-tier accounts cannot create keys — upgrade to a paid plan if you see a 403 on creation.
Click **Create key**, name it (e.g. `production-agent`), and copy the full value immediately. The full string is shown only once.
Set it as `BAVLIO_API_KEY` in your runtime environment. Never commit it to source. Keys start with `bav_live_` followed by 43 URL-safe characters.
**By design:** API keys cannot mint API keys. Key creation requires a logged-in dashboard session — this prevents a leaked key from cloning itself. Agent provisioning always involves a human-in-the-loop initial setup.
## 2. Authenticate
Pass the key as a Bearer token in the `Authorization` header on every request. Base URL: `https://api.bavlio.com`.
```bash cURL theme={null}
curl -X GET https://api.bavlio.com/api/v1/auth/me \
-H "Authorization: Bearer bav_live_REPLACE_WITH_YOUR_KEY"
```
```python Python theme={null}
import os
import httpx
api_key = os.environ["BAVLIO_API_KEY"] # bav_live_...
client = httpx.Client(
base_url="https://api.bavlio.com",
headers={"Authorization": f"Bearer {api_key}"},
timeout=30.0,
)
response = client.get("/api/v1/auth/me")
response.raise_for_status()
print(response.json())
```
```javascript Node theme={null}
const apiKey = process.env.BAVLIO_API_KEY; // bav_live_...
const response = await fetch("https://api.bavlio.com/api/v1/auth/me", {
headers: { Authorization: `Bearer ${apiKey}` },
});
if (!response.ok) {
throw new Error(`Bavlio ${response.status}: ${await response.text()}`);
}
console.log(await response.json());
```
## 3. Make your first call
List your campaigns. Most list endpoints accept `?offset=0&limit=100` — see [Pagination](/pagination) for endpoint-specific patterns.
```bash cURL theme={null}
curl -X GET "https://api.bavlio.com/api/v1/campaigns/?offset=0&limit=100" \
-H "Authorization: Bearer bav_live_REPLACE_WITH_YOUR_KEY"
```
## 4. Handle errors
Three error envelopes coexist today (a unification migration is on the roadmap). On 4xx, fix the request. On 429, wait `Retry-After` seconds. On 5xx, retry with exponential backoff. Full taxonomy at [Errors](/errors).
```python Python theme={null}
import time
import httpx
def call_with_backoff(client, method, path, *, max_retries=5, **kwargs):
"""Retry on 429 and 5xx with exponential backoff. Stop on 4xx others."""
for attempt in range(max_retries):
response = client.request(method, path, **kwargs)
if response.status_code < 400:
return response
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", "1"))
time.sleep(retry_after)
continue
if 500 <= response.status_code < 600:
time.sleep(2 ** attempt)
continue
response.raise_for_status()
response.raise_for_status()
```
## 5. Idempotency (current state)
Bavlio does **not yet honor** the `Idempotency-Key` header. Sending it has no effect server-side. A retried POST after a network failure will create a duplicate.
**Workaround until the middleware ships:** after a failed mutation, follow up with a read before retrying. For example, after a failed `POST /api/v1/campaigns/`, call `GET /api/v1/campaigns/?name=` to check whether your campaign was already created. Match on a stable client-side correlation field. See [Errors → Idempotency](/errors#idempotency) for the full pattern.
## 6. Drain a paginated list
Most list endpoints use offset+limit. Some return `has_more`. Some return the full collection. The helper below handles both common shapes.
```python Python theme={null}
def drain_all(client, path, *, page_size=100, **params):
"""Drain a list endpoint that uses offset+limit pagination."""
offset = 0
while True:
response = client.get(path, params={**params, "offset": offset, "limit": page_size})
response.raise_for_status()
items = response.json()
if not isinstance(items, list):
payload = items
items = payload.get("items", [])
yield from items
if not payload.get("has_more"):
return
else:
yield from items
if len(items) < page_size:
return
offset += page_size
```
## 7. Webhooks (poll instead, for now)
Customer-registered outbound webhooks are not yet available. Use polling endpoints for the events agents care about (campaign status, replies, email events). See [Webhooks (Polling)](/webhooks) for the full guide.
## 8. Respect rate limits
Bavlio sets `X-RateLimit-Limit` and `X-RateLimit-Reset` headers on responses to API-key authenticated requests. On a 429, the `Retry-After` header tells you exactly how long to wait. There is no `X-RateLimit-Remaining` header. See [Rate Limits](/rate-limits).
## Copy this for Claude / GPT / Codex
Paste this block into your AI coding assistant to bootstrap a Bavlio integration with the right context.
```python agent-context.py theme={null}
# Bavlio API — Quickstart for AI Agents
# Docs: https://bavlio.com/docs/quickstart
# Reference: https://bavlio.com/docs/api-reference/introduction
# OpenAPI: https://api.bavlio.com/openapi.json
#
# Auth: Authorization: Bearer bav_live_...
# Base URL: https://api.bavlio.com
#
# Errors: three envelopes coexist — see /docs/errors for shapes.
# Pagination: endpoint-specific — see /docs/pagination.
# Idempotency-Key header is NOT yet honored — see /docs/errors#idempotency.
# Customer webhooks NOT yet available — poll endpoints listed at /docs/webhooks.
# Rate limits: X-RateLimit-Limit + X-RateLimit-Reset headers; Retry-After on 429.
import os
import httpx
api_key = os.environ["BAVLIO_API_KEY"]
client = httpx.Client(
base_url="https://api.bavlio.com",
headers={"Authorization": f"Bearer {api_key}"},
timeout=30.0,
)
# Identity check
me = client.get("/api/v1/auth/me").raise_for_status().json()
print(f"Authenticated as user_id={me.get('user_id')}")
# List campaigns (offset+limit pagination)
campaigns = client.get("/api/v1/campaigns/", params={"offset": 0, "limit": 100}).json()
print(f"Got {len(campaigns)} campaigns")
```
## FAQ
Pass your API key as a Bearer token: `Authorization: Bearer bav_live_`. Generate keys in your Bavlio dashboard. Keys are scoped to the workspace that created them.
`https://api.bavlio.com` for the SaaS API. `https://api.bavlio.com/api/x402` for x402 pay-per-call endpoints (no auth required).
Bavlio does not yet honor the `Idempotency-Key` header. For non-mutating reads (GET), retry freely. For mutating writes (POST/PUT/PATCH/DELETE), check the resulting state with a follow-up GET before retrying. The Idempotency-Key middleware is on the roadmap.
Pagination is endpoint-specific. Most list endpoints accept `?offset=0&limit=100`. Some return `{ items, has_more }`. Some return the full collection. See [Pagination](/pagination) for per-endpoint guidance.
Customer-registered webhooks are not yet available. Poll the campaign stats and BaviMail email-events endpoints in the meantime. See [Webhooks](/webhooks) for the full polling guide and roadmap.
Rate limits apply only to API-key authenticated requests and depend on Redis availability. The `X-RateLimit-Limit` and `X-RateLimit-Reset` headers tell you the current limit window. On 429 the `Retry-After` header tells you how long to wait.
## Next
Full OpenAPI 3.1 spec, every endpoint.
Key format, rotation, scoping.
Docs MCP live now; API-action MCP on the roadmap.
# Rate Limits
Source: https://bavlio.mintlify.app/rate-limits
Bavlio sets X-RateLimit-Limit and X-RateLimit-Reset headers on API-key authenticated requests. How to read them and how to back off correctly.
Bavlio enforces per-key rate limits on requests authenticated with an API key. The limit varies by plan tier. Headers tell you the current state.
## Headers
| Header | Description |
| ------------------- | --------------------------------------------------------------- |
| `X-RateLimit-Limit` | Your current per-window limit (an integer). |
| `X-RateLimit-Reset` | Unix epoch seconds at which the current window resets. |
| `Retry-After` | Present only on 429 responses. Seconds to wait before retrying. |
**There is no `X-RateLimit-Remaining` header.** Compute remaining requests yourself by tracking your own send count within the current window if you need an in-flight estimate. The headers above are sent on every response (where available).
## Caveats
* **API-key auth only.** Requests authenticated with a Supabase JWT (dashboard sessions) do not get rate-limit headers and follow a different limit.
* **Redis-backed.** Rate limiting depends on Redis. If Redis is unavailable, Bavlio fails open: requests proceed, but no headers are set. This is a deliberate tradeoff; reliability beats strict enforcement during infrastructure incidents.
* **Per-key, not per-IP.** Limits are scoped to your API key. Two keys on the same workspace each have their own bucket.
## Example 429 response
```http theme={null}
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Reset: 1746590160
Retry-After: 13
Content-Type: application/json
{
"detail": "RATE_LIMITED",
"message": "Too many requests; retry after 13s"
}
```
## Backoff pattern
Honor `Retry-After` exactly on 429. On 5xx, exponential backoff capped at a few attempts.
```python Python theme={null}
import time
import httpx
def call_with_backoff(client, method, path, *, max_retries=5, **kwargs):
"""Retry on 429 and 5xx with exponential backoff."""
for attempt in range(max_retries):
response = client.request(method, path, **kwargs)
if response.status_code < 400:
return response
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", "1"))
time.sleep(retry_after)
continue
if 500 <= response.status_code < 600:
time.sleep(2 ** attempt)
continue
response.raise_for_status()
response.raise_for_status()
```
## See also
Full status code taxonomy, retry rules, and current idempotency state.
Minimal happy-path agent integration.
# Webhooks
Source: https://bavlio.mintlify.app/webhooks
Customer-registered webhooks are not yet available. Use polling endpoints for campaign state, replies, and email events.
**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
| Method | Path | Purpose |
| ------ | --------------------------------------------------- | ------------------------------------------------------------- |
| `GET` | `/api/v1/campaigns/{campaign_id}/stats` | Comprehensive campaign stats (sends, opens, clicks, replies). |
| `GET` | `/api/v1/campaigns/{campaign_id}/leads/{id}/events` | Per-lead email event timeline. |
| `GET` | `/api/v1/bavimail/emails` | List sent emails with status (delivered, opened, bounced). |
| `GET` | `/api/v1/bavimail/inbound-emails` | List inbound replies. |
| `GET` | `/api/v1/bavimail/conversations` | Threaded 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 Python theme={null}
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 Python theme={null}
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.