API reference

Every route on https://api.hakk.ai/v1. Field lists, status codes, streaming events, and account APIs. Download openapi.json for Postman or client generation.

Getting startedAPI referenceOpenAPI

Base URLs

OpenAI-shaped clients use https://api.hakk.ai/v1. The client appends /chat/completions, /responses, or /models.

Claude Code uses https://api.hakk.ai. That client appends /v1/messages itself.

CORS allows any origin. Browser tools can call /v1 with an API key.

Authentication

Send Authorization: Bearer YOUR_API_KEY or the same key as x-api-key. Keys start with hakk_ and are scoped to one organization.

Anthropic clients may send anthropic-version and anthropic-beta. We accept those headers and do not require them.

The key's created_by_user_id is the user for custom instructions and the conversation list. API-key completions persist only when the request includes conversation_id. Otherwise the turn completes and bills, and it does not create a dashboard thread.

A dashboard session is required to create keys, change profile or password, and mutate org members.

RouteAPI keyDashboard session
Inference, models, conversations, usage, billing reads, checkoutYesYes
GET /v1/me, GET /v1/api-keys, DELETE /v1/api-keys/{id}, GET /v1/org/membersYesYes
POST /v1/api-keysNoYes
PATCH /v1/me, POST /v1/me/passwordNoYes
POST/PATCH/DELETE /v1/org/membersNoOwner or org admin

Models

GET https://api.hakk.ai/v1/models requires a key. It returns the OpenAI list envelope {"object":"list","data":[...]}. Rows are enabled models the organization allowlist accepts. Use id (same as model_id) in requests.

GET https://api.hakk.ai/v1/public/models needs no auth. It is the catalog the site prices from: name, display_name, context_window, input_microcredits_per_token, output_microcredits_per_token, listing (featured, alias, compat), and default_effort.

Client IDs qwen-3.6, qwen-3.6-high, and qwen-3.6-fast map to qwen3.6, qwen3.6-high, and qwen3.6-fast.

ModelIDContextListing
Qwen3 Coder 30B A3Bchat-default64Kfeatured
Qwen 3.6qwen3.6256Kfeatured · max thinking
Qwen 3.6 Fastqwen3.6-fast256Kalias · thinking off
Qwen 3.6 Highqwen3.6-high256Kalias · faster thinking

Live prices are on the Models page.

Chat Completions

POST /v1/chat/completions

curl https://api.hakk.ai/v1/chat/completions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3.6",
    "messages": [{"role": "user", "content": "Write a haiku about server racks."}]
  }'
FieldNotes
modelCatalog ID. Required.
messagesArray of role plus content. Roles: system, user, assistant, tool. developer maps to system.
messages[].contentString, or [{"type":"text","text":"..."}]. Image parts are dropped.
messages[].tool_calls / tool_call_idForwarded to the model. Required for tool-result turns.
streamDefault false. See Streaming.
max_tokens / max_completion_tokensEither is accepted. max_completion_tokens fills max_tokens when that field is omitted.
temperature, top_p, stopOptional. stop may be a string or an array of strings.
tools, tool_choiceOpenAI function-tool shape.
inputResponses-shaped body on this path. Used when messages is empty.
conversation_idOptional UUID. Loads and appends server-side history. See Server history.
truncate_from_message_idOptional UUID. Requires conversation_id. Deletes that message and everything after it, then appends messages (may be empty for regenerate).

Unknown fields do not 422.

Success body:

FieldNotes
id, object, created, modelobject is chat.completion. created is a Unix timestamp.
conversation_idUUID when a thread was created or reused. Null for API-key turns that omitted it.
choices[0].messageAssistant content and optional tool_calls. Thinking may be wrapped in <think> tags inside content.
usageprompt_tokens, completion_tokens, total_tokens.

Thinking

Effort is resolved in this order. The first match wins.

  1. reasoning_effort
  2. reasoning.effort
  3. thinking.type equal to disabled (maps to none)
  4. chat_template_kwargs.enable_thinking false (maps to none), or chat_template_kwargs.reasoning_effort
  5. Catalog default_effort for the model
  6. Built-in alias defaults
