# 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.