API
One public endpoint, built for agents
This site exposes a single public endpoint: a chat assistant scoped to questions about Gabriel Tsunoda. There is no sign-up and no API key — it is open so an agent can ask a question instead of crawling every page. If all you need is the content, prefer markdown content negotiation, which is cheaper for both of us.
Endpoint
POST to the versioned path. The unversioned /api/chat is a permanent alias with identical behaviour, kept for the site's own chat UI and for earlier integrations.
POST https://tsunode.com/api/v1/chat
POST https://tsunode.com/api/chat (alias)Authentication
None. Do not send an Authorization header — it is ignored. Requests are identified by IP for rate limiting only.
Request
Send JSON with a `messages` array in the Vercel AI SDK UIMessage format. The optional `locale` ("en" or "pt-BR") is only a fallback: the assistant replies in the language of your last message.
curl -sN https://tsunode.com/api/v1/chat \
-H "Content-Type: application/json" \
-d '{
"messages": [
{ "role": "user", "parts": [{ "type": "text", "text": "Where does Tsunode work?" }] }
],
"locale": "en"
}'Response
A 200 streams the reply as server-sent events in the AI SDK UI message stream format: one `data:` line per event, with `text-delta` events carrying the text. Concatenate the deltas to rebuild the answer.
data: {"type":"start"}
data: {"type":"text-delta","delta":"Tsunode"}
data: {"type":"text-delta","delta":" works at "}
data: {"type":"text-delta","delta":"**Neil Patel Digital**"}
data: {"type":"finish"}Rate limits
10 requests per minute per IP address, in a fixed 60-second window. Every response carries the RFC 9331 headers below, so you can pace yourself without waiting for a 429. A 429 also carries `Retry-After` in seconds.
RateLimit-Limit: 10
RateLimit-Remaining: 7
RateLimit-Reset: 42
RateLimit-Policy: 10;w=60
Retry-After: 42 (429 only)Errors
Every failure is JSON with the same shape. Branch on `code` — it is stable. The `error` field holds a human message in Portuguese for the site's own UI, `message` and `hint` are machine-readable English.
{
"error": "Muitas requisições. Por favor, aguarde um momento antes de enviar mais mensagens.",
"code": "rate_limited",
"message": "Rate limit of 10 requests per minute per IP exceeded.",
"hint": "Wait 42 seconds, then retry. Read RateLimit-Remaining to pace yourself.",
"documentation": "https://tsunode.com/api"
}- invalid_request
- The body is not valid JSON, or `messages` is missing or empty.
- blocked_content
- The last message contains profanity the endpoint refuses.
- rate_limited
- Over 10 requests in the last minute. Wait for `Retry-After` seconds.
- method_not_allowed
- Wrong HTTP verb. Retry with POST.
- internal_error
- The assistant could not be reached. Retry in a few seconds.
Versioning and deprecation
The API is versioned in the URL path. Breaking changes ship as a new version (/api/v2/…), never as an edit to a released one. If a version is ever retired it will carry `Deprecation` and `Sunset` headers (RFC 9745 and RFC 8594) for at least six months before it stops answering, and this page will say so. /api/chat is not deprecated.
Prefer markdown for content
Any page on this site answers `Accept: text/markdown` with a clean markdown version of the same URL — no tokens spent on layout, no model call needed. Use the API when you have an actual question; use markdown when you want the content.
curl -s -H "Accept: text/markdown" https://tsunode.com/careerMachine-readable spec
The OpenAPI 3.1 description covers every field, response and error listed here.
https://tsunode.com/.well-known/openapi.json