PLATINUM DOCS

Inference

OpenAI-compatible model inference: one fixed price per model, zero data retention, billed per token from your credits.

Inference serves large language models behind an OpenAI-compatible API. Use any OpenAI client: set the base URL and an API key, then call chat completions.

  • One price per model. Every model has one fixed price per token, at all hours. The price is in GET /v1/inference/models and on every response as usage.cost.
  • Zero data retention. Prompts and outputs are never stored or used for training.
  • Tools, vision and reasoning. Function calling on every model; image input and reasoning_effort where the model lists them.
  • Billed from your credits, per token, like every other Platinum meter.

Early access

Inference is in early access. An organization without access gets 404 or 403 inference_not_enabled. Request access and say which models and volume you need.

Base URL and authentication

SettingValue
Base URLhttps://api.platinum.dev/v1/inference
AuthAuthorization: Bearer pt_live_…
Scopeinference (inference:read lists models and usage; inference:write sends completions)

Create a key with the inference scope:

  • Dashboard: Inference tab → Create an inference key, or API keys → new key → scope Inference.
  • CLI: pt key create --name inference --scope inference
  • API: POST /v1/auth/api-keys with {"name": "inference", "scopes": ["inference"]} (needs a * key or a dashboard session).

The key is shown once. See API keys.

Quickstart

curl https://api.platinum.dev/v1/inference/chat/completions \
  -H "Authorization: Bearer $PLATINUM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4.1-flash",
    "messages": [{"role": "user", "content": "What is 2 + 2? Answer with the number only."}]
  }'
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.platinum.dev/v1/inference",
    api_key=os.environ["PLATINUM_API_KEY"],
)

completion = client.chat.completions.create(
    model="deepseek-v4.1-flash",
    messages=[{"role": "user", "content": "What is 2 + 2? Answer with the number only."}],
)
print(completion.choices[0].message.content)
print(completion.usage)  # includes `cost` in USD
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.platinum.dev/v1/inference",
  apiKey: process.env.PLATINUM_API_KEY,
});

const completion = await client.chat.completions.create({
  model: "deepseek-v4.1-flash",
  messages: [{ role: "user", content: "What is 2 + 2? Answer with the number only." }],
});
console.log(completion.choices[0].message.content);

The response is the OpenAI chat completion object. usage.cost is what the request cost, in USD.

Streaming

Set stream: true. The response is server-sent events, ending with data: [DONE]. Ask for stream_options.include_usage to get a final chunk with usage (including cost). Lines starting with : are keepalive comments; skip them, as every SSE client does.

stream = client.chat.completions.create(
    model="glm-5.3-flash",
    messages=[{"role": "user", "content": "Count from 1 to 5."}],
    stream=True,
    stream_options={"include_usage": True},
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="")
    if chunk.usage:
        print("\ncost:", chunk.usage.cost)
const stream = await client.chat.completions.create({
  model: "glm-5.3-flash",
  messages: [{ role: "user", content: "Count from 1 to 5." }],
  stream: true,
  stream_options: { include_usage: true },
});
for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
  if (chunk.usage) console.log("\ncost:", (chunk.usage as any).cost);
}

Tool calling

Pass tools as in the OpenAI API. Send the tool result back as a tool message.

import json

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Weather for a city",
        "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]},
    },
}]
messages = [{"role": "user", "content": "What is the weather in Paris? Use the tool."}]

first = client.chat.completions.create(model="deepseek-v4.1-flash", messages=messages, tools=tools)
call = first.choices[0].message.tool_calls[0]
print(call.function.name, json.loads(call.function.arguments))

messages += [first.choices[0].message, {"role": "tool", "tool_call_id": call.id, "content": '{"temp_c": 21, "sky": "sunny"}'}]
final = client.chat.completions.create(model="deepseek-v4.1-flash", messages=messages, tools=tools)
print(final.choices[0].message.content)

Vision

On models whose modalities.input includes image, send an image_url content part: an https:// URL or a data: URL.

completion = client.chat.completions.create(
    model="deepseek-v4.1-flash",
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": "Describe this image in one sentence."},
            {"type": "image_url", "image_url": {"url": "https://platinum.dev/brand/platinum-app-icon-dark-512.png"}},
        ],
    }],
)

Reasoning effort

Set reasoning_effort to one of the model's reasoning_efforts. Lower effort answers faster with fewer reasoning tokens. Reasoning tokens are output tokens and are billed as such; the reasoning text is in message.reasoning_content.

completion = client.chat.completions.create(
    model="glm-5.3-flash",
    reasoning_effort="low",
    messages=[{"role": "user", "content": "Is 7 prime? Answer yes or no."}],
)

A value the model does not list returns 400.

List models

GET /v1/inference/models returns the models your organization can call, in order of preference.

curl https://api.platinum.dev/v1/inference/models -H "Authorization: Bearer $PLATINUM_API_KEY"

Usage and billing

  • Metered per token at the model's price: input, cached input and output. Cached input is the part of the prompt the model served from its prompt cache; it costs less. Repeat a long, stable prefix (system prompt, tool definitions, documents) at the start of your messages to benefit.
  • Every response carries usage.cost in USD; streams carry it on the final usage chunk.
  • Charged from your credits, on the billing page with your other usage. Spend limits apply: an organization or member over its limit gets 402.
  • An aborted stream is billed for the tokens it produced.

GET /v1/inference/usage?hours=720 returns your organization's usage: totals, per model, and a series (hourly up to 48 h, daily beyond).

curl "https://api.platinum.dev/v1/inference/usage?hours=24" -H "Authorization: Bearer $PLATINUM_API_KEY"
{
  "hours": 24, "days": 1, "bucket": "hour",
  "totals": { "requests": 12, "input_tokens": 4810, "cached_input_tokens": 2048, "output_tokens": 913, "cost_usd": 0.0026 },
  "models": [{ "model": "deepseek-v4.1-flash", "requests": 12, "input_tokens": 4810, "cached_input_tokens": 2048, "output_tokens": 913, "cost_usd": 0.0026 }],
  "series": [{ "start": "2026-10-22T00:00:00.000Z", "requests": 0, "input_tokens": 0, "cached_input_tokens": 0, "output_tokens": 0, "cost_usd": 0 }]
}

The dashboard Inference tab shows the same usage for 24 h, 7 d and 30 d, the model list with prices, quickstart snippets and a playground.

Errors

Errors use the OpenAI shape: {"error": {"message", "type", "code"}}.

StatusMeaningWhat to do
400 / 413 / 422The request is invalid (bad messages, context too long, unsupported reasoning_effort). The message explains why.Fix the request. Do not retry unchanged.
401Missing or invalid API keyCheck the key
403 inference_not_enabledYour organization has no Inference accessRequest access
403 scopeThe key lacks the inference scopeUse a key with inference
404Inference is not available to your organizationRequest access
402 insufficient_creditsNo credits left, or a spend limit is reachedAdd credits or raise the limit
429The model is busyRetry with exponential backoff, starting at 1 s
503The model is temporarily unavailableRetry with backoff

Inference retries internally before it returns 429 or 503, so a retry after a short wait usually succeeds.

Limits

  • Context and output limits per model are in GET /v1/inference/models.
  • Inference requests do not count against the per-organization write rate limit; your spend limits apply instead.