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

# Request & Response Shape

> Exactly what we send your endpoint and what we expect back.

## What we send

A single HTTPS `POST` per invocation. No retries on our side, if your endpoint errors, the AI handles it and moves on.

### URL

The endpoint URL you saved, exactly as configured. No path rewriting, no query string injection.

### Headers

| Header                  | Value                                                       | Notes                                                                                                     |
| ----------------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `Content-Type`          | `application/json`                                          | Always.                                                                                                   |
| `User-Agent`            | `SmartAlex/1.0 (+https://docs.getsmartalex.com/http-tools)` | Pinned.                                                                                                   |
| `Authorization`         | `Bearer <your-token>`                                       | Only when `auth_scheme = bearer`.                                                                         |
| `Authorization`         | `Basic <base64(user:pass)>`                                 | Only when `auth_scheme = basic`.                                                                          |
| `<Your-Header-Name>`    | `<your-token>`                                              | Only when `auth_scheme = custom_header`.                                                                  |
| `X-SmartAlex-Signature` | `t=<epoch_ms>,v1=<hex>`                                     | Envelope mode only. HMAC-SHA256, see [Signature verification](/guides/http-tools/signature-verification). |
| `X-SmartAlex-Tenant-Id` | UUID                                                        | Envelope mode only. Tenant making the call.                                                               |
| `X-SmartAlex-Tool`      | Tool name                                                   | Envelope mode only. Same as what you configured.                                                          |
| `X-SmartAlex-Call-Id`   | UUID or empty                                               | Envelope mode only. Empty string on test fires.                                                           |

### Body

Stable, alphabetically-key-sorted JSON for reproducible signing. You can pass it back through `JSON.stringify` and still get a verifiable signature.

```json theme={null}
{
  "agent_id": "00000000-0000-0000-0000-000000000000",
  "arguments": {
    "query": "billing"
  },
  "call_id": "11111111-1111-1111-1111-111111111111",
  "caller_number": "+27821234567",
  "tenant_id": "22222222-2222-2222-2222-222222222222",
  "timestamp": 1733839200123,
  "tool": "lookup_routing"
}
```

| Field           | Type                   | Notes                                                            |
| --------------- | ---------------------- | ---------------------------------------------------------------- |
| `tool`          | string                 | Same as the `X-SmartAlex-Tool` header.                           |
| `tenant_id`     | UUID string            | Your tenant.                                                     |
| `agent_id`      | UUID string or `null`  | `null` on test fires.                                            |
| `call_id`       | UUID string or `null`  | `null` on test fires.                                            |
| `caller_number` | E.164 string or `null` | Caller's phone number when known.                                |
| `timestamp`     | integer                | Epoch milliseconds. Same number as `t=` in the signature header. |
| `arguments`     | object                 | The LLM's call args, schema-validated before we send.            |

<Note>
  For signing, the canonical body is serialized with **alphabetical key ordering at every level**. If you re-serialize the body yourself before HMAC-verifying, do the same, or hash the raw bytes from the wire (preferred, see [Signature verification](/guides/http-tools/signature-verification)).
</Note>

### Passthrough mode (flat body)

Everything above describes the default **envelope mode**. If the tool is configured in **passthrough mode**, we don't wrap your arguments in the canonical envelope and we don't sign the request. Instead we POST the flat JSON body template you configured, after substituting two kinds of placeholder:

* `${vault.token}`, the credential you stored in Vault for this tool.
* `${arg.<name>}`, an argument the AI filled in (for example `${arg.query}`).

Only string values in the template are substituted; the overall shape is sent verbatim. No `X-SmartAlex-*` headers and no signature are added, so your endpoint authenticates on the credential baked into the body. Use passthrough when you're calling a third-party API that has its own request format and can't be changed to understand our envelope. Passthrough tools can also set a `cache_ttl_ms` to reuse a recent response for identical resolved bodies.

## What we expect back

We accept anything **JSON or text** under **64 KB**. The body is passed verbatim to the AI as the tool result.

### Accepted content types

