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

# Making requests

> Learn how to structure API requests, understand response formats, and use common patterns

## Request methods

The HelpGenie API supports two ways to make requests: the `ApiService.invoke()` pattern (recommended for TypeScript projects) and direct HTTP requests.

### ApiService.invoke() (recommended)

The `ApiService` class handles authentication, request formatting, and response unwrapping automatically:

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { ApiService } from "@/services/api/ApiService";

  const genies = await ApiService.invoke({
    resource: "genies",
    action: "all",
  });
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.helpgenie.ai/v1 \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "resource": "genies",
      "action": "all"
    }'
  ```
</CodeGroup>

The `invoke` method accepts an options object with these fields:

<ParamField body="resource" type="string" required>
  The API resource to target. Must be one of the 13 supported resources.
</ParamField>

<ParamField body="action" type="string" required>
  The action to perform. Common actions: `all`, `list`, `get`, `create`, `update`, `delete`.
</ParamField>

<ParamField body="id" type="string | number">
  The record identifier. Required for `get`, `update`, and `delete` actions.
</ParamField>

<ParamField body="data" type="object">
  The request payload. Used with `create` and `update` actions. Structure varies by resource.
</ParamField>

### Direct HTTP requests

You can also call the Edge Function directly. The API accepts both a body-based resource/action pattern and standard REST-style HTTP methods.

<Tabs>
  <Tab title="Body-based (POST)">
    Send the resource, action, and data in the request body:

    ```bash theme={null}
    curl -X POST https://api.helpgenie.ai/v1 \
      -H "Authorization: Bearer <token>" \
      -H "Content-Type: application/json" \
      -d '{
        "resource": "genies",
        "action": "get",
        "id": "abc-123"
      }'
    ```
  </Tab>

  <Tab title="REST-style">
    Use HTTP methods and URL paths:

    ```bash theme={null}
    # GET all genies
    GET /v1/genies

    # GET a single genie
    GET /v1/genies/abc-123

    # GET list (compact format)
    GET /v1/genies/list

    # CREATE a genie
    POST /v1/genies

    # UPDATE a genie
    PATCH /v1/genies/abc-123

    # DELETE a genie
    DELETE /v1/genies/abc-123
    ```
  </Tab>
</Tabs>

## Common actions

Most resources support a standard set of actions. Some resources add custom actions specific to their domain.

| Action | Description | Requires `id` | Requires `data` |
| - | - | - | - |
| `all` | Fetch all records with full details and relations | No | No |
| `list` | Fetch a compact list of records (for dropdowns and selectors) | No | No |
| `get` | Fetch a single record by ID | Yes | No |
| `create` | Create a new record | No | Yes |
| `update` | Update an existing record | Yes | Yes |
| `delete` | Delete a record | Yes | No |

### `list` vs `all`

The API distinguishes between two fetching actions:

* **`all`** returns full records with related data (joins, counts, nested objects). Use this when you need complete information.
* **`list`** returns minimal records with only key fields (typically `id` and `name`). Use this for populating dropdowns, selectors, or anywhere you need a lightweight list.

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Full records with all relations — use for detail views
  const allGenies = await ApiService.invoke({
    resource: "genies",
    action: "all",
  });

  // Compact records — use for dropdowns and selectors
  const genieList = await ApiService.invoke({
    resource: "genies",
    action: "list",
  });
  ```

  ```bash cURL theme={null}
  # Full records with all relations
  curl -X POST https://api.helpgenie.ai/v1 \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{"resource": "genies", "action": "all"}'

  # Compact records for dropdowns
  curl -X POST https://api.helpgenie.ai/v1 \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{"resource": "genies", "action": "list"}'
  ```
</CodeGroup>

<Note>
  **Pagination differs between `all` and `list`.**

  * The `all` action on **genies** uses **cursor-based** pagination. The response includes `nextCursor` and `hasMore` fields. Pass `cursor` in the request data to fetch the next page.
  * Most other resources use **offset-based** pagination. The response includes `count`, and you control paging with `limit` and `offset` in the request data.
</Note>

## Request examples

### Create a resource

<CodeGroup>
  ```typescript TypeScript theme={null}
  const newGenie = await ApiService.invoke({
    resource: "genies",
    action: "create",
    data: {
      genieName: "Support Agent",
      voiceId: "voice-abc-123",
      firstMessage: "Hi, how can I help you today?",
    },
  });
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.helpgenie.ai/v1 \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "resource": "genies",
      "action": "create",
      "data": {
        "genieName": "Support Agent",
        "voiceId": "voice-abc-123",
        "firstMessage": "Hi, how can I help you today?"
      }
    }'
  ```
</CodeGroup>

### Get a single resource

<CodeGroup>
  ```typescript TypeScript theme={null}
  const genie = await ApiService.invoke({
    resource: "genies",
    action: "get",
    id: "abc-123",
  });
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.helpgenie.ai/v1 \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "resource": "genies",
      "action": "get",
      "id": "abc-123"
    }'
  ```
