Saltar al contenido principal
nota
Esta página aún no está traducida, por eso se muestra en inglés.

API reference

Base URL https://api.oceantoken.ai/v1. Authenticate with Authorization: Bearer sk-.... Paths on this page are written out in full, so /v1/chat/completions is https://api.oceantoken.ai/v1/chat/completions.

Which API shape​

OceanToken does not invent request formats for models. Each model endpoint follows one existing API, named in the Shape column below, so the matching official SDK works with only the base URL and key changed:

ShapeEndpointsUse
OpenAIchat completions, responses, images, video, embeddings, speech, transcription, modelsThe OpenAI SDK with base_url="https://api.oceantoken.ai/v1"
Anthropic/v1/messagesThe Anthropic SDK with base_url="https://api.oceantoken.ai", for every chat model. That SDK adds /v1 itself
Cohere/v1/rerankCohere's rerank request: query, documents, top_n
OceanToken/v1/usage/{request_id}Our own, and the only one: what a request cost. See What a request cost

Within a shape, a parameter the chosen model does not support is dropped and the request runs without it. This is what lets one request body work across every model: top_k is meaningful to Claude and not to GPT, logit_bias the other way round, and a request carrying either still succeeds on both. Nothing is rewritten, and a parameter the model does support always reaches it.

The consequence is worth stating plainly: a successful response is not evidence that every parameter you sent took effect. When you depend on one, check the response for it rather than the absence of an error - tool_calls for a function call, tools echoed back for a hosted tool, response_format honoured in the content. A capability a model does not have is not reported as an error, because for most callers that would turn a portable request into a model-specific one.

Check this once at integration time, with the model you will use, rather than discovering in production that a parameter you rely on was never applied.

Endpoints​

EndpointQué haceFormatoModelos
POST/v1/chat/completions
Chat completions
Send a conversation to a language model and get the next message back. Streams with stream: true.OpenAIModelos de texto
POST/v1/responses
Responses
The stateful successor to chat completions, with built-in tools and multi-turn state.OpenAIModelos de texto
POST/v1/messages
Messages
Anthropic-style messages for every chat model, streaming or not. Use the Anthropic SDK unchanged.AnthropicModelos de texto
POST/v1/images/generations
Image generation
Generate images from a text prompt.OpenAIModelos de imagen
POST/v1/images/edits
Image edits
Edit an image with a prompt and an optional mask.OpenAIModelos de imagen
POST/v1/videos
Create a video job
Start a video generation job. Videos take minutes; poll the job, then fetch the finished file. Send an Idempotency-Key so a retry cannot start a second job.OpenAIModelos de video
GET/v1/videos
List video jobs
Your recent video jobs and their states.OpenAIModelos de video
GET/v1/videos/{video_id}
Video status
The state of a video job and, once finished, where to download it.OpenAIModelos de video
GET/v1/videos/{video_id}/content
Video content
Download the finished video file.OpenAIModelos de video
POST/v1/embeddings
Embeddings
Turn text into vectors for search and retrieval.OpenAIModelos de embeddings
POST/v1/audio/speech
Text to speech
Turn text into spoken audio.OpenAIModelos de voz
POST/v1/audio/transcriptions
Transcription
Turn an audio file into text.OpenAIModelos de transcripción
POST/v1/rerank
Rerank
Order a list of documents by relevance to a query.CohereModelos de rerank
GET/v1/models
List models
Every model your key can call, in OpenAI's list format.OpenAItodas las claves
GET/v1/usage/{request_id}
Request cost
What one request cost and the tokens it used, looked up by the id of its response. For streamed responses, whose cost cannot travel in a header.OceanTokentodas las claves

The Models column opens the Models page filtered to the models that endpoint serves; a model's type tells you which endpoint to call.

Text​

Guides: Text generation, Tool calling, Image input.

/v1/chat/completions is the endpoint most clients use, and the one the Quickstart shows. /v1/responses is the newer stateful API with the same models. /v1/messages takes the same models in the Anthropic shape, streaming or not, so the Anthropic SDK works unchanged with GPT, Gemini, DeepSeek and the other chat models as well as Claude.

Streaming​

Set "stream": true on any text endpoint to receive tokens as they are generated. The response is server-sent events (Content-Type: text/event-stream), each event a data: line carrying one JSON chunk in the same format the shape's SDK expects, and the stream ends with data: [DONE]. To receive token counts at the end of a chat-completions stream, send "stream_options": {"include_usage": true}; the last chunk before [DONE] then carries usage. Responses and Messages streams include usage in their own final events. Errors during a stream are described in Errors.

Prompt caching​

A prompt that starts with the same long text on every request, such as instructions, a document or tool definitions, can be read from the model's cache and billed at its Cached input price (on each model's page on oceantoken.ai). GPT, DeepSeek, Qwen and GLM models cache that repeated start on their own.

