What we send
A single HTTPSPOST 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. |
<Your-Header-Name> | <your-token> | Only when auth_scheme = custom_header. |
X-SmartAlex-Signature | t=<epoch_ms>,v1=<hex> | HMAC-SHA256 — see Signature verification. |
X-SmartAlex-Tenant-Id | UUID | Tenant making the call. |
X-SmartAlex-Tool | Tool name | Same as what you configured. |
X-SmartAlex-Call-Id | UUID or empty | Empty string on test fires. |
Body
Stable, alphabetically-key-sorted JSON for reproducible signing. You can pass it back throughJSON.stringify and still get a verifiable signature.
| 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. |
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).
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/plaintext/html(the AI can summarize HTML, but you’ll get a better response by sending JSON or plain text).text/csvand othertext/*subtypes.
Rejected content types
application/octet-streamand any binary content type →HTTP_TOOL_INVALID_RESPONSE_TYPE.- Missing
Content-Typeis 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. |
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.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.Response examples for common tools
Routing lookup
Routing lookup
Request:Response:
Caller lookup (CRM)
Caller lookup (CRM)
Request:Response:
Availability check
Availability check
Request:Response:
No data found
No data found
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.
Next: Signature verification
How to verify every request is actually from us, with code samples.

