---
title: Is the API broken, or just my network? How to test it with the API Tester
description: An integration reports API errors, yet the same call works from your laptop. To test an API online, send the request from a machine outside your network and read all of the response: status, timing, headers and body fields, not just the status code. Here's how with the free API Tester, a real request to the GitHub API that shows why rate-limit headers matter, and the curl commands to reproduce it.
canonical: https://watchfor.io/blog/how-to-test-an-api-online
---

# Is the API broken, or just my network? How to test it with the API Tester

2026-10-04 · WatchFor Team · Guides · guides, http, api

An integration reports API errors, yet the same call works from your laptop. To test an API online, send the request from a machine outside your network and read all of the response: status, timing, headers and body fields, not just the status code. Here's how with the free API Tester, a real request to the GitHub API that shows why rate-limit headers matter, and the curl commands to reproduce it.

To test an API online, send the same request from a machine outside your
own network and read the whole response: the status code, the timing, the
response headers and the fields in the body. If the API answers correctly
from outside, the problem is on the client side (credentials, network,
rate limits tied to an IP). If it fails from outside too, the API itself is
the problem.

The free [API Tester](/api-tester) sends a real HTTP request from a WatchFor
probe location and shows the status, timing, size, every header and every
JSON field in a searchable list. No signup and no code.

## What this tool answers

*What does this endpoint return to a request that isn't coming from my
machine?* Reach for it when a webhook or integration fails and your own
`curl` works, when you need to show a vendor exactly what their API
returned, when you're checking a health endpoint before wiring up
monitoring, or when you just want to see the fields of a JSON response
without opening Postman.

## A real example

### Testing an API online when it works from your laptop but not from the server

A common report: a nightly job that reads repository data from the GitHub
API starts failing with errors, but when you paste the same URL into your
terminal it works. We sent the job's request from outside our network with
the [API Tester](/api-tester): method **GET**, URL
`https://api.github.com/repos/microsoft/playwright`, no headers, default
location (Vilnius):