Claude caches only when the request asks for it. Mark the end of the part to cache with "cache_control": {"type": "ephemeral"} on a content block: everything up to and including that block is written to the cache on the first request and read from it on the next ones. Without the marker every Claude request is billed at the full input price. Claude caches only a prefix above a minimum length, 512 to 4,096 tokens depending on the model (Anthropic's table), and keeps it for five minutes after its last use.

On chat completions, the marker goes on a content part of a message:

# pip install openai
# Claude caches a prompt only when the request marks where the cached part
# ends. On chat completions, put cache_control on a content part: everything up
# to and including that part is cached. The second call reads it from the cache.
import os
from openai import OpenAI

client = OpenAI(
base_url=os.getenv("OCEANTOKEN_BASE_URL", "https://api.oceantoken.ai/v1"),
api_key=os.environ["OCEANTOKEN_API_KEY"],
)

# A long, unchanging prefix: instructions, a document, tool descriptions.
# Claude caches only prefixes above a minimum length (512 to 4,096 tokens,
# depending on the model).
manual = " ".join(f"Rule {i}: answer in plain English and keep it short." for i in range(1, 301))

for question in ["Which rule comes first?", "Which rule comes last?"]:
response = client.chat.completions.create(
model="anthropic/claude-sonnet-4.6",
max_tokens=64,
messages=[
{
"role": "system",
"content": [
{"type": "text", "text": manual, "cache_control": {"type": "ephemeral"}},
],
},
{"role": "user", "content": question},
],
)
details = response.usage.prompt_tokens_details
print("prompt tokens:", response.usage.prompt_tokens, "cached:", details.cached_tokens if details else 0)

On /v1/messages, it goes on a block, here of the system prompt:

# pip install anthropic
# The same on /v1/messages with the Anthropic SDK: cache_control on a block of
# the system prompt caches everything up to and including that block.
import os
import anthropic

client = anthropic.Anthropic(
base_url=os.getenv("OCEANTOKEN_BASE_URL", "https://api.oceantoken.ai/v1").removesuffix("/v1"),
api_key=os.environ["OCEANTOKEN_API_KEY"],
)

manual = " ".join(f"Rule {i}: answer in plain English and keep it short." for i in range(1, 301))

for question in ["Which rule comes first?", "Which rule comes last?"]:
message = client.messages.create(
model="anthropic/claude-sonnet-4.6",
max_tokens=64,
system=[{"type": "text", "text": manual, "cache_control": {"type": "ephemeral"}}],
messages=[{"role": "user", "content": question}],
)
usage = message.usage
print(
"input tokens:", usage.input_tokens,
"cache write:", usage.cache_creation_input_tokens,
"cache read:", usage.cache_read_input_tokens,
)

A hit shows in usage. On chat completions, usage.prompt_tokens_details.cached_tokens is the number of prompt tokens read from the cache, and cache_creation_tokens next to it the number written. On /v1/messages, the same numbers are usage.cache_read_input_tokens and usage.cache_creation_input_tokens, and input_tokens counts only the uncached rest. The console shows each request's cache Hit or Miss under Logs. Cached input is kept per channel, so a request that moves to another channel can miss once.

Images​

# Generate an image. The response carries a URL you can download from.
curl -sS "${OCEANTOKEN_BASE_URL:-https://api.oceantoken.ai/v1}/images/generations" \
-H "Authorization: Bearer $OCEANTOKEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-image-2",
"prompt": "A small lighthouse on a calm sea at dawn, watercolor",
"size": "1024x1024",
"n": 1
}'

The response contains a URL for each image, valid for 24 hours; download what you keep. For edits and reference images, send the source images, and an optional mask, to /v1/images/edits. Sizes, quality, edits, masks and a model's options: Images.

Video​

Video is asynchronous. Submit a job, poll its status, then download the file.

# Video generation is a job: submit it, poll until it is done, then download the file.
# Videos take minutes to render, so never wait on the first request.
import os
import time
import requests

BASE = os.getenv("OCEANTOKEN_BASE_URL", "https://api.oceantoken.ai/v1")
HEADERS = {"Authorization": f"Bearer {os.environ['OCEANTOKEN_API_KEY']}"}

job = requests.post(
f"{BASE}/videos",
headers=HEADERS,
json={
"model": "bytedance/seedance-1-5-pro",
"prompt": "A paper boat drifting down a rain gutter, close up, soft light",
"seconds": "4",
},
timeout=60,
)
if not job.ok:
# The error body says why (see Errors in the docs), e.g. insufficient_credits.
raise SystemExit(f"{job.status_code}: {job.text}")
video_id = job.json()["id"]
print("submitted", video_id)

while True:
status = requests.get(f"{BASE}/videos/{video_id}", headers=HEADERS, timeout=60).json()
if status["status"] not in ("queued", "in_progress"):
break # completed, or failed with an error code and message
time.sleep(10)

