▲HIGHLAND DOCS

Chat API

POST /v1/chat is a small chat completion endpoint for apps and agents that need a fast, cheap model next to the tools. It is billed per token from the same credits as every API, and it powers the chat in Obsidian and chat.highlnd-intel.group.

Model@cf/zai-org/glm-4.7-flash (GLM 4.7 Flash on Cloudflare Workers AI)
AuthAuthorization: Bearer hk_live_... (or a signed-in session in the browser)
Messagesup to 50, roles system, user, assistant, each up to 16,000 characters
max_tokensdefault 512, max 2048
Priceper 1,000 input and output tokens, live at GET /v1/chat/rates; minimum 1 credit per call
PrivacyPII is redacted before the model sees it. Messages and replies are never logged or stored.

Rates

bash
curl -s https://api.highlnd-intel.group/v1/chat/rates
json
{
  "model": "@cf/zai-org/glm-4.7-flash",
  "markup": 1.35,
  "currency": "CAD",
  "cents_per_1k_in": 0.01,
  "cents_per_1k_out": 0.07,
  "min_charge_cents": 1,
  "max_tokens": { "default": 512, "max": 2048 }
}

The numbers above are an example: always read the live endpoint.

Send a chat

curl
curl -s https://api.highlnd-intel.group/v1/chat \
  -H "authorization: Bearer $HIGHLAND_KEY" \
  -H "content-type: application/json" \
  -d '{
    "messages": [
      {"role": "system", "content": "You are a concise security analyst."},
      {"role": "user", "content": "Explain DMARC p=reject in two sentences."}
    ],
    "max_tokens": 300
  }'
json
{
  "reply": "DMARC p=reject tells receiving mail servers to refuse ...",
  "model": "@cf/zai-org/glm-4.7-flash",
  "tokens_in": 38,
  "tokens_out": 61,
  "charged_cents": 1,
  "balance_cents": 1287
}

The response headers x-highland-charged and x-highland-balance carry the same two numbers, so you can read them without parsing the body.

python
import os, requests

history = [{"role": "system", "content": "Answer in plain English."}]

def ask(text):
    history.append({"role": "user", "content": text})
    r = requests.post("https://api.highlnd-intel.group/v1/chat",
                      headers={"authorization": f"Bearer {os.environ['HIGHLAND_KEY']}"},
                      json={"messages": history[-50:], "max_tokens": 512}, timeout=60)
    r.raise_for_status()
    body = r.json()
    history.append({"role": "assistant", "content": body["reply"]})
    return body["reply"], body["balance_cents"]

print(ask("What is an SPF record?"))
print(ask("And how is DKIM different?"))
javascript
const res = await fetch("https://api.highlnd-intel.group/v1/chat", {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.HIGHLAND_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({ messages: [{ role: "user", content: "Write a commit message for: fix null check in parser" }], max_tokens: 120 }),
});
const { reply, charged_cents } = await res.json();
console.log(reply, `(${charged_cents} credit)`);

How billing works

  1. Hold. Before the model runs, the worst case for your max_tokens is reserved from your balance. If your balance is small, max_tokens is lowered so the worst case fits.
  2. Run. The model answers.
  3. Settle. You are charged the real token cost (never more than the hold), rounded up to the next credit.
  4. Release. The rest of the hold goes back. If the model fails, all of it goes back.

Errors

StatusErrorMeaning
400invalid_jsonThe body is not a JSON object.
400invalid_messagesMissing or malformed messages, more than 50, one over 16,000 characters, a bad role, or no user message.
400invalid_max_tokensmax_tokens is not a whole number from 1 to 2048.
401api_key_required / invalid_api_keyMissing or wrong key.
413body_too_largeThe request body is too big.
402insufficient_creditsBalance too low even for the minimum. Top up or redeem a coupon.
502ai_errorThe model failed. Nothing was charged; retry.
503not_configuredChat is temporarily off.

Free credits from coupons work here, which makes them a good way to try chat and Obsidian.