Home → Help

Unexpected token '<' when calling an OpenAI-compatible API

Your base URL is wrong, and the server is returning a web page instead of the API. The client then tries to parse HTML as JSON and fails on the very first character.

What you are seeing

Why it happens

Most OpenAI-compatible gateways serve their website and their API from the same domain. When you request a path the API does not recognise, you do not get a clean 404 — you get the site's front-end, with HTTP 200 and Content-Type: text/html.

From the client's point of view everything succeeded, so it goes ahead and parses the body. The error you see is a JSON parser complaining about the first character of an HTML document, which points nowhere near the real problem.

This also means the failed call usually leaves no trace in the provider's error logs — a 200 is not an error. Support will tell you they see nothing wrong, and they are being truthful.

Confirm it is this

Confirm it in one command. Send a request and look at the content type rather than the body:

curl -s -o /dev/null -w '%{http_code} %{content_type}\n' \
  -X POST 'YOUR_BASE_URL/chat/completions' \
  -H 'Authorization: Bearer YOUR_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"model":"MODEL","messages":[{"role":"user","content":"hi"}]}'

A working endpoint returns application/json — even when the key is wrong, you get JSON saying so. If you see text/html, the URL is the problem, not the key.

How to fix it

  1. Check whether your client appends /v1 for youThis is the whole trap. The OpenAI SDKs do not add /v1 — you must include it in the base URL. The Anthropic SDK and Claude Code do add it, so giving them a base URL that already ends in /v1 produces /v1/v1/messages, which fails exactly the same way.
  2. Watch for a trailing slashSome clients join paths naively. A base URL ending in a slash can produce a double slash in the final path, which some gateways route to the front-end rather than the API.
  3. Make sure you are on the API hostIf a provider offers a separate API subdomain, the main domain may serve the marketing site at the same paths. Same URL shape, completely different handler.
ClientBase URL should be
OpenAI SDK (Python, Node, Go)ends with /v1
Codex, Cherry Studio, Chatbox, LobeChatends with /v1
Anthropic SDKno /v1 — it appends /v1/messages
Claude Codeno /v1 — same reason
On APICLAN the base URL is https://apiclan.us/v1 for OpenAI-style clients and https://apiclan.us for Claude Code. Full setup for every client is in the quickstart.

Related

401 invalid API key — when the key looks right but still fails404 on /v1/chat/completions when the endpoint clearly exists

Last checked 2026-08-24. Written from problems diagnosed on a live OpenAI-compatible gateway, not collected from other sites.