* `application/json`, parsed as JSON, re-stringified for the AI.
* `text/plain`
* `text/html` (the AI can summarize HTML, but you'll get a better response by sending JSON or plain text).
* `text/csv` and other `text/*` subtypes.

### Rejected content types

* `application/octet-stream` and any binary content type → `HTTP_TOOL_INVALID_RESPONSE_TYPE`.
* Missing `Content-Type` is tolerated.

### Status codes

| Status        | Result                                                                                                             |
| ------------- | ------------------------------------------------------------------------------------------------------------------ |
| 2xx           | Body becomes the AI's tool result.                                                                                 |
| 3xx           | We don't follow redirects → `HTTP_TOOL_TOO_MANY_REDIRECTS`. Resolve your URL to its final destination and re-save. |
| 4xx           | `HTTP_TOOL_CUSTOMER_ERROR`. AI says "the lookup service returned an error" and continues without your data.        |
| 5xx           | Same as 4xx, different mental model, your service is down.                                                         |
| Timeout > 10s | `HTTP_TOOL_TIMEOUT`. AI says "the lookup timed out" and continues.                                                 |

See [Error codes](/guides/http-tools/error-codes) for the full taxonomy.

### Recommended response shapes

The AI parses whatever you return as text. To get the best behavior, give the AI a hint about what to say next.

<CodeGroup>
  ```json JSON (recommended) theme={null}
  {
    "extension": 6105,
    "hint": "Transfer the caller to extension 6105 (billing queue)."
  }
  ```

  ```text Plain text theme={null}
  Caller wants billing. Transfer them to ext 6105.
  ```

  ```json JSON with multiple fields theme={null}
  {
    "customer_name": "Sarah Patel",
    "open_tickets": 2,
    "last_call": "2026-05-10",
    "hint": "Greet Sarah by name, mention her two open tickets, and offer to escalate."
  }
  ```
</CodeGroup>

<Note>
  The AI reads the entire response body. Include a `hint` (or `instruction`, or `next_action`, any natural-language one-liner) so the AI knows exactly what to say next. Without it, the AI guesses, and the conversation gets generic.
</Note>

### Response examples for common tools

<AccordionGroup>
  <Accordion title="Routing lookup">
    Request:

    ```json theme={null}
    { "arguments": { "query": "I have a billing question" } }
    ```

    Response:

    ```json theme={null}
    {
      "extension": 6105,
      "queue_name": "Billing",
      "estimated_wait_seconds": 45,
      "hint": "Transfer to extension 6105 for billing. Mention the ~45s wait."
    }
    ```
  </Accordion>

  <Accordion title="Caller lookup (CRM)">
    Request:

    ```json theme={null}
    { "arguments": { "phone": "+27821234567" } }
    ```

    Response:

    ```json theme={null}
    {
      "found": true,
      "name": "Sarah Patel",
      "tier": "gold",
      "open_tickets": [{"id": 4421, "subject": "Refund pending"}],
      "hint": "Greet Sarah by name. She has an open refund ticket. Offer to check the status."
    }
    ```
  </Accordion>

  <Accordion title="Availability check">
    Request:

    ```json theme={null}
    { "arguments": { "date": "2026-05-20", "service": "consult" } }
    ```

    Response:

    ```json theme={null}
    {
      "available_slots": ["09:00", "11:30", "15:00"],
      "hint": "Offer 9:00, 11:30, or 15:00. Ask which works."
    }
    ```
  </Accordion>

  <Accordion title="No data found">
    ```json theme={null}
    {
      "found": false,
      "hint": "We don't have a record. Ask the caller for their account number."
    }
    ```
  </Accordion>
</AccordionGroup>

### What you should NOT return

* Raw stack traces, the AI may verbalize them. Strip / wrap in a friendly summary.
* Provider names (Twilio, Asterisk, etc.), the AI may say them. The dashboard preview obfuscates these but the wire-side AI gets the verbatim response.
* Sensitive PII you didn't intend to expose (national IDs, full card numbers). Once it crosses the wire the AI can speak it.
* Megabytes of data. We cap at 64 KB; design responses to fit in 4 KB ideally.

<Card title="Next: Signature verification" href="/guides/http-tools/signature-verification">
  How to verify every request is actually from us, with code samples.
</Card>
