> ## Documentation Index
> Fetch the complete documentation index at: https://lua.starline.one/llms.txt
> Use this file to discover all available pages before exploring further.

# HTTP

> Send asynchronous HTTP GET and POST requests from Lua scripts.

Requests run in the background and never block the game. Your callback fires on a later frame, once the response has arrived.

```lua theme={"dark"}
http.Get("https://api.example.com/ping", function(res)
    if res.ok and res.status == 200 then
        print(res.body)
    else
        print("failed: " .. (res.error or res.status))
    end
end)
```

<Warning>
  A script can send anything it can read to any address. Read a script before you run it, the same as you would with any code from someone else.
</Warning>

## Get

```lua theme={"dark"}
http.Get(url, callback)
http.Get(url, opts, callback)
```

| Name     | Type                                            |
| -------- | ----------------------------------------------- |
| Url      | String, must start with `http://` or `https://` |
| Opts     | Table, optional                                 |
| Callback | Function, receives the response                 |

## Post

```lua theme={"dark"}
http.Post(url, body, callback)
http.Post(url, body, opts, callback)
```

| Name     | Type            |
| -------- | --------------- |
| Url      | String          |
| Body     | String          |
| Opts     | Table, optional |
| Callback | Function        |

Sends `Content-Type: application/x-www-form-urlencoded` unless you set your own in `opts.headers`.

## Opts

| Field     | Type                      | Default |
| --------- | ------------------------- | ------- |
| `headers` | Table of string to string | none    |
| `timeout` | Number, milliseconds      | 5000    |

`Host`, `Connection`, `Content-Length`, and `Accept-Encoding` are set automatically. The timeout is capped at 5000 ms. Header names and values cannot contain newlines.

```lua theme={"dark"}
http.Post(url, payload, {
    headers = { ["Content-Type"] = "application/json" },
    timeout = 5000,
}, function(res) end)
```

## Response

| Field     | Type                                        |
| --------- | ------------------------------------------- |
| `ok`      | Boolean, whether the exchange completed     |
| `status`  | Integer HTTP status, `0` when `ok` is false |
| `body`    | String                                      |
| `headers` | Table of lowercased name to value           |
| `error`   | String, only present when `ok` is false     |

`ok` describes the transport, not the result. A 404 that arrived is `ok = true` with `status = 404`. A DNS failure or timeout is `ok = false` with `error` set.

```lua theme={"dark"}
http.Get(url, function(res)
    if not res.ok then return end
    print(res.headers["content-type"])
end)
```

## Limits

| Limit               | Value                   |
| ------------------- | ----------------------- |
| Concurrent requests | 4, the rest queue       |
| Requests in flight  | 32, further calls error |
| Request body        | 1 MB                    |
| Request headers     | 64 entries, 64 KB total |
| Response body       | 8 MB, larger fails      |
| Response headers    | 64 KB                   |

Redirects are not followed. Only IPv4 hosts resolve. Use [`json.Decode`](/json#decode) for JSON responses.

Callable at load time and from any callback. Pending requests are dropped when your script reloads or unloads, so a callback never runs against a dead script.
