コンテンツにスキップ

Model API

このコンテンツはまだ日本語訳がありません。

The Model API is a plain relay. You send the request your SDK already knows how to build, we send it upstream, and we take credits out of your account for what the call actually used.

It is separate from /open/v1. That surface plays cards on behalf of a signed-in user; this one is for your own code, authenticated with your own key.

Conversation Agent mode does not change this relay: your application still executes tool calls and sends their results back. Server-managed preparation belongs to the conversation API.

Base URL: https://api.harperharbor.com/v1

In the console, open Personal API keys, create a key, and tick Call models directly through the API. Then pick the models this key may call, or tick All models to let it call every model, including models added later.

You can also set a monthly credit limit per key. It stops that key once it has spent that much in a calendar month, and it does not affect your other keys.

POST /v1/chat/completions takes an OpenAI-shaped request. POST /v1/messages takes an Anthropic-shaped one. Either shape works with any model — the conversion happens upstream, so a Claude-shaped request against a DeepSeek model comes back Claude-shaped.

OpenAI SDK
from openai import OpenAI
client = OpenAI(api_key="hh_live_…", base_url="https://api.harperharbor.com/v1")
stream = client.chat.completions.create(
model="deepseek-v4-flash",
messages=[{"role": "user", "content": "Write one line about the sea."}],
stream=True,
)
for chunk in stream:
print(chunk.choices[0].delta.content or "", end="")
Anthropic SDK
from anthropic import Anthropic
client = Anthropic(api_key="hh_live_…", base_url="https://api.harperharbor.com")
message = client.messages.create(
model="deepseek-v4-flash",
max_tokens=256,
messages=[{"role": "user", "content": "Write one line about the sea."}],
)
print(message.content[0].text)
Node
import OpenAI from 'openai'
const client = new OpenAI({ apiKey: 'hh_live_…', baseURL: 'https://api.harperharbor.com/v1' })
const res = await client.chat.completions.create({
model: 'deepseek-v4-flash',
messages: [{ role: 'user', content: 'Write one line about the sea.' }],
})
console.log(res.choices[0].message.content)
curl
curl https://api.harperharbor.com/v1/chat/completions \
-H "Authorization: Bearer hh_live_…" \
-H "Content-Type: application/json" \
-d '{"model":"deepseek-v4-flash","messages":[{"role":"user","content":"hi"}]}'

The Anthropic x-api-key header works too, so an Anthropic SDK needs nothing beyond the base URL.

Terminal window
curl https://api.harperharbor.com/v1/models -H "Authorization: Bearer hh_live_…"
{
"object": "list",
"data": [
{
"id": "deepseek-v3.2-gmicloud",
"object": "model",
"owned_by": "harperharbor",
"type": "chat",
"max_input_tokens": 128000,
"max_output_tokens": 8192,
"pricing": {
"unit": "credits_per_million_tokens",
"input": 1728.86,
"output": 2563.49,
"cached_input": 178.85,
"cache_write": 2161.08
}
}
]
}

The list contains only the models this key may call, so it doubles as a check that the key is configured the way you think it is.

Every entry has a type: chat for the models on this page, image or video for the models of the image and video API.

max_input_tokens and max_output_tokens are what we accept and generate, not the model’s advertised window. They are usually the same thing; where they differ, ours is the one that applies.

One model often runs on several channels, and the price between them can differ several fold. The model id carries the channel: deepseek-v3.2-gmicloud and deepseek-v3.2-vertex are the same model bought from different places, at different prices and with different latency. Pick the id, not just the model — there is no automatic switching, so the channel you name is the channel you get.

Channel names follow one rule: where we buy at a negotiated rate the channel carries our own codename, and where we resell a public marketplace the channel carries that provider’s name.

Prices are credits per million tokens, listed per model and channel in the console and in /v1/models. A call is charged as:

Part Rate
Fresh input tokens input
Cache reads cached_input
Cache writes cache_write
Output tokens output

Input and output round to the nearest credit, cache reads round up, and a billed call costs at least one credit.

Credits are held when the call starts, based on your prompt plus the maximum output you asked for, and settled against real usage when it finishes. A call that produces nothing costs nothing.

If you disconnect mid-stream we close the upstream connection immediately and charge for what was already generated — so stopping early really does stop the meter.

Errors come back in the shape of the endpoint you called: OpenAI-shaped from /v1/chat/completions, Anthropic-shaped from /v1/messages.

Status What happened What to do
401 The key is missing, revoked or expired Create a new key in the console
403 The key has no model permission, or the model is not on its list Add the model to the key, or check /v1/models
404 No such model Take the id from /v1/models
402 Out of credits, or the key hit its monthly limit Top up, or raise the limit
400 The request body is rejected upstream The message is the provider’s own, unchanged
502 The provider did not answer Retry, or use another channel of the same model

Anything the provider says about your request is passed through untouched. Replacing it with our own wording would take away the only thing that tells you what to change.