> ## Documentation Index
> Fetch the complete documentation index at: https://bavlio.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

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

<Note>
  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.
</Note>

## 1. Get an API key

<Steps>
  <Step title="Sign in to bavlio.com">
    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.
  </Step>

  <Step title="Generate a key from Settings → API keys">
    Click **Create key**, name it (e.g. `production-agent`), and copy the full value immediately. The full string is shown only once.
  </Step>

  <Step title="Store it as a secret">
    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.
  </Step>
</Steps>

<Tip>
  **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.
</Tip>

## 2. Authenticate

Pass the key as a Bearer token in the `Authorization` header on every request. Base URL: `https://api.bavlio.com`.

<CodeGroup>
  ```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());
  ```
</CodeGroup>

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

<Warning>
  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.
</Warning>

**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=<your-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)

<Warning>
  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.
</Warning>

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

<AccordionGroup>
  <Accordion title="How do I authenticate?">
    Pass your API key as a Bearer token: `Authorization: Bearer bav_live_<your-key>`. Generate keys in your Bavlio dashboard. Keys are scoped to the workspace that created them.
  </Accordion>

  <Accordion title="What is the base URL?">
    `https://api.bavlio.com` for the SaaS API. `https://api.bavlio.com/api/x402` for x402 pay-per-call endpoints (no auth required).
  </Accordion>

  <Accordion title="How do I retry safely after a network failure?">
    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.
  </Accordion>

  <Accordion title="How do I paginate results?">
    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.
  </Accordion>

  <Accordion title="Are there webhooks?">
    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.
  </Accordion>

  <Accordion title="What is the rate limit?">
    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.
  </Accordion>
</AccordionGroup>

## Next

<CardGroup cols={3}>
  <Card title="API Reference" icon="terminal" href="/api-reference/introduction">
    Full OpenAPI 3.1 spec, every endpoint.
  </Card>

  <Card title="Authentication" icon="key" href="/authentication">
    Key format, rotation, scoping.
  </Card>

  <Card title="MCP" icon="plug" href="/integrations/mcp">
    Docs MCP live now; API-action MCP on the roadmap.
  </Card>
</CardGroup>
