Send your first request
A key, Evanesca's base URL and the OpenAI SDK you already use: one chat request, then streaming, choosing a model and the headers that say where the call ran.
SoonOpening soon: what follows describes the service as it will work.
Create a key
You create keys in your Evanesca account once the service opens. They start with sk-eva-; the full key shows once, when you create it, and after that only its first characters. Keep it on the server, in an environment variable — the examples read EVANESCA_API_KEY (authentication).
# Your key starts with sk-eva-. Keep it on the server.
export EVANESCA_API_KEY="<your key>"Send the request
The same request four ways. Python and JavaScript use OpenAI's official SDK (pip install openai, npm install openai): there is no Evanesca library to install.
curl https://evanesca.app/api/v1/chat/completions \
-H "Authorization: Bearer $EVANESCA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemma-4-26b",
"messages": [{"role": "user", "content": "Hello"}]
}'import os
from openai import OpenAI
client = OpenAI(
base_url="https://evanesca.app/api/v1",
api_key=os.environ["EVANESCA_API_KEY"],
)
answer = client.chat.completions.create(
model="gemma-4-26b",
messages=[{"role": "user", "content": "Hello"}],
)
print(answer.choices[0].message.content)import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://evanesca.app/api/v1",
apiKey: process.env.EVANESCA_API_KEY,
});
const answer = await client.chat.completions.create({
model: "gemma-4-26b",
messages: [{ role: "user", content: "Hello" }],
});
console.log(answer.choices[0].message.content);package main
import (
"fmt"
"io"
"net/http"
"os"
"strings"
)
func main() {
body := strings.NewReader(`{"model": "gemma-4-26b", "messages": [{"role": "user", "content": "Hello"}]}`)
req, err := http.NewRequest("POST", "https://evanesca.app/api/v1/chat/completions", body)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("EVANESCA_API_KEY"))
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.Status, string(out))
}The answer is a standard chat.completion object. Its model field carries the name the operator gives the model that answered; its usage block is what your credit pays for, to the token (every parameter).
{
"id": "chatcmpl-…",
"object": "chat.completion",
"model": "…",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "…" },
"finish_reason": "stop"
}
],
"usage": { "prompt_tokens": 9, "completion_tokens": 12, "total_tokens": 21 }
}Stream the answer
With "stream": true, the answer arrives as server-sent events: data: lines carrying OpenAI-format chunks, ending with data: [DONE]. It is OpenAI's wire format, so the SDKs' streaming helpers work as they are.
curl -N https://evanesca.app/api/v1/chat/completions \
-H "Authorization: Bearer $EVANESCA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemma-4-26b",
"messages": [{"role": "user", "content": "Hello"}],
"stream": true
}'stream = client.chat.completions.create(
model="gemma-4-26b",
messages=[{"role": "user", "content": "Hello"}],
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")const stream = await client.chat.completions.create({
model: "gemma-4-26b",
messages: [{ role: "user", content: "Hello" }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}Evanesca always asks the operator for usage in the stream (stream_options.include_usage): the last chunk before [DONE] carries the usage object and an empty choices array. That chunk is how a streamed call is charged to the token — expect it if you parse the stream yourself.
Choose a model
The model field takes an ID from the catalogue — gemma-4-26b in these examples. GET /models returns the list as JSON, with no key needed; it holds chat, embedding and image models, and ?kind=chat keeps the first (the reference). An ID Evanesca does not serve answers 404 model_not_found.
curl https://evanesca.app/api/v1/models?kind=chatWhere each model runs, what each operator keeps, which models call tools or reason before they answer: Models and Europe.
Read where it ran
Every chat, embeddings or image response that reached an operator, streamed or not, carries two headers:
| Response header | Value |
|---|---|
x-evanesca-operator | The operator that served the call: mistral, aki, scaleway, ovhcloud or infomaniak. |
x-evanesca-location | Where it ran: paris (Paris, France), gravelines (Gravelines, France), mistral-eu-region (EU region of Mistral AI), germany (Germany) or switzerland (Switzerland). |
curl -i https://evanesca.app/api/v1/chat/completions \
-H "Authorization: Bearer $EVANESCA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "gemma-4-26b", "messages": [{"role": "user", "content": "Hello"}]}'HTTP/2 200
content-type: application/json
x-evanesca-operator: aki
x-evanesca-location: germany