> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nano-gpt.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Compressed Request Bodies

> Send gzip, deflate, or Brotli compressed JSON to the text APIs for faster uploads

# Compressed Request Bodies

The text generation APIs accept compressed JSON request bodies. Compress your payload, add a `Content-Encoding` header, and everything else works exactly as before — same request schema, same response.

```
Content-Encoding: gzip
```

## Why compress?

Chat requests resend the full conversation history every turn, so request bodies grow with the conversation — multi-hundred-kilobyte payloads are common for agents and long chats, and tool schemas add more. JSON like this compresses roughly **5:1 with gzip**.

The win is mostly **your own latency**: the request body has to finish uploading before we can start model dispatch, and a large body costs multiple network round-trips just for TCP to ramp up. Compressing it:

* **Cuts time-to-first-token**, most noticeably on long conversations, on high-latency routes, and on constrained uplinks. The further you are from the origin and the bigger your payloads, the more you save on every single request.
* **Reduces your egress bandwidth** — relevant for server-to-server integrations that send us high volumes.
* **Makes retries cheaper and uploads more robust** on flaky networks: fewer bytes in flight, fewer mid-upload stalls.

If your bodies are small (a few KB), compression won't hurt but also won't buy you much — it matters once conversations get long.

## Supported endpoints and encodings

|                |                                                                                                              |
| -------------- | ------------------------------------------------------------------------------------------------------------ |
| Endpoints      | `POST /v1/chat/completions` · `POST /v1/responses` · `POST /v1/messages`                                     |
| Encodings      | `gzip` (also `x-gzip`), `deflate` (zlib-wrapped or raw), `br` (Brotli)                                       |
| Content-Type   | Must be JSON (`application/json`, `text/json`, or `*+json`)                                                  |
| Authentication | Required — compressed bodies are only decompressed for authenticated requests, so send your API key as usual |
| Size limit     | 32 MB, enforced on both the compressed and the decompressed body                                             |

A comma-separated `Content-Encoding` list (e.g. `gzip, identity`) is accepted and decoded in reverse order per the HTTP spec, but a single encoding is all you need.

## Examples

The OpenAI and Anthropic SDKs don't compress request bodies on their own, but both let you plug in a custom HTTP transport. The snippets below work with your existing SDK setup — or with plain `fetch`/`requests` if you don't use an SDK.

### curl

```bash theme={null}
echo '{"model":"openai/gpt-5.6-sol","messages":[{"role":"user","content":"Hello!"}]}' \
  | gzip \
  | curl https://nano-gpt.com/api/v1/chat/completions \
      -H "Authorization: Bearer $NANOGPT_API_KEY" \
      -H "Content-Type: application/json" \
      -H "Content-Encoding: gzip" \
      --data-binary @-
```

### Python

<CodeGroup>
  ```python requests theme={null}
  import gzip
  import json
  import requests

  payload = {
      "model": "openai/gpt-5.6-sol",
      "messages": [{"role": "user", "content": "Hello!"}],
  }

  response = requests.post(
      "https://nano-gpt.com/api/v1/chat/completions",
      data=gzip.compress(json.dumps(payload).encode("utf-8")),
      headers={
          "Authorization": f"Bearer {API_KEY}",
          "Content-Type": "application/json",
          "Content-Encoding": "gzip",
      },
  )
  ```

  ```python OpenAI SDK theme={null}
  import gzip

  import httpx
  from openai import OpenAI


  class GzipJsonTransport(httpx.BaseTransport):
      """Compress outgoing JSON request bodies with gzip."""

      def __init__(self, inner: httpx.BaseTransport | None = None):
          self._inner = inner or httpx.HTTPTransport()

      def handle_request(self, request: httpx.Request) -> httpx.Response:
          body = request.read()
          content_type = request.headers.get("Content-Type", "")
          if (
              body
              and "json" in content_type
              and "Content-Encoding" not in request.headers
          ):
              headers = dict(request.headers)
              headers.pop("content-length", None)
              headers["content-encoding"] = "gzip"
              request = httpx.Request(
                  request.method,
                  request.url,
                  headers=headers,
                  content=gzip.compress(body),
              )
          return self._inner.handle_request(request)


  client = OpenAI(
      base_url="https://nano-gpt.com/api/v1",
      api_key=API_KEY,
      http_client=httpx.Client(transport=GzipJsonTransport()),
  )

  completion = client.chat.completions.create(
      model="openai/gpt-5.6-sol",
      messages=[{"role": "user", "content": "Hello!"}],
  )
  ```
</CodeGroup>

### JavaScript / TypeScript

<CodeGroup>
  ```javascript fetch theme={null}
  import { gzipSync } from "node:zlib";

  const payload = {
    model: "openai/gpt-5.6-sol",
    messages: [{ role: "user", content: "Hello!" }],
  };

  const response = await fetch("https://nano-gpt.com/api/v1/chat/completions", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.NANOGPT_API_KEY}`,
      "Content-Type": "application/json",
      "Content-Encoding": "gzip",
    },
    body: gzipSync(Buffer.from(JSON.stringify(payload))),
  });
  ```

  ```javascript OpenAI SDK theme={null}
  import { gzipSync } from "node:zlib";
  import OpenAI from "openai";

  // Compress JSON bodies before they leave the process.
  const gzipFetch = async (url, init = {}) => {
    const headers = new Headers(init.headers);
    const contentType = headers.get("content-type") ?? "";
    if (
      typeof init.body === "string" &&
      contentType.includes("json") &&
      !headers.has("content-encoding")
    ) {
      headers.set("content-encoding", "gzip");
      return fetch(url, { ...init, headers, body: gzipSync(Buffer.from(init.body)) });
    }
    return fetch(url, init);
  };

  const client = new OpenAI({
    baseURL: "https://nano-gpt.com/api/v1",
    apiKey: process.env.NANOGPT_API_KEY,
    fetch: gzipFetch,
  });

  const completion = await client.chat.completions.create({
    model: "openai/gpt-5.6-sol",
    messages: [{ role: "user", content: "Hello!" }],
  });
  ```
</CodeGroup>

<Note>
  The same transport works for `/v1/responses` and (with the Anthropic SDK's equivalent custom-fetch option) `/v1/messages` — the compression handling is identical on all three endpoints.
</Note>

## Errors

| Status | Code                           | Meaning                                                   |
| ------ | ------------------------------ | --------------------------------------------------------- |
| `415`  | `unsupported_content_encoding` | `Content-Encoding` value we don't support (e.g. `zstd`)   |
| `415`  | `unsupported_media_type`       | Compressed body without a JSON `Content-Type`             |
| `401`  | `authentication_error`         | Compressed body on an unauthenticated request             |
| `413`  | —                              | Body exceeds the 32 MB limit (compressed or decompressed) |

Everything else — validation, billing, streaming — behaves exactly as with uncompressed requests.