</CodeGroup>

### Update a resource

<CodeGroup>
  ```typescript TypeScript theme={null}
  const updated = await ApiService.invoke({
    resource: "genies",
    action: "update",
    id: "abc-123",
    data: {
      genieName: "Updated Agent Name",
    },
  });
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.helpgenie.ai/v1 \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "resource": "genies",
      "action": "update",
      "id": "abc-123",
      "data": {
        "genieName": "Updated Agent Name"
      }
    }'
  ```
</CodeGroup>

### Delete a resource

<CodeGroup>
  ```typescript TypeScript theme={null}
  await ApiService.invoke({
    resource: "genies",
    action: "delete",
    id: "abc-123",
  });
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.helpgenie.ai/v1 \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "resource": "genies",
      "action": "delete",
      "id": "abc-123"
    }'
  ```
</CodeGroup>

## Response structure

All responses use a consistent envelope:

### Success response

```json theme={null}
{
  "success": true,
  "data": {
    "id": "abc-123",
    "genieName": "Support Agent",
    "voiceId": "voice-abc-123",
    "created_at": "2025-01-15T10:30:00Z"
  }
}
```

For list and all actions, `data` is an array:

```json theme={null}
{
  "success": true,
  "data": [
    { "id": "abc-123", "genieName": "Support Agent" },
    { "id": "def-456", "genieName": "Sales Agent" }
  ]
}
```

<Note>
  When using `ApiService.invoke()`, the response is automatically unwrapped. You receive the `data` value directly, not the full envelope.
</Note>

### Error response

```json theme={null}
{
  "success": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "Resource not found",
    "status": 404
  }
}
```

See [Error handling](/api-reference/errors) for all error codes.

### Warnings

A response can include a `warnings` array of strings next to `data`. A warning doesn't mean the request failed. It points out something you should check.

## Undocumented fields and strict mode

On `create` and `update` actions, the API compares the top-level keys in `data` with the fields documented for that action. You can get those fields from [`capabilities/schema`](/api-reference/capabilities#schema). If you send a field that isn't documented, it was most likely ignored. The request still runs, and the response includes a warning that names the field:

```json theme={null}
{
  "success": true,
  "data": { "agent": { "id": "abc-123" } },
  "warnings": [
    "Unrecognized field(s) for genies/update: prompt. They are not in the documented schema and were most likely ignored. Call capabilities/schema for the accepted fields, or send \"strict\": true next to \"resource\" to have such a request rejected."
  ]
}
```

To have such a request rejected instead, send `"strict": true` at the top level of the body, next to `resource`. Nothing is changed, and the error lists the unknown and accepted fields in `error.details`:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.helpgenie.ai/v1 \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "resource": "genies",
      "action": "update",
      "id": "abc-123",
      "strict": true,
      "data": { "prompt": "Be friendly." }
    }'
  ```

  ```json Response theme={null}
  {
    "success": false,
    "error": {
      "code": "VALIDATION_ERROR",
      "message": "Unrecognized field(s) for genies/update: prompt. They are not in the documented schema, so nothing was changed. Call capabilities/schema for the accepted fields and nested paths, then retry.",
      "status": 400,
      "details": {
        "unknown_fields": ["prompt"],
        "allowed_fields": ["name", "genieName", "description", "…"]
      }
    }
  }
  ```
</CodeGroup>

<Note>
  The check covers top-level `data` keys only, on `create` and `update`. Some keys are never flagged: `adminMode` and `impersonatedUserId`, the envelope keys of a body sent without a `data` wrapper, and the fields of actions that pass extra fields through, such as `knowledge-base/create`. Public (unauthenticated) requests aren't checked.
</Note>

## Admin mode and impersonation

Users with the `internal_admin` role can operate on behalf of other users by including an `impersonatedUserId` in the request data. This is used for provisioning trial agents, bulk operations, and testing.

```typescript theme={null}
const trialGenie = await ApiService.invoke({
  resource: "genies",
  action: "create",
  data: {
    genieName: "Trial Genie",
    voiceId: "voice-123",
    impersonatedUserId: "user-456",
  },
});
```

<Warning>
  Impersonation is only available to `internal_admin` users. Non-admin requests that include `impersonatedUserId` will be ignored or rejected.
</Warning>

## Query parameters

When using REST-style HTTP requests, query parameters are automatically extracted and passed to handlers:

```bash theme={null}
GET /v1/genies?limit=30&cursor=abc123
```

When using the body-based approach, include pagination and filter parameters in the `data` object:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const genies = await ApiService.invoke({
    resource: "genies",
    action: "all",
    data: {
      limit: 30,
      cursor: "abc123",
    },
  });
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.helpgenie.ai/v1 \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "resource": "genies",
      "action": "all",
      "data": {
        "limit": 30,
        "cursor": "abc123"
      }
    }'
  ```
</CodeGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.