Call the outside world
The http library lets your Lua scripts talk to external APIs — payment gateways, email services, weather data, AI models. SSRF protection blocks private IPs and internal networks.
Function reference
| Function | Description |
|---|---|
http.get(url, opts?) |
HTTP GET |
http.post(url, opts?) |
HTTP POST |
http.put(url, opts?) |
HTTP PUT |
http.patch(url, opts?) |
HTTP PATCH |
http.delete(url, opts?) |
HTTP DELETE |
http.head(url, opts?) |
HTTP HEAD |
http.request(method, url, opts?) |
Any HTTP method |
Response format
Every call returns a table:
{
status = 200, -- HTTP status code
body = "response content", -- raw body string
headers = { -- response headers
["content-type"] = "application/json"
}
}
GET request
local res = http.get("https://api.github.com/users/wapka")
if res.status == 200 then
local data = decoder.json(res.body)
return { repos = data.public_repos }
end
return ctx:error("GitHub API failed", 502)
POST with JSON
local res = http.post("https://api.example.com/webhook", {
body = encoder.json({ event = "user.created", id = 42 }),
headers = { ["content-type"] = "application/json" }
})
Setting headers and timeout
local res = http.get("https://api.example.com/data", {
headers = {
["authorization"] = "Bearer " .. api_key,
["accept"] = "application/json"
},
timeout = 10, -- seconds
user_agent = "MyWapkaApp/1.0"
})
SSL verification
-- Production: keep SSL verification (default)
http.get("https://api.example.com")
-- Development only: skip SSL check
http.get("https://localhost:8443", { verify_ssl = false })
All options
| Option | Type | Default | Description |
|---|---|---|---|
body |
string | — | Raw request body |
headers |
table | {} |
Request headers (lowercase keys) |
timeout |
number | 10 | Seconds before giving up |
user_agent |
string | — | Custom User-Agent header |
verify_ssl |
boolean | true | Validate SSL certificate |
Practical: call a payment API
app:post("/checkout", function(ctx)
local amount = tonumber(req.post.amount)
local res = http.post("https://api.stripe.com/v1/charges", {
body = "amount=" .. (amount * 100) .. "¤cy=usd",
headers = {
["authorization"] = "Bearer " .. STRIPE_SECRET,
["content-type"] = "application/x-www-form-urlencoded"
}
})
if res.status ~= 200 then
log.error("Stripe failed: " .. res.body)
ctx:flash("error", "Payment failed. Please try again.")
return ctx:redirect("/checkout")
end
log.info("Payment successful: $" .. amount)
ctx:flash("success", "Payment received!")
return ctx:redirect("/thank-you")
end)
Practical: fetch and display weather
app:get("/weather/:city", function(ctx)
local city = url.encode(ctx.params.city)
local res = http.get("https://api.openweathermap.org/data/2.5/weather?q="
.. city .. "&appid=" .. WEATHER_KEY)
if res.status ~= 200 then
return ctx:error("Weather data unavailable", 502)
end
local data = decoder.json(res.body)
return ctx:render("weather", {
city = data.name,
temp = math.floor(data.main.temp - 273.15),
description = data.weather[1].description
})
end)
Next: URL Utilities — parse, build, and encode URLs.