Client valueMapped effort
max, xhighmax
high, mediumhigh
lowlow
none, off, minimalnone

Alias defaults: qwen3.6, glm-5.3, and glm-5.2 are max. The -high suffix is high. The -fast suffix is none.

We send thinking to the model as chat_template_kwargs. When the model reasons, the stored assistant text is <think>…</think> plus the answer.

Server history

Dashboard sessions persist every turn into a conversation. API keys persist only when conversation_id is set.

With conversation_id, prior messages load from the server and the request's messages are appended. Oldest stored messages drop first when the prompt would exceed the model context window minus a completion reserve. The current request is never dropped for that trim.

truncate_from_message_id deletes that message and everything after it in the same transaction, then appends the request. There is no branch history. Regenerating the last assistant turn sends that id and an empty messages array. Editing a user turn sends that id and the new user message.

Custom instructions from Settings are prepended as a system message when the principal has a user id. That includes API keys created by that user.

Streaming

Set stream to true. Completions uses OpenAI SSE frames ending in data: [DONE].

curl https://api.hakk.ai/v1/chat/completions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3.6",
    "stream": true,
    "messages": [{"role": "user", "content": "hello"}]
  }'

Extra events on the Completions stream:

EventWhen
event: conversationFired first when a conversation id exists. Body: {"conversation_id":"<uuid>"}.
event: queuedFired when the admission queue position is greater than 1. Body: {"position":N}.
: heartbeatComment line every 10 seconds during queue wait, prefill, and silent gaps.
event: errorUpstream died, admission timed out, or the org concurrency cap was hit.

A client disconnect still writes usage and credits for tokens already produced.

Messages

POST /v1/messages. Anthropic Messages body. Same auth, catalog, admission, and credits as Completions.

FieldNotes
modelCatalog ID. Required.
messagesAnthropic turns. content may be a string or blocks (text, tool_use, tool_result, thinking).
systemString or text blocks. Flattened into a system Chat Completions message.
max_tokensRequired by Anthropic clients. Default 4096 if omitted.
stop_sequencesMapped to Completions stop.
toolsAnthropic tools with input_schema. Converted to OpenAI functions.
tool_choiceauto, any/required, none, or {"type":"tool","name":"..."}.
thinkingdisablednone. enabledhigh. adaptivemax.
streamDefault false.

Non-stream response: type: message, content blocks, stop_reason (end_turn, tool_use, max_tokens), and usage.input_tokens / usage.output_tokens.

Stream events:

  • message_start
  • content_block_start, content_block_delta, content_block_stop
  • ping (from Completions heartbeats)
  • message_delta, message_stop

Responses

POST /v1/responses. Thin translator onto Chat Completions. Codex CLI uses this path.

FieldNotes
modelCatalog ID. Required.
inputString or Responses items. Converted to Chat Completions messages.
messagesOptional Chat Completions messages, used if present.
max_output_tokens, max_tokens, max_completion_tokensAll map to Completions max_tokens.
tools, tool_choice, reasoning, reasoning_effort, temperature, streamPassed through the Completions pipeline.

Non-stream body: object: response, status: completed, output[0].content[0].text, and usage.input_tokens / usage.output_tokens.

Stream events include response.created, response.output_text.delta, and response.completed.

Out of scope

These are not served:

  • Vision and image generation
  • Embeddings
  • Legacy /v1/completions
  • Anthropic server tools (computer use, code execution, web search)
  • Responses background jobs, stored outputs, or retrieval

Image parts in multipart content are dropped. Text parts are kept.

Errors

Editor routes (/v1/chat/completions, /v1/messages, /v1/responses, /v1/models) return both envelopes:

