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

# Making requests

> Learn how to structure API requests, handle pagination, filter results, and work with the HoopAI API.

All HoopAI API requests follow REST conventions. This guide covers the patterns you'll use in every integration.

## Base URL

```
https://services.leadconnectorhq.com
```

<Note>
  The base URL uses a platform infrastructure domain. This is the API service that powers HoopAI — all data belongs to your HoopAI account.
</Note>

## Request structure

Every request needs the `Authorization` and `Version` headers:

```bash theme={null}
curl -X GET "https://services.leadconnectorhq.com/{endpoint}" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Version: 2021-07-28" \
  -H "Content-Type: application/json"
```

### Common parameters

| Parameter         | Description                                             | Used in              |
| ----------------- | ------------------------------------------------------- | -------------------- |
| `locationId`      | Account ID (required for most endpoints)                | Query string or body |
| `limit`           | Number of results per page (default varies by endpoint) | Query string         |
| `offset` / `page` | Pagination cursor                                       | Query string         |

## Pagination

Most list endpoints return paginated results. The response includes metadata about total results and how to fetch the next page.

```json theme={null}
{
  "contacts": [...],
  "meta": {
    "total": 342,
    "currentPage": 1,
    "nextPage": 2,
    "startAfter": 20,
    "startAfterId": "abc123"
  }
}
```

### Offset-based pagination

```bash theme={null}
# Page 1
GET /contacts/?locationId=LOC_ID&limit=20

# Page 2
GET /contacts/?locationId=LOC_ID&limit=20&startAfter=20
```

### Cursor-based pagination

Some endpoints use cursor-based pagination with `startAfterId`:

```bash theme={null}
# First page
GET /contacts/?locationId=LOC_ID&limit=20

# Next page (use the last item's ID)
GET /contacts/?locationId=LOC_ID&limit=20&startAfterId=abc123
```

<Tip>
  Always check the `meta` object in the response for pagination details. If `nextPage` is `null`, you've reached the last page.
</Tip>

## Filtering and searching

Many list endpoints support filtering via query parameters or a search body:

```bash theme={null}
# Filter contacts by tag
GET /contacts/?locationId=LOC_ID&query=tag:lead

# Search contacts (POST)
POST /contacts/search
{
  "locationId": "LOC_ID",
  "filters": [
    { "field": "tags", "operator": "contains", "value": "lead" }
  ],
  "page": 1,
  "pageLimit": 20
}
```

## Creating and updating resources

Use `POST` to create and `PUT` to update. Always send JSON bodies with the `Content-Type: application/json` header.

```bash theme={null}
# Create a contact
curl -X POST "https://services.leadconnectorhq.com/contacts/" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Version: 2021-07-28" \
  -H "Content-Type: application/json" \
  -d '{
    "locationId": "LOC_ID",
    "firstName": "Jane",
    "lastName": "Smith",
    "email": "jane@example.com",
    "phone": "+15551234567",
    "tags": ["lead", "website"]
  }'
```

## Error handling

All errors return a consistent JSON structure:

```json theme={null}
{
  "statusCode": 422,
  "message": "Validation failed",
  "errors": [
    { "field": "email", "message": "Invalid email format" }
  ]
}
```

| Status | Meaning          | What to do                                                                                                  |
| ------ | ---------------- | ----------------------------------------------------------------------------------------------------------- |
| `400`  | Bad request      | Check request body and parameters                                                                           |
| `401`  | Unauthorized     | Token missing, expired, or invalid — [refresh it](/developer/guide/authentication#step-4-refresh-the-token) |
| `403`  | Forbidden        | Token lacks required scope                                                                                  |
| `404`  | Not found        | Resource doesn't exist or wrong `locationId`                                                                |
| `422`  | Validation error | Check the `errors` array for field-level details                                                            |
| `429`  | Rate limited     | Wait and retry with exponential backoff                                                                     |
| `500`  | Server error     | Retry after a short delay                                                                                   |

## Rate limits

| Scope         | Limit                     |
| ------------- | ------------------------- |
| Per account   | 100 requests / 10 seconds |
| Token refresh | 5 requests / minute       |

Rate limit headers are included in every response:

| Header                  | Description                              |
| ----------------------- | ---------------------------------------- |
| `X-RateLimit-Remaining` | Requests remaining in the current window |
| `X-RateLimit-Reset`     | Unix timestamp when the limit resets     |

When you receive a `429` response, use exponential backoff:

```javascript theme={null}
async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const response = await fetch(url, options);
    if (response.status !== 429) return response;

    const resetAt = response.headers.get('X-RateLimit-Reset');
    const waitMs = resetAt
      ? (parseInt(resetAt) * 1000) - Date.now()
      : Math.pow(2, i) * 1000;

    await new Promise(resolve => setTimeout(resolve, Math.max(waitMs, 1000)));
  }
  throw new Error('Max retries exceeded');
}
```

## Next steps

<CardGroup cols={2}>
  <Card title="Webhooks" icon="bell" href="/developer/guide/webhooks">
    Receive real-time events from HoopAI
  </Card>

  <Card title="API reference" icon="terminal" href="/api-reference/introduction">
    Browse all available endpoints
  </Card>
</CardGroup>
