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

# HTTP Client

> Minimal async HTTP requests with JSON bodies, headers, timeouts, and built-in retry/backoff.

`xyz.refineryteam.refinerycore.api.http.Http` is a minimal async HTTP client for plugin-sized needs: update checks, Discord webhooks, REST APIs. Requests run on a dedicated daemon pool — never the common ForkJoinPool and never the main thread — with retry/backoff scheduled through your plugin's async scheduler.

## Quick start

```java UpdateChecker.java icon="java" theme={"system"}
Http http = Http.of(plugin);

// GET with a header
http.get("https://api.example.com/version")
    .header("Authorization", "Bearer " + token)
    .executeAsync()
    .thenAccept(response -> {
        if (response.ok()) handle(response.body());
    });

// POST a JSON body (e.g. a Discord webhook) with retries
http.post(webhookUrl)
    .jsonBody("{\"content\":\"Server started\"}")
    .retries(2)
    .executeAsync();
```

Call `http.close()` from `onDisable()` if you own the instance — safe to skip, since the worker threads are daemons.

## Building requests

Start with `get(url)`, `post(url)`, `put(url)`, or `delete(url)`, then configure the fluent `Request` builder:

| Method                                  | Description                                                                                                                                                                                |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `header(String name, String value)`     | Adds a request header (e.g. `"Authorization"`)                                                                                                                                             |
| `jsonBody(String json)`                 | Sets a JSON body and the `application/json` content type in one call                                                                                                                       |
| `body(String body, String contentType)` | Sets an arbitrary body with an explicit MIME type (e.g. `"text/plain"`)                                                                                                                    |
| `formBody(Map<String, String> fields)`  | Form-encoded convenience: builds `key1=value1&key2=value2` with URL encoding and the matching content type                                                                                 |
| `retries(int count)`                    | How many times to retry on `IOException` or a 5xx status. Backoff is exponential: 500ms, 1s, 2s…                                                                                           |
| `timeout(Duration)`                     | Per-attempt timeout (default 15 seconds)                                                                                                                                                   |
| `executeAsync()`                        | Executes asynchronously, returning a `CompletableFuture<Response>` after any retries. Never blocks the calling thread and never throws — errors arrive as a completed-exceptionally future |
| `execute()`                             | Blocking variant for use **off the main thread only**. Transport failures yield a response with status `-1` and the error attached                                                         |

## Responses

`executeAsync()` completes with a `Response` record:

| Member         | Description                                         |
| -------------- | --------------------------------------------------- |
| `statusCode()` | HTTP status code, or `-1` on transport failure      |
| `body()`       | Response body as a string                           |
| `ok()`         | Whether the status code is in the 2xx range         |
| `error()`      | The throwable behind a transport failure, or `null` |

<Warning>
  Never call the blocking `execute()` from the main thread — network latency will freeze the server tick. Use `executeAsync()` and react in the future's callback, or hop off the thread first with [RefineryScheduler](/refinerycore/cooldowns-and-scheduler#refineriescheduler).
</Warning>

<Note>
  For anything heavier — connection pooling tuning, multipart uploads, streaming — reach for a dedicated HTTP library. `Http` intentionally covers the simple request/response cases well and nothing else.
</Note>
