Skip to content

HTTP

The http library provides asynchronous HTTP GET and POST requests. Requests run on background threads and deliver responses via callbacks on the next tick, so they never block your script.

Useful for fetching player or Steam data, calling external APIs, integrating with AI services, or anything that needs network access.

Kill switch

HTTP can be turned off in Dev Studio (the bug icon in the navbar), General page, Security panel, Allow Lua HTTP Requests (on by default). When off, every http.get and http.post fails immediately with error = "http requests are disabled". A script cannot bypass it.

http.get(url, opts, callback)

Performs an asynchronous HTTP GET request.

Signatures:

http.get(url, opts, callback)
http.get(url, callback)

The two-argument form omits opts and uses all defaults (no custom headers, default timeout, default user-agent).

Parameters:

  • url (string). The URL to request.
  • opts (table, optional). Configuration:
    • headers (table). Key-value pairs of request headers.
    • user_agent (string). Custom User-Agent string. Default: "TsukiLua/1.0".
    • timeout (number). Request timeout in milliseconds. Default: 5000.
  • callback (function). Called with a response table when the request completes.

Examples:

lua
-- With opts
http.get("https://api.example.com/data", {
    headers = {
        ["Authorization"] = "Bearer my_token",
        ["Accept"] = "application/json"
    },
    timeout = 3000
}, function(res)
    if res.ok then
        print("Got:", res.body)
    else
        print("Failed:", res.status, res.error)
    end
end)
lua
-- Without opts (two-argument form)
http.get("https://api.example.com/data", function(res)
    if res.ok then
        print("Got:", res.body)
    end
end)

http.post(url, opts, callback)

Performs an asynchronous HTTP POST request.

Signatures:

http.post(url, opts, callback)
http.post(url, callback)

The two-argument form omits opts and sends no body with all defaults.

Parameters:

  • url (string). The URL to request.
  • opts (table, optional). Configuration:
    • headers (table). Key-value pairs of request headers.
    • body (string). The request body content.
    • user_agent (string). Custom User-Agent string. Default: "TsukiLua/1.0".
    • timeout (number). Request timeout in milliseconds. Default: 5000.
  • callback (function). Called with a response table when the request completes.

Examples:

lua
-- With opts
http.post("https://api.example.com/submit", {
    headers = {
        ["Content-Type"] = "application/json"
    },
    body = '{"username": "player1", "score": 100}'
}, function(res)
    if res.ok then
        print("Submitted successfully")
    else
        print("Error:", res.status, res.error)
    end
end)
lua
-- Without opts (two-argument form)
http.post("https://api.example.com/ping", function(res)
    print("Status:", res.status)
end)

Response table

The callback receives a single table with the following fields:

FieldTypeDescription
statusnumberHTTP status code (200, 404, etc.). 0 if the connection failed entirely.
bodystringResponse body as a string. Truncated to 1 MB if larger.
okbooleantrue if status is in the 200-299 range.
errorstringTransport-level error message (DNS failure, connection refused, timeout, TLS failure). Empty whenever the server answered at all, including non-2xx. A 404 comes back as status = 404, ok = false, error = "". Branch on res.ok or res.status to detect an HTTP error status. res.error ~= "" only catches requests that never reached the server.

Limits

  • At most 4 requests in flight, counted across every loaded script. Past that the callback fires immediately, inside the http.get or http.post call, with status = 0, body = "", ok = false and error = "too many concurrent requests".
  • Default timeout is 5 seconds. Configurable per-request via opts.timeout.
  • Response bodies are capped at 1 MB.
  • Requests are fully asynchronous. They never block on_tick.
  • SSL certificate verification is always on and cannot be turned off. opts accepts only headers, body, user_agent and timeout, and there is no verify_ssl flag. A host with a bad or self-signed certificate fails with a TLS error in response.error.

Notes

  • Callbacks are delivered at the start of the next tick after the request completes, not during on_tick.

  • Callbacks fire on the Lua thread, but not inside your script's context. The engine drains them at the top of the tick, before any script runs, and does not restore the owning script's identity first. In practice:

    • config.get_* always returns the default you passed, and config.set_* is a silent no-op.
    • storage.get / storage.set / storage.keys read and write whichever script ticked last, not necessarily yours. With more than one script enabled that is the wrong file.
    • print still works, but its [script] prefix names that same last-ticked script. The engine credits ui.* calls to it too.

    Everything else is live: input.*, memory.*, draw.* and the player/entity API all behave normally inside a callback. If the response needs to touch config or storage, stash it in a Lua variable and do the work from on_tick.

  • Reloading (the Reload button, or saving a file) tears the Lua VM down and discards any callback still in flight. Disabling a script does not: its requests still complete and their callbacks run against the old environment, so if you re-enable before a response lands, whatever the callback stores is invisible to the new instance.

  • Use http.post with Content-Type: application/json for JSON APIs. The body field is sent as-is, format it as needed.