# HTTP Checks

An HTTP Check makes Tickingora send `GET` to your endpoint at the scheduled times and evaluate the response.

```json
{
  "type": "http",
  "name": "Production API",
  "timezone": "Europe/Warsaw",
  "schedule": { "preset": "custom", "days": [1,2,3,4,5,6,7], "windows": [{ "start": "07:00" }, { "start": "19:00" }] },
  "http": {
    "url": "https://api.example.com/health",
    "expected_status": "2xx",
    "headers": [{ "name": "Authorization", "value": "Bearer status-check-token" }]
  },
  "recovery": { "enabled": true, "interval_minutes": 15 }
}
```

## Target URL

- Only **public HTTPS** addresses, on port 443 or 8443.
- `localhost`, private and link-local ranges, cloud metadata endpoints and `.local` / `.internal` names are blocked. DNS is checked before **every** attempt and the connection is pinned to the checked address, so a DNS change cannot redirect a check to an internal host.
- Redirects are **not** followed: a `301` is a response like any other (useful with `expected_status: "301"`).
- Only the status line and headers are read; the body is never downloaded or stored.

## Expected status

| `expected_status` | Success when the response is |
| --- | --- |
| `"200"` (default) | exactly 200 |
| `"2xx"` | any 200–299 |
| `"204"`, `"301"`, … | exactly that code (100–599) |

## Attempts and retries

- Each attempt has a **10 s** timeout.
- Up to **3 attempts**: the first one plus two retries, **30 s** after the previous attempt finished.
- The first response that meets `expected_status` ends the check with `success`.
- Timeouts, DNS/TLS/connection errors and wrong status codes are failed attempts. After the third one the check is `failed`, an incident opens and you get an alert.
- Every attempt is recorded with its status code, duration and error — `GET /monitors/{id}/runs` returns them in `attempts` (`number`, `at`, `http_status`, `duration_ms`, `error_type`, `error`).
- If Tickingora itself could not run a check on time, the run is `not_executed` and nothing is blamed on your service.

Retry settings are fixed in the MVP.

## Headers with secrets

Add up to 5 headers (Free plan), e.g. `Authorization` or `X-API-Key`.

- Values are **encrypted** at rest and **never returned** by the API — responses show `{ "name": "Authorization", "has_value": true }`.
- They are kept out of logs, error messages and e-mails.
- On `PATCH`, `http.headers` replaces the list. A header sent **without** `value` keeps its stored secret; send a `value` to replace it; leave a header out to delete it.
- Not allowed (they change transport or routing): `Host`, `Content-Length`, `Transfer-Encoding`, `Connection`, `Keep-Alive`, `Upgrade`, `TE`, `Trailer`, `Expect`, `Forwarded`, `Via`, `X-Forwarded-*`, `X-Real-IP`, `Proxy-*`.

```bash
# Rotate the check's token, keep the API key header as it is
curl -sS -X PATCH https://dev.tickingora.com/api/v1/monitors/7 \
  -H "Authorization: Bearer $TICKINGORA_API_KEY" -H "Content-Type: application/json" \
  -d '{ "http": { "headers": [
        { "name": "X-API-Key" },
        { "name": "Authorization", "value": "Bearer new-status-token" }
      ] } }'
```

Use a dedicated token with minimal permissions for status checks.

## Recovery checks

With `recovery.enabled`, after a failure Tickingora also checks every `interval_minutes` (Free: 15, 30 or 60) — one attempt each — until the service answers correctly. Then the incident closes, a recovery e-mail is sent and the extra checks stop. Regular and recovery checks never hit your endpoint at the same time.

## Testing

The dashboard has **Test now** (also in the wizard before saving). It uses the same URL rules and headers but creates no runs, incidents or statistics.
