API
Use Estelle's OpenAI-compatible chat completions endpoint from scripts and services, with bearer authentication, repository scoping, and explicit errors.
View as MarkdownThe HTTP API lets an OpenAI-compatible client ask Estelle a question without using MCP. It is a good fit for scripts, backend services, and tools that already use the chat completions format and need access to your indexed repositories and memory.
Use the MCP server instead when an agent needs discrete navigation, session, monitoring, or job tools.
#Connection values
base_url = "https://api.fatelabs.ca/v1"
model = "estelle"
api_key = "estelle_live_..."Create a key in Settings → API keys. It is shown once. Store it on your server in an environment variable or secret manager, never in source control or browser code. Anyone with the key can use your account's data and credits.
| Endpoint | Purpose |
|---|---|
POST /v1/chat/completions | Send a conversation and receive a completed answer. |
GET /v1/models | Return the available model id, estelle. |
#Make a request
Send Authorization: Bearer <key> and a JSON body containing model and messages:
curl https://api.fatelabs.ca/v1/chat/completions \
-H "Authorization: Bearer $ESTELLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "estelle",
"messages": [
{ "role": "user", "content": "What changed in auth last week?" }
]
}'With the OpenAI Python SDK:
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.fatelabs.ca/v1",
api_key=os.environ["ESTELLE_API_KEY"],
)
response = client.chat.completions.create(
model="estelle",
messages=[{"role": "user", "content": "Why does /refresh return 401 after deploy?"}],
)
print(response.choices[0].message.content)#Request fields
| Field | Type | Required | Meaning |
|---|---|---|---|
model | string | Yes | Use estelle. |
messages | array | Yes | Non-empty conversation messages as objects with role and content. The final message supplies the new turn. |
response_format | object | No | Only {"type": "text"} is accepted. JSON modes are refused. |
Send a non-streaming request and read the answer from choices[0].message.content.
A successful response has an OpenAI-compatible shape and can include Estelle-specific fields:
{
"id": "estelle-cmpl",
"object": "chat.completion",
"model": "estelle",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "..." },
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 20,
"completion_tokens": 80,
"total_tokens": 100
},
"credits_used": 1
}The token counts in usage are estimates. credits_used reports the Estelle Credits charged to the request; the value depends on the work performed and is not always the example value above.
#Scope the question to one repository
On a multi-repository account, add the repository as owner/name:
-H "X-Estelle-Repo: your-org/api"This header selects the repository context for the request. Omit it to use the account's normal repository-selection behavior.
#Attach files
You can include OpenAI file content blocks in a message. Each file read uses one Estelle Credit. A deployment that cannot read attachments refuses the request rather than pretending the files were inspected.
#Structured output and streaming
This endpoint returns plain-text answers. It does not stream responses, and it does not guarantee JSON output.
{"type": "text"}is accepted.{"type": "json_object"}and{"type": "json_schema"}return422.- Other malformed or unsupported
response_formatvalues return400.
For a strict JSON contract, validate or transform the answer in your application, or use a provider endpoint that supports structured output.
#Check connectivity and authentication
curl https://api.fatelabs.ca/v1/models{ "object": "list", "data": [{ "id": "estelle", "object": "model" }] }GET /v1/models returns this response with or without a key. It proves that the base URL is reachable, not that authentication works. To test a key, make a short chat completion and check for 200 rather than 401.
#Errors and retries
Errors use an OpenAI-style object:
{ "error": { "message": "...", "code": 429, "wait_s": 3.0 } }| Status | Meaning | Next step |
|---|---|---|
400 | The body or a request option is malformed. | Fix the field named in error.message. |
401 | The key is missing, malformed, or revoked. | Check the bearer header and create or select a valid key. |
402 | The account cannot fund the request with its current credits or plan allowance. | Add credits, wait for the applicable usage window, or change plan. |
422 | The requested content or option is unsupported, such as structured JSON output. | Change the request. |
429 | A request-rate or in-flight limit was reached. | Retry only after the advertised wait, or reduce request volume. |
5xx | The request failed before a usable answer was produced. | Retry with backoff; contact us if it continues. |
A retryable 429 includes error.wait_s and the same delay in the Retry-After header. Honour that delay. An error without wait_s does not instruct you to repeat the identical request immediately.
401 and 402 are deliberately different: 401 means fix the credential; 402 means the credential was accepted but the account needs funding or allowance.