Chat Completions
Generate a chat completion from one or more messages, with optional streaming. The model searches your team’s document libraries and returns an answer grounded in those sources, together with citations.
POST /api/chat/completions
Authentication
Requires a Bearer token. See Getting Started.
Authorization: Bearer <your-api-key>
Request body
| Field | Type | Default | Description |
|---|---|---|---|
model | "vulgate-1" | "vulgate" | Required | Model to use. Both values behave identically. |
messages | Message[] | Required | Conversation messages. See Message format. |
stream | boolean | false | Enable server-sent events (SSE) streaming. |
max_tokens | integer | — | Maximum tokens in the response. Range: 1–128 000. |
temperature | number | — | Sampling temperature. Range: 0–2. |
top_p | number | — | Nucleus sampling threshold. Range: 0–1. |
reasoning_effort | string | "medium" | How much reasoning the model should perform. One of "minimal", "low", "medium", "high". |
return_citations | boolean | true | Include source citations in the response. Vulgate-specific. |
stop | string | string[] | — | Accepted for compatibility but not currently supported. |
response_format | object | — | Only { "type": "text" } is supported. |
Fields marked with — in the Default column use the model’s own defaults when omitted.
Message format
Each message has a role ("system", "user", or "assistant") and content. The content field can be a plain string or an array of typed parts for multimodal input.
Text
{ "role": "user", "content": "What does Aquinas say about natural law?" }
Or, using the parts array:
{
"role": "user",
"content": [
{ "type": "text", "text": "What does Aquinas say about natural law?" }
]
}
Image input
Pass an image URL using the image_url part type:
{
"role": "user",
"content": [
{ "type": "text", "text": "What does this diagram represent?" },
{ "type": "image_url", "image_url": "https://example.com/diagram.png" }
]
}
The image_url field also accepts an object form:
{ "type": "image_url", "image_url": { "url": "https://example.com/diagram.png" } }
File input
Attach a file using the file_url part type. You can optionally provide a file_name to help the model identify the document:
{
"role": "user",
"content": [
{ "type": "text", "text": "Summarize this document." },
{ "type": "file_url", "file_url": "https://example.com/paper.pdf", "file_name": "paper.pdf" }
]
}
The file_url field also accepts an object form:
{ "type": "file_url", "file_url": { "url": "https://example.com/paper.pdf" }, "file_name": "paper.pdf" }
Response
Non-streaming
When stream is false (the default), the API returns a single JSON object:
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1741200000,
"model": "vulgate-1",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Thomas Aquinas defines natural law as..."
},
"finish_reason": "stop"
}
],
"citations": [
{
"cited_text": "<p>Natural law is a participation of the eternal law...</p>",
"document_title": "Summa Theologiae",
"document_index": 0,
"document_author": "Thomas Aquinas",
"source_url": null
}
]
}
| Field | Type | Description |
|---|---|---|
id | string | Unique completion ID. |
object | string | Always "chat.completion". |
created | integer | Unix timestamp of creation. |
model | string | Model used. |
choices | array | Array containing the completion. |
choices[].message | object | The assistant’s response (role + content). |
choices[].finish_reason | string | null | Why generation stopped: "stop", "length", or null. |
citations | Citation[] | Source citations. See Citations. Omitted when return_citations is false. |
Streaming
When stream is true, the API returns server-sent events (SSE). Each event contains a JSON chunk with incremental content:
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1741200000,"model":"vulgate-1","choices":[{"index":0,"delta":{"content":"Thomas "},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1741200000,"model":"vulgate-1","choices":[{"index":0,"delta":{"content":"Aquinas "},"finish_reason":null}]}
data: [DONE]
- Text chunks have
choices[0].delta.contentwith the next piece of text. Clients should not assume every event carries text content. - The stream ends with
data: [DONE]. - Citations, if enabled, are sent as a final event before
[DONE]in acitationsfield.
Citations
The citations array is a Vulgate-specific extension to the OpenAI format. Each citation references a source passage from your document libraries.
| Field | Type | Description |
|---|---|---|
cited_text | string | HTML content of the cited passage. |
document_title | string | null | Title of the source document. |
document_index | integer | Position of this citation in the list. |
document_author | string | null | Author of the source document. |
source_url | string | null | Link to the source, if available. |
Set return_citations to false in the request body to omit citations entirely.
Error codes
The API uses standard HTTP status codes. Below are the most common errors you may encounter:
| HTTP Status | Description |
|---|---|
400 | Invalid request body. Returns a JSON validation error from the request schema. |
401 | Missing or invalid API key. |
429 | Rate limit exceeded. Includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. |
Examples
Basic completion
curl -X POST "https://vulgate.ai/api/chat/completions" \
-H "Authorization: Bearer $VULGATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "vulgate-1",
"messages": [
{ "role": "user", "content": "What is the Filioque clause?" }
]
}'
Multi-turn conversation
curl -X POST "https://vulgate.ai/api/chat/completions" \
-H "Authorization: Bearer $VULGATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "vulgate-1",
"messages": [
{ "role": "system", "content": "You are a theology research assistant." },
{ "role": "user", "content": "Explain the concept of transubstantiation." },
{ "role": "assistant", "content": "Transubstantiation is the teaching that..." },
{ "role": "user", "content": "How does the Orthodox view differ?" }
]
}'
Streaming
curl -N -X POST "https://vulgate.ai/api/chat/completions" \
-H "Authorization: Bearer $VULGATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "vulgate-1",
"stream": true,
"messages": [
{ "role": "user", "content": "Summarize Lumen Gentium chapter 2." }
]
}'
Image input
curl -X POST "https://vulgate.ai/api/chat/completions" \
-H "Authorization: Bearer $VULGATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "vulgate-1",
"messages": [
{
"role": "user",
"content": [
{ "type": "text", "text": "What does this image depict?" },
{ "type": "image_url", "image_url": "https://example.com/icon.jpg" }
]
}
]
}'
File input
curl -X POST "https://vulgate.ai/api/chat/completions" \
-H "Authorization: Bearer $VULGATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "vulgate-1",
"messages": [
{
"role": "user",
"content": [
{ "type": "text", "text": "Summarize this document." },
{ "type": "file_url", "file_url": "https://example.com/paper.pdf", "file_name": "paper.pdf" }
]
}
]
}'
Adjusting reasoning effort
curl -X POST "https://vulgate.ai/api/chat/completions" \
-H "Authorization: Bearer $VULGATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "vulgate-1",
"reasoning_effort": "high",
"messages": [
{ "role": "user", "content": "Compare Augustine and Pelagius on original sin, citing primary sources." }
]
}'
Without citations
curl -X POST "https://vulgate.ai/api/chat/completions" \
-H "Authorization: Bearer $VULGATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "vulgate-1",
"return_citations": false,
"messages": [
{ "role": "user", "content": "What are the seven sacraments?" }
]
}'