ipa.raymati.com

Errors

Failed calls use application/problem+json (RFC 9457).

{
  "type": "https://ipa.raymati.com/docs/errors#bad-request",
  "title": "Bad Request",
  "status": 400,
  "detail": "request must be a JSON object",
  "instance": "/v1/tutor"
}

type is a section of this page. detail is one sentence. Success JSON is not a problem document.

Bad request

Status 400. The body was not a JSON object, the target was empty, the audio was not a wav, or neither ipa nor audio was usable. detail is request must be a JSON object, target must be a Greek word or verse, or send ipa, audio_base64, or audio_url, among the scorer's own sentences. Inline audio over 256 KiB says to call create_upload.

Not found

Status 404. detail is not found.

Method not allowed

Status 405. Allow names the methods that path accepts. GET /mcp is 405 because this server does not open an SSE stream.

Not acceptable

Status 406. POST /mcp received an Accept header that allows neither application/json nor text/event-stream.

HTML guides are different. Accept: text/markdown is a 200 Markdown body (draft-consolidated-content-01), not a 406. */* stays HTML.

Too many requests

Status 429. detail is rate limit exceeded. code is rate-limit-exceeded.

POST /v1/tutor and POST /mcp with method tools/call count toward 60 requests per 60 seconds for one client. The client is CF-Connecting-IP, or the first X-Forwarded-For hop when that header is missing. The Workers Rate Limiting binding TUTOR (namespace_id ipa-tutor-anonymous, limit 60, period 60) is the cross-isolate counter. An in-memory window is the fallback for local tests and the native process. GET pages, /health, /openapi.json, initialize, and tools/list are not counted.

A POST body over 400 KiB is status 413, code body-too-large, and is refused from Content-Length before the body is read. PUT /v1/uploads/{id} uses the 8 MiB upload cap the same way.

create_upload keeps 32 slots. When they are all still live the response is status 503, code upload-slots-full, and Retry-After is the seconds until the oldest slot expires. The call does not drop another caller's wav.

The headers follow draft-ietf-httpapi-ratelimit-headers, which is still a draft:

RateLimit-Policy: "tutor";q=60;w=60
RateLimit: "tutor";r=59;t=60

q is the quota, w is the window in seconds, r is how many requests remain, and t is whole seconds until the oldest counted request leaves the window. A 429 also sets Retry-After to t.

Bad gateway

Status 502. The recognizer returned an error. detail starts with recognizer returned.

Service unavailable

Status 503. Audio was sent and neither RECOGNIZER_URL nor the ZIPA service binding is available. An IPA request does not need either. detail on the worker is RECOGNIZER_URL is unset and the ZIPA service binding is missing. IPA requests do not need either. The native process says RECOGNIZER_URL is empty when that variable is blank.

A warming ZIPA container is also 503. detail starts with recognizer returned 503 and the response sets Retry-After. Retry that request. It is not a 502.

create_upload slot exhaustion is 503 with code upload-slots-full.

Audio URL

audio_url is https, or an upload from create_upload. The worker rejects http, userinfo, and hosts that are localhost, *.local, *.internal, or an IP literal in a private, loopback, link-local, multicast, or unspecified range, including IPv4-mapped forms of those addresses. It follows at most 3 redirects and checks every hop. Connect budget is 5 seconds when the transport reports it. The total budget is 20 seconds. The body is read in chunks and aborted at 256 KiB, the same cap as decoded audio_base64. Content-Type must be audio/wav, audio/x-wav, audio/wave, or audio/vnd.wave.

The code values are audio-url-not-https, audio-url-host, audio-url-userinfo, audio-url-redirect-host, audio-url-redirects, audio-url-status, audio-url-type, audio-url-too-large, audio-url-connect, and audio-url-timeout. The body is application/problem+json.

Unscored audio

Audio shorter than 0.12 s after the trim is HTTP 200. proximity is null and unscored is too_short. That is not a problem document.