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

shell
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

EndpointMethodDocs
/lookup/ip/{format}/lvl{level}/{ip}GETIP Address Lookup
/lookup/dns/{domain}/{type}/{server}GETDNS Lookup
/lookup/mac/json/{mac}GETMAC Address Vendor Lookup
/lookup/port/json/{host}/{port}GETPort Checker
/lookup/portPOSTPort Checker
/check/sonos/streamPOSTSonos Stream Checker
/check/traceroutePOSTTraceroute

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.

FormatSegmentAvailable on
JSON/json/everything
Plain textomittedIP, 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.

EndpointHow failure arrives
IP LookupAlways HTTP 200. Check the invalid and reserved booleans.
DNS LookupHTTP 400 with {"error": [...]}, an array of messages. 405 for non-GET.
MAC LookupHTTP 200 with a per-address error string inside the array. HTTP 500 only for database failures.
Port CheckerHTTP 400 with {"error": "..."}. A closed port is a success, not an error.
TracerouteHTTP 400 with {"success": false, "error": "..."} before streaming; an error record inside the stream afterwards.
Sonos Stream CheckerHTTP 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

LimitValue
Requests per second, per IP50
Burst allowance100
Concurrent connections, per IP50
Response when exceededHTTP 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.

shell
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. /v1 is not edited to accommodate it.
  • Undocumented behaviour is not a promise. The /api/*.php paths in particular are implementation detail and may move.
  • Values described here as strings, including the literal not provided in registry data and No 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.