跳到主要内容

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 Claude models. 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​

EndpointWhat it doesShapeModels
POST/v1/chat/completions
Chat completions
Send a conversation to a language model and get the next message back. Streams with stream: true.OpenAIText models
POST/v1/responses
Responses
The stateful successor to chat completions, with built-in tools and multi-turn state.OpenAIText models
POST/v1/messages
Messages
Anthropic-style messages for Claude models. Use the Anthropic SDK unchanged.AnthropicClaude models
POST/v1/images/generations
Image generation
Generate images from a text prompt.OpenAIImage models
POST/v1/images/edits
Image edits
Edit an image with a prompt and an optional mask.OpenAIImage models
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.OpenAIVideo models
GET/v1/videos
List video jobs
Your recent video jobs and their states.OpenAIVideo models
GET/v1/videos/{video_id}
Video status
The state of a video job and, once finished, where to download it.OpenAIVideo models
GET/v1/videos/{video_id}/content
Video content
Download the finished video file.OpenAIVideo models
POST/v1/embeddings
Embeddings
Turn text into vectors for search and retrieval.OpenAIEmbedding models
POST/v1/audio/speech
Text to speech
Turn text into spoken audio.OpenAISpeech models
POST/v1/audio/transcriptions
Transcription
Turn an audio file into text.OpenAITranscription models
POST/v1/rerank
Rerank
Order a list of documents by relevance to a query.CohereRerank models
GET/v1/models
List models
Every model your key can call, in OpenAI's list format.OpenAIall keys
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.OceanTokenall keys

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

Text​

/v1/chat/completions is the endpoint most clients use, and the one the first request shows. /v1/responses is the newer stateful API with the same models. Claude models answer on /v1/messages with the Anthropic SDK unchanged.

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.

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. Download it promptly; URLs are not permanent. For edits, send the source image and an optional mask to /v1/images/edits.

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"] in ("completed", "failed"):
break
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, 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).

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."
}'

Speech, transcription, rerank​

/v1/audio/speech takes model, input text and a voice and returns audio bytes. /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; the model's page in the console shows an example for each.

Retries and idempotency​

Retry on 429, 5xx and network failures with backoff; 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.