Guide · Developer tools

Debugging an API response, step by step

An integration that worked yesterday now fails: the app shows an error, a record cannot be found, or dates are off by fifty years. This guide follows four common causes in the order you are likely to meet them, and shows how to confirm each one in a minute without pasting production data into a random website.

Updated 28 September 2026

First, keep the data on your machine

When something breaks, the reflex is to copy the response into the first online formatter a search turns up. API responses routinely contain customer names, email addresses, access tokens and internal identifiers, and a token pasted into a third-party site should be treated as leaked. Every tool used in this guide runs entirely in your browser; you can confirm it by opening the Network tab of the developer tools while you use them. That makes it reasonable to paste a real response or a real token while you investigate — and it is still good practice to revoke any token you have copied around.

Problem 1: "Unexpected token" — the response is not valid JSON

The client reports something like "Unexpected token } in JSON". The server returned text that looks like JSON but breaks the rules, and the parser gave up. Paste the response body into the JSON formatter and press Format. Instead of a generic error it tells you the line and column of the first problem and the likely cause.

Take this response:

{
  "a": 1,
}

The formatter reports line 3, column 1 — the closing brace — and explains that a trailing comma is not allowed. The usual culprits, in order of how often they appear:

  • Trailing commas, typically from a template or a hand-edited fixture that appends a comma after every field.
  • Single quotes instead of double quotes, from code that printed a Python dict or a JavaScript object instead of serialising JSON.
  • Comments left in configuration files that are served as JSON.
  • Truncation: the body ends in the middle of a string or object. That usually means a timeout, a proxy limit or a crash while writing the response, not a serialisation bug. The formatter reports it as an unexpected end of input.
  • An HTML error page where JSON was expected — the first character is <. Check the HTTP status and the Content-Type header: a 502 from a load balancer is not the application's fault.

Problem 2: "record not found" — an ID was silently rounded

Everything parses, but looking up the record by its ID fails, or two different records appear to share an ID. Compare the ID in the raw response with the one your code used. If the raw one is 12345678901234567890 and the one in your logs is 12345678901234567000, the ID was rounded.

JavaScript numbers are 64-bit floating point and represent integers exactly only up to 2^53 − 1, which is 9,007,199,254,740,991. Many databases and ID generators — Twitter-style snowflake IDs, 64-bit auto-increment keys — produce larger values. JSON.parse in the browser and in Node.js turns them into the nearest representable number without any warning. The response was fine; the parser changed it.

The JSON formatter on this site does not use JSON.parse and keeps numbers exactly as written, so formatting {"n": 12345678901234567890} gives back the same digits. That makes it a quick way to see the true value. The fixes are on the client or server: send IDs as strings (the most robust option, and what many public APIs do), or use a JSON parser that supports big integers.

Problem 3: "401 Unauthorized" — look inside the token

Requests that worked yesterday now return 401. If the API uses bearer tokens in JWT format, paste the Authorization header value into the JWT decoder; the "Bearer " prefix is removed automatically. The decoder shows the header, the payload and, most usefully, the time claims converted to dates.

Using the example token from RFC 7519, the payload contains "exp": 1300819380. The decoder shows that as 22 March 2011, 18:43:00 UTC and marks the token as expired. In a real incident, the usual findings are:

  • exp is in the past — the token expired and the refresh logic did not run, or failed silently.
  • nbf is in the future — the token is not valid yet, typically because the issuing server's clock is ahead of the verifying server's.
  • aud or iss is wrong — a token issued for the staging environment is being sent to production.
  • alg is none — something is minting unsigned tokens, which a server must reject.

Remember that the decoder cannot tell you whether the signature is valid; it only shows what the token claims. If the claims look right but the server still rejects it, check the signing key and algorithm configured on the server.

Problem 4: dates in 1970 or in the year 55,000

A date field shows 20 January 1970, or a date tens of thousands of years in the future. Both are signs of a unit mix-up between seconds and milliseconds. The value 1700000000 means 14 November 2023, 22:13:20 UTC when read as seconds; read as milliseconds it is about 20 days after 1 January 1970. Going the other way, 1700000000000 milliseconds read as seconds lands in the year 55,840.

Paste the value into the timestamp converter. It decides the unit from the number of digits — up to 11 digits is read as seconds, up to 14 as milliseconds, up to 17 as microseconds and anything longer as nanoseconds — and says which it chose, then shows the date in UTC and in your time zone. If the correct reading is obvious, the fix is to multiply or divide by 1,000 in the code that produced or consumed it, and to document the unit in the API contract.

A related source of confusion is time zones: Unix timestamps are always UTC. If a date is off by exactly your UTC offset — eight hours in Beijing, five in New York in winter — the timestamp is right and the display code is formatting it in the wrong zone.

Bonus: fields that look like gibberish

Some APIs return binary data or nested documents as Base64 strings: attachments, signatures, cursors for pagination, or JSON wrapped inside JSON. Paste the value into the Base64 decoder. SGVsbG8sIOS4lueVjA== decodes to "Hello, 世界"; if the bytes are not text, the decoder recognises common formats such as PNG and PDF and offers them as a file. Pagination cursors often decode to small JSON objects that reveal how the API pages through results — useful when a page is skipped or repeated.

The order to check things in

  1. Look at the HTTP status and Content-Type first. If it is not a 2xx with application/json, the problem is usually not in the data.
  2. If parsing fails, use the JSON formatter to find the line and column.
  3. If it parses but the data looks wrong, compare the raw response with the values in your code, starting with long numeric IDs.
  4. For 401 or 403, decode the token and read exp, nbf and aud.
  5. For absurd dates, guess the unit first, then the time zone.

Reporting it to whoever owns the API

Once you know the cause, a good report gets it fixed in one round instead of five. Include the request (method, path, and the relevant headers with any token removed), the HTTP status, the smallest part of the response that shows the problem, and one sentence on what you expected instead. "Line 3, column 1: trailing comma after the last field" or "id 12345678901234567890 arrives as a JSON number; please send it as a string" is something the other side can act on straight away; "the API is broken" is not. Remove personal data from the sample before you send it — the tools here make it easy to trim a response down to the one field that matters.

Limits

  • These tools inspect data; they do not replay requests. To reproduce a failing request, use your HTTP client or the browser's network tab.
  • The JSON formatter reports only the first syntax error. Fix it and format again to find the next one.
  • JWT signatures are not verified. Verification needs the issuer's key and belongs on the server.
  • Timestamp unit detection is based on length. Values from the early 1970s, or deliberately unusual units, can be misread; the converter always says which unit it assumed.

Frequently asked questions

How do I find where my JSON is broken?

Paste it into the JSON formatter. It reports the line and column of the first error and the most likely cause, such as a trailing comma or single quotes.

Why did my large ID change after parsing?

JavaScript numbers lose precision above 2^53. JSON.parse rounds larger integers silently. Send such IDs as strings or use a big-integer-aware parser.

How do I check if a JWT is expired?

Paste it into the JWT decoder; it converts the exp claim to a date and says whether it has passed.

Sources and further reading

Tools used in this guide

↵ to open · Esc to close