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

# API Overview

> Base URL, headers, and error handling

## Base URL

All API requests should be made to:

```
https://api.bouncewatch.com/api/v1
```

## Request Headers

Include these headers with every request:

| Header         | Required | Description                            |
| -------------- | -------- | -------------------------------------- |
| `X-API-Key`    | Yes      | Your API authentication key            |
| `Content-Type` | No       | `application/json` (for POST requests) |
| `Accept`       | No       | `application/json`                     |

```bash theme={null}
curl -X GET "https://api.bouncewatch.com/api/v1/company/stripe.com" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
```

## Response Format

All responses are returned in JSON format with a consistent structure:

### Successful Response

```json theme={null}
{
  "success": true,
  "credits_used": 10,
  "credits_breakdown": {
    "base": 10,
    "enrichments": {}
  },
  "modules_included": ["base"],
  "data": {
    // Response data here
  }
}
```

### Error Response

```json theme={null}
{
  "success": false,
  "error": "error_code",
  "message": "Human-readable error message",
  "credits_used": 0
}
```

## HTTP Status Codes

| Code  | Status                | Description                                     |
| ----- | --------------------- | ----------------------------------------------- |
| `200` | OK                    | Request successful (data served from 24h cache) |
| `202` | Accepted              | Enrichment queued (results via webhook)         |
| `400` | Bad Request           | Invalid parameters or missing webhook URL       |
| `401` | Unauthorized          | Invalid or missing API key                      |
| `402` | Payment Required      | Insufficient credits                            |
| `410` | Gone                  | Deprecated endpoint or mode                     |
| `429` | Too Many Requests     | Rate limit or cooldown exceeded                 |
| `500` | Internal Server Error | Server error - please retry                     |

## Error Codes

<AccordionGroup>
  <Accordion title="Authentication Errors" icon="lock">
    | Error Code         | Message                  | Solution                      |
    | ------------------ | ------------------------ | ----------------------------- |
    | `invalid_api_key`  | Invalid API key provided | Check your API key is correct |
    | `missing_api_key`  | API key is required      | Add `X-API-Key` header        |
    | `api_key_expired`  | API key has expired      | Generate a new key            |
    | `api_key_disabled` | API key is disabled      | Contact support               |
  </Accordion>

  <Accordion title="Request Errors" icon="circle-exclamation">
    | Error Code          | Message                    | Solution                                    |
    | ------------------- | -------------------------- | ------------------------------------------- |
    | `invalid_domain`    | Invalid domain format      | Provide a valid domain (e.g., `stripe.com`) |
    | `invalid_module`    | Invalid enrichment module  | Check available modules                     |
    | `missing_parameter` | Required parameter missing | Include all required parameters             |
  </Accordion>

  <Accordion title="Resource Errors" icon="magnifying-glass">
    | Error Code         | Message                             | Solution                                      |
    | ------------------ | ----------------------------------- | --------------------------------------------- |
    | `data_unavailable` | Requested data not available        | Try a different module                        |
    | `webhook_required` | Webhook URL required for new domain | Configure webhook or use X-Webhook-URL header |

    <Info>
      **Note:** `company_not_found` no longer returns as an error. Instead, the API automatically triggers realtime enrichment (202 Accepted) for domains not in our database.
    </Info>
  </Accordion>

  <Accordion title="Limit Errors" icon="gauge">
    | Error Code             | Message                     | Solution              |
    | ---------------------- | --------------------------- | --------------------- |
    | `insufficient_credits` | Not enough credits          | Purchase more credits |
    | `rate_limit_exceeded`  | Too many requests           | Wait and retry        |
    | `daily_limit_exceeded` | Daily request limit reached | Wait until reset      |
  </Accordion>
</AccordionGroup>

## Error Handling Example

<Info>
  **Note:** When a domain requires enrichment, the API returns `202 Accepted` and starts enrichment automatically. Handle this by checking for `status === 202` and the `batch_id` in the response. Results will be delivered to your webhook.
</Info>

<CodeGroup>
  ```javascript JavaScript theme={null}
  async function getCompanyData(domain) {
    try {
      const response = await fetch(
        `https://api.bouncewatch.com/api/v1/company/${domain}`,
        { headers: { 'X-API-Key': API_KEY } }
      );
      
      const data = await response.json();
      
      // Handle realtime enrichment (202 Accepted - domain not in cache)
      if (response.status === 202) {
        console.log(`Domain ${domain} not in cache. Enrichment started.`);
        console.log(`Batch ID: ${data.batch_id}. Results will be sent to webhook.`);
        return { status: 'enriching', batch_id: data.batch_id };
      }
      
      if (!data.success) {
        switch (data.error) {
          case 'insufficient_credits':
            console.log(`Need ${data.credits_needed} credits, have ${data.credits_available}`);
            break;
          case 'rate_limit_exceeded':
            console.log(`Rate limited. Retry after ${data.retry_after}s`);
            break;
          case 'webhook_required':
            console.log(`Webhook URL required for new domain enrichment`);
            break;
          default:
            console.log(`Error: ${data.message}`);
        }
        return null;
      }
      
      return data.data;
    } catch (error) {
      console.error('Network error:', error);
      return null;
    }
  }
  ```

  ```python Python theme={null}
  import requests

  def get_company_data(domain):
      try:
          response = requests.get(
              f'https://api.bouncewatch.com/api/v1/company/{domain}',
              headers={'X-API-Key': API_KEY}
          )
          data = response.json()
          
          # Handle realtime enrichment (202 Accepted - domain not in cache)
          if response.status_code == 202:
              print(f"Domain {domain} not in cache. Enrichment started.")
              print(f"Batch ID: {data['batch_id']}. Results will be sent to webhook.")
              return {'status': 'enriching', 'batch_id': data['batch_id']}
          
          if not data['success']:
              error = data.get('error')
              if error == 'insufficient_credits':
                  print(f"Need {data['credits_needed']} credits")
              elif error == 'rate_limit_exceeded':
                  print(f"Rate limited. Retry after {data['retry_after']}s")
              elif error == 'webhook_required':
                  print(f"Webhook URL required for new domain enrichment")
              else:
                  print(f"Error: {data['message']}")
              return None
          
          return data['data']
      except requests.RequestException as e:
          print(f"Network error: {e}")
          return None
  ```

  ```php PHP theme={null}
  function getCompanyData($domain) {
      $ch = curl_init("https://api.bouncewatch.com/api/v1/company/{$domain}");
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: ' . API_KEY]);
      
      $response = curl_exec($ch);
      $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      curl_close($ch);
      
      if ($response === false) {
          echo "Network error\n";
          return null;
      }
      
      $data = json_decode($response, true);
      
      // Handle realtime enrichment (202 Accepted - domain not in cache)
      if ($httpCode === 202) {
          echo "Domain {$domain} not in cache. Enrichment started.\n";
          echo "Batch ID: {$data['batch_id']}. Results will be sent to webhook.\n";
          return ['status' => 'enriching', 'batch_id' => $data['batch_id']];
      }
      
      if (!$data['success']) {
          switch ($data['error']) {
              case 'insufficient_credits':
                  echo "Need {$data['credits_needed']} credits\n";
                  break;
              case 'rate_limit_exceeded':
                  echo "Rate limited. Retry after {$data['retry_after']}s\n";
                  break;
              case 'webhook_required':
                  echo "Webhook URL required for new domain enrichment\n";
                  break;
              default:
                  echo "Error: {$data['message']}\n";
          }
          return null;
      }
      
      return $data['data'];
  }
  ```
</CodeGroup>