if status["status"] != "completed":
raise SystemExit(f"video failed: {status.get('error')}")

content = requests.get(f"{BASE}/videos/{video_id}/content", headers=HEADERS, timeout=120)
content.raise_for_status()
with open(f"{video_id}.mp4", "wb") as f:
f.write(content.content)
print("saved", f"{video_id}.mp4", len(content.content), "bytes")

A job moves through queued → in_progress → completed or failed. POST /v1/videos returns the job with its id and initial state; GET /v1/videos/{video_id} returns the current state, and once it is completed, a content_url to download from, and GET /v1/videos/{video_id}/content streams the file. Rendering takes minutes, so poll every 10 to 20 seconds rather than continuously; GET /v1/videos lists your recent jobs if you lose an id.

A job's estimated cost is held against your balance when it starts and settled to the actual cost when it finishes; a failed job is not charged. Download URLs are valid for 24 hours. Send an Idempotency-Key with the POST so a retry after a timeout cannot start a second job (see below).

Image to video, first and last frames, reference images, video and audio, duration, resolution, sound, and what a failed job's error means: Video.

Embeddings​

# Embeddings for search and retrieval.
curl -sS "${OCEANTOKEN_BASE_URL:-https://api.oceantoken.ai/v1}/embeddings" \
-H "Authorization: Bearer $OCEANTOKEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "baai/bge-m3",
"input": "The lighthouse keeper rowed out before dawn."
}'

Batching, dimensions and rerank: Embeddings and rerank.

Speech, transcription, rerank​

/v1/audio/speech takes model, input text and a voice and returns audio bytes. voice is required, and its names belong to the model. /v1/audio/transcriptions takes a multipart upload with model and file and returns text. /v1/rerank takes a query and documents and returns them scored. Speech and transcription follow the OpenAI request shape, rerank the Cohere one. Samples, the voices each speech model takes, and subtitles: Speech and transcription and Embeddings and rerank.

Retries and idempotency​

Retry with backoff on 429, on any 5xx except 501, and on network failures; never on other 4xx. On the endpoints that cost money to run - /v1/images/generations, /v1/images/edits, /v1/videos and /v1/audio/speech - send an Idempotency-Key header so a retry replays the first answer instead of running again:

#!/usr/bin/env bash
# Retry a billable request safely: the same Idempotency-Key with the same body
# replays the first response instead of generating (and charging) again.
set -euo pipefail
BASE_URL="${OCEANTOKEN_BASE_URL:-https://api.oceantoken.ai/v1}"
KEY="demo-$(date +%s)-$RANDOM"
BODY='{"model": "openai/gpt-image-2", "prompt": "A paper boat on a pond at dawn", "size": "1024x1024", "quality": "low"}'

first=$(curl -s "$BASE_URL/images/generations" \
-H "Authorization: Bearer $OCEANTOKEN_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $KEY" \
-d "$BODY")
# An error answer is replayed too, so check the first call made an image.
grep -q '"data"' <<<"$first" || { echo "request failed: $first" >&2; exit 1; }

# The retry: identical key and body. Nothing runs; the stored answer comes back
# with the header Idempotency-Replayed: true.
second=$(curl -s -D /tmp/idem-headers "$BASE_URL/images/generations" \
-H "Authorization: Bearer $OCEANTOKEN_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $KEY" \
-d "$BODY")

grep -qi '^idempotency-replayed: true' /tmp/idem-headers
[ "$first" = "$second" ]
echo "replayed: identical response, charged once"

The rules (24-hour window, 409 on reuse with a different body, Retry-After while the first call runs) are in Errors.

What a request cost​

Every successful response includes usage, and every request appears in the console under Logs with what it was charged. To read the cost from code:

  • A non-streaming response carries it in the header x-oceantoken-cost, in US dollars, rounded to four significant figures. Your balance is charged the exact amount.
  • A streamed chat completion cannot: headers are sent before the first token, and the cost is known only after the last. Look it up afterwards with GET /v1/usage/{request_id}, where request_id is the id of the completion. Every chunk of a stream carries it.
curl https://api.oceantoken.ai/v1/usage/$REQUEST_ID \
-H "Authorization: Bearer $OCEANTOKEN_API_KEY"

The answer has id, model, cost (US dollars, four significant figures), status, usage with prompt_tokens, completion_tokens and total_tokens, started_at, ended_at and duration_ms.

  • Use the key that made the request. With any other key the answer is 404, so the endpoint never confirms that someone else's request exists.
  • The cost is recorded a few seconds after the request finishes, and until then the answer is also 404. Retry after a few seconds.
  • The lookup takes the id in the response body, not the x-oceantoken-request-id header described in Errors.

Errors are described in Errors.