Chat completions
POST /v1/chat/completions
The OpenAI chat completions API. The request and response shapes are theirs; what follows covers what is ours.
curl https://endpoint.pirol.ai/v1/chat/completions \
-H "Authorization: Bearer $PIROL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "pirol/pirol-ai",
"messages": [
{"role": "system", "content": "Answer in one sentence."},
{"role": "user", "content": "What is an embedding?"}
]
}'
model and messages are required. A request without them is refused with 400.
Streaming
Set stream: true and read server-sent events, exactly as with OpenAI:
curl https://endpoint.pirol.ai/v1/chat/completions \
-H "Authorization: Bearer $PIROL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "pirol/pirol-ai", "stream": true,
"messages": [{"role": "user", "content": "Count to five."}]}'
data: {"id":"chatcmpl-…","choices":[{"delta":{"content":"One"}}]}
data: {"id":"chatcmpl-…","choices":[{"delta":{"content":", two"}}]}
data: [DONE]
Tool calls arrive whole. A function call is never split across two chunks, so you can parse
arguments as it comes rather than stitching fragments together. Empty arguments arrive as {},
not as an empty string — both paths promise the same thing, so JSON.parse always works.
Response headers
x-endpoint-provider says which provider answered.
Message content
content may be a plain string or a list of blocks:
{"role": "user", "content": [{"type": "text", "text": "What is an embedding?"}]}
Both are treated the same. The list form is what you need for prompt caching, and it behaves identically to the string form everywhere else.