![The API Tester after a GET request to https://api.github.com/repos/microsoft/playwright from Vilnius: status 200 OK in 317 ms, 6.7 KB, HTTP/2.0, application/json, and the Fields tab listing 144 fields starting with id 221981891, name playwright, full_name microsoft/playwright and private false](/blog/how-to-test-an-api-online-fields.webp)

**200 OK in 317 ms**, 6,840 bytes of JSON over HTTP/2, flattened into 144
fields (`stargazers_count` was 97,057 at the time). So the endpoint works
from a second network too. The body doesn't explain the failing job, but the
**Headers** tab does:

| Header | Value from the probe | What it means |
| --- | --- | --- |
| `X-RateLimit-Limit` | 60 | Requests allowed per hour for this caller |
| `X-RateLimit-Remaining` | 49 | Left in the current window |
| `X-RateLimit-Used` | 11 | Already spent in this window |
| `X-RateLimit-Resource` | core | Which quota this endpoint counts against |
| `Cache-Control` | public, max-age=60, s-maxage=60 | The response may be cached for 60 s |

We sent no token, and unauthenticated GitHub API requests are limited to 60
per hour per IP address. The probe's address had already spent 11 of them,
on requests that weren't ours: everyone behind that IP shares the same
budget. From our own machine a minute later, curl reported 54 remaining
(see the command-line section).

**The answer:** the API was fine. A job that runs from a shared address (a
CI runner, a NAT gateway, a busy cloud egress IP) shares those 60 requests
with every other unauthenticated caller on it, and once they're gone GitHub
answers with an error until the window resets. The fix is to send a token:
authenticated requests get their own, much larger quota (GitHub documents
5,000 per hour for a user token), counted per token rather than per IP. In
any API you test, look for headers like these before blaming the endpoint.

## How to read the results

| What you see | What it means |
| --- | --- |
| **Status (200 OK)** | The HTTP status code. Green for 2xx, neutral for 3xx, amber for 4xx, red for 5xx. |
| **Time chip (317 ms)** | Total time to the response, including DNS, connection and TLS from the probe. |
| **Size chip (6.7 KB)** | Bytes of response body received. |
| **HTTP/2.0** | The protocol version that was negotiated. |
| **Content type** | From the `Content-Type` header, without parameters. If it isn't `application/json`, the Fields tab is empty. |
| **Fields (144)** | Every JSON value flattened to a path such as `owner.login` or `topics.0`. Paths are what you'd use in an assertion later. Up to 300 fields are listed. |
| **Body** | The raw response, pretty-printed when it's JSON. Bodies over 512 KB are cut off. |
| **Headers** | Every response header (up to 100), sorted. Look here for rate limits, caching, `Retry-After`, CORS and request IDs to quote to support. |
| **Timestamp** | When the request ran, in your local time. |

## More ways to use it

- **Prove it to a vendor.** Send the failing request, then quote the status,
  the body and the request ID header in your ticket.
- **Check a health endpoint before monitoring it.** Make sure it returns
  JSON with a field you can assert on, such as `status: "ok"`, and not just
  a 200 with an empty body.
- **Test a webhook receiver.** POST a sample JSON payload to your endpoint
  and see what it answers to a request from the internet.
- **Debug CORS and caching.** The headers tab shows
  `Access-Control-Allow-Origin` and `Cache-Control` as a server sends them,
  without a browser in between.
- **Read an unfamiliar API.** The Fields tab is a quick way to see what a
  response contains before writing a client.

## Tips and gotchas

- **Anonymous runs allow GET, HEAD and POST.** PUT, PATCH, DELETE and
  OPTIONS need a free account, so a public page can't be used to change
  someone's data.
- **Don't paste real secrets into any web tool.** You can add headers, but
  use a scoped test token or run the authenticated version with curl on
  your own machine.
- **One location, one moment.** The request comes from the probe nearest to
  you; geo-blocking, IP allowlists and per-IP rate limits apply to that
  address, as in the example.
- **The request times out after 15 seconds.** A slower endpoint reads as a
  failure.
- **200 doesn't mean correct.** An API can return 200 with
  `{"status":"degraded"}` or an empty list. Read the fields; the
  [API monitoring guide](/blog/api-monitoring-beyond-status-codes) explains
  what to assert on.
- **Status codes have specific meanings.** A 401 means no valid credentials,
  a 403 means the credentials are fine but not allowed, a 429 means rate
  limited. See [401 vs 403](/blog/401-vs-403) and
  [rate limiting explained](/blog/rate-limiting-explained).

## Check it from the command line too

The same request with curl, saving the body and printing the interesting
headers:

```bash
curl -s -D - -o repo.json https://api.github.com/repos/microsoft/playwright \
  | grep -iE '^(HTTP|x-ratelimit|content-type|cache-control)'
jq '{full_name, stargazers_count, default_branch, license: .license.spdx_id}' repo.json
```

```text
HTTP/2 200
content-type: application/json; charset=utf-8
cache-control: public, max-age=60, s-maxage=60
x-ratelimit-limit: 60
x-ratelimit-remaining: 54
x-ratelimit-used: 6
x-ratelimit-resource: core
x-ratelimit-reset: 1791068136
{
  "full_name": "microsoft/playwright",
  "stargazers_count": 97057,
  "default_branch": "main",
  "license": "Apache-2.0"
}
```

Same status and fields, but a different `remaining`: our address had used 6
requests, the probe's 11. `x-ratelimit-reset` is a Unix timestamp;
`date -d @1791068136` turns it into the time the window resets. For a
timing breakdown like the tester's:

```bash
curl -s -o /dev/null -w 'dns %{time_namelookup}s connect %{time_connect}s tls %{time_appconnect}s ttfb %{time_starttransfer}s total %{time_total}s\n' \
  https://api.github.com/repos/microsoft/playwright
```

```text
dns 0.006172s connect 0.112733s tls 0.223609s ttfb 0.333273s total 0.333829s
```

## Keep watching it

The tester shows one response. An [API monitor](/api-monitoring) sends the
same request on a schedule and checks the content: assertions on any JSON
field, header or body text (for example `X-RateLimit-Remaining` greater
than 10, or `status` equals `ok`), numbers extracted from the body and
charted over time, and an incident when an assertion fails or the status
leaves the range you accept.

## FAQ

**How do I test an API without Postman?**
Use an online API tester for quick requests from outside your network, or
curl on the command line: `curl -i <url>` shows the status, headers and
body.

**Why does my API work in the browser but not in my app?**
The browser may send cookies or credentials your app doesn't, the app may
run from an IP with a different rate limit or allowlist, or CORS may block
a browser call that works from a server. Compare the status and headers
from both places.

**What does HTTP 429 Too Many Requests mean?**
You hit a rate limit. Check headers like `Retry-After` or
`X-RateLimit-Reset` for when to retry, and authenticate or slow down so
your requests get their own quota. Some APIs, GitHub included, may answer
403 instead of 429 when the limit is exceeded.

---

Canonical page: https://watchfor.io/blog/how-to-test-an-api-online · All articles: https://watchfor.io/blog/all.md · Site guide: https://watchfor.io/llms.txt
