# HTTP API

> Send logs from any language with one POST request: headers, compression, responses and retries.

Any language or tool that can make an HTTPS POST request can send logs. The body is plain text; every line of it is one log line. Send a batch of lines per request rather than one request per line. A machine-readable description is at [/openapi.json](https://jl3-cloud.site/openapi.json) (OpenAPI 3.1).

## Endpoint

```text
POST https://jl3-cloud.site/api/logs/
Authorization: Bearer YOUR_API_TOKEN
Content-Type: text/plain
```

## Examples

curl (macOS, Linux):

```bash
curl -X POST "https://jl3-cloud.site/api/logs/" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: text/plain" \
  -H "X-JustLog-Logger: manual" \
  --data "Hello from HTTP!"
```

Windows PowerShell:

```powershell
Invoke-RestMethod -Method Post -Uri "https://jl3-cloud.site/api/logs/" `
  -Headers @{ Authorization = "Bearer YOUR_API_TOKEN"; "X-JustLog-Logger" = "manual" } `
  -ContentType "text/plain" -Body "Hello from HTTP!"
```

A gzip-compressed batch with curl:

```bash
printf 'line one\nline two\n' | gzip | curl -X POST "https://jl3-cloud.site/api/logs/" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: text/plain" \
  -H "Content-Encoding: gzip" \
  --data-binary @-
```

## Request headers

| Header | Meaning |
|---|---|
| `Authorization` | Required. `Bearer YOUR_API_TOKEN` |
| `Content-Type` | Required. `text/plain` |
| `Content-Encoding` | Optional. `gzip`, `deflate` or `zstd` for a compressed body |
| `X-JustLog-Logger` | Source name shown in Logs, e.g. `api` (up to 255 characters, default `unknown`) |
| `X-JustLog-Session` | Groups the requests of one run (up to 255 characters) |
| `X-JustLog-Seq` | A positive number that orders a session. A retry with the same session and Seq within 30 minutes is acknowledged and stored once |
| `X-JustLog-UTC-Offset` | Your UTC offset in seconds east of UTC, e.g. `18000` for UTC+5 |

## Responses

| Status | Meaning |
|---|---|
| `202` | Stored. `X-JustLog-Lines-Accepted` is how many lines were stored, `X-JustLog-Lines-Rejected` how many did not fit into today's limit, `X-JustLog-Lines-Remaining` what is left today. `X-JustLog-Repeat: 1` means this session and Seq were already stored |
| `400` | Not `text/plain`, an empty body, or a corrupt compressed body |
| `401` | Missing, wrong or rotated token |
| `405` | Only POST is allowed |
| `413` | Over 1 MB as sent or 4 MB after decompression |
| `415` | Unknown `Content-Encoding` |
| `429` | Over 120 requests a minute for this token (`Retry-After: 60`), or the daily line limit is spent (`Retry-After` until 00:00 UTC) |

Errors are JSON: `{"error": "..."}`. The daily-limit 429 also carries `limit`, `retry_after` and `plans_url`.

## Limits and retries

- Lines longer than 8 KB are cut; NUL characters are replaced.
- When a batch is larger than what is left of today's quota, the lines that fit are stored and the rest are rejected (see `X-JustLog-Lines-Rejected`).
- On a network error or a 5xx, resend the same body with the same `X-JustLog-Session` and `X-JustLog-Seq`: if the first attempt did arrive, the server answers `202` with `X-JustLog-Repeat: 1` and does not store it twice.
- On 429, wait for `Retry-After` seconds. On 401, stop and ask for a new token.