{
  "error": {
    "message": "Insufficient credits: your organization's balance is exhausted. Top up at https://hakk.ai/dashboard/billing to continue.",
    "type": "insufficient_quota",
    "code": "insufficient_quota"
  },
  "detail": "Insufficient credits: your organization's balance is exhausted. Top up at https://hakk.ai/dashboard/billing to continue."
}

Other /v1 routes keep FastAPI {"detail": ...}. Validation errors there are a list of type, loc, and msg.

StatusTypeTypical cause
400invalid_request_errorEmpty messages without truncate, or truncate without conversation_id.
401authentication_errorMissing or invalid key.
402insufficient_quotaOrganization balance is at or below zero, or the monthly spend cap is reached.
403permission_errorSuspended org, model allowlist, or a session-only route called with an API key.
404invalid_request_errorUnknown model or conversation.
409invalid_request_errorMember already exists.
422invalid_request_errorSchema validation failed.
429rate_limit_errorOrganization concurrency cap. Waitlist: more than 5 posts per IP per hour.
502server_errorUpstream inference error.
503server_errorAdmission queue timed out. Retry.

Credits

1 credit = $0.01. The ledger stores integer microcredits (1 credit = 1,000,000 microcredits). A model priced at N microcredits per token costs N credits per 1M tokens.

Each successful turn writes a usage event and a debit. Token counts come from the model usage block when present. A disconnect mid-stream falls back to a chunk count and marks the event as estimated.

POST https://api.hakk.ai/v1/billing/checkout body: {"package_id":"starter"}. Returns {"url":"https://checkout.stripe.com/..."}. Invoice organizations cannot self-checkout.

package_idUSDCredits
starter$101,000
builder$252,500 + 125 bonus
scale$10010,000 + 1,000 bonus

POST /v1/billing/webhook is Stripe-only. Auth is the stripe-signature header. Partners do not call it.

Account routes

Conversations

MethodPathBody / queryResponse
GET/v1/conversationsOptional q title searchArray of conversation_id, model_id, title, pinned_at, created_at, updated_at
GET/v1/conversations/{id}Same fields plus messages (message_id, role, content, created_at)
PATCH/v1/conversations/{id}title (1–200), pinned booleanUpdated conversation
DELETE/v1/conversations/{id}204

Profile

MethodPathNotes
GET/v1/meuser_id, org_id, role, auth_method, email, display_name, instructions, kind, billing_mode, org_status, memberships
PATCH/v1/meSession only. Body: display_name (max 200), instructions (max 4000)
POST/v1/me/passwordSession only. Body: current_password, new_password (min 8). 204

API keys

MethodPathNotes
GET/v1/api-keysMetadata only: key_id, name, prefix, last_used_at, expires_at, revoked_at, created_at
POST/v1/api-keysSession only. Body: name, optional expires_at. Response includes api_key once.
DELETE/v1/api-keys/{key_id}Revokes the key. 204

Organization members

MethodPathNotes
GET/v1/org/membersuser_id, email, role, created_at
POST/v1/org/membersSession, owner or admin. Body: email, optional password, role (owner, admin, member). Generated password is returned when we create the user.
PATCH/v1/org/members/{user_id}Session, owner only. Body: {"role":"admin"}. 204
DELETE/v1/org/members/{user_id}Session, owner or admin. You cannot remove yourself. 204

Billing and usage

MethodPathNotes
GET/v1/billing/balancebalance_microcredits, billing_mode, kind
GET/v1/billing/ledgerQuery limit (1–200, default 50). Entries: kind, delta_microcredits, description, created_at
GET/v1/usageQuery limit (1–200), since, until (date or ISO datetime). Rows include tokens, latency_ms, status, cost_microcredits

Public

MethodPathNotes
GET/v1/public/health{"status":"ok","models":N}
GET/v1/public/modelsUnauthenticated catalog with prices.
POST/v1/public/waitlistBody: email, optional name, company, use_case, source (access or gpu). Always 202 with {"status":"ok"}. 5 posts per IP per hour.

Import the machine-readable contract from /openapi.json. Getting started and editor setup stay on the docs page.