API Overview
One base URL, no authentication, no keys, no quota. What follows is what every endpoint has in common, and where they honestly disagree.
Base URL
https://api.troubleshooting.tools/v1
Everything is HTTPS. Plain HTTP is redirected permanently and never serves a response.
The version lives in the path. Every endpoint below is written relative to that base, so
/lookup/mac/json/{mac} is requested as
https://api.troubleshooting.tools/v1/lookup/mac/json/{mac}.
Authentication
There is none. No key, no token, no registration, no Authorization header. Every endpoint is
open to anyone.
This is a deliberate design decision, not an oversight, and it has a consequence worth stating plainly: because there is nothing to identify you, there is also nothing to raise your limits. Everyone gets the same allowance, and the way to stay inside it is to cache.
Endpoints
| Endpoint | Method | Docs |
|---|---|---|
| /lookup/ip/{format}/lvl{level}/{ip} | GET | IP Address Lookup |
| /lookup/dns/{domain}/{type}/{server} | GET | DNS Lookup |
| /lookup/mac/json/{mac} | GET | MAC Address Vendor Lookup |
| /lookup/port/json/{host}/{port} | GET | Port Checker |
| /lookup/port | POST | Port Checker |
| /check/sonos/stream | POST | Sonos Stream Checker |
| /check/traceroute | POST | Traceroute |
Each of those has a plain-text sibling without the format segment, where a plain-text answer makes sense:
/lookup/ip/{ip}, /lookup/mac/{mac} and
/lookup/port/{host}/{port}. They return one bare value, which is what you want in a shell
pipeline and never what you want in a program.
Two further endpoints have no tool page of their own yet:
/lookup/spotify/track/ and /lookup/deezer/track/ resolve a track id to its metadata.
They work, but they are undocumented and unsupported until their tools ship.
Output formats
Only the IP lookup offers the full set. Everything else returns JSON, or plain text where a bare value is the natural answer.
| Format | Segment | Available on |
|---|---|---|
| JSON | /json/ | everything |
| Plain text | omitted | IP, MAC, port |
| JSONP | /jsonp/ | IP only |
| XML | /xml/ | IP only |
| YAML | /yaml/ | IP only |
| CSV | /csv/ | IP only |
| HTML | /html/ | IP only |
Traceroute is the exception to all of this: it streams newline-delimited JSON, one object per line, and cannot be parsed as a single document.
Error conventions
The endpoints do not agree on how failure is reported. This is a historical wart, not a design. Read the per-endpoint docs before writing error handling, and prefer inspecting the body over branching on the status code.
| Endpoint | How failure arrives |
|---|---|
| IP Lookup | Always HTTP 200. Check the invalid and reserved booleans. |
| DNS Lookup | HTTP 400 with {"error": [...]}, an array of messages. 405 for non-GET. |
| MAC Lookup | HTTP 200 with a per-address error string inside the array. HTTP 500 only for database failures. |
| Port Checker | HTTP 400 with {"error": "..."}. A closed port is a success, not an error. |
| Traceroute | HTTP 400 with {"success": false, "error": "..."} before streaming; an error record inside the stream afterwards. |
| Sonos Stream Checker | HTTP 200 with {"error": "..."}, including for validation failures. |
The one thing they do agree on: HTTP 429 always means the rate limit, and it comes from the
edge before the endpoint runs.
Rate limits
| Limit | Value |
|---|---|
| Requests per second, per IP | 50 |
| Burst allowance | 100 |
| Concurrent connections, per IP | 50 |
| Response when exceeded | HTTP 429 |
The limit is per source address and applies across all endpoints together, not per endpoint. There are no
X-RateLimit-* headers; a 429 is the only signal you get.
These numbers exist to keep the service responsive under abuse, not to meter you. Ordinary scripted use will never approach them. If you are looping over a list, cache what you already resolved and pace yourself particularly for the endpoints that reach out to third parties on every call, which are IP lookup at level 2, traceroute and the Sonos checker.
CORS
Every endpoint on api.troubleshooting.tools is reachable from browser JavaScript.
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Expose-Headers: Content-Length
Any origin, no credentials. Since there is nothing to authenticate, there is nothing a permissive policy could leak.
This applies to the documented /v1 routes. The underlying /api/*.php paths
are implementation detail: most of them send no CORS headers at all, so calling them cross-origin
mostly will not work. Use the versioned routes.
Stability
The version in the path is the contract. Everything documented under /v1 keeps answering the
way it is described here, so an integration written today does not need revisiting.
- New fields may appear in a response at any time. Parse defensively and ignore what you do not know.
- Documented fields are not removed and do not change type within a version.
- A change that cannot be made compatibly becomes
/v2./v1is not edited to accommodate it. - Undocumented behaviour is not a promise. The
/api/*.phppaths in particular are implementation detail and may move. - Values described here as strings, including the literal
not providedin registry data andNo records found for record type X.in DNS results, are part of the contract. They are awkward, and changing them would break callers, so they stay within this version.
Requests without the version prefix are answered for the time being, since they predate it, but they are
not documented and not covered by the promises above. Move to /v1.
The service is free and has no SLA. It is run carefully and monitored, but do not put it in the critical path of something that must not fail.