Skip to content

AI chat proxy (X-Ai-Chat-Secret)

POST
/wp-json/wp2tutor/ai/v1/chat
curl --request POST \
--url https://example.com/wp-json/wp2tutor/ai/v1/chat \
--header 'Content-Type: application/json' \
--header 'X-Ai-Chat-Secret: <X-Ai-Chat-Secret>' \
--data '"What is RAG?"'

Proxy to the selected LLM (ChatProxyService::chat). Permission is not cookie and not manage_options: check_secret_permission compares header X-Ai-Chat-Secret to SecretKeyManager::get() (option wp2lms_ai_chat_secret_key) with hash_equals. Empty or wrong secret → WP_Error rest_forbidden (status 401, message Missing or invalid secret). Body is raw $request->get_body(), not a Chat Completions schema. AiRequestBodyNormalizer: JSON string "prompt" or base64 of that JSON string (frontend when encode_request). PHP does not parse a messages object. Rate limit RequestRateLimiter: 30 requests / 60 s, key ai-chat|{ip}|{first 8 chars of secret}. Over limit → 429 with { error } (not WP_Error). Success: HTTP 200, body = provider data string (LLM text). Config/provider errors are not forwarded: 400 if the internal error string contains API key, otherwise 500; body is always { error: AI request failed. Please try again later. } (i18n).

JSON string prompt (on the wire "text"). PHP reads the raw body; AiRequestBodyNormalizer json_decode → string.

string
Example
What is RAG?

ChatProxyService success (success true). Body is data (LLM string), not a success/error object. If data is missing, JSON array [].

Media typeapplication/json
One of:
string
Example
Embedding is a vector representation of a text chunk.

Internal error contains substring API key (missing key API key not configured or API key error: …). Client gets { error } with the generic text, not WP_Error.

Media typeapplication/json
object
error

Client-facing text. 429 — Too many requests… (i18n). 400/500 — generic AI request failed. Please try again later. (i18n). Not a WP_Error code.

string
Example
{
"error": "AI request failed. Please try again later."
}

Rest_forbidden — missing or invalid X-Ai-Chat-Secret. WP_Error, data.status 401.

Media typeapplication/json
object
code

WP_Error code. For POST /chat 401 — rest_forbidden. DualRest cookie — rest_forbidden / rest_not_logged_in / rest_cookie_invalid_nonce.

string
message

WP_Error message (for the chat secret — Missing or invalid secret.).

string
data

Usually { status: HTTP code }, as PHP stores in WP_Error data.

object
Example
{
"code": "rest_forbidden",
"message": "Missing or invalid secret.",
"data": {
"status": 401
}
}

Rest_forbidden — capability / DualRest cookie nonce rejection when the request is treated as a cookie session (rare for this secret-gated route). WP_Error, data.status 403.

Media typeapplication/json
object
code

WP_Error code. For POST /chat 401 — rest_forbidden. DualRest cookie — rest_forbidden / rest_not_logged_in / rest_cookie_invalid_nonce.

string
message

WP_Error message (for the chat secret — Missing or invalid secret.).

string
data

Usually { status: HTTP code }, as PHP stores in WP_Error data.

object
Example
{
"code": "rest_forbidden",
"message": "Missing or invalid secret.",
"data": {
"status": 401
}
}

Too many requests (30 / 60 s per IP+secret prefix). Not WP_Error: { error: Too many requests. Please try again later. } (i18n).

Media typeapplication/json
object
error

Client-facing text. 429 — Too many requests… (i18n). 400/500 — generic AI request failed. Please try again later. (i18n). Not a WP_Error code.

string
Example
{
"error": "Too many requests. Please try again later."
}

Other proxy failures (empty prompt No messages in request, provider not implemented, LLM failure). Same { error } body, not WP_Error.

Media typeapplication/json
object
error

Client-facing text. 429 — Too many requests… (i18n). 400/500 — generic AI request failed. Please try again later. (i18n). Not a WP_Error code.

string
Example
{
"error": "AI request failed. Please try again later."
}