curl https://compute.prentis.ai/v1/chat/completions \
-H "Authorization: Bearer $PRENTIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-v4.1-flash",
"messages": [
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "Summarise the CAP theorem in two sentences."}
],
"max_tokens": 200,
"temperature": 0.7
}'import os
from openai import OpenAI
client = OpenAI(base_url="https://compute.prentis.ai/v1", api_key=os.environ["PRENTIS_API_KEY"])
resp = client.chat.completions.create(
model="deepseek-v4.1-flash",
messages=[
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "Summarise the CAP theorem in two sentences."},
],
max_tokens=200,
temperature=0.7,
)
print(resp.choices[0].message.content)
print(resp.usage.total_tokens, "tokens billed")import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://compute.prentis.ai/v1",
apiKey: process.env.PRENTIS_API_KEY,
});
const resp = await client.chat.completions.create({
model: "deepseek-v4.1-flash",
messages: [
{ role: "system", content: "You are a concise assistant." },
{ role: "user", content: "Summarise the CAP theorem in two sentences." },
],
max_tokens: 200,
temperature: 0.7,
});
console.log(resp.choices[0]?.message.content);const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
model: '<string>',
messages: [
{
content: '<string>',
name: '<string>',
tool_calls: [
{
id: '<string>',
type: 'function',
function: {name: '<string>', arguments: '<string>'}
}
],
tool_call_id: '<string>'
}
],
stream: false,
stream_options: {include_usage: false},
max_tokens: 2,
max_completion_tokens: 2,
temperature: 1,
top_p: 1,
stop: '<string>',
seed: 123,
frequency_penalty: 0,
presence_penalty: 0,
user: '<string>',
tools: [{type: 'function', function: {name: '<string>', parameters: {}, strict: true}}],
response_format: {json_schema: {}},
service_tier: 'standard',
n: 1,
logprobs: false
})
};
fetch('https://compute.prentis.ai/v1/chat/completions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://compute.prentis.ai/v1/chat/completions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'model' => '<string>',
'messages' => [
[
'content' => '<string>',
'name' => '<string>',
'tool_calls' => [
[
'id' => '<string>',
'type' => 'function',
'function' => [
'name' => '<string>',
'arguments' => '<string>'
]
]
],
'tool_call_id' => '<string>'
]
],
'stream' => false,
'stream_options' => [
'include_usage' => false
],
'max_tokens' => 2,
'max_completion_tokens' => 2,
'temperature' => 1,
'top_p' => 1,
'stop' => '<string>',
'seed' => 123,
'frequency_penalty' => 0,
'presence_penalty' => 0,
'user' => '<string>',
'tools' => [
[
'type' => 'function',
'function' => [
'name' => '<string>',
'parameters' => [
],
'strict' => true
]
]
],
'response_format' => [
'json_schema' => [
]
],
'service_tier' => 'standard',
'n' => 1,
'logprobs' => false
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://compute.prentis.ai/v1/chat/completions"
payload := strings.NewReader("{\n \"model\": \"<string>\",\n \"messages\": [\n {\n \"content\": \"<string>\",\n \"name\": \"<string>\",\n \"tool_calls\": [\n {\n \"id\": \"<string>\",\n \"type\": \"function\",\n \"function\": {\n \"name\": \"<string>\",\n \"arguments\": \"<string>\"\n }\n }\n ],\n \"tool_call_id\": \"<string>\"\n }\n ],\n \"stream\": false,\n \"stream_options\": {\n \"include_usage\": false\n },\n \"max_tokens\": 2,\n \"max_completion_tokens\": 2,\n \"temperature\": 1,\n \"top_p\": 1,\n \"stop\": \"<string>\",\n \"seed\": 123,\n \"frequency_penalty\": 0,\n \"presence_penalty\": 0,\n \"user\": \"<string>\",\n \"tools\": [\n {\n \"type\": \"function\",\n \"function\": {\n \"name\": \"<string>\",\n \"parameters\": {},\n \"strict\": true\n }\n }\n ],\n \"response_format\": {\n \"json_schema\": {}\n },\n \"service_tier\": \"standard\",\n \"n\": 1,\n \"logprobs\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://compute.prentis.ai/v1/chat/completions")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"model\": \"<string>\",\n \"messages\": [\n {\n \"content\": \"<string>\",\n \"name\": \"<string>\",\n \"tool_calls\": [\n {\n \"id\": \"<string>\",\n \"type\": \"function\",\n \"function\": {\n \"name\": \"<string>\",\n \"arguments\": \"<string>\"\n }\n }\n ],\n \"tool_call_id\": \"<string>\"\n }\n ],\n \"stream\": false,\n \"stream_options\": {\n \"include_usage\": false\n },\n \"max_tokens\": 2,\n \"max_completion_tokens\": 2,\n \"temperature\": 1,\n \"top_p\": 1,\n \"stop\": \"<string>\",\n \"seed\": 123,\n \"frequency_penalty\": 0,\n \"presence_penalty\": 0,\n \"user\": \"<string>\",\n \"tools\": [\n {\n \"type\": \"function\",\n \"function\": {\n \"name\": \"<string>\",\n \"parameters\": {},\n \"strict\": true\n }\n }\n ],\n \"response_format\": {\n \"json_schema\": {}\n },\n \"service_tier\": \"standard\",\n \"n\": 1,\n \"logprobs\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://compute.prentis.ai/v1/chat/completions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"model\": \"<string>\",\n \"messages\": [\n {\n \"content\": \"<string>\",\n \"name\": \"<string>\",\n \"tool_calls\": [\n {\n \"id\": \"<string>\",\n \"type\": \"function\",\n \"function\": {\n \"name\": \"<string>\",\n \"arguments\": \"<string>\"\n }\n }\n ],\n \"tool_call_id\": \"<string>\"\n }\n ],\n \"stream\": false,\n \"stream_options\": {\n \"include_usage\": false\n },\n \"max_tokens\": 2,\n \"max_completion_tokens\": 2,\n \"temperature\": 1,\n \"top_p\": 1,\n \"stop\": \"<string>\",\n \"seed\": 123,\n \"frequency_penalty\": 0,\n \"presence_penalty\": 0,\n \"user\": \"<string>\",\n \"tools\": [\n {\n \"type\": \"function\",\n \"function\": {\n \"name\": \"<string>\",\n \"parameters\": {},\n \"strict\": true\n }\n }\n ],\n \"response_format\": {\n \"json_schema\": {}\n },\n \"service_tier\": \"standard\",\n \"n\": 1,\n \"logprobs\": false\n}"
response = http.request(request)
puts response.read_body{
"id": "chatcmpl-01K5S8N4Q2VZ",
"object": "chat.completion",
"created": 1789286400,
"model": "deepseek-v4.1-flash",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "A distributed store can hold at most two of consistency, availability and partition tolerance at once. Because partitions do happen in practice, the real choice is between answering with stale data and not answering at all."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 28,
"completion_tokens": 47,
"total_tokens": 75
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}Chat completions
OpenAI-compatible chat completion. Point any OpenAI SDK at this base URL with a Prentis key and nothing else in your code changes.
curl https://compute.prentis.ai/v1/chat/completions \
-H "Authorization: Bearer $PRENTIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-v4.1-flash",
"messages": [
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "Summarise the CAP theorem in two sentences."}
],
"max_tokens": 200,
"temperature": 0.7
}'import os
from openai import OpenAI
client = OpenAI(base_url="https://compute.prentis.ai/v1", api_key=os.environ["PRENTIS_API_KEY"])
resp = client.chat.completions.create(
model="deepseek-v4.1-flash",
messages=[
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "Summarise the CAP theorem in two sentences."},
],
max_tokens=200,
temperature=0.7,
)
print(resp.choices[0].message.content)
print(resp.usage.total_tokens, "tokens billed")import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://compute.prentis.ai/v1",
apiKey: process.env.PRENTIS_API_KEY,
});
const resp = await client.chat.completions.create({
model: "deepseek-v4.1-flash",
messages: [
{ role: "system", content: "You are a concise assistant." },
{ role: "user", content: "Summarise the CAP theorem in two sentences." },
],
max_tokens: 200,
temperature: 0.7,
});
console.log(resp.choices[0]?.message.content);const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
model: '<string>',
messages: [
{
content: '<string>',
name: '<string>',
tool_calls: [
{
id: '<string>',
type: 'function',
function: {name: '<string>', arguments: '<string>'}
}
],
tool_call_id: '<string>'
}
],
stream: false,
stream_options: {include_usage: false},
max_tokens: 2,
max_completion_tokens: 2,
temperature: 1,
top_p: 1,
stop: '<string>',
seed: 123,
frequency_penalty: 0,
presence_penalty: 0,
user: '<string>',
tools: [{type: 'function', function: {name: '<string>', parameters: {}, strict: true}}],
response_format: {json_schema: {}},
service_tier: 'standard',
n: 1,
logprobs: false
})
};
fetch('https://compute.prentis.ai/v1/chat/completions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://compute.prentis.ai/v1/chat/completions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'model' => '<string>',
'messages' => [
[
'content' => '<string>',
'name' => '<string>',
'tool_calls' => [
[
'id' => '<string>',
'type' => 'function',
'function' => [
'name' => '<string>',
'arguments' => '<string>'
]
]
],
'tool_call_id' => '<string>'
]
],
'stream' => false,
'stream_options' => [
'include_usage' => false
],
'max_tokens' => 2,
'max_completion_tokens' => 2,
'temperature' => 1,
'top_p' => 1,
'stop' => '<string>',
'seed' => 123,
'frequency_penalty' => 0,
'presence_penalty' => 0,
'user' => '<string>',
'tools' => [
[
'type' => 'function',
'function' => [
'name' => '<string>',
'parameters' => [
],
'strict' => true
]
]
],
'response_format' => [
'json_schema' => [
]
],
'service_tier' => 'standard',
'n' => 1,
'logprobs' => false
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://compute.prentis.ai/v1/chat/completions"
payload := strings.NewReader("{\n \"model\": \"<string>\",\n \"messages\": [\n {\n \"content\": \"<string>\",\n \"name\": \"<string>\",\n \"tool_calls\": [\n {\n \"id\": \"<string>\",\n \"type\": \"function\",\n \"function\": {\n \"name\": \"<string>\",\n \"arguments\": \"<string>\"\n }\n }\n ],\n \"tool_call_id\": \"<string>\"\n }\n ],\n \"stream\": false,\n \"stream_options\": {\n \"include_usage\": false\n },\n \"max_tokens\": 2,\n \"max_completion_tokens\": 2,\n \"temperature\": 1,\n \"top_p\": 1,\n \"stop\": \"<string>\",\n \"seed\": 123,\n \"frequency_penalty\": 0,\n \"presence_penalty\": 0,\n \"user\": \"<string>\",\n \"tools\": [\n {\n \"type\": \"function\",\n \"function\": {\n \"name\": \"<string>\",\n \"parameters\": {},\n \"strict\": true\n }\n }\n ],\n \"response_format\": {\n \"json_schema\": {}\n },\n \"service_tier\": \"standard\",\n \"n\": 1,\n \"logprobs\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://compute.prentis.ai/v1/chat/completions")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"model\": \"<string>\",\n \"messages\": [\n {\n \"content\": \"<string>\",\n \"name\": \"<string>\",\n \"tool_calls\": [\n {\n \"id\": \"<string>\",\n \"type\": \"function\",\n \"function\": {\n \"name\": \"<string>\",\n \"arguments\": \"<string>\"\n }\n }\n ],\n \"tool_call_id\": \"<string>\"\n }\n ],\n \"stream\": false,\n \"stream_options\": {\n \"include_usage\": false\n },\n \"max_tokens\": 2,\n \"max_completion_tokens\": 2,\n \"temperature\": 1,\n \"top_p\": 1,\n \"stop\": \"<string>\",\n \"seed\": 123,\n \"frequency_penalty\": 0,\n \"presence_penalty\": 0,\n \"user\": \"<string>\",\n \"tools\": [\n {\n \"type\": \"function\",\n \"function\": {\n \"name\": \"<string>\",\n \"parameters\": {},\n \"strict\": true\n }\n }\n ],\n \"response_format\": {\n \"json_schema\": {}\n },\n \"service_tier\": \"standard\",\n \"n\": 1,\n \"logprobs\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://compute.prentis.ai/v1/chat/completions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"model\": \"<string>\",\n \"messages\": [\n {\n \"content\": \"<string>\",\n \"name\": \"<string>\",\n \"tool_calls\": [\n {\n \"id\": \"<string>\",\n \"type\": \"function\",\n \"function\": {\n \"name\": \"<string>\",\n \"arguments\": \"<string>\"\n }\n }\n ],\n \"tool_call_id\": \"<string>\"\n }\n ],\n \"stream\": false,\n \"stream_options\": {\n \"include_usage\": false\n },\n \"max_tokens\": 2,\n \"max_completion_tokens\": 2,\n \"temperature\": 1,\n \"top_p\": 1,\n \"stop\": \"<string>\",\n \"seed\": 123,\n \"frequency_penalty\": 0,\n \"presence_penalty\": 0,\n \"user\": \"<string>\",\n \"tools\": [\n {\n \"type\": \"function\",\n \"function\": {\n \"name\": \"<string>\",\n \"parameters\": {},\n \"strict\": true\n }\n }\n ],\n \"response_format\": {\n \"json_schema\": {}\n },\n \"service_tier\": \"standard\",\n \"n\": 1,\n \"logprobs\": false\n}"
response = http.request(request)
puts response.read_body{
"id": "chatcmpl-01K5S8N4Q2VZ",
"object": "chat.completion",
"created": 1789286400,
"model": "deepseek-v4.1-flash",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "A distributed store can hold at most two of consistency, availability and partition tolerance at once. Because partitions do happen in practice, the real choice is between answering with stale data and not answering at all."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 28,
"completion_tokens": 47,
"total_tokens": 75
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}{
"error": {
"message": "<string>",
"type": "invalid_request_error",
"code": "INVALID_API_KEY",
"param": "<string>"
}
}Streaming
Withstream: true the response is text/event-stream: one data: event per chunk,
terminated by data: [DONE]. The last data event carries usage whether or not you
sent stream_options.include_usage — you never have to choose between streaming and
knowing what you were billed.
If a stream fails partway, chunks already sent are not withdrawn. You get one more event
carrying an error object, then [DONE]. Treat a stream that ended without [DONE] as
incomplete.
Token accounting
Theusage object is the number you are billed on, not an estimate of it. When a stream is
cancelled after the model has begun producing output, those tokens are still billed — see
Errors for the two codes where that happens.Authorizations
Authorization: Bearer <your API key>. On /v1/messages, the Anthropic-style x-api-key: <your API key> header is accepted instead.
Headers
Your own key for making a retry safe (up to 255 characters). It is accepted and echoed back today; de-duplication of replays arrives in a later release, so a retry is currently a second billable call.
255Body
Which model answers the call. A bare slug for platform models (deepseek-v4.1-flash), or a full resource name for something your account owns (accounts/{account}/models/{model}, or a deployment). Never an upstream vendor's own name.
256The conversation so far, oldest first. Each turn carries a role (system, user, assistant or tool) and its content.
1Show child attributes
Show child attributes
Return the answer as server-sent events as it is generated, instead of one response at the end. The last data event carries the usage numbers either way.
Streaming options. include_usage is accepted for compatibility; usage arrives on the final event whether or not you ask for it.
Show child attributes
Show child attributes
Ceiling on how many tokens may be generated. Omit it to use the model's own default.
x >= 1Ceiling on generated tokens. Wins over max_tokens when both are sent.
x >= 1How much randomness to allow when picking each token. Lower is more repeatable, higher is more varied.
0 <= x <= 2Nucleus sampling: only consider the most likely tokens up to this share of the probability mass. Tune this or temperature, not both.
0 <= x <= 1Up to 4 strings that end generation as soon as the model produces one. The matched string is not included in the output.
Best effort repeatability: the same seed with the same parameters returns the same answer on models that support it.
Pushes the model away from tokens it has already used often in this answer. Negative values do the opposite.
-2 <= x <= 2Pushes the model away from tokens that have appeared at all in this answer, which tends to move it on to new ground.
-2 <= x <= 2Your own identifier for the end user behind the call. It is echoed back in this request's log line so you can correlate the two; it is not kept on the usage record.
256Function definitions the model may call. If none of the providers that can serve this model support tools, the call is rejected rather than answered as though you had not asked.
Show child attributes
Show child attributes
Whether the model may, must, or must not call a tool: none, auto, required, or one named function.
none, auto, required Ask for free text, a JSON object, or JSON matching a schema. Rejected if no provider behind this model can honour it.
Show child attributes
Show child attributes
Which service tier serves the call. Only standard is accepted today.
standard, priority, fast How many completions to return.
Only 1 is accepted. Any other value returns INVALID_REQUEST.
Per-token log probabilities.
Only false is accepted. true returns INVALID_REQUEST.
Response
OK. With stream: true the same call answers text/event-stream instead, one chunk per event, terminated by data: [DONE]; the last data event carries usage whether or not you asked for it.