# Free tools API

Source: https://getuptimely.com/docs/free-tools-api

> No-key endpoints behind Uptimely's free tools — check whether a site is up from curl, a script or an AI agent.

The free tools on getuptimely.com have an API that needs no account and no
key. Call it from a terminal, a script, a CI job or an AI agent. It is the same
check the [Is it down?](https://getuptimely.com/is-it-down) pages run.

Every endpoint follows the same rules:

* **No authentication.** No key, no cookie, no login.
* **CORS is open** to every origin, so a browser page on any site can call it.
* **JSON by default.** Send `Accept: text/markdown` to get the answer as
  Markdown, which reads better in an agent's context.
* **Errors are [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) problem
  details** (`application/problem+json`). Branch on `code`, or on `type`, which
  is a link to the matching section below.
* **Rate limited per address:** 30 calls a minute and 300 a day. Past either,
  the answer is `429` with a `Retry-After` header.
* Every answer carries `X-Tool-Docs`, the address of this page.

The OpenAPI 3.1 description is at
[getuptimely.com/api/tools/openapi.json](https://getuptimely.com/api/tools/openapi.json),
and both it and the /v1 API are listed in the
[API catalog](https://getuptimely.com/.well-known/api-catalog).

## Is a site up? `GET /api/tools/check` [#is-a-site-up-get-apitoolscheck]

```bash
curl "https://getuptimely.com/api/tools/check?url=github.com"
```

```bash
curl -H "Accept: text/markdown" "https://getuptimely.com/api/tools/check?url=github.com"
```

`url` is a domain (`example.com`) or an `http://` or `https://` address. The
path is ignored: the check requests the site's home page. `POST` with the JSON
body `{"url": "example.com"}` does the same.

What the check does:

1. Resolves the name and refuses the request if any address is not on the
   public internet (private, loopback, link-local and cloud metadata ranges).
2. Requests the home page on port 443 (or 80 for `http://`), following up to 5
   redirects. Each redirect is checked the same way; one to another port or a
   private address is not followed.
3. Reads the status line, the response time and, over HTTPS, the certificate.
   The page body is never downloaded.

The whole check takes at most 10 seconds. A result is reused for 60 seconds,
for every caller, so a site is never sent more than one check a minute from
this API.

### The answer [#the-answer]

```json
{
  "tool": "is-it-down",
  "target": {
    "scheme": "https",
    "host": "github.com",
    "url": "https://github.com/"
  },
  "verdict": "up",
  "summary": "github.com is up. It answered HTTP 200 OK in 182 ms.",
  "checkedAt": "2026-10-21T18:04:11.402Z",
  "http": {
    "status": 200,
    "statusText": "OK",
    "finalUrl": "https://github.com/",
    "responseTimeMs": 182,
    "redirects": []
  },
  "failure": null,
  "certificate": {
    "validTo": "2027-02-05T23:59:59.000Z",
    "daysLeft": 107,
    "issuer": "Sectigo Limited",
    "trusted": true,
    "problem": null
  },
  "warnings": [],
  "cached": false,
  "ageSeconds": 0,
  "cacheTtlSeconds": 60,
  "vantage": "One HTTP request from Uptimely's checker, a single location. A site can be up for us and down in your region, or the reverse.",
  "links": {
    "page": "https://getuptimely.com/is-it-down/github.com",
    "monitor": "https://app.getuptimely.com/accounts/register",
    "docs": "https://getuptimely.com/docs/free-tools-api"
  }
}
```

`verdict` is `down` when the site did not answer (the reason is in
`failure.reason`: `dns_failed`, `dns_unavailable`, `connection_refused`,
`connection_reset`, `timeout`, `tls_failed`, `connection_failed` or
`too_many_redirects`) or when it answered with a 5xx status. A 4xx answer is
`up` with a warning: the server is running, and some sites refuse automated
requests this way. A site that is down is still an HTTP `200` answer from this
API — the finding is in the body.

The check runs from one location. For continuous checks from more than one,
with alerts, create a monitor in Uptimely.

## Errors [#errors]

| Status | `code`                                                            | Meaning                                                                                                                                        |
| ------ | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| 400    | <a id="problem-missing_url" />`missing_url`                       | No `url` query parameter.                                                                                                                      |
| 400    | <a id="problem-invalid_url" />`invalid_url`                       | Not a public web address. `reason` says why: `empty`, `not_a_url`, `unsupported_scheme`, `unsupported_port`, `credentials` or `reserved_name`. |
| 400    | <a id="problem-invalid_body" />`invalid_body`                     | A POST body that is not `{"url": "..."}`.                                                                                                      |
| 413    | <a id="problem-payload_too_large" />`payload_too_large`           | A POST body over 1 KB.                                                                                                                         |
| 415    | <a id="problem-unsupported_media_type" />`unsupported_media_type` | A POST that is not `application/json`.                                                                                                         |
| 422    | <a id="problem-blocked_address" />`blocked_address`               | The name resolves to an address that is not on the public internet.                                                                            |
| 429    | <a id="problem-rate_limited" />`rate_limited`                     | Over 30 calls a minute or 300 a day from one address. Wait for `Retry-After` seconds.                                                          |
| 500    | <a id="problem-internal" />`internal`                             | A fault on our side. Try again.                                                                                                                |
| 503    | <a id="problem-busy" />`busy`                                     | Too many checks are running. Try again in a few seconds.                                                                                       |

```json
{
  "type": "https://getuptimely.com/docs/free-tools-api#problem-invalid_url",
  "title": "Invalid url",
  "status": 400,
  "detail": "Only the standard web ports (80 for http, 443 for https) can be checked.",
  "code": "invalid_url",
  "reason": "unsupported_port"
}
```
