Skip to content

HTTP Module

Make HTTP requests from scripts to interact with external APIs and services.

Overview

Lua scripts can make HTTP requests:

  • GET, POST, PUT, PATCH, DELETE methods
  • Custom headers and request bodies
  • Configurable timeouts
  • JSON response parsing

Lua API

The canonical path is cru.http. The standalone http global is a backwards-compatible alias.

-- Simple GET request
local response = cru.http.get("https://api.example.com/data")
if response.ok then
local data = cru.oq.parse(response.body)
print(data.name)
end
-- POST with JSON body
local response = cru.http.post("https://api.example.com/users", {
headers = { ["Content-Type"] = "application/json" },
body = cru.oq.json({ name = "Alice", age = 30 })
})
-- Custom request with full control
local response = cru.http.request({
url = "https://api.example.com/resource",
method = "PUT",
headers = { Authorization = "Bearer token123" },
body = "data payload",
timeout = 60
})

Note: http.get(...), oq.parse(...), etc. still work as standalone globals for backwards compatibility.

Response Format

All HTTP functions return a table with:

FieldTypeDescription
statusnumberHTTP status code
headerstableResponse headers
bodystringResponse body
okbooleanTrue if status is 2xx
errorstringError message (only on failure)

Handler Integration

Use HTTP in handlers to fetch external data:

-- Handler that enriches tool calls with external data.
-- Handlers register with `cru.on` at load time; `pattern` globs the
-- tool name. Handlers may call async APIs like `cru.http` directly.
cru.on("pre_tool_call", { pattern = "fetch_prices", priority = 10 }, function(ctx, event)
local response = cru.http.get("https://api.prices.com/latest")
if not response.ok then
-- Cancel blocks the call with an error; `pre_tool_call` is the only
-- hook that fails CLOSED, so a raising handler denies the call too.
return { cancel = true, reason = response.error }
end
-- Rewrite the args the tool runs with. `args` REPLACES the whole table,
-- so extend the existing one rather than returning just the new key.
-- Mutating `event.args` alone is ignored — the rewrite must be RETURNED.
event.args.prices = cru.oq.parse(response.body)
return { args = event.args }
end)

Error Handling

Always check response.ok before using the response:

local response = cru.http.get(url)
if response.ok then
-- Success: use response.body
process(response.body)
elseif response.error then
-- Request failed (network error, timeout)
cru.log("error", "Request failed: " .. response.error)
else
-- HTTP error (4xx, 5xx)
cru.log("error", "HTTP " .. response.status)
end

See Also