mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-07-27 04:31:57 +00:00
fix(docs): every published quickstart was dead on arrival
Two independent defects made every documented 'first API call' fail: 1. FICTIONAL MODEL IDS. `zen-omni` and `zen-coder` appear ZERO times in the live catalog (api.hanzo.ai/v1/models, 440 models). Every SDK sample - python, typescript, go, cpp, swift, kotlin - told the customer to call a model that does not exist, so even a correct request 400s. Corrected to the real ids: zen5 and zen5-coder. 2. DEAD HOST + STALE PINNED MODEL. llm.hanzo.ai is retired and 301s (a POST returns the literal string 'Permanent Redirect', not a completion), and `claude-sonnet-4-5-20250929` is long superseded. Both removed: the host is gone from customer-facing docs entirely rather than documented as retired, and pinned upstream ids give way to our own current zen5. 50 files. Verified against the live catalog, not assumed.
This commit is contained in:
@@ -119,7 +119,7 @@ jobs:
|
||||
-p "{\"spec\":{\"image\":{\"tag\":\"${GITHUB_SHA}\"}}}"
|
||||
./kubectl -n hanzo rollout status deploy/docs --timeout=300s
|
||||
|
||||
# Re-index search (search.hanzo.ai) + the zen-coder-flash doc chat so both
|
||||
# Re-index search (search.hanzo.ai) + the zen5-coder-flash doc chat so both
|
||||
# answer from the just-shipped content. Best-effort — never block a deploy.
|
||||
- name: Re-index docs corpus
|
||||
continue-on-error: true
|
||||
|
||||
@@ -259,7 +259,7 @@ export default function PlatformPage() {
|
||||
<div className="flex flex-col items-center gap-0.5 text-fd-muted-foreground/40">
|
||||
<span className="text-[10px] font-mono">AI API</span>
|
||||
<span className="text-xs">|</span>
|
||||
<span className="text-[10px] font-mono">llm.hanzo.ai</span>
|
||||
<span className="text-[10px] font-mono">api.hanzo.ai/v1</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1600,7 +1600,7 @@ Example:
|
||||
agents: {
|
||||
defaults: {
|
||||
models: {
|
||||
"anthropic/claude-sonnet-4-5-20250929": {
|
||||
"anthropic/zen5": {
|
||||
params: { temperature: 0.6 }
|
||||
},
|
||||
"openai/gpt-5.2": {
|
||||
|
||||
@@ -184,7 +184,7 @@ export default function Page() {
|
||||
<span className="text-blue-400">{'"model"'}</span>
|
||||
{': '}
|
||||
<span className="text-green-400">
|
||||
{'"claude-sonnet-4-5-20250929"'}
|
||||
{'"zen5"'}
|
||||
</span>
|
||||
{',\n'}
|
||||
{' '}
|
||||
|
||||
@@ -16,7 +16,7 @@ import { Agent, Runtime } from '@hanzo/agents'
|
||||
|
||||
const agent = new Agent({
|
||||
name: 'researcher',
|
||||
model: 'claude-sonnet-4-5-20250929',
|
||||
model: 'zen5',
|
||||
brain: { org: 'startx' }, // shared memory
|
||||
tools: ['search', 'fetch', 'brain.recall'],
|
||||
})
|
||||
@@ -30,7 +30,7 @@ from hanzo_agents import Agent, Runtime
|
||||
|
||||
agent = Agent(
|
||||
name="researcher",
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
model="zen5",
|
||||
brain={"org": "startx"},
|
||||
tools=["search", "fetch", "brain.recall"],
|
||||
)
|
||||
|
||||
@@ -57,20 +57,7 @@ Widget keys are designed for client-side use. They have restricted scopes -- typ
|
||||
- **Rate limit** -- requests per minute cap
|
||||
7. Copy the key immediately -- it will not be shown again
|
||||
|
||||
### Via the API
|
||||
|
||||
```bash
|
||||
curl -X POST https://llm.hanzo.ai/key/generate \
|
||||
-H "Authorization: Bearer hk-your-admin-key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"key_alias": "ci-pipeline",
|
||||
"max_budget": 100.0,
|
||||
"budget_duration": "monthly",
|
||||
"tpm_limit": 100000,
|
||||
"rpm_limit": 600
|
||||
}'
|
||||
```
|
||||
Key issuance, budgets, and revocation are console operations — there is no public key-minting endpoint, by design: a credential that can mint credentials is the one thing you never want reachable over HTTP with a bearer token.
|
||||
|
||||
## Using Keys
|
||||
|
||||
@@ -80,14 +67,17 @@ All Hanzo APIs accept keys via the `Authorization` header with the `Bearer` sche
|
||||
Authorization: Bearer hk-proj-abc123...
|
||||
```
|
||||
|
||||
This works uniformly across every endpoint:
|
||||
Every service answers on the one host, `api.hanzo.ai`, under `/v1/<service>` — the same key works across all of them:
|
||||
|
||||
| Service | Base URL | Example |
|
||||
|---------|----------|---------|
|
||||
| API Gateway | `api.hanzo.ai` | `api.hanzo.ai/v1/models` |
|
||||
| AI API | `llm.hanzo.ai` | `llm.hanzo.ai/v1/chat/completions` |
|
||||
| Service | Path | Example |
|
||||
|---------|------|---------|
|
||||
| AI | `/v1/chat/completions`, `/v1/models`, `/v1/embeddings` | `api.hanzo.ai/v1/chat/completions` |
|
||||
| Search | `/v1/search` | `api.hanzo.ai/v1/search` |
|
||||
| Secrets | `/v1/kms` | `api.hanzo.ai/v1/kms/orgs/{org}/secrets` |
|
||||
| Deploys | `/v1/platform` | `api.hanzo.ai/v1/platform/projects` |
|
||||
| Analytics | `/v1/analytics` | `api.hanzo.ai/v1/analytics/overview` |
|
||||
| Observability | `/v1/o11y` | `api.hanzo.ai/v1/o11y/status?product=cloud` |
|
||||
| Tasks | `tasks-api.hanzo.ai` | gRPC with metadata header |
|
||||
| Search | `search.hanzo.ai` | `search.hanzo.ai/v1/search` |
|
||||
|
||||
### SDK Configuration
|
||||
|
||||
@@ -96,13 +86,13 @@ All official SDKs accept the API key as a constructor parameter:
|
||||
```python
|
||||
# Python
|
||||
from openai import OpenAI
|
||||
client = OpenAI(api_key="hk-your-key", base_url="https://llm.hanzo.ai/v1")
|
||||
client = OpenAI(api_key="hk-your-key", base_url="https://api.hanzo.ai/v1")
|
||||
```
|
||||
|
||||
```typescript
|
||||
// TypeScript
|
||||
import OpenAI from 'openai'
|
||||
const client = new OpenAI({ apiKey: 'hk-your-key', baseURL: 'https://llm.hanzo.ai/v1' })
|
||||
const client = new OpenAI({ apiKey: 'hk-your-key', baseURL: 'https://api.hanzo.ai/v1' })
|
||||
```
|
||||
|
||||
```go
|
||||
@@ -123,42 +113,53 @@ These keys operate across all projects within an organization. They are used for
|
||||
|
||||
## Key Information and Usage
|
||||
|
||||
Check a key's budget and usage:
|
||||
Spend and usage for the calling credential come from the billing and analytics APIs — same host, same key:
|
||||
|
||||
```bash
|
||||
curl https://llm.hanzo.ai/key/info \
|
||||
# Current balance
|
||||
curl https://api.hanzo.ai/v1/billing/balance \
|
||||
-H "Authorization: Bearer hk-your-key"
|
||||
|
||||
# Itemized metered usage
|
||||
curl https://api.hanzo.ai/v1/billing/usage \
|
||||
-H "Authorization: Bearer hk-your-key"
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{ "balance": 0, "holds": 0, "available": 0 }
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"key_alias": "prod-backend",
|
||||
"max_budget": 500.0,
|
||||
"spend": 127.43,
|
||||
"budget_duration": "monthly",
|
||||
"tpm_limit": 500000,
|
||||
"rpm_limit": 3000,
|
||||
"expires": "2026-12-31T00:00:00Z"
|
||||
"count": 2000,
|
||||
"usage": [
|
||||
{
|
||||
"amount": 24,
|
||||
"createdAt": "2026-07-25T21:59:35Z",
|
||||
"metadata": { "model": "zen-image" },
|
||||
"transactionId": "use_daff3c10f561635114c7a78e8d0eea5d"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
For rolled-up request/token/spend counts across a range, use `GET /v1/analytics/overview?range=30d` — see [Analytics](/docs/services/analytics).
|
||||
|
||||
## Rotation Best Practices
|
||||
|
||||
1. **Rotate regularly** -- Set key expiration at creation time. 90 days is a reasonable default for production keys.
|
||||
2. **Use KMS for production** -- Store keys in [Hanzo KMS](https://kms.hanzo.ai) and sync them to your runtime environment via KMSSecret CRDs. Never hardcode keys in source or commit them to git.
|
||||
2. **Use KMS for production** -- Store keys in [Hanzo KMS](/docs/services/kms) and sync them to your runtime environment via KMSSecret CRDs. Never hardcode keys in source or commit them to git.
|
||||
3. **Create before you revoke** -- Generate the replacement key, deploy it, verify it works, then revoke the old one. Zero-downtime rotation.
|
||||
4. **One key per service** -- Give each service or environment its own key. This limits blast radius and makes audit logs useful.
|
||||
5. **Set budgets** -- Every production key should have a monthly budget. This prevents runaway costs from bugs or abuse.
|
||||
6. **Monitor usage** -- Check `key/info` or the console dashboard regularly. Unusual spend patterns may indicate a leak.
|
||||
6. **Monitor usage** -- Check `/v1/billing/usage` or the console dashboard regularly. Unusual spend patterns may indicate a leak.
|
||||
|
||||
### KMS Integration
|
||||
|
||||
For production deployments, use Hanzo KMS to manage API keys as secrets:
|
||||
|
||||
```yaml
|
||||
# KMSSecret CRD -- syncs secret from kms.hanzo.ai to K8s
|
||||
# KMSSecret CRD -- syncs a secret from Hanzo KMS into K8s
|
||||
apiVersion: secrets.hanzo.ai/v1alpha1
|
||||
kind: KMSSecret
|
||||
metadata:
|
||||
@@ -175,16 +176,7 @@ spec:
|
||||
|
||||
## Revoking Keys
|
||||
|
||||
Revoke a key immediately from the console or via the API:
|
||||
|
||||
```bash
|
||||
curl -X POST https://llm.hanzo.ai/key/delete \
|
||||
-H "Authorization: Bearer hk-your-admin-key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"keys": ["hk-proj-abc123..."]}'
|
||||
```
|
||||
|
||||
Revocation is immediate. Any in-flight request using the key will fail with `401 Unauthorized`.
|
||||
Revoke a key from the console: **Project → API Keys → Revoke**. Revocation is immediate — any in-flight request using the key fails with `401 Unauthorized`.
|
||||
|
||||
## Security Rules
|
||||
|
||||
|
||||
@@ -7,15 +7,15 @@ description: The one way to authenticate against Hanzo IAM — canonical OIDC en
|
||||
|
||||
Hanzo uses one identity provider per brand, a standards-compliant OIDC provider. You integrate through exactly one library — [`@hanzo/iam`](https://www.npmjs.com/package/@hanzo/iam) — against one set of endpoints. There is no second way.
|
||||
|
||||
| Brand | IAM origin (`serverUrl`) | Login UI |
|
||||
|-------|--------------------------|----------|
|
||||
| Hanzo | `https://iam.hanzo.ai` | `hanzo.id` |
|
||||
| Lux | `https://lux.id` | `lux.id` |
|
||||
| Zoo | `https://zoo.id` | `zoo.id` |
|
||||
| Bootnode | `https://id.bootno.de` | `id.bootno.de` |
|
||||
| Pars | `https://pars.id` | `pars.id` |
|
||||
| Brand | IAM origin (`serverUrl`) = issuer + login UI |
|
||||
|-------|----------------------------------------------|
|
||||
| Hanzo | `https://hanzo.id` |
|
||||
| Lux | `https://lux.id` |
|
||||
| Zoo | `https://zoo.id` |
|
||||
| Bootnode | `https://id.bootno.de` |
|
||||
| Pars | `https://pars.id` |
|
||||
|
||||
The SDK is brand-agnostic. Select the brand with `serverUrl`; nothing else changes.
|
||||
One origin per brand — it is the OIDC `issuer`, the login UI, and the endpoint base, all the same host. The SDK is brand-agnostic: select the brand with `serverUrl`; nothing else changes.
|
||||
|
||||
## OIDC Endpoints
|
||||
|
||||
@@ -23,12 +23,16 @@ These `/v1/iam/oauth/*` paths are the only endpoints. There is no `/oauth/*`, no
|
||||
|
||||
| Purpose | Path |
|
||||
|---------|------|
|
||||
| Discovery | `https://iam.hanzo.ai/.well-known/openid-configuration` |
|
||||
| Authorize | `https://iam.hanzo.ai/v1/iam/oauth/authorize` |
|
||||
| Token | `https://iam.hanzo.ai/v1/iam/oauth/token` |
|
||||
| UserInfo | `https://iam.hanzo.ai/v1/iam/oauth/userinfo` |
|
||||
| JWKS | `https://iam.hanzo.ai/v1/iam/.well-known/jwks` |
|
||||
| Logout | `https://iam.hanzo.ai/v1/iam/oauth/logout` |
|
||||
| Discovery | `https://hanzo.id/.well-known/openid-configuration` |
|
||||
| Authorize | `https://hanzo.id/v1/iam/oauth/authorize` |
|
||||
| Token | `https://hanzo.id/v1/iam/oauth/token` |
|
||||
| UserInfo | `https://hanzo.id/v1/iam/oauth/userinfo` |
|
||||
| JWKS | `https://hanzo.id/v1/iam/.well-known/jwks` |
|
||||
| Logout | `https://hanzo.id/v1/iam/oauth/logout` |
|
||||
|
||||
<Callout title="Why these live on hanzo.id, not api.hanzo.ai">
|
||||
Every Hanzo **API** call goes to `api.hanzo.ai/v1/<service>` — one host, one key. OIDC is the one exception, and not by choice: the endpoint URLs must match the `issuer` the server publishes, because that is what clients validate the `iss` claim against. `curl https://hanzo.id/.well-known/openid-configuration` returns `"issuer": "https://hanzo.id"`, so `hanzo.id` is the answer. The IAM **management** API (`get-account`, `get-users`, …) is a normal API and lives at `api.hanzo.ai/v1/iam/*` like everything else.
|
||||
</Callout>
|
||||
|
||||
Every flow uses **PKCE `S256`**, **`client_secret_basic`** for confidential clients, and scopes **`openid profile email`**. The flow is Authorization Code + PKCE; implicit grant is not supported.
|
||||
|
||||
@@ -60,7 +64,7 @@ Any backend validates a bearer token like this:
|
||||
import { validateToken } from '@hanzo/iam/server'
|
||||
|
||||
const result = await validateToken(accessToken, {
|
||||
serverUrl: process.env.IAM_ENDPOINT!, // https://iam.hanzo.ai
|
||||
serverUrl: process.env.IAM_ENDPOINT!, // https://hanzo.id
|
||||
clientId: process.env.IAM_CLIENT_ID!,
|
||||
})
|
||||
|
||||
@@ -135,7 +139,7 @@ Register the redirect URI `https://<app-host>/api/auth/callback/iam`.
|
||||
import { IAM } from '@hanzo/iam/browser'
|
||||
|
||||
const iam = new IAM({
|
||||
serverUrl: 'https://iam.hanzo.ai',
|
||||
serverUrl: 'https://hanzo.id',
|
||||
clientId: 'hanzo-myspa',
|
||||
redirectUri: `${location.origin}/auth/callback`,
|
||||
})
|
||||
@@ -152,7 +156,7 @@ import { IamProvider, useIam } from '@hanzo/iam/react'
|
||||
|
||||
function Root() {
|
||||
return (
|
||||
<IamProvider serverUrl="https://iam.hanzo.ai" clientId="hanzo-myspa">
|
||||
<IamProvider serverUrl="https://hanzo.id" clientId="hanzo-myspa">
|
||||
<App />
|
||||
</IamProvider>
|
||||
)
|
||||
@@ -173,7 +177,7 @@ import passport from 'passport'
|
||||
import { createIamPassportStrategy } from '@hanzo/iam/passport'
|
||||
|
||||
passport.use('iam', createIamPassportStrategy({
|
||||
serverUrl: 'https://iam.hanzo.ai',
|
||||
serverUrl: 'https://hanzo.id',
|
||||
clientId: 'hanzo-myservice',
|
||||
clientSecret: process.env.IAM_CLIENT_SECRET!,
|
||||
callbackUrl: 'https://myservice.hanzo.ai/v1/sso/oidc/callback',
|
||||
|
||||
@@ -30,14 +30,11 @@ curl https://api.hanzo.ai/v1/billing/balance \
|
||||
|
||||
Top up credits with a card through the billing portal, or on-chain with HUSD (see below).
|
||||
|
||||
### Trial vs. Prepaid Credits
|
||||
### Credits
|
||||
|
||||
Your balance is made of two kinds of credit, and they spend in a fixed order:
|
||||
Your balance is **prepaid credit** -- what you add yourself by topping up (card or HUSD), plus any program awards such as the [Startup Program](/docs/startups) or [Referrals](/docs/referrals).
|
||||
|
||||
- **Trial credits** -- every new account starts with **$5 in free trial credits**, no card required. They exist so you can build before you pay.
|
||||
- **Prepaid credits** -- what you add yourself by topping up (card or HUSD), plus any program awards such as the [Startup Program](/docs/startups) or [Referrals](/docs/referrals).
|
||||
|
||||
**Trial credits always burn first.** Only once they are exhausted does metering start drawing down your prepaid balance. Both live in the one balance above, and every billable action -- an API call, a [deploy](/docs/deploy), a stored object, a compute-second -- draws from it. When your prepaid balance runs low you get a `402 Payment Required` until you top up.
|
||||
It is one balance, and every billable action -- an API call, a [deploy](/docs/deploy), a stored object, a compute-second -- draws from it. When it runs low you get a `402 Payment Required` until you top up.
|
||||
|
||||
Watch it all in the console's **Usage** and **Billing** views, or at [billing.hanzo.ai](https://billing.hanzo.ai) -- both read the same live balance and metered usage as the API below.
|
||||
|
||||
@@ -108,7 +105,7 @@ Metering, pricing, credits, invoices, and payment methods are one connected syst
|
||||
|
||||
## Related
|
||||
|
||||
- [Getting Started](/docs/getting-started) -- claim your $5 free credits and make your first call
|
||||
- [Getting Started](/docs/getting-started) -- create an account, get a key, make your first call
|
||||
- [Startup Program](/docs/startups) -- up to $150,000 in credits for venture-backed startups
|
||||
- [Plans & Pricing](/docs/services/platform/pricing/plans) -- subscription tiers and per-unit rates
|
||||
- [Referrals & Affiliates](/docs/referrals) -- earn cloud credits by referring developers
|
||||
|
||||
@@ -57,7 +57,7 @@ endpoints:
|
||||
apiKey: "${ANTHROPIC_API_KEY}"
|
||||
models:
|
||||
default:
|
||||
- claude-sonnet-4-5-20250929
|
||||
- zen5
|
||||
- claude-opus-4-20250514
|
||||
|
||||
google:
|
||||
|
||||
@@ -22,7 +22,7 @@ curl -X POST https://api.hanzo.ai/v1/evals/runs \
|
||||
"model": "qwen3-4b",
|
||||
"runName": "qwen3-baseline",
|
||||
"judge": {
|
||||
"model": "claude-sonnet-4-5-20250929",
|
||||
"model": "zen5",
|
||||
"criteria": "Is the answer correct and grounded in the expected output?"
|
||||
}
|
||||
}'
|
||||
@@ -32,7 +32,7 @@ curl -X POST https://api.hanzo.ai/v1/evals/runs \
|
||||
{
|
||||
"dataset": "support-qa",
|
||||
"model": "qwen3-4b",
|
||||
"judgeModel": "claude-sonnet-4-5-20250929",
|
||||
"judgeModel": "zen5",
|
||||
"runName": "qwen3-baseline",
|
||||
"items": 40,
|
||||
"scored": 40,
|
||||
|
||||
@@ -18,8 +18,8 @@ Go to [hanzo.id](https://hanzo.id) and sign up with:
|
||||
|
||||
Your Hanzo identity works everywhere: console, chat, platform, cloud, and all API services. One account, one login.
|
||||
|
||||
<Callout title="$5 free to start -- no card required">
|
||||
Every new account gets **$5 in free trial credits**. That is enough to make your first API calls, run a chat, or try a deploy today -- no payment method needed. Trial credits burn first; you only add a card or crypto balance when you are ready to keep going. See [Credits & Billing](/docs/billing).
|
||||
<Callout title="One account, one balance">
|
||||
The same identity and the same prepaid balance cover every product -- AI calls, deploys, storage. Add a card or crypto balance when you are ready to make your first call. See [Credits & Billing](/docs/billing).
|
||||
</Callout>
|
||||
|
||||
## 2. Open the Console
|
||||
@@ -58,20 +58,22 @@ The `hk-` prefix identifies it as a Hanzo API key. See [API Keys](/docs/api-keys
|
||||
|
||||
## 5. Make Your First API Call
|
||||
|
||||
All Hanzo services are available through `api.hanzo.ai`. The AI API is at `llm.hanzo.ai`. Both accept the same `hk-*` API key.
|
||||
Every Hanzo service — AI, storage, identity, deploys — answers on **one host, `api.hanzo.ai`**, under `/v1/<service>`, with the same `hk-*` key. There is no second API host to configure.
|
||||
|
||||
### curl
|
||||
|
||||
```bash
|
||||
curl https://llm.hanzo.ai/v1/chat/completions \
|
||||
curl https://api.hanzo.ai/v1/chat/completions \
|
||||
-H "Authorization: Bearer hk-your-api-key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"model": "claude-sonnet-4-5-20250929",
|
||||
"model": "zen5",
|
||||
"messages": [{"role": "user", "content": "Hello from Hanzo!"}]
|
||||
}'
|
||||
```
|
||||
|
||||
Browse every model id with `curl https://api.hanzo.ai/v1/models` — the Zen family plus 400+ third-party models, all on the same key.
|
||||
|
||||
### Python
|
||||
|
||||
Install the SDK:
|
||||
@@ -89,11 +91,11 @@ from openai import OpenAI
|
||||
|
||||
client = OpenAI(
|
||||
api_key="hk-your-api-key",
|
||||
base_url="https://llm.hanzo.ai/v1",
|
||||
base_url="https://api.hanzo.ai/v1",
|
||||
)
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
model="zen5",
|
||||
messages=[{"role": "user", "content": "Hello from Hanzo!"}],
|
||||
)
|
||||
print(response.choices[0].message.content)
|
||||
@@ -116,26 +118,26 @@ import OpenAI from 'openai'
|
||||
|
||||
const client = new OpenAI({
|
||||
apiKey: 'hk-your-api-key',
|
||||
baseURL: 'https://llm.hanzo.ai/v1',
|
||||
baseURL: 'https://api.hanzo.ai/v1',
|
||||
})
|
||||
|
||||
const completion = await client.chat.completions.create({
|
||||
model: 'claude-sonnet-4-5-20250929',
|
||||
model: 'zen5',
|
||||
messages: [{ role: 'user', content: 'Hello from Hanzo!' }],
|
||||
})
|
||||
console.log(completion.choices[0].message.content)
|
||||
```
|
||||
|
||||
Prefer a UI? Open [chat.hanzo.ai](https://chat.hanzo.ai) and start chatting -- it spends from the same balance, so your $5 works there too.
|
||||
Prefer a UI? Open [chat.hanzo.ai](https://chat.hanzo.ai) and start chatting -- it spends from the same balance.
|
||||
|
||||
## 6. Add Credits When You're Ready
|
||||
## 6. Add Credits
|
||||
|
||||
Your $5 in trial credits burn down first as you make calls. When you want to keep going, top up a **prepaid balance** at [billing.hanzo.ai](https://billing.hanzo.ai):
|
||||
Top up a **prepaid balance** at [billing.hanzo.ai](https://billing.hanzo.ai):
|
||||
|
||||
- **Card** -- pay by card through the billing portal (processed by Square).
|
||||
- **Crypto** -- top up on-chain with **HUSD**, the platform stablecoin, from a connected wallet.
|
||||
|
||||
Trial credits always spend before your prepaid balance, and every product -- API calls, deploys, storage -- draws down the same balance. Watch usage in the console's [Usage & Billing](/docs/billing) views. For how metering, credits, and invoices fit together, see [Credits & Billing](/docs/billing).
|
||||
Every product -- API calls, deploys, storage -- draws down the same balance. Watch usage in the console's [Usage & Billing](/docs/billing) views. For how metering, credits, and invoices fit together, see [Credits & Billing](/docs/billing).
|
||||
|
||||
Building a funded startup? You may qualify for **up to $150,000 in credits** through the [Startup Program](/docs/startups).
|
||||
|
||||
|
||||
@@ -13,15 +13,17 @@ import { Card, Cards } from '@hanzo/docs-base-ui/components/card';
|
||||
One API for **200+ language models** from every major provider. OpenAI-compatible interface with load balancing, caching, rate limiting, fallbacks, and full observability.
|
||||
|
||||
```bash title="Quick Start"
|
||||
curl https://llm.hanzo.ai/v1/chat/completions \
|
||||
curl https://api.hanzo.ai/v1/chat/completions \
|
||||
-H "Authorization: Bearer $HANZO_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"model": "claude-sonnet-4-5-20250929",
|
||||
"model": "zen5",
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
}'
|
||||
```
|
||||
|
||||
The AI API is on the same host as every other Hanzo service: `api.hanzo.ai`, one `hk-*` key, no second base URL. List model ids with `GET https://api.hanzo.ai/v1/models`.
|
||||
|
||||
## Why Hanzo AI API?
|
||||
|
||||
- **200+ Models** — Claude, GPT, Gemini, Llama, Mistral, and more
|
||||
@@ -53,11 +55,11 @@ from openai import OpenAI
|
||||
|
||||
client = OpenAI(
|
||||
api_key="your-hanzo-api-key",
|
||||
base_url="https://llm.hanzo.ai/v1"
|
||||
base_url="https://api.hanzo.ai/v1"
|
||||
)
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
model="zen5",
|
||||
messages=[{"role": "user", "content": "Explain quantum computing"}]
|
||||
)
|
||||
print(response.choices[0].message.content)
|
||||
@@ -70,11 +72,11 @@ import OpenAI from 'openai'
|
||||
|
||||
const client = new OpenAI({
|
||||
apiKey: process.env.HANZO_API_KEY,
|
||||
baseURL: 'https://llm.hanzo.ai/v1',
|
||||
baseURL: 'https://api.hanzo.ai/v1',
|
||||
})
|
||||
|
||||
const completion = await client.chat.completions.create({
|
||||
model: 'claude-sonnet-4-5-20250929',
|
||||
model: 'zen5',
|
||||
messages: [{ role: 'user', content: 'Explain quantum computing' }],
|
||||
})
|
||||
console.log(completion.choices[0].message.content)
|
||||
@@ -97,7 +99,7 @@ console.log(completion.choices[0].message.content)
|
||||
model_list:
|
||||
- model_name: "default"
|
||||
litellm_params:
|
||||
model: "anthropic/claude-sonnet-4-5-20250929"
|
||||
model: "anthropic/zen5"
|
||||
api_key: "os.environ/ANTHROPIC_API_KEY"
|
||||
|
||||
- model_name: "default"
|
||||
@@ -118,6 +120,8 @@ router_settings:
|
||||
|
||||
## API Endpoints
|
||||
|
||||
All relative to `https://api.hanzo.ai`.
|
||||
|
||||
| Endpoint | Description |
|
||||
|----------|-------------|
|
||||
| `POST /v1/chat/completions` | Chat completions (streaming supported) |
|
||||
@@ -125,8 +129,8 @@ router_settings:
|
||||
| `POST /v1/embeddings` | Text embeddings |
|
||||
| `POST /v1/images/generations` | Image generation |
|
||||
| `GET /v1/models` | List available models |
|
||||
| `POST /key/generate` | Create API keys with budgets |
|
||||
| `GET /key/info` | Key usage and budget info |
|
||||
|
||||
API keys, budgets, and per-key usage are managed in the [Console](https://console.hanzo.ai) — see [API Keys](/docs/api-keys).
|
||||
|
||||
## Related
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ curl https://api.hanzo.ai/v1/pricing/models \
|
||||
{
|
||||
"models": [
|
||||
{
|
||||
"id": "claude-sonnet-4-5-20250929",
|
||||
"id": "zen5",
|
||||
"name": "Claude Sonnet 4.5",
|
||||
"provider": "anthropic",
|
||||
"context": 200000,
|
||||
@@ -46,7 +46,7 @@ curl https://api.hanzo.ai/v1/chat/completions \
|
||||
-H "Authorization: Bearer hk-..." \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"model": "claude-sonnet-4-5-20250929",
|
||||
"model": "zen5",
|
||||
"messages": [{"role": "user", "content": "Hi"}]
|
||||
}'
|
||||
```
|
||||
|
||||
@@ -541,7 +541,7 @@ ai:
|
||||
|
||||
- `model` - The model to use (default: provider-specific)
|
||||
- OpenAI: `gpt-4o`, `gpt-4`, `gpt-3.5-turbo`, etc.
|
||||
- Anthropic: `claude-3-5-sonnet-20241022`, `claude-3-opus-20240229`, etc.
|
||||
- Anthropic: `claude-3-5-sonnet-20241022`, `zen5`, etc.
|
||||
- OpenRouter: Use their model naming like `anthropic/claude-3.5-sonnet`
|
||||
|
||||
</details>
|
||||
|
||||
@@ -64,7 +64,7 @@ Add to VS Code settings.json:
|
||||
|
||||
// Anthropic
|
||||
"hanzo.llm.anthropic.apiKey": "sk-ant-...",
|
||||
"hanzo.llm.anthropic.model": "claude-3-opus-20240229"
|
||||
"hanzo.llm.anthropic.model": "zen5"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ the historical mess where `HANZO_IAM_URL` / `HANZO_CLIENT_ID` /
|
||||
| Prefix | What it's for | Examples |
|
||||
|---|---|---|
|
||||
| `IAM_*` | The auth/OIDC engine (user identity, JWT issuance, session) | `IAM_URL`, `IAM_CLIENT_ID`, `IAM_CLIENT_SECRET`, `IAM_AUDIENCE`, `IAM_ORG`, `IAM_REDIRECT_URI` |
|
||||
| `HANZO_*` | Hanzo **product** API access at `api.hanzo.ai` / `llm.hanzo.ai` / `chat.hanzo.ai` etc — your developer credentials to *use* Hanzo as a paid service | `HANZO_API_KEY`, `HANZO_OAUTH_CLIENT_ID`, `HANZO_OAUTH_CLIENT_SECRET`, `HANZO_OAUTH_REDIRECT_URI` |
|
||||
| `HANZO_*` | Hanzo **product** API access at `api.hanzo.ai` (one host for every `/v1/<service>`), `chat.hanzo.ai` etc — your developer credentials to *use* Hanzo as a paid service | `HANZO_API_KEY`, `HANZO_OAUTH_CLIENT_ID`, `HANZO_OAUTH_CLIENT_SECRET`, `HANZO_OAUTH_REDIRECT_URI` |
|
||||
| `IDV_*` | Identity-verification providers (biometric, KYC vendors) | `IDV_URL`, `IDV_CLIENT_ID`, `IDV_CLIENT_SECRET` |
|
||||
| `CASDOOR_*` | **DEAD** — engine isn't Casdoor-branded anymore | (delete) |
|
||||
|
||||
@@ -81,7 +81,7 @@ where the value is consumed:
|
||||
- Used by `@hanzo/iam` SDK, points at an IAM instance, validates JWKS,
|
||||
hits `/v1/iam/oauth/*` → IAM_*
|
||||
- Used by `@hanzo/api` (or raw fetch) against `https://api.hanzo.ai` /
|
||||
`https://llm.hanzo.ai` for LLM/Chat/MCP → HANZO_*
|
||||
`https://api.hanzo.ai/v1` for AI/Chat/MCP → HANZO_*
|
||||
- Used by a biometric / KYC IDV provider → IDV_*
|
||||
|
||||
A single app can (and often does) carry env vars from all three
|
||||
|
||||
@@ -12,7 +12,7 @@ project rather than introduce a new sync.
|
||||
|
||||
| Attribute | Value |
|
||||
|---|---|
|
||||
| Hostname | `kms.hanzo.ai` |
|
||||
| Hostname | `api.hanzo.ai` (one API host; KMS is the `/v1/kms` prefix) |
|
||||
| Project slug | `hanzo-iam` |
|
||||
| Environment slug | `prod` (mainnet), `test` (testnet), `dev` (devnet) |
|
||||
| Path | `/` (existing IAM secrets are flat under root) |
|
||||
@@ -47,20 +47,23 @@ export those values into your shell:
|
||||
|
||||
```bash
|
||||
export KMS_CLIENT_ID=$(kubectl --context=do-sfo3-hanzo-k8s -n hanzo \
|
||||
get secret iam-kms-auth -o jsonpath='{.data.CLIENTID}' | base64 -d)
|
||||
get secret iam-kms-auth -o jsonpath='{.data.clientId}' | base64 -d)
|
||||
export KMS_CLIENT_SECRET=$(kubectl --context=do-sfo3-hanzo-k8s -n hanzo \
|
||||
get secret iam-kms-auth -o jsonpath='{.data.CLIENTSECRET}' | base64 -d)
|
||||
get secret iam-kms-auth -o jsonpath='{.data.clientSecret}' | base64 -d)
|
||||
```
|
||||
|
||||
Mint a short-lived token (KMS Universal Auth is an OIDC-bearer scheme):
|
||||
Exchange the machine identity for a short-lived bearer (JSON body, not form-encoded):
|
||||
|
||||
```bash
|
||||
TOKEN=$(curl -sS -X POST https://kms.hanzo.ai/v1/auth/universal/login \
|
||||
-d "clientId=$KMS_CLIENT_ID&clientSecret=$KMS_CLIENT_SECRET" \
|
||||
TOKEN=$(curl -sS -X POST https://api.hanzo.ai/v1/kms/auth/login \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"clientId\":\"$KMS_CLIENT_ID\",\"clientSecret\":\"$KMS_CLIENT_SECRET\"}" \
|
||||
| jq -r .accessToken)
|
||||
test -n "$TOKEN" || { echo "auth failed"; exit 1; }
|
||||
test -n "$TOKEN" -a "$TOKEN" != null || { echo "auth failed"; exit 1; }
|
||||
```
|
||||
|
||||
Response: `{"accessToken":"<RS256 JWT>","expiresIn":604800,"tokenType":"Bearer"}`.
|
||||
|
||||
## Write the 12 secrets
|
||||
|
||||
Repeat once per env (mainnet→prod, testnet→test, devnet→dev). Substitute
|
||||
@@ -82,24 +85,24 @@ declare -A SECRETS=(
|
||||
[IAM_GOOGLE_CLIENT_SECRET]="<phase-1-${ENV}-google-client-secret>"
|
||||
)
|
||||
for key in "${!SECRETS[@]}"; do
|
||||
curl -sS -X PATCH "https://kms.hanzo.ai/api/v3/secrets/raw/$key" \
|
||||
curl -sS -X POST "https://api.hanzo.ai/v1/kms/orgs/hanzo/secrets" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$(jq -n \
|
||||
--arg project hanzo-iam \
|
||||
--arg path "/hanzo-iam" \
|
||||
--arg name "$key" \
|
||||
--arg env "$KMS_ENV" \
|
||||
--arg path "/" \
|
||||
--arg val "${SECRETS[$key]}" \
|
||||
'{projectSlug:$project, environment:$env, secretPath:$path, secretValue:$val}')"
|
||||
'{path:$path, name:$name, env:$env, value:$val}')"
|
||||
echo
|
||||
done
|
||||
```
|
||||
|
||||
Verify by listing the path:
|
||||
Verify by listing the namespace (metadata only — values are never listed):
|
||||
|
||||
```bash
|
||||
curl -sS "https://kms.hanzo.ai/api/v3/secrets/list?projectSlug=hanzo-iam&environment=$KMS_ENV&secretPath=/" \
|
||||
-H "Authorization: Bearer $TOKEN" | jq '.secrets[].secretKey' \
|
||||
curl -sS "https://api.hanzo.ai/v1/kms/orgs/hanzo/secrets?env=$KMS_ENV" \
|
||||
-H "Authorization: Bearer $TOKEN" | jq -r '.secrets[].name' \
|
||||
| grep -E 'IAM_(GITHUB|GOOGLE)_CLIENT_(ID|SECRET)'
|
||||
```
|
||||
|
||||
@@ -147,11 +150,13 @@ env:
|
||||
## Rotation
|
||||
|
||||
```bash
|
||||
# 1. PATCH the new value into KMS
|
||||
curl -sS -X PATCH "https://kms.hanzo.ai/api/v3/secrets/raw/IAM_GITHUB_CLIENT_SECRET" \
|
||||
# 1. PATCH the new value into KMS (If-Match carries the current version;
|
||||
# a missing precondition is 428, a stale one is 409)
|
||||
curl -sS -X PATCH "https://api.hanzo.ai/v1/kms/orgs/hanzo/secrets/hanzo-iam/IAM_GITHUB_CLIENT_SECRET?env=prod" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "If-Match: $CURRENT_VERSION" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"projectSlug":"hanzo-iam","environment":"prod","secretPath":"/","secretValue":"<new-secret>"}'
|
||||
-d '{"value":"<new-secret>"}'
|
||||
|
||||
# 2. KMSSecret reconciles within 60s; force-roll the Job to pick up:
|
||||
kubectl --context=do-sfo3-hanzo-k8s -n hanzo delete job iam-init-providers --ignore-not-found
|
||||
|
||||
+1
-1
@@ -156,7 +156,7 @@ export const getAnthropicSteps = (ctx: OnboardingComponentsContext): StepDefinit
|
||||
file: 'Python',
|
||||
code: dedent`
|
||||
response = client.messages.create(
|
||||
model="claude-3-opus-20240229",
|
||||
model="zen5",
|
||||
messages=[
|
||||
{
|
||||
"role": "user",
|
||||
|
||||
@@ -116,8 +116,8 @@ Architecture, training methodology, and evaluation for the Zen frontier models
|
||||
| [Zen Chain Of Thought](https://github.com/hanzoai/papers/blob/main/zen/zen-chain-of-thought.pdf) | `zen/zen-chain-of-thought.tex` |
|
||||
| [Zen Code](https://github.com/hanzoai/papers/blob/main/zen/zen-code_whitepaper.pdf) | `zen/zen-code_whitepaper.tex` |
|
||||
| [Zen Code Benchmarks](https://github.com/hanzoai/papers/blob/main/zen/zen-code-benchmarks.pdf) | `zen/zen-code-benchmarks.tex` |
|
||||
| [Zen Coder](https://github.com/hanzoai/papers/blob/main/zen/zen-coder_whitepaper.pdf) | `zen/zen-coder_whitepaper.tex` |
|
||||
| [Zen Coder Flash](https://github.com/hanzoai/papers/blob/main/zen/zen-coder-flash_whitepaper.pdf) | `zen/zen-coder-flash_whitepaper.tex` |
|
||||
| [Zen Coder](https://github.com/hanzoai/papers/blob/main/zen/zen5-coder_whitepaper.pdf) | `zen/zen5-coder_whitepaper.tex` |
|
||||
| [Zen Coder Flash](https://github.com/hanzoai/papers/blob/main/zen/zen5-coder-flash_whitepaper.pdf) | `zen/zen5-coder-flash_whitepaper.tex` |
|
||||
| [Zen Context Extension](https://github.com/hanzoai/papers/blob/main/zen/zen-context-extension.pdf) | `zen/zen-context-extension.tex` |
|
||||
| [Zen Designer Instruct](https://github.com/hanzoai/papers/blob/main/zen/zen-designer-instruct_whitepaper.pdf) | `zen/zen-designer-instruct_whitepaper.tex` |
|
||||
| [Zen Designer Thinking](https://github.com/hanzoai/papers/blob/main/zen/zen-designer-thinking_whitepaper.pdf) | `zen/zen-designer-thinking_whitepaper.tex` |
|
||||
@@ -151,7 +151,7 @@ Architecture, training methodology, and evaluation for the Zen frontier models
|
||||
| [Zen Musician](https://github.com/hanzoai/papers/blob/main/zen/zen-musician.pdf) | `zen/zen-musician.tex` |
|
||||
| [Zen Nano](https://github.com/hanzoai/papers/blob/main/zen/zen-nano_whitepaper.pdf) | `zen/zen-nano_whitepaper.tex` |
|
||||
| [Zen Next](https://github.com/hanzoai/papers/blob/main/zen/zen-next_whitepaper.pdf) | `zen/zen-next_whitepaper.tex` |
|
||||
| [Zen Omni](https://github.com/hanzoai/papers/blob/main/zen/zen-omni_whitepaper.pdf) | `zen/zen-omni_whitepaper.tex` |
|
||||
| [Zen Omni](https://github.com/hanzoai/papers/blob/main/zen/zen5_whitepaper.pdf) | `zen/zen5_whitepaper.tex` |
|
||||
| [Zen Privacy Federated](https://github.com/hanzoai/papers/blob/main/zen/zen-privacy-federated.pdf) | `zen/zen-privacy-federated.tex` |
|
||||
| [Zen Pro](https://github.com/hanzoai/papers/blob/main/zen/zen-pro_whitepaper.pdf) | `zen/zen-pro_whitepaper.tex` |
|
||||
| [Zen Quantization](https://github.com/hanzoai/papers/blob/main/zen/zen-quantization.pdf) | `zen/zen-quantization.tex` |
|
||||
|
||||
@@ -102,7 +102,7 @@ await ast.recordInteraction({
|
||||
role: 'assistant',
|
||||
content: 'Quantum computing uses quantum bits (qubits) that can be 0, 1, or both at the same time...',
|
||||
},
|
||||
model: 'zen-coder-32b-instruct',
|
||||
model: 'zen5-coder-32b-instruct',
|
||||
tokens: { input: 42, output: 156 },
|
||||
latencyMs: 1240,
|
||||
},
|
||||
@@ -224,7 +224,7 @@ app.post('/api/chat', async (req, res) => {
|
||||
const { messages } = req.body;
|
||||
|
||||
const completion = await llm.chat.completions.create({
|
||||
model: 'zen-coder-32b-instruct',
|
||||
model: 'zen5-coder-32b-instruct',
|
||||
messages,
|
||||
});
|
||||
|
||||
@@ -284,7 +284,7 @@ AST stores all records in a normalized JSON format compatible with common fine-t
|
||||
},
|
||||
"output": {
|
||||
"message": {"role": "assistant", "content": "..."},
|
||||
"model": "zen-coder-32b-instruct",
|
||||
"model": "zen5-coder-32b-instruct",
|
||||
"tokens": {"input": 42, "output": 156},
|
||||
"latency_ms": 1240
|
||||
},
|
||||
|
||||
@@ -45,7 +45,7 @@ int main() {
|
||||
hanzo::Client client{std::getenv("HANZO_API_KEY")};
|
||||
|
||||
auto response = client.chat().completions().create({
|
||||
.model = "zen-omni",
|
||||
.model = "zen5",
|
||||
.messages = {{"user", "Explain quantum computing"}},
|
||||
});
|
||||
|
||||
@@ -59,7 +59,7 @@ int main() {
|
||||
curl https://api.hanzo.ai/v1/chat/completions \
|
||||
-H "Authorization: Bearer $HANZO_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"model":"zen-omni","messages":[{"role":"user","content":"Hello"}]}'
|
||||
-d '{"model":"zen5","messages":[{"role":"user","content":"Hello"}]}'
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
@@ -48,7 +48,7 @@ func main() {
|
||||
)
|
||||
|
||||
resp, err := client.Chat.Completions.New(context.TODO(), hanzoai.ChatCompletionNewParams{
|
||||
Model: hanzoai.F("zen-omni"),
|
||||
Model: hanzoai.F("zen5"),
|
||||
Messages: hanzoai.F([]hanzoai.ChatCompletionMessageParamUnion{
|
||||
hanzoai.UserMessage("Explain quantum computing"),
|
||||
}),
|
||||
@@ -64,7 +64,7 @@ func main() {
|
||||
|
||||
```go
|
||||
stream := client.Chat.Completions.NewStreaming(ctx, hanzoai.ChatCompletionNewParams{
|
||||
Model: hanzoai.F("zen-coder"),
|
||||
Model: hanzoai.F("zen5-coder"),
|
||||
Messages: hanzoai.F([]hanzoai.ChatCompletionMessageParamUnion{
|
||||
hanzoai.UserMessage("Write a haiku about AI"),
|
||||
}),
|
||||
|
||||
@@ -115,7 +115,7 @@ from hanzoai import Hanzo
|
||||
|
||||
client = Hanzo(api_key="hk-your-key")
|
||||
response = client.chat.completions.create(
|
||||
model="zen-omni",
|
||||
model="zen5",
|
||||
messages=[{"role": "user", "content": "Hello"}],
|
||||
)
|
||||
print(response.choices[0].message.content)
|
||||
@@ -126,7 +126,7 @@ import Hanzo from '@hanzo/sdk';
|
||||
|
||||
const client = new Hanzo({ apiKey: 'hk-your-key' });
|
||||
const response = await client.chat.completions.create({
|
||||
model: 'zen-omni',
|
||||
model: 'zen5',
|
||||
messages: [{ role: 'user', content: 'Hello' }],
|
||||
});
|
||||
```
|
||||
@@ -134,7 +134,7 @@ const response = await client.chat.completions.create({
|
||||
```go tab="Go"
|
||||
client := hanzoai.NewClient(option.WithAPIKey("hk-your-key"))
|
||||
response, _ := client.Chat.Completions.New(ctx, hanzoai.ChatCompletionNewParams{
|
||||
Model: hanzoai.F("zen-omni"),
|
||||
Model: hanzoai.F("zen5"),
|
||||
Messages: hanzoai.F([]hanzoai.ChatCompletionMessageParamUnion{
|
||||
hanzoai.UserMessage("Hello"),
|
||||
}),
|
||||
|
||||
@@ -46,7 +46,7 @@ import ai.hanzo.Hanzo
|
||||
val client = Hanzo(apiKey = System.getenv("HANZO_API_KEY"))
|
||||
|
||||
val response = client.chat.completions.create(
|
||||
model = "zen-omni",
|
||||
model = "zen5",
|
||||
messages = listOf(Message.user("Explain quantum computing")),
|
||||
)
|
||||
println(response.choices.first().message.content)
|
||||
@@ -58,7 +58,7 @@ println(response.choices.first().message.content)
|
||||
val response = HttpClient().post("https://api.hanzo.ai/v1/chat/completions") {
|
||||
header("Authorization", "Bearer $apiKey")
|
||||
contentType(ContentType.Application.Json)
|
||||
setBody("""{"model":"zen-omni","messages":[{"role":"user","content":"Hello"}]}""")
|
||||
setBody("""{"model":"zen5","messages":[{"role":"user","content":"Hello"}]}""")
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ from hanzoai import Hanzo
|
||||
client = Hanzo(api_key="hk-your-key") # or reads HANZO_API_KEY
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="zen-omni",
|
||||
model="zen5",
|
||||
messages=[{"role": "user", "content": "Explain quantum computing"}],
|
||||
)
|
||||
print(response.choices[0].message.content)
|
||||
@@ -59,7 +59,7 @@ print(response.choices[0].message.content)
|
||||
|
||||
```python
|
||||
stream = client.chat.completions.create(
|
||||
model="zen-coder",
|
||||
model="zen5-coder",
|
||||
messages=[{"role": "user", "content": "Write a haiku about AI"}],
|
||||
stream=True,
|
||||
)
|
||||
@@ -77,7 +77,7 @@ from hanzoai import AsyncHanzo
|
||||
async def main():
|
||||
client = AsyncHanzo(api_key="hk-your-key")
|
||||
response = await client.chat.completions.create(
|
||||
model="zen-omni",
|
||||
model="zen5",
|
||||
messages=[{"role": "user", "content": "Hello!"}],
|
||||
)
|
||||
print(response.choices[0].message.content)
|
||||
@@ -93,7 +93,7 @@ top of the same cloud:
|
||||
```python
|
||||
from hanzo import Agent
|
||||
|
||||
agent = Agent(model="zen-omni", tools=["search", "shell", "browser"])
|
||||
agent = Agent(model="zen5", tools=["search", "shell", "browser"])
|
||||
result = agent.run("Find the latest release and summarize the changelog.")
|
||||
print(result.output)
|
||||
```
|
||||
@@ -120,7 +120,7 @@ tools = [{
|
||||
}]
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="zen-omni",
|
||||
model="zen5",
|
||||
messages=[{"role": "user", "content": "Weather in Tokyo?"}],
|
||||
tools=tools,
|
||||
tool_choice="auto",
|
||||
|
||||
@@ -50,7 +50,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
let response = client
|
||||
.chat()
|
||||
.completions()
|
||||
.create("zen-omni", "Explain quantum computing")
|
||||
.create("zen5", "Explain quantum computing")
|
||||
.await?;
|
||||
|
||||
println!("{}", response.choices[0].message.content);
|
||||
@@ -66,7 +66,7 @@ use futures::StreamExt;
|
||||
let mut stream = client
|
||||
.chat()
|
||||
.completions()
|
||||
.stream("zen-coder", "Write a haiku about AI")
|
||||
.stream("zen5-coder", "Write a haiku about AI")
|
||||
.await?;
|
||||
|
||||
while let Some(chunk) = stream.next().await {
|
||||
|
||||
@@ -38,7 +38,7 @@ import Hanzo
|
||||
let client = HanzoClient(apiKey: ProcessInfo.processInfo.environment["HANZO_API_KEY"]!)
|
||||
|
||||
let response = try await client.chat.completions.create(
|
||||
model: "zen-omni",
|
||||
model: "zen5",
|
||||
messages: [.user("Explain quantum computing")]
|
||||
)
|
||||
print(response.choices.first?.message.content ?? "")
|
||||
@@ -52,7 +52,7 @@ request.httpMethod = "POST"
|
||||
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
|
||||
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
request.httpBody = try JSONSerialization.data(withJSONObject: [
|
||||
"model": "zen-omni",
|
||||
"model": "zen5",
|
||||
"messages": [["role": "user", "content": "Hello"]],
|
||||
])
|
||||
let (data, _) = try await URLSession.shared.data(for: request)
|
||||
|
||||
@@ -54,7 +54,7 @@ import Hanzo from '@hanzo/sdk';
|
||||
const client = new Hanzo({ apiKey: process.env.HANZO_API_KEY });
|
||||
|
||||
const response = await client.chat.completions.create({
|
||||
model: 'zen-omni',
|
||||
model: 'zen5',
|
||||
messages: [{ role: 'user', content: 'Explain quantum computing' }],
|
||||
});
|
||||
|
||||
@@ -65,7 +65,7 @@ console.log(response.choices[0].message.content);
|
||||
|
||||
```typescript
|
||||
const stream = await client.chat.completions.create({
|
||||
model: 'zen-coder',
|
||||
model: 'zen5-coder',
|
||||
messages: [{ role: 'user', content: 'Write a haiku about AI' }],
|
||||
stream: true,
|
||||
});
|
||||
@@ -80,7 +80,7 @@ for await (const chunk of stream) {
|
||||
```typescript
|
||||
import { Agent } from '@hanzo/ai';
|
||||
|
||||
const agent = new Agent({ model: 'zen-omni', tools: ['search', 'shell'] });
|
||||
const agent = new Agent({ model: 'zen5', tools: ['search', 'shell'] });
|
||||
const result = await agent.run('Summarize the latest release notes.');
|
||||
console.log(result.output);
|
||||
```
|
||||
|
||||
@@ -82,7 +82,7 @@ import { Agent, Runtime } from '@hanzo/agents'
|
||||
|
||||
const agent = new Agent({
|
||||
name: 'researcher',
|
||||
model: 'claude-sonnet-4-5-20250929',
|
||||
model: 'zen5',
|
||||
brain: { org: 'startx' }, // wires Hanzo Brain
|
||||
tools: ['search', 'fetch', 'brain.recall'],
|
||||
})
|
||||
@@ -102,7 +102,7 @@ from hanzo_agents import Agent, Runtime
|
||||
|
||||
agent = Agent(
|
||||
name="researcher",
|
||||
model="claude-sonnet-4-5-20250929",
|
||||
model="zen5",
|
||||
brain={"org": "startx"},
|
||||
tools=["search", "fetch", "brain.recall"],
|
||||
)
|
||||
@@ -122,7 +122,7 @@ import agents "github.com/hanzoai/agents/sdk/go"
|
||||
|
||||
agent := agents.New(agents.Config{
|
||||
Name: "researcher",
|
||||
Model: "claude-sonnet-4-5-20250929",
|
||||
Model: "zen5",
|
||||
Brain: agents.Brain{Org: "startx"},
|
||||
Tools: []string{"search", "fetch", "brain.recall"},
|
||||
})
|
||||
|
||||
@@ -50,158 +50,180 @@ The Analytics dashboard is available at `console.hanzo.ai`:
|
||||
|
||||
## Metrics API
|
||||
|
||||
Query usage and cost metrics programmatically:
|
||||
Every call is on the one Hanzo API host, `https://api.hanzo.ai/v1/analytics`, with your normal bearer.
|
||||
|
||||
| Method | Path | Purpose |
|
||||
|--------|------|---------|
|
||||
| `GET` | `/v1/analytics/overview?range=` | One roll-up per lens for the range |
|
||||
| `GET` | `/v1/analytics/timeseries?range=` | Bucketed series (requests, tokens, spend) |
|
||||
| `GET` | `/v1/analytics/top?range=` | Leaderboards — top models, providers, pages |
|
||||
| `GET` | `/v1/analytics/health` | Datastore + per-lens availability |
|
||||
| `POST` | `/v1/analytics` | Capture one event |
|
||||
| `POST` | `/v1/analytics/batch` | Capture a batch of events |
|
||||
|
||||
`range` accepts `24h`, `7d`, `30d`, … The org is never passed by hand: the gateway re-mints `X-Org-Id` from your validated token, and every response echoes the resolved `scope`.
|
||||
|
||||
### Overview
|
||||
|
||||
```bash
|
||||
# Get usage summary for the last 7 days
|
||||
curl https://cloud.hanzo.ai/v1/analytics/usage \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN" \
|
||||
-d '{
|
||||
"start_date": "2025-06-01",
|
||||
"end_date": "2025-06-07",
|
||||
"group_by": ["model", "project"],
|
||||
"metrics": ["requests", "tokens", "cost"]
|
||||
}'
|
||||
curl -fsS "https://api.hanzo.ai/v1/analytics/overview?range=7d" \
|
||||
-H "Authorization: Bearer $HANZO_API_KEY"
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"model": "claude-sonnet-4-5-20250929",
|
||||
"project": "platform",
|
||||
"requests": 142500,
|
||||
"input_tokens": 285000000,
|
||||
"output_tokens": 71250000,
|
||||
"cost": 854.25
|
||||
}
|
||||
],
|
||||
"summary": {
|
||||
"total_requests": 1200000,
|
||||
"total_tokens": 847000000,
|
||||
"total_cost": 2341.50
|
||||
"range": "7d",
|
||||
"start": "2026-07-18T22:21:04Z",
|
||||
"end": "2026-07-25T22:21:04Z",
|
||||
"interval": "day",
|
||||
"scope": { "org": "hanzo" },
|
||||
"llm": {
|
||||
"available": true,
|
||||
"requests": 8661,
|
||||
"tokens": 130586947,
|
||||
"promptTokens": 126558231,
|
||||
"completionTokens": 4028716,
|
||||
"spendCents": 206418,
|
||||
"models": 115,
|
||||
"providers": 7,
|
||||
"errors": 212,
|
||||
"errorRate": 0.024,
|
||||
"source": "hanzo.cloud_usage"
|
||||
},
|
||||
"web": {
|
||||
"available": true,
|
||||
"pageviews": 4164,
|
||||
"visitors": 1159,
|
||||
"sessions": 875,
|
||||
"source": "hanzo.events"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Cost Tracking
|
||||
Each lens carries `available` and the `source` table it read, so a zero is never ambiguous — you can tell "nothing happened" from "that lens is not wired up".
|
||||
|
||||
### Budgets
|
||||
|
||||
Set per-project spending limits with automatic enforcement:
|
||||
### Time series
|
||||
|
||||
```bash
|
||||
# Set a monthly budget
|
||||
curl -X POST https://cloud.hanzo.ai/v1/analytics/budgets \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN" \
|
||||
-d '{
|
||||
"project_id": "proj_abc123",
|
||||
"monthly_limit": 5000.00,
|
||||
"alert_thresholds": [0.50, 0.75, 0.90],
|
||||
"action_on_exceed": "soft_limit"
|
||||
}'
|
||||
curl -fsS "https://api.hanzo.ai/v1/analytics/timeseries?range=7d" \
|
||||
-H "Authorization: Bearer $HANZO_API_KEY"
|
||||
```
|
||||
|
||||
### Cost Breakdown
|
||||
```json
|
||||
{
|
||||
"range": "7d",
|
||||
"interval": "day",
|
||||
"scope": { "org": "hanzo" },
|
||||
"series": [
|
||||
{ "t": "2026-07-18T00:00:00Z", "requests": 399, "tokens": 57306163, "spendCents": 88746 },
|
||||
{ "t": "2026-07-19T00:00:00Z", "requests": 5165, "tokens": 11717502, "spendCents": 23348 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
| Dimension | Description |
|
||||
|-----------|-------------|
|
||||
| By model | Cost per LLM model (input/output tokens) |
|
||||
| By project | Cost per project/team |
|
||||
| By API key | Cost per individual API key |
|
||||
| By endpoint | Cost per service endpoint |
|
||||
| By time | Hourly, daily, weekly, monthly aggregation |
|
||||
### Leaderboards
|
||||
|
||||
```bash
|
||||
curl -fsS "https://api.hanzo.ai/v1/analytics/top?range=7d" \
|
||||
-H "Authorization: Bearer $HANZO_API_KEY"
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"range": "7d",
|
||||
"scope": { "org": "hanzo" },
|
||||
"models": {
|
||||
"available": true,
|
||||
"items": [
|
||||
{ "model": "zen5", "provider": "hanzo", "requests": 483, "tokens": 64757117, "spendCents": 98732, "pct": 48.2 }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Health
|
||||
|
||||
```bash
|
||||
curl -fsS https://api.hanzo.ai/v1/analytics/health
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"datastore": true,
|
||||
"lenses": {
|
||||
"events": { "available": true, "table": "hanzo.events" },
|
||||
"llm": { "available": true, "table": "hanzo.cloud_usage" }
|
||||
},
|
||||
"service": "analytics",
|
||||
"status": "ok",
|
||||
"warehouse": "hanzo"
|
||||
}
|
||||
```
|
||||
|
||||
## Cost and budgets
|
||||
|
||||
Spend is metered into the same balance every product draws from, so cost lives with billing rather than in a second budgeting system:
|
||||
|
||||
- **Balance and itemized usage** — `GET /v1/billing/balance`, `GET /v1/billing/usage`
|
||||
- **Spend alerts** — `GET` · `POST /v1/billing/spend-alerts`
|
||||
- **Roll-ups by model, provider, and day** — the analytics endpoints above
|
||||
|
||||
See [Credits & Billing](/docs/billing).
|
||||
|
||||
### Cost breakdown dimensions
|
||||
|
||||
| Dimension | Where |
|
||||
|-----------|-------|
|
||||
| By model | `/v1/analytics/top` → `models.items[].spendCents` |
|
||||
| By provider | `/v1/analytics/top` → `models.items[].provider` |
|
||||
| By time | `/v1/analytics/timeseries` → `series[].spendCents` |
|
||||
| By transaction | `/v1/billing/usage` → `usage[].metadata` |
|
||||
|
||||
## Operational Health
|
||||
|
||||
Monitor service health with real-time metrics:
|
||||
Request rate, error rate, and latency for a running service come from the observability lens, not this one — see [Hanzo o11y](/docs/services/o11y):
|
||||
|
||||
```bash
|
||||
curl -fsS "https://api.hanzo.ai/v1/o11y/metrics?product=cloud" \
|
||||
-H "Authorization: Bearer $HANZO_API_KEY"
|
||||
```
|
||||
|
||||
| Metric | Description | Alert Threshold |
|
||||
|--------|-------------|-----------------|
|
||||
| `error_rate` | Percentage of 4xx/5xx responses | > 1% |
|
||||
| `latency_p50` | Median response time | > 200ms |
|
||||
| `latency_p99` | 99th percentile response time | > 2000ms |
|
||||
| `saturation` | Queue depth / capacity ratio | > 0.8 |
|
||||
| `availability` | Successful requests / total requests | < 99.9% |
|
||||
|
||||
## Alerting
|
||||
|
||||
Configure alerts that trigger on metric thresholds:
|
||||
|
||||
```bash
|
||||
# Create an alert rule
|
||||
curl -X POST https://cloud.hanzo.ai/v1/analytics/alerts \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN" \
|
||||
-d '{
|
||||
"name": "High error rate",
|
||||
"metric": "error_rate",
|
||||
"condition": "gt",
|
||||
"threshold": 0.01,
|
||||
"window": "5m",
|
||||
"channels": [
|
||||
{"type": "slack", "webhook": "https://hooks.slack.com/..."},
|
||||
{"type": "pagerduty", "routing_key": "..."}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
## Data Export
|
||||
|
||||
Export analytics data for external BI tools:
|
||||
|
||||
```bash
|
||||
# Export as CSV
|
||||
curl "https://cloud.hanzo.ai/v1/analytics/export?format=csv&range=30d" \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN" \
|
||||
-o analytics-export.csv
|
||||
|
||||
# Stream to webhook (real-time)
|
||||
curl -X POST https://cloud.hanzo.ai/v1/analytics/streams \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN" \
|
||||
-d '{
|
||||
"destination": "https://your-bi-tool.com/ingest",
|
||||
"events": ["request.completed", "cost.updated"],
|
||||
"format": "json"
|
||||
}'
|
||||
```
|
||||
|
||||
## SDK Integration
|
||||
|
||||
The analytics endpoints are plain REST on `api.hanzo.ai`, so any HTTP client works — no analytics-specific SDK to install.
|
||||
|
||||
### Python
|
||||
|
||||
```python
|
||||
from hanzoai import Hanzo
|
||||
import httpx, os
|
||||
|
||||
client = Hanzo(api_key="your-key")
|
||||
|
||||
# Get usage for current billing period
|
||||
usage = client.analytics.usage(
|
||||
group_by=["model"],
|
||||
metrics=["requests", "tokens", "cost"]
|
||||
r = httpx.get(
|
||||
"https://api.hanzo.ai/v1/analytics/top",
|
||||
params={"range": "7d"},
|
||||
headers={"Authorization": f"Bearer {os.environ['HANZO_API_KEY']}"},
|
||||
)
|
||||
|
||||
for row in usage.data:
|
||||
print(f"{row.model}: {row.requests} requests, ${row.cost:.2f}")
|
||||
for row in r.json()["models"]["items"]:
|
||||
print(f"{row['model']}: {row['requests']} requests, ${row['spendCents'] / 100:.2f}")
|
||||
```
|
||||
|
||||
### TypeScript
|
||||
|
||||
```typescript
|
||||
import Hanzo from '@hanzo/ai'
|
||||
|
||||
const client = new Hanzo({ apiKey: 'your-key' })
|
||||
|
||||
const usage = await client.analytics.usage({
|
||||
groupBy: ['model', 'project'],
|
||||
metrics: ['requests', 'tokens', 'cost'],
|
||||
range: '7d'
|
||||
const res = await fetch('https://api.hanzo.ai/v1/analytics/top?range=7d', {
|
||||
headers: { Authorization: `Bearer ${process.env.HANZO_API_KEY}` },
|
||||
})
|
||||
const { models } = await res.json()
|
||||
|
||||
usage.data.forEach(row => {
|
||||
console.log(`${row.model}: ${row.requests} requests, $${row.cost}`)
|
||||
})
|
||||
for (const row of models.items) {
|
||||
console.log(`${row.model}: ${row.requests} requests, $${(row.spendCents / 100).toFixed(2)}`)
|
||||
}
|
||||
```
|
||||
|
||||
## Related Services
|
||||
|
||||
@@ -148,7 +148,7 @@ endpoints:
|
||||
apiKey: "${ANTHROPIC_API_KEY}"
|
||||
models:
|
||||
default:
|
||||
- claude-sonnet-4-5-20250929
|
||||
- zen5
|
||||
- claude-opus-4-20250514
|
||||
```
|
||||
|
||||
|
||||
@@ -336,7 +336,6 @@ The Hanzo cluster is exposed via an nginx Ingress with TLS (cert-manager + Let's
|
||||
| Domain | Type | Target |
|
||||
|--------|------|--------|
|
||||
| `api.hanzo.ai` | A (CF proxied) | `24.199.76.156` (hanzo-k8s LB) |
|
||||
| `llm.hanzo.ai` | CNAME | `api.hanzo.ai` |
|
||||
| `api.lux.network` | A | `134.199.141.71` (lux-k8s LB) |
|
||||
|
||||
### Operations
|
||||
|
||||
@@ -9,7 +9,7 @@ The Hanzo IAM web UI is a React [SPA](https://developer.mozilla.org/en-US/docs/G
|
||||
- Hanzo IAM SDKs (e.g. iam-go-sdk)
|
||||
- Your own applications and scripts
|
||||
|
||||
**API reference:** [https://iam.hanzo.ai/swagger](https://iam.hanzo.ai/swagger). To regenerate the Swagger spec, see [Developer guide – Swagger](/docs/developer-guide/swagger#generate-swagger-files).
|
||||
**API reference:** [https://hanzo.id/swagger](https://hanzo.id/swagger). To regenerate the Swagger spec, see [Developer guide – Swagger](/docs/developer-guide/swagger#generate-swagger-files).
|
||||
|
||||
## Response language
|
||||
|
||||
@@ -17,7 +17,7 @@ Responses can be localized. Send the `Accept-Language` header to get error messa
|
||||
|
||||
```bash
|
||||
# Example: Get error messages in French
|
||||
curl -X GET https://iam.hanzo.ai/v1/iam/get-account \
|
||||
curl -X GET https://api.hanzo.ai/v1/iam/get-account \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
-H "Accept-Language: fr"
|
||||
|
||||
@@ -52,7 +52,7 @@ Use the access token obtained after a user signs in (e.g. from the OAuth code ex
|
||||
|
||||
#### Getting the token
|
||||
|
||||
The app receives the token at the end of the OAuth login flow (code + state). Issued tokens are also visible in the Hanzo IAM UI (**Tokens** page, e.g. `https://iam.hanzo.ai/tokens`).
|
||||
The app receives the token at the end of the OAuth login flow (code + state). Issued tokens are also visible in the Hanzo IAM UI (**Tokens** page, e.g. `https://hanzo.id/tokens`).
|
||||
|
||||
Example (Go, iam-go-sdk):
|
||||
|
||||
@@ -97,7 +97,7 @@ func (c *ApiController) Signin() {
|
||||
/page?access_token=<The access token>
|
||||
```
|
||||
|
||||
Demo site example: `https://iam.hanzo.ai/api/get-global-providers?access_token=eyJhbGciOiJSUzI1NiIs`
|
||||
Demo site example: `https://api.hanzo.ai/v1/iam/get-global-providers?access_token=eyJhbGciOiJSUzI1NiIs`
|
||||
|
||||
2. **Bearer header:**
|
||||
|
||||
@@ -111,7 +111,7 @@ Use this for **machine-to-machine** calls (no user). Permissions are those of th
|
||||
|
||||
#### Getting credentials
|
||||
|
||||
On the application edit page (e.g. `https://iam.hanzo.ai/applications/casbin/app-vue-python-example`) you’ll see **Client ID** and **Client Secret**.
|
||||
On the application edit page (e.g. `https://hanzo.id/applications/casbin/app-vue-python-example`) you’ll see **Client ID** and **Client Secret**.
|
||||
|
||||
#### Use cases
|
||||
|
||||
@@ -189,12 +189,12 @@ Create a key pair on the user’s account settings page.
|
||||
/page?accessKey=<The user's access key>&accessSecret=<the user's access secret>"
|
||||
```
|
||||
|
||||
Example: `https://iam.hanzo.ai/api/get-global-providers?accessKey=...&accessSecret=...`
|
||||
Example: `https://api.hanzo.ai/v1/iam/get-global-providers?accessKey=...&accessSecret=...`
|
||||
|
||||

|
||||
|
||||
```bash
|
||||
curl --location 'http://iam.hanzo.ai/api/user?accessKey=b86db9dc-6bd7-4997-935c-af480dd2c796&accessSecret=79911517-fc36-4093-b115-65a9741f6b14'
|
||||
curl --location 'https://api.hanzo.ai/v1/iam/user?accessKey=b86db9dc-6bd7-4997-935c-af480dd2c796&accessSecret=79911517-fc36-4093-b115-65a9741f6b14'
|
||||
|
||||
### 4. Username and password
|
||||
|
||||
@@ -212,12 +212,12 @@ Username format: `<organization>/<username>`. API calls run as that user.
|
||||
|
||||
## SSO logout
|
||||
|
||||
The `/api/sso-logout` endpoint logs a user out from all applications or only the current session, depending on `logoutAll`.
|
||||
The `/v1/iam/sso-logout` endpoint logs a user out from all applications or only the current session, depending on `logoutAll`.
|
||||
|
||||
### Endpoint
|
||||
|
||||
```http
|
||||
GET or POST /api/sso-logout?logoutAll=<true|false>
|
||||
GET or POST /v1/iam/sso-logout?logoutAll=<true|false>
|
||||
|
||||
### Parameters
|
||||
|
||||
@@ -247,15 +247,15 @@ The user must be authenticated. Use any of the [authentication methods](#how-to-
|
||||
|
||||
```bash
|
||||
# Full SSO logout (all sessions)
|
||||
curl -X POST https://iam.hanzo.ai/api/sso-logout \
|
||||
curl -X POST https://api.hanzo.ai/v1/iam/sso-logout \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||||
|
||||
# Session-level logout (current session only)
|
||||
curl -X POST "https://iam.hanzo.ai/api/sso-logout?logoutAll=false" \
|
||||
curl -X POST "https://api.hanzo.ai/v1/iam/sso-logout?logoutAll=false" \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||||
|
||||
# Using session cookie
|
||||
curl -X POST https://iam.hanzo.ai/api/sso-logout \
|
||||
curl -X POST https://api.hanzo.ai/v1/iam/sso-logout \
|
||||
--cookie "iam_session_id=abc123def456"
|
||||
|
||||
### Response
|
||||
|
||||
@@ -114,7 +114,7 @@ insights.capture({
|
||||
event: 'api_request',
|
||||
properties: {
|
||||
endpoint: '/v1/chat/completions',
|
||||
model: 'zen-coder-32b-instruct',
|
||||
model: 'zen5-coder-32b-instruct',
|
||||
tokens: 1500,
|
||||
latency_ms: 340,
|
||||
},
|
||||
@@ -249,7 +249,7 @@ insights.capture('purchase_completed', {
|
||||
|
||||
// AI/LLM
|
||||
insights.capture('model_inference', {
|
||||
model: 'zen-coder-32b-instruct',
|
||||
model: 'zen5-coder-32b-instruct',
|
||||
tokens_in: 150,
|
||||
tokens_out: 500,
|
||||
latency_ms: 1240,
|
||||
|
||||
@@ -11,7 +11,7 @@ Hanzo KMS is the key management service for the Hanzo platform. It stores secret
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **API** | `https://kms.hanzo.ai` |
|
||||
| **API** | `https://api.hanzo.ai` — one host for every Hanzo service |
|
||||
| **API prefix** | `/v1/kms` |
|
||||
| **Auth** | Machine-identity login → bearer JWT (verified against [Hanzo IAM](/docs/services/iam)) |
|
||||
| **K8s sync** | `KMSSecret` CRD via the kms-operator |
|
||||
@@ -27,7 +27,7 @@ KMS uses **machine identities**: a non-human `clientId` + `clientSecret` minted
|
||||
|
||||
```bash
|
||||
# Log in (clientId/clientSecret come from a K8s Secret or your secret store — never inline them)
|
||||
ACCESS_TOKEN=$(curl -sS -X POST https://kms.hanzo.ai/v1/kms/auth/login \
|
||||
ACCESS_TOKEN=$(curl -sS -X POST https://api.hanzo.ai/v1/kms/auth/login \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"clientId\":\"$KMS_CLIENT_ID\",\"clientSecret\":\"$KMS_CLIENT_SECRET\"}" \
|
||||
| jq -r .accessToken)
|
||||
@@ -47,7 +47,7 @@ A secret is addressed by four coordinates:
|
||||
|
||||
```
|
||||
org / path / name ? env
|
||||
hanzo / providers / OPENAI_API_KEY ? env=production
|
||||
hanzo / providers / OPENAI_API_KEY ? env=prod
|
||||
```
|
||||
|
||||
- **org** — the organization slug; must match the token's `owner` claim.
|
||||
@@ -56,24 +56,29 @@ hanzo / providers / OPENAI_API_KEY ? env=production
|
||||
- **env** — a query parameter; defaults to `default` when omitted.
|
||||
|
||||
<Callout type="info">
|
||||
KMS reads are **exact-name** — there is no "list all secrets in a folder" endpoint. Enumerate the keys your workload needs (the `KMSSecret` CRD does exactly this).
|
||||
Reads are **exact-name**: `GET …/secrets/{path}/{name}?env=` returns one value. `GET …/secrets?env=` lists a namespace's secret **metadata** (name, path, env, scheme) — never values. Enumerate the keys your workload needs; the `KMSSecret` CRD does exactly this.
|
||||
</Callout>
|
||||
|
||||
## Reading & writing secrets
|
||||
|
||||
All routes are under `https://kms.hanzo.ai/v1/kms/orgs/{org}/secrets`.
|
||||
All routes are under `https://api.hanzo.ai/v1/kms/orgs/{org}/secrets`.
|
||||
|
||||
| Method | Path | Purpose |
|
||||
|--------|------|---------|
|
||||
| `GET` | `/v1/kms/orgs/{org}/secrets?env=` | List secret metadata in the namespace (no values) |
|
||||
| `GET` | `/v1/kms/orgs/{org}/secrets/{path}/{name}?env=` | Read a secret value + version |
|
||||
| `POST` | `/v1/kms/orgs/{org}/secrets` | Create/upsert (`{path,name,env,value}`) → `{ok,version}` |
|
||||
| `PATCH` | `/v1/kms/orgs/{org}/secrets/{path}/{name}` | Update (optimistic concurrency — see below) |
|
||||
| `DELETE` | `/v1/kms/orgs/{org}/secrets/{path}/{name}?env=` | Delete |
|
||||
|
||||
<Callout type="warn">
|
||||
`env` is **required** on every read and write. Omitting it silently buckets the secret into the `default` environment, where the workload looking for `env=prod` will never find it. Always pass it explicitly.
|
||||
</Callout>
|
||||
|
||||
### Read
|
||||
|
||||
```bash
|
||||
curl -sS "https://kms.hanzo.ai/v1/kms/orgs/hanzo/secrets/providers/OPENAI_API_KEY?env=production" \
|
||||
curl -sS "https://api.hanzo.ai/v1/kms/orgs/hanzo/secrets/providers/OPENAI_API_KEY?env=prod" \
|
||||
-H "Authorization: Bearer $ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
@@ -81,15 +86,15 @@ curl -sS "https://kms.hanzo.ai/v1/kms/orgs/hanzo/secrets/providers/OPENAI_API_KE
|
||||
{ "secret": { "value": "<secret value>" }, "version": 3 }
|
||||
```
|
||||
|
||||
A root-path secret omits the folder segment: `…/secrets/STRIPE_SECRET_KEY?env=production`.
|
||||
A root-path secret omits the folder segment: `…/secrets/STRIPE_SECRET_KEY?env=prod`.
|
||||
|
||||
### Create
|
||||
|
||||
```bash
|
||||
curl -sS -X POST "https://kms.hanzo.ai/v1/kms/orgs/hanzo/secrets" \
|
||||
curl -sS -X POST "https://api.hanzo.ai/v1/kms/orgs/hanzo/secrets" \
|
||||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "path": "/providers", "name": "OPENAI_API_KEY", "env": "production", "value": "<new value>" }'
|
||||
-d '{ "path": "/providers", "name": "OPENAI_API_KEY", "env": "prod", "value": "<new value>" }'
|
||||
```
|
||||
|
||||
```json
|
||||
@@ -101,7 +106,7 @@ curl -sS -X POST "https://kms.hanzo.ai/v1/kms/orgs/hanzo/secrets" \
|
||||
Updates require the current version, supplied either as an `If-Match` header or `version` in the body. A missing precondition returns `428 Precondition Required`; a stale version returns `409 Conflict` with the current version.
|
||||
|
||||
```bash
|
||||
curl -sS -X PATCH "https://kms.hanzo.ai/v1/kms/orgs/hanzo/secrets/providers/OPENAI_API_KEY?env=production" \
|
||||
curl -sS -X PATCH "https://api.hanzo.ai/v1/kms/orgs/hanzo/secrets/providers/OPENAI_API_KEY?env=prod" \
|
||||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-H "If-Match: 3" \
|
||||
-H "Content-Type: application/json" \
|
||||
@@ -141,7 +146,7 @@ spec:
|
||||
secretNamespace: hanzo
|
||||
secretsScope:
|
||||
projectSlug: hanzo # -> {org}
|
||||
envSlug: production # -> ?env=production
|
||||
envSlug: production # -> ?env=prod
|
||||
secretsPath: /providers # -> {path}
|
||||
keys: # enumerated; no list endpoint
|
||||
- OPENAI_API_KEY
|
||||
|
||||
@@ -89,7 +89,7 @@ A machine identity is a client-credentials application in [Hanzo IAM](/docs/serv
|
||||
Once you have a `clientId`/`clientSecret`, log in to KMS:
|
||||
|
||||
```bash
|
||||
curl -X POST https://kms.hanzo.ai/v1/kms/auth/login \
|
||||
curl -X POST https://api.hanzo.ai/v1/kms/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"clientId\":\"$KMS_CLIENT_ID\",\"clientSecret\":\"$KMS_CLIENT_SECRET\"}"
|
||||
```
|
||||
|
||||
@@ -9,9 +9,10 @@ description: Full-stack observability platform — Prometheus metrics, Grafana d
|
||||
|
||||
Hanzo O11y is the unified observability stack for the entire Hanzo platform. It collects metrics, logs, and distributed traces from every service, aggregates them into a single pane of glass, and drives alerting and SLO enforcement. Built on Prometheus, Grafana, and OpenTelemetry, O11y gives operators and developers real-time visibility into infrastructure health, application performance, and service mesh telemetry.
|
||||
|
||||
**Endpoint:** `o11y.hanzo.ai`
|
||||
**Prometheus:** `o11y.hanzo.ai:9090`
|
||||
**Gateway:** `api.hanzo.ai/v1/o11y/*`
|
||||
**API:** `https://api.hanzo.ai/v1/o11y` — one host, one bearer, like every other Hanzo service.
|
||||
**Dashboards:** `o11y.hanzo.ai`, which 301-redirects to `console.hanzo.ai/o11y`.
|
||||
|
||||
There is no separately-addressable Prometheus, Loki, or OTLP port on the public internet: `o11y.hanzo.ai:9090` and `:4317` are closed. Every read and every write goes through `/v1/o11y`.
|
||||
|
||||
## Features
|
||||
|
||||
@@ -86,38 +87,64 @@ Hanzo O11y is the unified observability stack for the entire Hanzo platform. It
|
||||
### Send Metrics via OTLP
|
||||
|
||||
```bash
|
||||
# Push metrics using the OpenTelemetry HTTP endpoint
|
||||
curl -X POST https://o11y.hanzo.ai/v1/metrics \
|
||||
# Ingest telemetry
|
||||
curl -X POST https://api.hanzo.ai/v1/o11y/ingestion \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN" \
|
||||
-H "Content-Type: application/x-protobuf" \
|
||||
--data-binary @metrics.pb
|
||||
-H "Content-Type: application/json" \
|
||||
--data-binary @batch.json
|
||||
# → {"accepted":1,"dropped":0}
|
||||
```
|
||||
|
||||
# Or query Prometheus directly
|
||||
curl "https://o11y.hanzo.ai:9090/api/v1/query?query=up" \
|
||||
### Read a service's health
|
||||
|
||||
`product` names the service you are asking about, and is required:
|
||||
|
||||
```bash
|
||||
curl -fsS "https://api.hanzo.ai/v1/o11y/status?product=cloud" \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN"
|
||||
```
|
||||
|
||||
### Query Logs
|
||||
|
||||
```bash
|
||||
curl "https://o11y.hanzo.ai/loki/api/v1/query_range" \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN" \
|
||||
--data-urlencode 'query={service="gateway"} |= "error"' \
|
||||
--data-urlencode 'start=1708560000' \
|
||||
--data-urlencode 'end=1708646400' \
|
||||
--data-urlencode 'limit=100'
|
||||
```json
|
||||
{ "product": "cloud", "up": true, "latencyMs": 12, "deployments": [], "checkedAt": "2026-07-25T21:56:23Z" }
|
||||
```
|
||||
|
||||
### Instrument Your Application
|
||||
### Query metrics, logs, and traces
|
||||
|
||||
```bash
|
||||
# Set environment variables for any OTLP-compatible application
|
||||
export OTEL_EXPORTER_OTLP_ENDPOINT=https://o11y.hanzo.ai:4317
|
||||
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer $HANZO_TOKEN"
|
||||
export OTEL_SERVICE_NAME=my-service
|
||||
export OTEL_RESOURCE_ATTRIBUTES="deployment.environment=production"
|
||||
# Request/error/latency series for one product
|
||||
curl -fsS "https://api.hanzo.ai/v1/o11y/metrics?product=cloud" \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN"
|
||||
|
||||
# Recent log lines
|
||||
curl -fsS "https://api.hanzo.ai/v1/o11y/logs?product=cloud&limit=100" \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN"
|
||||
|
||||
# Traces
|
||||
curl -fsS "https://api.hanzo.ai/v1/o11y/traces" \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN"
|
||||
|
||||
# Raw PromQL
|
||||
curl -fsS "https://api.hanzo.ai/v1/o11y/query?query=up" \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN"
|
||||
curl -fsS "https://api.hanzo.ai/v1/o11y/query_range?query=sum(up)&start=1&end=2&step=15" \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN"
|
||||
```
|
||||
|
||||
### Endpoints
|
||||
|
||||
| Method | Path | Purpose |
|
||||
|--------|------|---------|
|
||||
| `GET` | `/v1/o11y/health` | Liveness |
|
||||
| `GET` | `/v1/o11y/status?product=` | Up/down, latency, live deployments |
|
||||
| `GET` | `/v1/o11y/metrics?product=` | Request, error, and latency series |
|
||||
| `GET` | `/v1/o11y/logs?product=` | Log lines with a cursor |
|
||||
| `GET` | `/v1/o11y/traces` | Trace list |
|
||||
| `GET` | `/v1/o11y/query` · `/v1/o11y/query_range` | PromQL instant / range |
|
||||
| `POST` | `/v1/o11y/ingestion` | Telemetry ingest |
|
||||
| `GET` | `/v1/o11y/sessions` · `/v1/o11y/annotation-queues` | Session replay, review queues |
|
||||
|
||||
`/v1/o11y/vm/*` is fleet-wide platform infrastructure health and is restricted to platform administrators — a normal org bearer gets `403`.
|
||||
|
||||
## Metrics
|
||||
|
||||
### Prometheus Collection
|
||||
@@ -187,8 +214,8 @@ inference_requests.labels(model="qwen3-4b", status="ok").inc()
|
||||
O11y aggregates logs from all Hanzo services via Loki. Logs are structured as JSON and enriched with K8s metadata (namespace, pod, container, node) automatically.
|
||||
|
||||
```bash
|
||||
# Push logs directly via the Loki API
|
||||
curl -X POST https://o11y.hanzo.ai/loki/api/v1/push \
|
||||
# Push logs through the one o11y door
|
||||
curl -X POST https://api.hanzo.ai/v1/o11y/ingestion \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
@@ -233,12 +260,8 @@ sum by (service) (rate({namespace="hanzo"} [5m]))
|
||||
O11y collects distributed traces via the OpenTelemetry Collector and stores them in Tempo. Traces automatically propagate across service boundaries using W3C Trace Context headers.
|
||||
|
||||
```bash
|
||||
# Query traces by service
|
||||
curl "https://o11y.hanzo.ai/tempo/api/search?service.name=gateway&limit=20" \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN"
|
||||
|
||||
# Get a specific trace by ID
|
||||
curl "https://o11y.hanzo.ai/tempo/api/traces/abc123def456" \
|
||||
# Query traces
|
||||
curl -fsS "https://api.hanzo.ai/v1/o11y/traces" \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN"
|
||||
```
|
||||
|
||||
@@ -252,7 +275,7 @@ from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExport
|
||||
|
||||
# Configure exporter
|
||||
exporter = OTLPSpanExporter(
|
||||
endpoint="https://o11y.hanzo.ai:4317",
|
||||
endpoint="https://api.hanzo.ai/v1/o11y/ingestion",
|
||||
headers={"Authorization": f"Bearer {HANZO_TOKEN}"}
|
||||
)
|
||||
|
||||
@@ -356,54 +379,35 @@ O11y ships with curated Grafana dashboards for every layer of the stack:
|
||||
|
||||
### Custom Dashboards
|
||||
|
||||
Create dashboards via the Grafana API or UI at `o11y.hanzo.ai`:
|
||||
Build dashboards in the console at [console.hanzo.ai/o11y](https://console.hanzo.ai/o11y) (`o11y.hanzo.ai` redirects there). A dashboard is a saved set of `/v1/o11y` queries — the panel definition below is the shape the console stores:
|
||||
|
||||
```bash
|
||||
# Import a dashboard from JSON
|
||||
curl -X POST https://o11y.hanzo.ai/api/dashboards/db \
|
||||
-H "Authorization: Bearer $GRAFANA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"dashboard": {
|
||||
"title": "My Service Dashboard",
|
||||
"panels": [
|
||||
{
|
||||
"title": "Request Rate",
|
||||
"type": "timeseries",
|
||||
"targets": [
|
||||
{"expr": "rate(http_requests_total{service=\"my-service\"}[5m])"}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"overwrite": false
|
||||
}'
|
||||
```json
|
||||
{
|
||||
"dashboard": {
|
||||
"title": "My Service Dashboard",
|
||||
"panels": [
|
||||
{
|
||||
"title": "Request Rate",
|
||||
"type": "timeseries",
|
||||
"targets": [
|
||||
{ "expr": "rate(http_requests_total{service=\"my-service\"}[5m])" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## SLO Management
|
||||
|
||||
Define Service Level Objectives and track error budgets:
|
||||
|
||||
SLOs are defined in the console at [console.hanzo.ai/o11y](https://console.hanzo.ai/o11y). An SLO is a saved SLI query plus a target and a window; the live alert state it drives is readable over the API:
|
||||
|
||||
```bash
|
||||
# Create an SLO
|
||||
curl -X POST https://api.hanzo.ai/v1/o11y/slos \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "Gateway Availability",
|
||||
"description": "99.9% of requests return non-5xx in a 30-day window",
|
||||
"sli": {
|
||||
"type": "availability",
|
||||
"good": "http_requests_total{service=\"gateway\",status!~\"5..\"}",
|
||||
"total": "http_requests_total{service=\"gateway\"}"
|
||||
},
|
||||
"target": 0.999,
|
||||
"window": "30d",
|
||||
"alerts": {
|
||||
"burn_rate_1h": 14.4,
|
||||
"burn_rate_6h": 6.0
|
||||
}
|
||||
}'
|
||||
curl -fsS https://api.hanzo.ai/v1/o11y/alerts \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN"
|
||||
# → {"status":"success","data":[]}
|
||||
```
|
||||
|
||||
| SLO | Target | SLI | Error Budget (30d) |
|
||||
@@ -450,7 +454,7 @@ Sidecar proxies automatically emit RED metrics (Rate, Errors, Duration) for all
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP collector endpoint | `https://o11y.hanzo.ai:4317` |
|
||||
| `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP ingest endpoint | `https://api.hanzo.ai/v1/o11y/ingestion` |
|
||||
| `OTEL_EXPORTER_OTLP_HEADERS` | Auth headers for OTLP | - |
|
||||
| `OTEL_SERVICE_NAME` | Service name for telemetry | - |
|
||||
| `OTEL_RESOURCE_ATTRIBUTES` | Additional resource attributes | - |
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
---
|
||||
title: Hanzo PaaS
|
||||
description: The platform.hanzo.ai control plane for deploying and operating services on Hanzo's Kubernetes clusters.
|
||||
description: The Hanzo control plane for deploying and operating services on Hanzo's Kubernetes clusters — Studio at platform.hanzo.ai, API at api.hanzo.ai/v1/platform.
|
||||
---
|
||||
|
||||
# Hanzo PaaS
|
||||
|
||||
> **API reference** · [Hanzo PaaS API →](/docs/openapi/paas) — every endpoint, generated from the OpenAPI spec.
|
||||
|
||||
Hanzo PaaS is the deployment and operations control plane for the Hanzo platform, served at **`platform.hanzo.ai`**. You register an application, point it at a container image or Git repository, attach a domain, and the platform builds, deploys, and operates it on Hanzo's Kubernetes clusters — with deployment history, rolling updates, and drift detection.
|
||||
Hanzo PaaS is the deployment and operations control plane for the Hanzo platform. The Studio (browser UI) is at **`platform.hanzo.ai`**; every programmatic call goes to **`api.hanzo.ai/v1/platform`**, the one Hanzo API host. You register an application, point it at a container image or Git repository, attach a domain, and the platform builds, deploys, and operates it on Hanzo's Kubernetes clusters — with deployment history, rolling updates, and drift detection.
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **Control plane** | `https://platform.hanzo.ai` |
|
||||
| **Canonical API** | `https://platform.hanzo.ai/v1` |
|
||||
| **Studio** (browser UI) | `https://platform.hanzo.ai` |
|
||||
| **API** | `https://api.hanzo.ai/v1/platform` |
|
||||
| **Build** | `POST https://api.hanzo.ai/v1/runner` |
|
||||
| **Auth** | [Hanzo IAM](/docs/services/iam) (interactive) · API key / service token (machine) |
|
||||
| **Secrets** | [Hanzo KMS](/docs/services/kms) via `KMSSecret` CRDs — zero plaintext |
|
||||
| **Ingress** | Hanzo Ingress + cert-manager (automatic Let's Encrypt TLS) |
|
||||
@@ -20,8 +21,8 @@ Hanzo PaaS is the deployment and operations control plane for the Hanzo platform
|
||||
## How it fits together
|
||||
|
||||
```
|
||||
push image / git ──▶ platform.hanzo.ai ──▶ operator ──▶ Kubernetes
|
||||
(declare + drive) (reconcile) (run + serve)
|
||||
push image / git ──▶ api.hanzo.ai/v1 ──▶ operator ──▶ Kubernetes
|
||||
(declare + drive) (reconcile) (run + serve)
|
||||
▲ │
|
||||
└────────── observe (drift) ────────┘
|
||||
```
|
||||
@@ -34,7 +35,7 @@ Secrets are never embedded in manifests — workloads read them from [Hanzo KMS]
|
||||
|
||||
## Get started
|
||||
|
||||
The full control-plane reference — the project/environment/application model, the `/v1` container redeploy, the build pipeline, clusters, domains, and the observe/drift board — lives in the Platform docs:
|
||||
The full control-plane reference — the project/application model, `/v1/platform` deploys, `/v1/runner` builds, clusters, and domains — lives in the Platform docs:
|
||||
|
||||
<Cards>
|
||||
<Card title="Platform Overview" href="/docs/services/platform">
|
||||
|
||||
@@ -3,13 +3,14 @@ title: Authentication
|
||||
description: IAM tokens, API keys, and service tokens for the Hanzo PaaS API
|
||||
---
|
||||
|
||||
Hanzo PaaS has three credential types, matched to its two API surfaces. Machine credentials are stored in [Hanzo KMS](/docs/services/kms) and read at runtime — never hard-coded.
|
||||
Hanzo PaaS has **one** API surface — `https://api.hanzo.ai/v1/platform` — and one credential shape: a bearer token. Machine credentials live in [Hanzo KMS](/docs/services/kms) and are read at runtime, never hard-coded.
|
||||
|
||||
| Credential | Header | Surface | Use |
|
||||
|------------|--------|---------|-----|
|
||||
| **IAM token** | `Authorization: Bearer <jwt>` | `/api` | Interactive / user access via SSO |
|
||||
| **API key** | `x-api-key: <key>` | `/api` | Machine access to the build pipeline; org-scoped |
|
||||
| **Service token** | `Authorization: Bearer <token>` | `/v1` | Container redeploy and observe (M2M) |
|
||||
| Credential | Header | Use |
|
||||
|------------|--------|-----|
|
||||
| **IAM token** | `Authorization: Bearer <jwt>` | Everything — interactive SSO *and* machine access. An org-admin IAM login also authorizes `POST /v1/runner` builds. |
|
||||
| **Build token** | `Authorization: Bearer <build-token>` | Fabric automation only (git-push-to-deploy, self-release). Never held by a user. |
|
||||
|
||||
There is no `x-api-key` header and no separate service token.
|
||||
|
||||
## OAuth2 via Hanzo ID
|
||||
|
||||
@@ -59,41 +60,32 @@ curl -X POST https://hanzo.id/v1/iam/oauth/token \
|
||||
|
||||
Refresh with `grant_type=refresh_token`. See [Hanzo IAM](/docs/services/iam) for the full flow.
|
||||
|
||||
## API keys (build pipeline)
|
||||
## Machine identity (no user present)
|
||||
|
||||
API keys authenticate machine callers to the `/api` build-pipeline surface. Create one in the Studio under **Settings → API Keys** — the key is scoped to the organization you create it under and shown once.
|
||||
|
||||
<Callout type="warn">
|
||||
Store API keys in [Hanzo KMS](/docs/services/kms) immediately. They are shown only at creation. If lost, revoke and create a new one.
|
||||
</Callout>
|
||||
A service exchanges its KMS machine identity for the same kind of bearer — no second credential type, no key file:
|
||||
|
||||
```bash
|
||||
curl https://platform.hanzo.ai/api/application.all \
|
||||
-H "x-api-key: $PLATFORM_API_KEY"
|
||||
TOKEN=$(curl -sS -X POST https://api.hanzo.ai/v1/kms/auth/login \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"clientId\":\"$KMS_CLIENT_ID\",\"clientSecret\":\"$KMS_CLIENT_SECRET\"}" | jq -r .accessToken)
|
||||
```
|
||||
|
||||
## Service tokens (`/v1` surface)
|
||||
|
||||
The canonical `/v1` control surface (container redeploy, `/v1/apps` observe) uses a service token presented as a bearer:
|
||||
|
||||
```bash
|
||||
curl -fsS -X POST \
|
||||
"https://platform.hanzo.ai/v1/org/$ORG_ID/project/$PROJECT_ID/env/$ENV_ID/container/$CONTAINER_ID/redeploy" \
|
||||
-H "Authorization: Bearer $PAAS_SERVICE_TOKEN"
|
||||
```
|
||||
|
||||
The service token is issued out-of-band and stored in KMS (e.g. `kms.hanzo.ai/v1/kms/orgs/hanzo/secrets/paas/SERVICE_TOKEN`). It is a pure machine-to-machine credential with no user session.
|
||||
`clientId` / `clientSecret` come from a Kubernetes Secret or your secret store — never inline them. The response is `{"accessToken":"<RS256 JWT>","expiresIn":604800,"tokenType":"Bearer"}`.
|
||||
|
||||
## Request examples
|
||||
|
||||
```bash
|
||||
# List organizations (build pipeline, API key)
|
||||
curl https://platform.hanzo.ai/api/organization.all \
|
||||
-H "x-api-key: $PLATFORM_API_KEY"
|
||||
# List projects
|
||||
curl -fsS https://api.hanzo.ai/v1/platform/projects \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
|
||||
# Register an application
|
||||
curl -X POST https://platform.hanzo.ai/api/application.create \
|
||||
-H "x-api-key: $PLATFORM_API_KEY" \
|
||||
# Create an application
|
||||
curl -fsS -X POST https://api.hanzo.ai/v1/platform/projects/$PROJECT/apps \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "name": "web", "environmentId": "'$ENV_ID'" }'
|
||||
-d '{ "name": "web" }'
|
||||
|
||||
# Roll it forward
|
||||
curl -fsS -X POST https://api.hanzo.ai/v1/platform/projects/$PROJECT/apps/web/deploy \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
@@ -1,227 +1,66 @@
|
||||
---
|
||||
title: Clusters API
|
||||
description: Manage Kubernetes and Docker Swarm clusters via the API
|
||||
description: List, attach, scale, and detach Kubernetes clusters through api.hanzo.ai/v1.
|
||||
---
|
||||
|
||||
The Clusters API handles the full lifecycle of compute clusters: creation, configuration, scaling, and deletion.
|
||||
Clusters are a top-level noun on the one Hanzo API host. Managed clusters (Visor-provisioned DOKS/AWS/…) and bring-your-own clusters attached with a kubeconfig surface together.
|
||||
|
||||
All calls take an IAM bearer — see [Authentication](/docs/services/platform/api/authentication).
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Procedure | Method | Description |
|
||||
|-----------|--------|-------------|
|
||||
| `cluster.all` | GET | List all clusters in the organization |
|
||||
| `cluster.one` | GET | Get cluster details |
|
||||
| `cluster.create` | POST | Provision a new cluster |
|
||||
| `cluster.update` | PATCH | Update cluster settings |
|
||||
| `cluster.remove` | DELETE | Destroy a cluster |
|
||||
| `cluster.nodes` | GET | List nodes in a cluster |
|
||||
| `cluster.addNode` | POST | Add a node to a cluster |
|
||||
| `cluster.removeNode` | DELETE | Remove a node from a cluster |
|
||||
| `cluster.grantAccess` | POST | Grant user access to a cluster |
|
||||
| `cluster.listAccess` | GET | List cluster access permissions |
|
||||
| `cluster.revokeAccess` | DELETE | Revoke user access |
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `GET` | `/v1/clusters` | List every cluster the org can see (managed + BYO) |
|
||||
| `POST` | `/v1/clusters` | Attach an existing cluster by kubeconfig |
|
||||
| `DELETE` | `/v1/clusters/{id}` | Detach a cluster |
|
||||
| `POST` | `/v1/clusters/{clusterId}/pools` | Create a node pool |
|
||||
| `POST` | `/v1/clusters/{clusterId}/pools/{poolId}/scale` | Scale a node pool |
|
||||
| `DELETE` | `/v1/clusters/{clusterId}/pools/{poolId}` | Delete a node pool |
|
||||
| `GET` | `/v1/k8s/clusters` | Managed-cluster lifecycle view (DOKS detail + nodes) |
|
||||
|
||||
## List Clusters
|
||||
Reads are org-scoped; create and delete are admin-gated, because they spend real infrastructure budget.
|
||||
|
||||
`GET /api/cluster.all?organizationId=org_abc123`
|
||||
## List clusters
|
||||
|
||||
```bash
|
||||
curl "https://platform.hanzo.ai/api/cluster.all?organizationId=org_abc123" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
curl -fsS https://api.hanzo.ai/v1/clusters \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"result": {
|
||||
"data": [
|
||||
{
|
||||
"id": "cluster_abc123",
|
||||
"name": "production",
|
||||
"provider": "digitalocean",
|
||||
"region": "sfo3",
|
||||
"orchestrator": "kubernetes",
|
||||
"status": "running",
|
||||
"nodeCount": 3,
|
||||
"createdAt": "2025-06-01T10:00:00Z"
|
||||
},
|
||||
{
|
||||
"id": "cluster_def456",
|
||||
"name": "staging",
|
||||
"provider": "hetzner",
|
||||
"region": "nbg1",
|
||||
"orchestrator": "swarm",
|
||||
"status": "running",
|
||||
"nodeCount": 1,
|
||||
"createdAt": "2025-08-15T14:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
{ "clusters": [] }
|
||||
```
|
||||
|
||||
## Get Cluster
|
||||
|
||||
`GET /api/cluster.one?clusterId=cluster_abc123`
|
||||
## Attach a cluster
|
||||
|
||||
```bash
|
||||
curl "https://platform.hanzo.ai/api/cluster.one?clusterId=cluster_abc123" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"result": {
|
||||
"data": {
|
||||
"id": "cluster_abc123",
|
||||
"name": "production",
|
||||
"provider": "digitalocean",
|
||||
"region": "sfo3",
|
||||
"orchestrator": "kubernetes",
|
||||
"status": "running",
|
||||
"nodeCount": 3,
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node_001",
|
||||
"role": "manager",
|
||||
"plan": "medium",
|
||||
"ip": "203.0.113.10",
|
||||
"status": "running"
|
||||
},
|
||||
{
|
||||
"id": "node_002",
|
||||
"role": "worker",
|
||||
"plan": "small",
|
||||
"ip": "203.0.113.11",
|
||||
"status": "running"
|
||||
}
|
||||
],
|
||||
"createdAt": "2025-06-01T10:00:00Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Create Cluster
|
||||
|
||||
`POST /api/cluster.create`
|
||||
|
||||
```bash
|
||||
curl -X POST https://platform.hanzo.ai/api/cluster.create \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
curl -fsS -X POST https://api.hanzo.ai/v1/clusters \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"organizationId": "org_abc123",
|
||||
"name": "production",
|
||||
"provider": "digitalocean",
|
||||
"region": "sfo3",
|
||||
"orchestrator": "kubernetes",
|
||||
"nodes": [
|
||||
{ "role": "manager", "plan": "medium", "count": 1 },
|
||||
{ "role": "worker", "plan": "small", "count": 2 }
|
||||
]
|
||||
}'
|
||||
-d '{ "name": "prod", "kubeconfig": "'"$(base64 < ~/.kube/config)"'" }'
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `organizationId` | string | Yes | Organization ID |
|
||||
| `name` | string | Yes | Cluster name |
|
||||
| `provider` | string | Yes | `digitalocean`, `hetzner`, or `aws` |
|
||||
| `region` | string | Yes | Provider region code |
|
||||
| `orchestrator` | string | Yes | `kubernetes` or `swarm` |
|
||||
| `nodes` | array | Yes | Node configuration |
|
||||
|
||||
**Node object:**
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `role` | string | Yes | `manager` or `worker` |
|
||||
| `plan` | string | Yes | VM plan (nano, micro, small, medium, power) |
|
||||
| `count` | number | Yes | Number of nodes |
|
||||
|
||||
**Response:** `201 Created`
|
||||
|
||||
Cluster provisioning is asynchronous. The cluster enters `provisioning` status and transitions to `running` once all nodes are ready (typically 2-5 minutes).
|
||||
|
||||
## Update Cluster
|
||||
|
||||
`PATCH /api/cluster.update`
|
||||
## Scale a node pool
|
||||
|
||||
```bash
|
||||
curl -X PATCH https://platform.hanzo.ai/api/cluster.update \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
curl -fsS -X POST \
|
||||
"https://api.hanzo.ai/v1/clusters/$CLUSTER_ID/pools/$POOL_ID/scale" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"clusterId": "cluster_abc123",
|
||||
"name": "production-us-east"
|
||||
}'
|
||||
-d '{ "count": 5 }'
|
||||
```
|
||||
|
||||
## Add Node
|
||||
|
||||
`POST /api/cluster.addNode`
|
||||
## Detach a cluster
|
||||
|
||||
```bash
|
||||
curl -X POST https://platform.hanzo.ai/api/cluster.addNode \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"clusterId": "cluster_abc123",
|
||||
"role": "worker",
|
||||
"plan": "small"
|
||||
}'
|
||||
curl -fsS -X DELETE "https://api.hanzo.ai/v1/clusters/$CLUSTER_ID" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
The node joins the cluster automatically. For Kubernetes clusters, it is registered as a worker node. For Swarm clusters, it joins as a Swarm worker.
|
||||
Detaching removes Hanzo's handle on the cluster; it does not destroy a BYO cluster you brought in.
|
||||
|
||||
## Remove Node
|
||||
## Related
|
||||
|
||||
`DELETE /api/cluster.removeNode`
|
||||
|
||||
```bash
|
||||
curl -X DELETE https://platform.hanzo.ai/api/cluster.removeNode \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"clusterId": "cluster_abc123",
|
||||
"nodeId": "node_002"
|
||||
}'
|
||||
```
|
||||
|
||||
<Callout type="warn">
|
||||
Workloads on the removed node are automatically rescheduled to remaining nodes. Ensure sufficient capacity before removing nodes.
|
||||
</Callout>
|
||||
|
||||
## Delete Cluster
|
||||
|
||||
`DELETE /api/cluster.remove`
|
||||
|
||||
```bash
|
||||
curl -X DELETE https://platform.hanzo.ai/api/cluster.remove \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"clusterId": "cluster_abc123"
|
||||
}'
|
||||
```
|
||||
|
||||
**Response:** `204 No Content`
|
||||
|
||||
Destroys all nodes and associated resources. Requires **Manage** cluster permission.
|
||||
|
||||
## Cluster Status Values
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| `provisioning` | Nodes are being created |
|
||||
| `running` | Cluster is healthy and accepting workloads |
|
||||
| `degraded` | One or more nodes are unhealthy |
|
||||
| `updating` | Cluster is being reconfigured |
|
||||
| `deleting` | Cluster is being destroyed |
|
||||
| `error` | Provisioning or operation failed |
|
||||
- [Machines API](/docs/services/platform/api/vms) — individual compute units and GPUs
|
||||
- [Containers API](/docs/services/platform/api/containers) — the workloads that run on these clusters
|
||||
|
||||
@@ -1,96 +1,72 @@
|
||||
---
|
||||
title: Containers API
|
||||
description: Deploy, redeploy, and operate container workloads
|
||||
description: Deploy, redeploy, and operate container workloads through api.hanzo.ai/v1/platform.
|
||||
---
|
||||
|
||||
A **container** is a deployable workload on Hanzo PaaS. There are two ways to act on one:
|
||||
A **container** is a deployable workload on Hanzo PaaS — an *app* inside a *project*. Everything you do to one goes through the same host, the same bearer, and the same path shape:
|
||||
|
||||
- the canonical **`/v1` container surface** — a machine-driven, zero-downtime **redeploy** (rolling restart) of a running workload, authenticated with a service token;
|
||||
- the **`/api` build pipeline** — the Dokploy-derived tRPC procedures (`application.*`) that register sources and run builds, authenticated with an API key.
|
||||
```
|
||||
https://api.hanzo.ai/v1/platform/projects/{project}/apps/{app}[/action]
|
||||
```
|
||||
|
||||
Under the hood a container maps to an `application` row whose `appName` is the live workload's name.
|
||||
Get a bearer first — see [Authentication](/docs/services/platform/api/authentication):
|
||||
|
||||
## Redeploy a running container (`/v1`)
|
||||
```bash
|
||||
TOKEN=$(curl -sS -X POST https://api.hanzo.ai/v1/kms/auth/login \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"clientId\":\"$KMS_CLIENT_ID\",\"clientSecret\":\"$KMS_CLIENT_SECRET\"}" | jq -r .accessToken)
|
||||
```
|
||||
|
||||
## Create an app
|
||||
|
||||
```bash
|
||||
curl -fsS -X POST https://api.hanzo.ai/v1/platform/projects/$PROJECT/apps \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "name": "web", "description": "Public web app" }'
|
||||
```
|
||||
|
||||
## Deploy
|
||||
|
||||
```bash
|
||||
curl -fsS -X POST \
|
||||
"https://platform.hanzo.ai/v1/org/$ORG_ID/project/$PROJECT_ID/env/$ENV_ID/container/$CONTAINER_ID/redeploy" \
|
||||
-H "Authorization: Bearer $PAAS_SERVICE_TOKEN"
|
||||
"https://api.hanzo.ai/v1/platform/projects/$PROJECT/apps/web/deploy" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
```json
|
||||
{ "ok": true }
|
||||
```
|
||||
|
||||
This re-pulls the image and recreates pods with a rolling update — no new build. The service token comes from [Hanzo KMS](/docs/services/kms).
|
||||
|
||||
## Build pipeline procedures (`/api`)
|
||||
|
||||
Each procedure is an HTTP `POST` to `https://platform.hanzo.ai/api/<procedure>` with `x-api-key`.
|
||||
|
||||
| Procedure | Purpose |
|
||||
|-----------|---------|
|
||||
| `application.create` | Register a new application (does not deploy) |
|
||||
| `application.one` | Get application details |
|
||||
| `application.all` | List applications in a project |
|
||||
| `application.update` | Update configuration |
|
||||
| `application.deploy` | Build & deploy (manual deployment) |
|
||||
| `application.redeploy` | Rebuild an existing application |
|
||||
| `application.start` · `application.stop` · `application.reload` | Lifecycle operations |
|
||||
| `application.remove` | Delete the application |
|
||||
|
||||
### Create an application
|
||||
|
||||
`name` and `environmentId` are required; `appName` is generated if omitted.
|
||||
This rolls the workload forward with a zero-downtime rolling update — it re-pulls the image and recreates pods. It does **not** build. To produce a new image first, enqueue a build:
|
||||
|
||||
```bash
|
||||
curl -fsS -X POST https://platform.hanzo.ai/api/application.create \
|
||||
-H "x-api-key: $PLATFORM_API_KEY" \
|
||||
curl -fsS -X POST https://api.hanzo.ai/v1/runner \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "web",
|
||||
"environmentId": "'$ENV_ID'",
|
||||
"description": "Public web app"
|
||||
"repo": "https://github.com/hanzoai/docs",
|
||||
"sha": "'$SHA'",
|
||||
"image": "ghcr.io/hanzoai/docs:v1.4.0"
|
||||
}'
|
||||
# → 202 {"buildJobId":"…","status":"queued","runnerPool":"…","image":"…","target":"…"}
|
||||
```
|
||||
|
||||
Attach a Docker image source with `application.saveDockerProvider` (or a Git source with `application.saveGithubProvider`), then deploy.
|
||||
Builds run on Hanzo's own in-cluster BuildKit. `repo` must be a full `https://` URL, and `image` must push to a registry we own (`ghcr.io/{hanzoai,luxfi,zooai}/*`) in the caller's own org namespace — the server refuses anything else. Never build images locally.
|
||||
|
||||
### Deploy & redeploy
|
||||
## Lifecycle
|
||||
|
||||
```bash
|
||||
# Build and deploy
|
||||
curl -fsS -X POST https://platform.hanzo.ai/api/application.deploy \
|
||||
-H "x-api-key: $PLATFORM_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "applicationId": "'$APP_ID'" }'
|
||||
|
||||
# Rebuild an existing application
|
||||
curl -fsS -X POST https://platform.hanzo.ai/api/application.redeploy \
|
||||
-H "x-api-key: $PLATFORM_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "applicationId": "'$APP_ID'", "title": "ship v1.3.0" }'
|
||||
curl -fsS -X POST ".../apps/web/stop" -H "Authorization: Bearer $TOKEN"
|
||||
curl -fsS -X POST ".../apps/web/start" -H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
`application.deploy` and `application.redeploy` enqueue a build job and return after it is scheduled. Deployments roll out with a zero-downtime strategy by default.
|
||||
## Inspect
|
||||
|
||||
### Lifecycle
|
||||
|
||||
```bash
|
||||
# Stop / start / restart-in-place
|
||||
curl -fsS -X POST https://platform.hanzo.ai/api/application.stop -H "x-api-key: $PLATFORM_API_KEY" -d '{"applicationId":"'$APP_ID'"}'
|
||||
curl -fsS -X POST https://platform.hanzo.ai/api/application.start -H "x-api-key: $PLATFORM_API_KEY" -d '{"applicationId":"'$APP_ID'"}'
|
||||
curl -fsS -X POST https://platform.hanzo.ai/api/application.reload -H "x-api-key: $PLATFORM_API_KEY" -d '{"applicationId":"'$APP_ID'","appName":"'$APP_NAME'"}'
|
||||
```
|
||||
|
||||
## Inspect & observe
|
||||
|
||||
Use the [observe surface](/docs/services/platform) to see declared vs running vs latest image tags and drift:
|
||||
|
||||
```bash
|
||||
curl -fsS "https://platform.hanzo.ai/v1/apps?org=hanzo" \
|
||||
-H "Authorization: Bearer $PLATFORM_SERVICE_TOKEN"
|
||||
```
|
||||
| Method | Path | Purpose |
|
||||
|--------|------|---------|
|
||||
| `GET` | `/v1/platform/projects/{project}/apps` | List apps |
|
||||
| `GET` | `/v1/platform/projects/{project}/apps/{app}` | One app |
|
||||
| `GET` | `/v1/platform/projects/{project}/apps/{app}/deployments` | Deployment history |
|
||||
| `GET` | `/v1/platform/projects/{project}/apps/{app}/deployments/{id}` | One deployment |
|
||||
| `GET` | `/v1/platform/projects/{project}/apps/{app}/deployments/{id}/logs` | Deployment logs |
|
||||
| `DELETE` | `/v1/platform/projects/{project}/apps/{app}` | Remove the app |
|
||||
|
||||
## Application status values
|
||||
|
||||
@@ -102,5 +78,5 @@ curl -fsS "https://platform.hanzo.ai/v1/apps?org=hanzo" \
|
||||
| `error` | A deployment or replica failed |
|
||||
|
||||
<Callout type="warn">
|
||||
`application.remove` stops all instances and removes associated domains and volumes. This cannot be undone.
|
||||
`DELETE` stops all instances and removes associated domains and volumes. This cannot be undone.
|
||||
</Callout>
|
||||
|
||||
@@ -1,120 +1,85 @@
|
||||
---
|
||||
title: API Reference
|
||||
description: Platform REST and tRPC API for managing organizations, clusters, containers, and VMs
|
||||
description: The one Hanzo PaaS API surface — api.hanzo.ai/v1/platform for projects and apps, api.hanzo.ai/v1/runner for builds.
|
||||
---
|
||||
|
||||
Hanzo Platform exposes two API surfaces: **tRPC** for the dashboard and **REST** for external integrations. Both share the same authentication and authorization layer.
|
||||
Hanzo PaaS has **one** API surface, on the **one** Hanzo API host.
|
||||
|
||||
## Base URLs
|
||||
## Base URL
|
||||
|
||||
| Surface | Base | Auth | Use |
|
||||
|---------|------|------|-----|
|
||||
| **Canonical control** | `https://platform.hanzo.ai/v1` | `Authorization: Bearer <service-token>` | Container redeploy, observe/drift (machine) |
|
||||
| **Build pipeline** | `https://platform.hanzo.ai/api` | `x-api-key: <key>` | Build/deploy applications via tRPC-over-OpenAPI |
|
||||
| Surface | Base | Auth |
|
||||
|---------|------|------|
|
||||
| Control plane | `https://api.hanzo.ai/v1/platform` | `Authorization: Bearer <iam-jwt>` |
|
||||
| Builds | `https://api.hanzo.ai/v1/runner` | `Authorization: Bearer <iam-jwt>` (org admin) or the fabric build token |
|
||||
|
||||
The `/v1` surface is the canonical Hanzo control plane. The `/api` surface is the Dokploy-derived build pipeline, where each endpoint is a tRPC procedure exposed over HTTP as `<router>.<procedure>` (e.g. `application.create`, `domain.create`).
|
||||
`platform.hanzo.ai` is the **Studio** — the browser UI. It is not an API host: `platform.hanzo.ai/v1/*` answers `500 Service token is not configured on the server`, and `platform.hanzo.ai/api/*` answers the Studio's HTML shell with a `404`. There is no `x-api-key` header, no tRPC procedure surface, and no `/api` prefix anywhere in Hanzo.
|
||||
|
||||
## Authentication
|
||||
|
||||
The build-pipeline surface accepts an API key (machine) or an IAM bearer token (interactive):
|
||||
One bearer, minted from a machine identity in [Hanzo KMS](/docs/services/kms) or from an interactive [Hanzo IAM](/docs/services/iam) login:
|
||||
|
||||
```bash
|
||||
curl https://platform.hanzo.ai/api/organization.all \
|
||||
-H "x-api-key: $PLATFORM_API_KEY"
|
||||
TOKEN=$(curl -sS -X POST https://api.hanzo.ai/v1/kms/auth/login \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"clientId\":\"$KMS_CLIENT_ID\",\"clientSecret\":\"$KMS_CLIENT_SECRET\"}" | jq -r .accessToken)
|
||||
|
||||
curl -fsS https://api.hanzo.ai/v1/platform/projects \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
The canonical `/v1` surface uses a service token: `Authorization: Bearer $PAAS_SERVICE_TOKEN`. Both credential types come from [Hanzo KMS](/docs/services/kms). See [Authentication](/docs/services/platform/api/authentication) for details.
|
||||
See [Authentication](/docs/services/platform/api/authentication).
|
||||
|
||||
## tRPC Procedures
|
||||
## Endpoints
|
||||
|
||||
The build pipeline exposes these tRPC routers:
|
||||
| Method | Path | Purpose |
|
||||
|--------|------|---------|
|
||||
| `GET` · `POST` | `/v1/platform/projects` | List / create projects |
|
||||
| `GET` · `DELETE` | `/v1/platform/projects/{project}` | Inspect / delete a project |
|
||||
| `GET` · `POST` | `/v1/platform/projects/{project}/apps` | List / create apps |
|
||||
| `GET` · `DELETE` | `/v1/platform/projects/{project}/apps/{app}` | Inspect / delete an app |
|
||||
| `POST` | `/v1/platform/projects/{project}/apps/{app}/deploy` | Roll the app forward |
|
||||
| `POST` | `/v1/platform/projects/{project}/apps/{app}/start` | Start the workload |
|
||||
| `POST` | `/v1/platform/projects/{project}/apps/{app}/stop` | Stop the workload |
|
||||
| `GET` | `/v1/platform/projects/{project}/apps/{app}/deployments` | Deployment history |
|
||||
| `GET` | `/v1/platform/projects/{project}/apps/{app}/deployments/{id}` | One deployment |
|
||||
| `GET` | `/v1/platform/projects/{project}/apps/{app}/deployments/{id}/logs` | Deployment logs |
|
||||
| `GET` · `POST` | `/v1/platform/sites` | Static sites |
|
||||
| `GET` | `/v1/platform/health` | Liveness |
|
||||
| `POST` | `/v1/runner` | Enqueue an in-cluster image build |
|
||||
|
||||
| Router | Description |
|
||||
|--------|-------------|
|
||||
| `organization` | Organization CRUD |
|
||||
| `orgTeam` | Team member management |
|
||||
| `cluster` | Cluster lifecycle |
|
||||
| `application` | Application deployments (the unit a container maps to) |
|
||||
| `compose` | Multi-service compose/stack units |
|
||||
| `project` | Project management |
|
||||
| `environment` | Environment configuration |
|
||||
| `build` | Build pipelines |
|
||||
| `log` | Log streaming |
|
||||
| `registry` | Container registry |
|
||||
| `domain` | Domain and DNS management |
|
||||
| `git` | Git integration |
|
||||
| `user` | User profile |
|
||||
| `provisioner` | Infrastructure provisioning |
|
||||
| `audit` | Audit log |
|
||||
| `invitation` | Team invitations |
|
||||
| `system` | System health and status |
|
||||
## Request format
|
||||
|
||||
## Request Format
|
||||
|
||||
tRPC requests use HTTP POST with a JSON body:
|
||||
JSON in, JSON out. Requests are plain REST — no envelope, no procedure names:
|
||||
|
||||
```bash
|
||||
curl -X POST https://platform.hanzo.ai/api/cluster.create \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
curl -fsS -X POST https://api.hanzo.ai/v1/platform/projects \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "production",
|
||||
"provider": "digitalocean",
|
||||
"region": "sfo3"
|
||||
}'
|
||||
-d '{ "slug": "web", "name": "Web" }'
|
||||
```
|
||||
|
||||
## Response Format
|
||||
## Error responses
|
||||
|
||||
All responses return JSON:
|
||||
Errors are a flat JSON object with the HTTP status echoed in the body:
|
||||
|
||||
```json
|
||||
{
|
||||
"result": {
|
||||
"data": {
|
||||
"id": "cluster_abc123",
|
||||
"name": "production",
|
||||
"status": "provisioning"
|
||||
}
|
||||
}
|
||||
}
|
||||
{ "status": 403, "error": "X-Org-Id required" }
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
| Status | Meaning |
|
||||
|--------|---------|
|
||||
| `400` | Invalid input |
|
||||
| `401` | Missing or invalid bearer |
|
||||
| `403` | Validated principal lacks the scope (or no org context) |
|
||||
| `404` | Resource does not exist |
|
||||
| `409` | Conflict (stale version, duplicate slug) |
|
||||
| `500` | Server error |
|
||||
|
||||
Errors return an appropriate HTTP status code with a JSON body:
|
||||
## Rate limits
|
||||
|
||||
```json
|
||||
{
|
||||
"error": {
|
||||
"message": "Cluster not found",
|
||||
"code": "NOT_FOUND",
|
||||
"httpStatus": 404
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| `BAD_REQUEST` | Invalid input |
|
||||
| `UNAUTHORIZED` | Missing or invalid token |
|
||||
| `FORBIDDEN` | Insufficient permissions |
|
||||
| `NOT_FOUND` | Resource does not exist |
|
||||
| `CONFLICT` | Resource already exists |
|
||||
| `INTERNAL_SERVER_ERROR` | Server error |
|
||||
|
||||
## Rate Limits
|
||||
|
||||
| Endpoint Type | Rate Limit |
|
||||
|--------------|------------|
|
||||
| Read operations | 100 requests/minute |
|
||||
| Write operations | 30 requests/minute |
|
||||
| Log streaming | 10 concurrent connections |
|
||||
|
||||
Rate limit headers are included in every response:
|
||||
Rate-limit headers ride every response:
|
||||
|
||||
```
|
||||
X-RateLimit-Limit: 100
|
||||
X-RateLimit-Remaining: 97
|
||||
X-RateLimit-Reset: 1709000000
|
||||
```
|
||||
|
||||
@@ -1,205 +1,40 @@
|
||||
---
|
||||
title: Organizations API
|
||||
description: Create, read, update, and delete organizations
|
||||
description: Organizations are an identity concept — they live in Hanzo IAM at api.hanzo.ai/v1/iam.
|
||||
---
|
||||
|
||||
The Organizations API manages the top-level entity in Hanzo Platform. Every cluster, project, and team member belongs to an organization.
|
||||
An organization is the top-level tenant: every cluster, project, machine, secret, and team member belongs to one. It is an **identity** object, so it lives in [Hanzo IAM](/docs/services/iam) — not in a second directory owned by the deploy plane.
|
||||
|
||||
All calls take an IAM bearer — see [Authentication](/docs/services/platform/api/authentication).
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Procedure | Method | Description |
|
||||
|-----------|--------|-------------|
|
||||
| `organization.all` | GET | List all organizations for the authenticated user |
|
||||
| `organization.one` | GET | Get a single organization by ID |
|
||||
| `organization.create` | POST | Create a new organization |
|
||||
| `organization.update` | PATCH | Update organization settings |
|
||||
| `organization.remove` | DELETE | Delete an organization |
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `GET` | `/v1/iam/get-organizations?owner=admin` | List organizations visible to the caller |
|
||||
| `GET` | `/v1/iam/get-organization?id=<owner>/<name>` | One organization |
|
||||
| `POST` | `/v1/iam/add-organization` | Create an organization |
|
||||
| `POST` | `/v1/iam/update-organization?id=<owner>/<name>` | Update an organization |
|
||||
| `POST` | `/v1/iam/delete-organization` | Delete an organization |
|
||||
|
||||
## List Organizations
|
||||
|
||||
`GET /api/organization.all`
|
||||
|
||||
Returns all organizations the authenticated user is a member of.
|
||||
These are administrative endpoints: a normal member bearer gets `403 forbidden`. Org membership and roles for ordinary users are managed in the [Console](https://console.hanzo.ai).
|
||||
|
||||
```bash
|
||||
curl https://platform.hanzo.ai/api/organization.all \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
curl -fsS "https://api.hanzo.ai/v1/iam/get-organizations?owner=admin" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
## How the org reaches the rest of the API
|
||||
|
||||
You never pass an org id by hand. The gateway strips every client-supplied identity header and re-mints `X-Org-Id` from the validated JWT's `owner` claim, so each request is scoped to exactly the org the token belongs to. A call with no org context answers:
|
||||
|
||||
```json
|
||||
{
|
||||
"result": {
|
||||
"data": [
|
||||
{
|
||||
"id": "org_abc123",
|
||||
"name": "Acme Corp",
|
||||
"description": "Production infrastructure",
|
||||
"createdAt": "2025-01-15T10:00:00Z",
|
||||
"memberCount": 12,
|
||||
"clusterCount": 3
|
||||
},
|
||||
{
|
||||
"id": "org_def456",
|
||||
"name": "Staging",
|
||||
"description": "Development and testing",
|
||||
"createdAt": "2025-03-20T14:30:00Z",
|
||||
"memberCount": 5,
|
||||
"clusterCount": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
{ "status": 403, "error": "X-Org-Id required" }
|
||||
```
|
||||
|
||||
## Get Organization
|
||||
That is the signal to re-authenticate, not to add a header.
|
||||
|
||||
`GET /api/organization.one?organizationId=org_abc123`
|
||||
## Related
|
||||
|
||||
```bash
|
||||
curl "https://platform.hanzo.ai/api/organization.one?organizationId=org_abc123" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"result": {
|
||||
"data": {
|
||||
"id": "org_abc123",
|
||||
"name": "Acme Corp",
|
||||
"description": "Production infrastructure",
|
||||
"createdAt": "2025-01-15T10:00:00Z",
|
||||
"memberCount": 12,
|
||||
"clusterCount": 3,
|
||||
"members": [
|
||||
{
|
||||
"userId": "user_abc",
|
||||
"email": "alice@acme.com",
|
||||
"role": "owner",
|
||||
"joinedAt": "2025-01-15T10:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Create Organization
|
||||
|
||||
`POST /api/organization.create`
|
||||
|
||||
```bash
|
||||
curl -X POST https://platform.hanzo.ai/api/organization.create \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "Acme Corp",
|
||||
"description": "Production infrastructure"
|
||||
}'
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `name` | string | Yes | Organization name (2-50 characters) |
|
||||
| `description` | string | No | Short description |
|
||||
|
||||
**Response:** `201 Created`
|
||||
|
||||
```json
|
||||
{
|
||||
"result": {
|
||||
"data": {
|
||||
"id": "org_new789",
|
||||
"name": "Acme Corp",
|
||||
"description": "Production infrastructure",
|
||||
"createdAt": "2026-02-26T10:00:00Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The authenticated user is automatically assigned the **Owner** role.
|
||||
|
||||
## Update Organization
|
||||
|
||||
`PATCH /api/organization.update`
|
||||
|
||||
```bash
|
||||
curl -X PATCH https://platform.hanzo.ai/api/organization.update \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"organizationId": "org_abc123",
|
||||
"name": "Acme Corporation",
|
||||
"description": "Updated description"
|
||||
}'
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `organizationId` | string | Yes | Organization ID |
|
||||
| `name` | string | No | New name |
|
||||
| `description` | string | No | New description |
|
||||
|
||||
Requires **Owner** or **Admin** role.
|
||||
|
||||
## Delete Organization
|
||||
|
||||
`DELETE /api/organization.remove`
|
||||
|
||||
```bash
|
||||
curl -X DELETE https://platform.hanzo.ai/api/organization.remove \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"organizationId": "org_abc123"
|
||||
}'
|
||||
```
|
||||
|
||||
**Response:** `204 No Content`
|
||||
|
||||
<Callout type="warn">
|
||||
Deleting an organization permanently removes all clusters, projects, environments, and data. This action cannot be undone. Requires the **Owner** role.
|
||||
</Callout>
|
||||
|
||||
## Team Management
|
||||
|
||||
Team members are managed via the `orgTeam` router:
|
||||
|
||||
| Procedure | Method | Description |
|
||||
|-----------|--------|-------------|
|
||||
| `orgTeam.all` | GET | List all members of an organization |
|
||||
| `orgTeam.update` | PATCH | Change a member's role |
|
||||
| `orgTeam.remove` | DELETE | Remove a member |
|
||||
|
||||
```bash
|
||||
# List members
|
||||
curl "https://platform.hanzo.ai/api/orgTeam.all?organizationId=org_abc123" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
|
||||
# Change role
|
||||
curl -X PATCH https://platform.hanzo.ai/api/orgTeam.update \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"organizationId": "org_abc123",
|
||||
"userId": "user_def456",
|
||||
"role": "admin"
|
||||
}'
|
||||
|
||||
# Remove member
|
||||
curl -X DELETE https://platform.hanzo.ai/api/orgTeam.remove \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"organizationId": "org_abc123",
|
||||
"userId": "user_def456"
|
||||
}'
|
||||
```
|
||||
- [Hanzo IAM](/docs/services/iam) — identity, SSO, and org membership
|
||||
- [Authentication](/docs/authentication) — the one OIDC integration path
|
||||
|
||||
@@ -1,277 +1,83 @@
|
||||
---
|
||||
title: Virtual Machines API
|
||||
description: Launch, manage, and destroy Visor VMs via the API
|
||||
title: Machines API
|
||||
description: Launch, inspect, and destroy machines and GPUs through api.hanzo.ai/v1.
|
||||
---
|
||||
|
||||
The Virtual Machines API manages Visor VMs -- full Linux virtual machines with root access, persistent storage, and SSH connectivity.
|
||||
A **machine** is a compute unit — a Visor-provisioned VM, or a bring-your-own worker that dialed in with `hanzo link`. Both appear in the same list, distinguished by `provider`.
|
||||
|
||||
All calls take an IAM bearer — see [Authentication](/docs/services/platform/api/authentication).
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Procedure | Method | Description |
|
||||
|-----------|--------|-------------|
|
||||
| `vm.all` | GET | List all VMs |
|
||||
| `vm.one` | GET | Get VM details |
|
||||
| `vm.launch` | POST | Launch a new VM |
|
||||
| `vm.start` | POST | Start a stopped VM |
|
||||
| `vm.stop` | POST | Stop a running VM |
|
||||
| `vm.restart` | POST | Restart a VM |
|
||||
| `vm.destroy` | DELETE | Permanently destroy a VM |
|
||||
| `vm.volumes` | GET | List attached volumes |
|
||||
| `vm.attachVolume` | POST | Attach a storage volume |
|
||||
| `vm.detachVolume` | POST | Detach a storage volume |
|
||||
| `vm.terminal` | GET | Open a web terminal session |
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `GET` | `/v1/machines` | List every machine the org can see |
|
||||
| `POST` | `/v1/machines` | Launch a machine |
|
||||
| `GET` | `/v1/machines/{id}` | Machine detail |
|
||||
| `DELETE` | `/v1/machines/{id}` | Destroy a machine |
|
||||
| `GET` | `/v1/gpus` | Every GPU across the org's compute |
|
||||
| `GET` | `/v1/gpus/alerts` | GPU health alerts |
|
||||
| `GET` | `/v1/fleet` | The unified board — every compute source with its latest utilization |
|
||||
| `GET` | `/v1/fleet/workers` | BYO workers only |
|
||||
| `GET` | `/v1/fleet/jobs` | The org's GPU job queue |
|
||||
| `POST` | `/v1/fleet/jobs/{id}/cancel` | Cancel a queued or running job |
|
||||
| `GET` · `POST` | `/v1/fleet/samples` | Read back / self-report utilization samples |
|
||||
|
||||
## List VMs
|
||||
|
||||
`GET /api/vm.all?organizationId=org_abc123`
|
||||
## List machines
|
||||
|
||||
```bash
|
||||
curl "https://platform.hanzo.ai/api/vm.all?organizationId=org_abc123" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
curl -fsS https://api.hanzo.ai/v1/machines \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"result": {
|
||||
"data": [
|
||||
{
|
||||
"id": "vm_abc123",
|
||||
"name": "ml-training",
|
||||
"plan": "power",
|
||||
"region": "us-east",
|
||||
"os": "ubuntu-22.04",
|
||||
"ip": "203.0.113.50",
|
||||
"status": "running",
|
||||
"createdAt": "2026-01-10T10:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Get VM
|
||||
|
||||
`GET /api/vm.one?vmId=vm_abc123`
|
||||
|
||||
```bash
|
||||
curl "https://platform.hanzo.ai/api/vm.one?vmId=vm_abc123" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"result": {
|
||||
"data": {
|
||||
"id": "vm_abc123",
|
||||
"name": "ml-training",
|
||||
"plan": "power",
|
||||
"region": "us-east",
|
||||
"os": "ubuntu-22.04",
|
||||
"ip": "203.0.113.50",
|
||||
"privateIp": "10.0.1.50",
|
||||
"status": "running",
|
||||
"specs": {
|
||||
"vcpu": 8,
|
||||
"memoryGb": 16,
|
||||
"diskGb": 320,
|
||||
"diskType": "ssd"
|
||||
},
|
||||
"sshKeys": ["ssh-ed25519 AAAA..."],
|
||||
"volumes": [
|
||||
{
|
||||
"id": "vol_xyz789",
|
||||
"name": "training-data",
|
||||
"sizeGb": 500,
|
||||
"mountPath": "/mnt/data"
|
||||
}
|
||||
],
|
||||
"createdAt": "2026-01-10T10:00:00Z"
|
||||
"machines": [
|
||||
{
|
||||
"id": "dbc",
|
||||
"name": "dbc",
|
||||
"region": "on-prem",
|
||||
"type": "byo-gpu",
|
||||
"status": "offline",
|
||||
"provider": "byo"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Launch VM
|
||||
|
||||
`POST /api/vm.launch`
|
||||
## List GPUs
|
||||
|
||||
```bash
|
||||
curl -X POST https://platform.hanzo.ai/api/vm.launch \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"organizationId": "org_abc123",
|
||||
"name": "ml-training",
|
||||
"plan": "power",
|
||||
"region": "us-east",
|
||||
"os": "ubuntu-22.04",
|
||||
"sshKeys": ["ssh-ed25519 AAAA..."],
|
||||
"userData": "#!/bin/bash\napt-get update && apt-get install -y docker.io"
|
||||
}'
|
||||
curl -fsS https://api.hanzo.ai/v1/gpus \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `organizationId` | string | Yes | Organization ID |
|
||||
| `name` | string | Yes | VM name |
|
||||
| `plan` | string | Yes | VM plan (nano, micro, small, medium, power, power-dedicated) |
|
||||
| `region` | string | Yes | Region code (us-east, us-west, eu-west, ap-south) |
|
||||
| `os` | string | Yes | OS image |
|
||||
| `sshKeys` | array | No | SSH public keys for root access |
|
||||
| `userData` | string | No | Cloud-init script (runs on first boot) |
|
||||
|
||||
**Available OS images:**
|
||||
|
||||
| Image | Description |
|
||||
|-------|-------------|
|
||||
| `ubuntu-22.04` | Ubuntu 22.04 LTS |
|
||||
| `ubuntu-24.04` | Ubuntu 24.04 LTS |
|
||||
| `debian-12` | Debian 12 Bookworm |
|
||||
| `rocky-9` | Rocky Linux 9 |
|
||||
| `fedora-40` | Fedora 40 |
|
||||
|
||||
**Response:** `201 Created`
|
||||
|
||||
```json
|
||||
{
|
||||
"result": {
|
||||
"data": {
|
||||
"id": "vm_new456",
|
||||
"name": "ml-training",
|
||||
"status": "provisioning",
|
||||
"ip": null,
|
||||
"createdAt": "2026-02-26T10:00:00Z"
|
||||
"gpus": [
|
||||
{
|
||||
"id": "dbc#0",
|
||||
"name": "dbc",
|
||||
"model": "Apple M4 Max (Metal)",
|
||||
"region": "on-prem",
|
||||
"status": "offline"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The VM enters `provisioning` status. It transitions to `running` with an assigned IP within 30-90 seconds.
|
||||
|
||||
## Stop VM
|
||||
|
||||
`POST /api/vm.stop`
|
||||
|
||||
Gracefully shuts down the VM. The VM retains its IP address and storage. You are not billed for compute while stopped, but storage charges continue.
|
||||
## Destroy a machine
|
||||
|
||||
```bash
|
||||
curl -X POST https://platform.hanzo.ai/api/vm.stop \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "vmId": "vm_abc123" }'
|
||||
```
|
||||
|
||||
## Start VM
|
||||
|
||||
`POST /api/vm.start`
|
||||
|
||||
Boots a stopped VM. The VM retains its previous IP and all attached volumes.
|
||||
|
||||
```bash
|
||||
curl -X POST https://platform.hanzo.ai/api/vm.start \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "vmId": "vm_abc123" }'
|
||||
```
|
||||
|
||||
## Restart VM
|
||||
|
||||
`POST /api/vm.restart`
|
||||
|
||||
Performs a graceful reboot.
|
||||
|
||||
```bash
|
||||
curl -X POST https://platform.hanzo.ai/api/vm.restart \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "vmId": "vm_abc123" }'
|
||||
```
|
||||
|
||||
## Destroy VM
|
||||
|
||||
`DELETE /api/vm.destroy`
|
||||
|
||||
Permanently destroys the VM and its boot disk. Attached volumes are detached but not deleted.
|
||||
|
||||
```bash
|
||||
curl -X DELETE https://platform.hanzo.ai/api/vm.destroy \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "vmId": "vm_abc123" }'
|
||||
```
|
||||
|
||||
**Response:** `204 No Content`
|
||||
|
||||
<Callout type="warn">
|
||||
Destroying a VM deletes its boot disk permanently. Attached volumes are preserved. Back up any data on the boot disk before destroying.
|
||||
</Callout>
|
||||
|
||||
## Volume Management
|
||||
|
||||
### List Volumes
|
||||
|
||||
```bash
|
||||
curl "https://platform.hanzo.ai/api/vm.volumes?vmId=vm_abc123" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
```
|
||||
|
||||
### Attach Volume
|
||||
|
||||
```bash
|
||||
curl -X POST https://platform.hanzo.ai/api/vm.attachVolume \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"vmId": "vm_abc123",
|
||||
"volumeId": "vol_xyz789",
|
||||
"mountPath": "/mnt/data"
|
||||
}'
|
||||
```
|
||||
|
||||
The volume is attached as a block device. If `mountPath` is provided, the platform mounts it automatically (requires the Hanzo agent on the VM).
|
||||
|
||||
### Detach Volume
|
||||
|
||||
```bash
|
||||
curl -X POST https://platform.hanzo.ai/api/vm.detachVolume \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"vmId": "vm_abc123",
|
||||
"volumeId": "vol_xyz789"
|
||||
}'
|
||||
curl -fsS -X DELETE "https://api.hanzo.ai/v1/machines/$MACHINE_ID" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
<Callout type="warn">
|
||||
Always unmount the filesystem inside the VM before detaching a volume to prevent data corruption.
|
||||
Destroying a machine is permanent. Detach or snapshot any volume you still need first.
|
||||
</Callout>
|
||||
|
||||
## Web Terminal
|
||||
## Related
|
||||
|
||||
`GET /api/vm.terminal?vmId=vm_abc123`
|
||||
|
||||
Opens a WebSocket-based terminal session to the VM. Used by the dashboard for browser-based SSH.
|
||||
|
||||
```bash
|
||||
# The dashboard uses this endpoint internally.
|
||||
# For direct SSH access, use the VM's public IP:
|
||||
ssh root@203.0.113.50
|
||||
```
|
||||
|
||||
## VM Status Values
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| `provisioning` | VM is being created |
|
||||
| `running` | VM is up and accepting connections |
|
||||
| `stopping` | Graceful shutdown in progress |
|
||||
| `stopped` | VM is off (storage preserved) |
|
||||
| `restarting` | Reboot in progress |
|
||||
| `destroying` | VM is being deleted |
|
||||
| `error` | Provisioning or operation failed |
|
||||
- [Clusters API](/docs/services/platform/api/clusters) — Kubernetes clusters and node pools
|
||||
- [Containers API](/docs/services/platform/api/containers) — the workloads that run on this compute
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
---
|
||||
title: Hanzo PaaS
|
||||
description: The platform.hanzo.ai control plane — deploy and operate applications, containers, and custom domains across your clusters, with IAM-native multi-org access.
|
||||
description: Deploy and operate applications, containers, and custom domains across your clusters — Studio at platform.hanzo.ai, API at api.hanzo.ai/v1/platform, with IAM-native multi-org access.
|
||||
---
|
||||
|
||||
# Hanzo PaaS
|
||||
|
||||
> **API reference** · [Hanzo Platform API →](/docs/openapi/platform) — every endpoint, generated from the OpenAPI spec.
|
||||
|
||||
Hanzo PaaS (`platform.hanzo.ai`) is the control plane for shipping software on Hanzo infrastructure. You register an application, point it at a Docker image or Git repo, attach a domain, and the platform builds, deploys, and operates it on your clusters — with deployment history, rolling updates, and drift detection. Authentication is delegated to [Hanzo IAM](/docs/services/iam) with per-organization isolation.
|
||||
Hanzo PaaS is the control plane for shipping software on Hanzo infrastructure — Studio at `platform.hanzo.ai`, API at `api.hanzo.ai/v1/platform`. You register an application, point it at a Docker image or Git repo, attach a domain, and the platform builds, deploys, and operates it on your clusters — with deployment history, rolling updates, and drift detection. Authentication is delegated to [Hanzo IAM](/docs/services/iam) with per-organization isolation.
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **Studio** | `https://platform.hanzo.ai` |
|
||||
| **Canonical API** | `https://platform.hanzo.ai/v1` |
|
||||
| **Build pipeline API** | `https://platform.hanzo.ai/api` (tRPC + OpenAPI) |
|
||||
| **Auth** | Hanzo IAM (interactive) · API key / service token (machine) |
|
||||
| **Studio** (browser UI) | `https://platform.hanzo.ai` |
|
||||
| **API** | `https://api.hanzo.ai/v1/platform` — the one Hanzo API host |
|
||||
| **Build** | `POST https://api.hanzo.ai/v1/runner` — the one build door |
|
||||
| **Auth** | Hanzo IAM bearer (interactive **and** machine); build token for fabric automation |
|
||||
| **Source** | [github.com/hanzoai/platform](https://github.com/hanzoai/platform) |
|
||||
|
||||
<Callout>
|
||||
`platform.hanzo.ai` is the **Studio** — a browser UI, not an API host. Every programmatic call goes to `api.hanzo.ai/v1/platform/...`, the same host and the same key as AI, KMS, and analytics.
|
||||
</Callout>
|
||||
|
||||
## The model
|
||||
|
||||
Hanzo PaaS organizes work into a simple hierarchy:
|
||||
@@ -45,9 +49,10 @@ Two credential types, both retrieved from [Hanzo KMS](/docs/services/kms) — ne
|
||||
|
||||
| Credential | Header | Use |
|
||||
|------------|--------|-----|
|
||||
| **API key** | `x-api-key: <key>` | Machine access to the build-pipeline API (`/api/*`). Org-scoped; issued under **Settings → API Keys** |
|
||||
| **Service token** | `Authorization: Bearer <token>` | The canonical `/v1` container surface (redeploy, observe) |
|
||||
| **IAM token** | `Authorization: Bearer <iam-jwt>` | Interactive / user access, via [Hanzo IAM](/docs/services/iam) SSO |
|
||||
| **IAM token** | `Authorization: Bearer <iam-jwt>` | Everything. One login authorizes reads, deploys, and builds. Mint it with the machine-identity exchange below, or via [Hanzo IAM](/docs/services/iam) SSO. |
|
||||
| **Build token** | `Authorization: Bearer <build-token>` | Fabric automation only (git-push-to-deploy, self-release). Never held by a user. |
|
||||
|
||||
There is no `x-api-key` header and no second credential type — one bearer, one host.
|
||||
|
||||
## Deploy
|
||||
|
||||
@@ -58,96 +63,75 @@ Two credential types, both retrieved from [Hanzo KMS](/docs/services/kms) — ne
|
||||
3. Add an application — choose a Docker image or connect a Git repository.
|
||||
4. Attach a domain and deploy.
|
||||
|
||||
### Redeploy a running container (canonical `/v1`)
|
||||
### Get a bearer
|
||||
|
||||
The canonical, machine-driven redeploy performs a zero-downtime rolling restart of the live workload — it re-pulls the image and recreates pods. It takes a service token and no body:
|
||||
The machine identity comes from [Hanzo KMS](/docs/services/kms); the exchange is the same one every Hanzo service uses.
|
||||
|
||||
```bash
|
||||
# Service token comes from KMS — never inline a real value
|
||||
TOKEN=$(curl -sS -X POST https://kms.hanzo.ai/v1/kms/auth/login \
|
||||
TOKEN=$(curl -sS -X POST https://api.hanzo.ai/v1/kms/auth/login \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"clientId\":\"$KMS_CLIENT_ID\",\"clientSecret\":\"$KMS_CLIENT_SECRET\"}" | jq -r .accessToken)
|
||||
PAAS_TOKEN=$(curl -sS "https://kms.hanzo.ai/v1/kms/orgs/hanzo/secrets/paas/SERVICE_TOKEN?env=production" \
|
||||
-H "Authorization: Bearer $TOKEN" | jq -r .secret.value)
|
||||
```
|
||||
|
||||
### Projects and apps
|
||||
|
||||
```bash
|
||||
# List projects in the caller's org
|
||||
curl -fsS https://api.hanzo.ai/v1/platform/projects \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
|
||||
# Apps in a project
|
||||
curl -fsS https://api.hanzo.ai/v1/platform/projects/$PROJECT/apps \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
| Method | Path | Purpose |
|
||||
|--------|------|---------|
|
||||
| `GET` · `POST` | `/v1/platform/projects` | List / create projects |
|
||||
| `GET` · `DELETE` | `/v1/platform/projects/{project}` | Inspect / delete a project |
|
||||
| `GET` · `POST` | `/v1/platform/projects/{project}/apps` | List / create apps |
|
||||
| `GET` · `DELETE` | `/v1/platform/projects/{project}/apps/{app}` | Inspect / delete an app |
|
||||
| `POST` | `/v1/platform/projects/{project}/apps/{app}/deploy` | Roll the app forward |
|
||||
| `POST` | `/v1/platform/projects/{project}/apps/{app}/start` · `/stop` | Manage the running workload |
|
||||
| `GET` | `/v1/platform/projects/{project}/apps/{app}/deployments[/{id}[/logs]]` | Deployment history and logs |
|
||||
| `GET` · `POST` | `/v1/platform/sites` | Static sites |
|
||||
| `GET` | `/v1/platform/health` | Liveness — `{"k8s":true,"service":"platform","status":"ok"}` |
|
||||
|
||||
### Redeploy
|
||||
|
||||
```bash
|
||||
curl -fsS -X POST \
|
||||
"https://platform.hanzo.ai/v1/org/$ORG_ID/project/$PROJECT_ID/env/$ENV_ID/container/$APP_ID/redeploy" \
|
||||
-H "Authorization: Bearer $PAAS_TOKEN"
|
||||
# → {"ok":true}
|
||||
"https://api.hanzo.ai/v1/platform/projects/$PROJECT/apps/$APP/deploy" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
### Build and deploy (pipeline `/api`)
|
||||
### Build an image
|
||||
|
||||
To register a new app and run a build through the deployment pipeline, use the OpenAPI surface with an API key. Procedures are `<router>.<procedure>`:
|
||||
Builds run in-cluster on Hanzo's own BuildKit — never on a laptop, never on a third-party runner. One door:
|
||||
|
||||
```bash
|
||||
# 1. Register the application (does not deploy)
|
||||
curl -fsS -X POST https://platform.hanzo.ai/api/application.create \
|
||||
-H "x-api-key: $PLATFORM_API_KEY" \
|
||||
curl -fsS -X POST https://api.hanzo.ai/v1/runner \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "name": "web", "environmentId": "'$ENV_ID'" }'
|
||||
|
||||
# 2. Attach a Docker image source, then deploy
|
||||
curl -fsS -X POST https://platform.hanzo.ai/api/application.deploy \
|
||||
-H "x-api-key: $PLATFORM_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "applicationId": "'$APP_ID'" }'
|
||||
|
||||
# Rebuild an existing application
|
||||
curl -fsS -X POST https://platform.hanzo.ai/api/application.redeploy \
|
||||
-H "x-api-key: $PLATFORM_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "applicationId": "'$APP_ID'", "title": "ship v1.3.0" }'
|
||||
-d '{
|
||||
"repo": "https://github.com/hanzoai/docs",
|
||||
"sha": "'$SHA'",
|
||||
"image": "ghcr.io/hanzoai/docs:v1.4.0"
|
||||
}'
|
||||
# → 202 {"buildJobId":"…","status":"queued","runnerPool":"…","image":"…","target":"…"}
|
||||
```
|
||||
|
||||
`application.deploy` and `application.redeploy` enqueue a build job; `application.start`, `application.stop`, and `application.reload` manage the running workload. See the [Containers API](/docs/services/platform/api/containers) for the full procedure set.
|
||||
`repo` must be a full `https://` URL; `image` must push to a registry we own (`ghcr.io/{hanzoai,luxfi,zooai}/*`) whose namespace matches the caller's org. `sha` pins the commit — `ref` or `branch` are accepted, defaulting to `main`.
|
||||
|
||||
## Observe & drift
|
||||
|
||||
The platform continuously reconciles three views of every app and computes drift:
|
||||
|
||||
| Tag | Meaning |
|
||||
|-----|---------|
|
||||
| `declared` | The version your operator/manifest declares |
|
||||
| `running` | The image actually live in the cluster |
|
||||
| `latest` | The newest released version available |
|
||||
|
||||
```bash
|
||||
# List apps with drift, scoped to an org
|
||||
curl -fsS "https://platform.hanzo.ai/v1/apps?org=hanzo&drift=true" \
|
||||
-H "Authorization: Bearer $PLATFORM_SERVICE_TOKEN"
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"apps": [
|
||||
{ "org": "hanzo", "app": "docs", "env": "production",
|
||||
"declared_tag": "v1.4.0", "running_tag": "v1.3.0", "latest_tag": "v1.4.0",
|
||||
"health": "yellow", "drift": ["un-rolled"] }
|
||||
],
|
||||
"summary": { "total": 1, "byDrift": { "un-rolled": 1 } }
|
||||
}
|
||||
```
|
||||
|
||||
Drift is never stored — it is recomputed from declared/running/latest each time. `POST /v1/apps/sync` refreshes the observed columns from the cluster and release feeds.
|
||||
<Callout type="warn">
|
||||
Do not post to `platform.hanzo.ai/v1/*` or `platform.hanzo.ai/api/*`. The first returns `500 Service token is not configured on the server`; the second returns the Studio's HTML shell with a `404`. Neither is an API.
|
||||
</Callout>
|
||||
|
||||
## Custom domains & TLS
|
||||
|
||||
Attach a hostname to an application; TLS is provisioned automatically (Let's Encrypt) and a DNS record is created:
|
||||
|
||||
```bash
|
||||
curl -fsS -X POST https://platform.hanzo.ai/api/domain.create \
|
||||
-H "x-api-key: $PLATFORM_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"applicationId": "'$APP_ID'",
|
||||
"host": "app.example.com",
|
||||
"https": true,
|
||||
"certificateType": "letsencrypt"
|
||||
}'
|
||||
```
|
||||
|
||||
Point your DNS at the platform ingress IP shown on the project's **Domains** tab.
|
||||
Attach it in the Studio under the project's **Domains** tab, then point your DNS at the ingress IP shown there. Records themselves are managed through [Hanzo DNS](/docs/services/dns) at `api.hanzo.ai/v1/dns`.
|
||||
|
||||
## Self-hosting
|
||||
|
||||
@@ -164,10 +148,10 @@ The platform runs as a Next.js application with an embedded SQLite database; for
|
||||
|
||||
<Cards>
|
||||
<Card title="API Overview" href="/docs/services/platform/api">
|
||||
The `/v1` control surface and the `/api` build pipeline
|
||||
The `/v1/platform` control surface and `/v1/runner` builds
|
||||
</Card>
|
||||
<Card title="Authentication" href="/docs/services/platform/api/authentication">
|
||||
API keys, service tokens, and IAM tokens
|
||||
IAM bearers and the fabric build token
|
||||
</Card>
|
||||
<Card title="Containers API" href="/docs/services/platform/api/containers">
|
||||
Create, deploy, redeploy, and operate applications
|
||||
|
||||
@@ -60,7 +60,6 @@ Hanzo Extensions is a **monorepo of browser and IDE extensions** providing AI-po
|
||||
5. Extracts token, closes tab
|
||||
```
|
||||
|
||||
**LLM endpoint**: `api.hanzo.ai/v1/chat/completions` (NOT `llm.hanzo.ai` which is Cloud UI)
|
||||
|
||||
### Auth Implementation
|
||||
|
||||
@@ -101,7 +100,7 @@ async function startAuth(): Promise<string> {
|
||||
```typescript
|
||||
// /oauth/userinfo only returns `sub` — use /v1/iam/get-account for full profile
|
||||
async function getProfile(token: string) {
|
||||
const res = await fetch("https://iam.hanzo.ai/v1/iam/get-account", {
|
||||
const res = await fetch("https://api.hanzo.ai/v1/iam/get-account", {
|
||||
headers: { "Authorization": `Bearer ${token}` }
|
||||
})
|
||||
return res.json() // { name, email, avatar, ... }
|
||||
@@ -141,7 +140,6 @@ cd packages/jetbrains
|
||||
| Issue | Cause | Solution |
|
||||
|-------|-------|----------|
|
||||
| Code flow fails | Hanzo IAM empty grant_type bug | Use implicit flow (response_type=token) |
|
||||
| LLM returns 404 | Using llm.hanzo.ai | Use api.hanzo.ai/v1/chat/completions |
|
||||
| Safari build fails | Missing Xcode | Build on macOS with Xcode installed |
|
||||
| JetBrains build fails | Missing gradle wrapper | Commit gradle-wrapper.jar |
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ For **client-side OAuth flows** (login UI, token extraction, redirect handling),
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Admin UI | `https://iam.hanzo.ai` (internal) |
|
||||
| Admin UI | `https://hanzo.id` (internal) |
|
||||
| Login UI | `https://hanzo.id` (separate repo: hanzoai/id) |
|
||||
| API port | 8000 |
|
||||
| LDAP port | 389 (LDAPS: 636) |
|
||||
@@ -162,11 +162,11 @@ cp conf/app.dev.conf conf/app.conf
|
||||
|
||||
```bash
|
||||
# Get all users in an organization
|
||||
curl -s "https://iam.hanzo.ai/v1/iam/get-users?owner=hanzo" \
|
||||
curl -s "https://api.hanzo.ai/v1/iam/get-users?owner=hanzo" \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}"
|
||||
|
||||
# Create a new application
|
||||
curl -X POST "https://iam.hanzo.ai/v1/iam/add-application" \
|
||||
curl -X POST "https://api.hanzo.ai/v1/iam/add-application" \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
@@ -181,7 +181,7 @@ curl -X POST "https://iam.hanzo.ai/v1/iam/add-application" \
|
||||
}'
|
||||
|
||||
# Update user balance (billing integration)
|
||||
curl -X POST "https://iam.hanzo.ai/api/update-user" \
|
||||
curl -X POST "https://api.hanzo.ai/v1/iam/update-user" \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
@@ -378,7 +378,7 @@ POSTGRES_PASSWORD=<generate-secure-password>
|
||||
POSTGRES_DB=iam
|
||||
|
||||
# IAM server
|
||||
IAM_ORIGIN=https://iam.hanzo.ai
|
||||
IAM_ORIGIN=https://hanzo.id
|
||||
ENCRYPTION_KEY=<32-byte-hex-key>
|
||||
ENABLE_MULTI_TENANT=true
|
||||
ALLOWED_ORIGINS=hanzo.id,zoo.id,lux.id,pars.id,iam.hanzo.ai
|
||||
|
||||
@@ -38,7 +38,7 @@ Hanzo ID is the **unified identity platform** for the entire Hanzo/Lux/Zoo ecosy
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Login UI | `https://hanzo.id` |
|
||||
| IAM API | `https://iam.hanzo.ai` (backend) |
|
||||
| IAM API | `https://hanzo.id` (backend) |
|
||||
| Authorize | `/oauth/authorize` |
|
||||
| Token | `/oauth/token` |
|
||||
| Userinfo | `/oauth/userinfo` (limited: sub/iss/aud only) |
|
||||
@@ -89,7 +89,7 @@ const accessToken = hash.get("access_token")
|
||||
const state = hash.get("state")
|
||||
|
||||
// Get full profile (userinfo only returns sub)
|
||||
const profile = await fetch("https://iam.hanzo.ai/v1/iam/get-account", {
|
||||
const profile = await fetch("https://api.hanzo.ai/v1/iam/get-account", {
|
||||
headers: { "Authorization": `Bearer ${accessToken}` }
|
||||
}).then(r => r.json())
|
||||
// profile.name, profile.email, profile.avatar, etc.
|
||||
|
||||
@@ -171,7 +171,7 @@ spec:
|
||||
| Domain | Backend Service |
|
||||
|--------|-----------------|
|
||||
| `hanzo.ai` | hanzo-app |
|
||||
| `api.hanzo.ai`, `llm.hanzo.ai` | Hanzo Gateway |
|
||||
| `api.hanzo.ai` | Hanzo API (one host for every `/v1/<service>`) |
|
||||
| `hanzo.id`, `lux.id`, `zoo.id` | IAM (Hanzo IAM) |
|
||||
| `kms.hanzo.ai` | KMS (Hanzo KMS) |
|
||||
| `platform.hanzo.ai` | Platform (Dokploy) |
|
||||
|
||||
@@ -41,7 +41,7 @@ Repo: `github.com/hanzoai/llm`.
|
||||
| Internal endpoint | `http://llm.hanzo.svc.cluster.local:4000/v1` |
|
||||
| Port | 4000 |
|
||||
| Config | `config.yaml` or env vars |
|
||||
| Dashboard | `https://llm.hanzo.ai` (Cloud UI, NOT LLM endpoint) |
|
||||
| Dashboard | `https://console.hanzo.ai` |
|
||||
| Repo | `github.com/hanzoai/llm` |
|
||||
|
||||
## One-file quickstart
|
||||
|
||||
@@ -46,8 +46,8 @@ Repo: `hanzoai/paas`.
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| UI | `https://platform.hanzo.ai` |
|
||||
| API | `https://platform.hanzo.ai/v1` |
|
||||
| Studio (UI) | `https://platform.hanzo.ai` |
|
||||
| API | `https://api.hanzo.ai/v1/platform` (builds: `POST /v1/runner`) |
|
||||
| Auth | IAM via hanzo.id (OAuth2) |
|
||||
| Images | `ghcr.io/hanzoai/paas-{api,studio,monitor,sync,webhook}` |
|
||||
| K8s SA | `hanzo-paas-sa` |
|
||||
@@ -60,16 +60,19 @@ Repo: `hanzoai/paas`.
|
||||
|
||||
```bash
|
||||
# Create a project
|
||||
curl -X POST https://platform.hanzo.ai/v1/projects \
|
||||
curl -X POST https://api.hanzo.ai/v1/platform/projects \
|
||||
-H "Authorization: Bearer ${HANZO_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "my-ai-app",
|
||||
"environment": "production",
|
||||
"image": "ghcr.io/myorg/my-app:latest",
|
||||
"port": 3000,
|
||||
"replicas": 2
|
||||
}'
|
||||
-d '{ "slug": "my-ai-app", "name": "My AI App" }'
|
||||
|
||||
# Add an app to it, then roll it forward
|
||||
curl -X POST https://api.hanzo.ai/v1/platform/projects/my-ai-app/apps \
|
||||
-H "Authorization: Bearer ${HANZO_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "name": "web", "image": "ghcr.io/hanzoai/my-app:v1.0.0", "port": 3000, "replicas": 2 }'
|
||||
|
||||
curl -X POST https://api.hanzo.ai/v1/platform/projects/my-ai-app/apps/web/deploy \
|
||||
-H "Authorization: Bearer ${HANZO_TOKEN}"
|
||||
```
|
||||
|
||||
### Docker Compose (self-hosted)
|
||||
|
||||
@@ -117,7 +117,7 @@ I need it to extract titles from a list of URLs.
|
||||
|
||||
%tools # List available MCP tools
|
||||
%tool read_file {"file_path": "README.md"} # Execute specific tool
|
||||
%model claude-3-opus-20240229 # Change model
|
||||
%model zen5 # Change model
|
||||
%edit_self ipython_repl.py # Edit REPL source code
|
||||
```
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ const res = await client.chat.completions.create({
|
||||
});
|
||||
|
||||
// The model that actually served the request:
|
||||
console.log(res.model); // e.g. "zen-nano" | "zen-omni" | a frontier model
|
||||
console.log(res.model); // e.g. "zen-nano" | "zen5" | a frontier model
|
||||
```
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
@@ -259,7 +259,7 @@ export default function PlatformPage() {
|
||||
<div className="flex flex-col items-center gap-0.5 text-fd-muted-foreground/40">
|
||||
<span className="text-[10px] font-mono">AI API</span>
|
||||
<span className="text-xs">|</span>
|
||||
<span className="text-[10px] font-mono">llm.hanzo.ai</span>
|
||||
<span className="text-[10px] font-mono">api.hanzo.ai/v1</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -25,12 +25,12 @@ A generation is an LLM call with full input/output capture, token counts, model
|
||||
## Instrumentation
|
||||
|
||||
### Auto-Instrumentation (Hanzo AI API)
|
||||
If routing through `llm.hanzo.ai`, all calls are automatically traced:
|
||||
Calls through the Hanzo AI API (`api.hanzo.ai/v1`), all calls are automatically traced:
|
||||
|
||||
```bash
|
||||
curl https://llm.hanzo.ai/v1/chat/completions \
|
||||
curl https://api.hanzo.ai/v1/chat/completions \
|
||||
-H "Authorization: Bearer $HANZO_API_KEY" \
|
||||
-d '{"model": "zen-4o", "messages": [{"role": "user", "content": "Hello"}]}'
|
||||
-d '{"model": "zen5", "messages": [{"role": "user", "content": "Hello"}]}'
|
||||
# → Automatically creates trace + generation in Insights
|
||||
```
|
||||
|
||||
|
||||
@@ -259,7 +259,7 @@ export default function PlatformPage() {
|
||||
<div className="flex flex-col items-center gap-0.5 text-fd-muted-foreground/40">
|
||||
<span className="text-[10px] font-mono">AI API</span>
|
||||
<span className="text-xs">|</span>
|
||||
<span className="text-[10px] font-mono">llm.hanzo.ai</span>
|
||||
<span className="text-[10px] font-mono">api.hanzo.ai/v1</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -259,7 +259,7 @@ export default function PlatformPage() {
|
||||
<div className="flex flex-col items-center gap-0.5 text-fd-muted-foreground/40">
|
||||
<span className="text-[10px] font-mono">AI API</span>
|
||||
<span className="text-xs">|</span>
|
||||
<span className="text-[10px] font-mono">llm.hanzo.ai</span>
|
||||
<span className="text-[10px] font-mono">api.hanzo.ai/v1</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -22,9 +22,9 @@ Activities are the **building blocks of work** in Hanzo Tasks. They perform the
|
||||
<Tab value="Go">
|
||||
```go
|
||||
func CallLLM(ctx context.Context, prompt string) (LLMResponse, error) {
|
||||
resp, err := http.Post("https://llm.hanzo.ai/v1/chat/completions",
|
||||
resp, err := http.Post("https://api.hanzo.ai/v1/chat/completions",
|
||||
"application/json",
|
||||
strings.NewReader(fmt.Sprintf(`{"model":"zen-70b","messages":[{"role":"user","content":"%s"}]}`, prompt)),
|
||||
strings.NewReader(fmt.Sprintf(`{"model":"zen5","messages":[{"role":"user","content":"%s"}]}`, prompt)),
|
||||
)
|
||||
if err != nil {
|
||||
return LLMResponse{}, fmt.Errorf("llm request failed: %w", err)
|
||||
@@ -46,9 +46,9 @@ func CallLLM(ctx context.Context, prompt string) (LLMResponse, error) {
|
||||
async def call_llm(prompt: str) -> LLMResponse:
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.post(
|
||||
"https://llm.hanzo.ai/v1/chat/completions",
|
||||
"https://api.hanzo.ai/v1/chat/completions",
|
||||
json={
|
||||
"model": "zen-70b",
|
||||
"model": "zen5",
|
||||
"messages": [{"role": "user", "content": prompt}],
|
||||
},
|
||||
)
|
||||
|
||||
@@ -45,14 +45,14 @@ const MODELS = [
|
||||
gguf: 'https://huggingface.co/zenlm/zen-pro-32b',
|
||||
},
|
||||
{
|
||||
id: 'zen-coder',
|
||||
id: 'zen5-coder',
|
||||
name: 'Zen Coder',
|
||||
size: '32B',
|
||||
ram: '~20 GB RAM',
|
||||
hf: 'zenlm/zen-coder',
|
||||
ollama: 'ollama run hf.co/zenlm/zen-coder',
|
||||
lmstudio: 'zenlm/zen-coder',
|
||||
gguf: 'https://huggingface.co/zenlm/zen-coder',
|
||||
hf: 'zenlm/zen5-coder',
|
||||
ollama: 'ollama run hf.co/zenlm/zen5-coder',
|
||||
lmstudio: 'zenlm/zen5-coder',
|
||||
gguf: 'https://huggingface.co/zenlm/zen5-coder',
|
||||
},
|
||||
{
|
||||
id: 'zen-max',
|
||||
|
||||
@@ -265,7 +265,7 @@ export default function HomePage() {
|
||||
<OpenModelCard name="Zen" id="zen" hf="zenlm/zen-8b" size="8–32B" ctx="32K" arch="Dense" ollama="hf.co/zenlm/zen-8b" />
|
||||
<OpenModelCard name="Zen Pro" id="zen-pro" hf="zenlm/zen-pro-32b" size="32B" ctx="32K" arch="Dense" ollama="hf.co/zenlm/zen-pro-32b" />
|
||||
<OpenModelCard name="Zen Max" id="zen-max" hf="zenlm/zen-max" size="235B (22B active)" ctx="131K" arch="MoE" ollama="hf.co/zenlm/zen-max" />
|
||||
<OpenModelCard name="Zen Coder" id="zen-coder" hf="zenlm/zen-coder" size="32B" ctx="131K" arch="Dense" ollama="hf.co/zenlm/zen-coder" />
|
||||
<OpenModelCard name="Zen Coder" id="zen5-coder" hf="zenlm/zen5-coder" size="32B" ctx="131K" arch="Dense" ollama="hf.co/zenlm/zen5-coder" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -40,10 +40,10 @@ pip install sglang[all]
|
||||
| Model | Minimum VRAM | Recommended |
|
||||
|-------|--------------|-------------|
|
||||
| zen-nano | 2GB | 4GB |
|
||||
| zen-coder-4b | 8GB | 16GB |
|
||||
| zen-coder-flash | 24GB | 48GB |
|
||||
| zen5-coder-4b | 8GB | 16GB |
|
||||
| zen5-coder-flash | 24GB | 48GB |
|
||||
| zen-max | 160GB | 320GB |
|
||||
|
||||
<Callout type="info">
|
||||
zen-coder-flash uses MoE architecture with 31B total params but only 3B active, making it efficient for its capability level.
|
||||
zen5-coder-flash uses MoE architecture with 31B total params but only 3B active, making it efficient for its capability level.
|
||||
</Callout>
|
||||
|
||||
@@ -37,7 +37,7 @@ The easiest way to use Zen models:
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
model_id = "zenlm/zen-coder-flash"
|
||||
model_id = "zenlm/zen5-coder-flash"
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(model_id)
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
@@ -57,7 +57,7 @@ print(tokenizer.decode(outputs[0], skip_special_tokens=True))
|
||||
For high-throughput production serving:
|
||||
|
||||
```bash
|
||||
vllm serve zenlm/zen-coder-flash \
|
||||
vllm serve zenlm/zen5-coder-flash \
|
||||
--tensor-parallel-size 4 \
|
||||
--enable-auto-tool-choice
|
||||
```
|
||||
@@ -68,7 +68,7 @@ With EAGLE speculative decoding:
|
||||
|
||||
```bash
|
||||
python -m sglang.launch_server \
|
||||
--model-path zenlm/zen-coder-flash \
|
||||
--model-path zenlm/zen5-coder-flash \
|
||||
--tp-size 4 \
|
||||
--speculative-algorithm EAGLE
|
||||
```
|
||||
@@ -80,7 +80,7 @@ Optimized for M1/M2/M3 Macs:
|
||||
```python
|
||||
from mlx_lm import load, generate
|
||||
|
||||
model, tokenizer = load("zenlm/zen-coder-flash")
|
||||
model, tokenizer = load("zenlm/zen5-coder-flash")
|
||||
response = generate(model, tokenizer, prompt="Write a Rust function for quicksort", max_tokens=256)
|
||||
print(response)
|
||||
```
|
||||
|
||||
@@ -33,7 +33,7 @@ Latest generation production models with MoDE architecture. The recommended choi
|
||||
|
||||
Specialized models for code generation, review, debugging, and agentic programming.
|
||||
|
||||
<ModelTable ids={["zen4-coder", "zen4-coder-flash", "zen4-coder-pro", "zen-coder", "zen-coder-flash", "zen-code"]} showArch />
|
||||
<ModelTable ids={["zen4-coder", "zen4-coder-flash", "zen4-coder-pro", "zen5-coder", "zen5-coder-flash", "zen-code"]} showArch />
|
||||
|
||||
---
|
||||
|
||||
@@ -81,7 +81,7 @@ General-purpose open-weight models available on [HuggingFace](https://huggingfac
|
||||
|
||||
Vision-language and multimodal open-weight models.
|
||||
|
||||
<ModelTable ids={["zen-vl", "zen-omni"]} showPricing={false} />
|
||||
<ModelTable ids={["zen-vl", "zen5"]} showPricing={false} />
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -77,5 +77,5 @@ else:
|
||||
## See Also
|
||||
|
||||
- [zen4](/docs/models/zen4) -- 744B MoE flagship model
|
||||
- [zen-coder](/docs/models/zen-coder) -- 32B code-specialized model
|
||||
- [zen5-coder](/docs/models/zen5-coder) -- 32B code-specialized model
|
||||
- [zen-pro](/docs/models/zen-pro) -- 32B professional foundation model
|
||||
|
||||
@@ -7,7 +7,7 @@ description: Legacy 14B dense code model for general programming tasks.
|
||||
|
||||
**Code (Legacy)**
|
||||
|
||||
A 14B dense transformer for code generation and understanding. This is a legacy model -- for new projects, consider [zen-coder](/docs/models/zen-coder) (32B) or [zen4-coder](/docs/models/zen4-coder) (480B MoE).
|
||||
A 14B dense transformer for code generation and understanding. This is a legacy model -- for new projects, consider [zen5-coder](/docs/models/zen5-coder) (32B) or [zen4-coder](/docs/models/zen4-coder) (480B MoE).
|
||||
|
||||
## Specifications
|
||||
|
||||
@@ -63,6 +63,6 @@ print(response.choices[0].message.content)
|
||||
|
||||
## See Also
|
||||
|
||||
- [zen-coder](/docs/models/zen-coder) -- 32B recommended replacement
|
||||
- [zen-coder-flash](/docs/models/zen-coder-flash) -- 7B low-latency alternative
|
||||
- [zen5-coder](/docs/models/zen5-coder) -- 32B recommended replacement
|
||||
- [zen5-coder-flash](/docs/models/zen5-coder-flash) -- 7B low-latency alternative
|
||||
- [zen4-coder](/docs/models/zen4-coder) -- 480B MoE flagship code model
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
title: zen-coder-flash
|
||||
title: zen5-coder-flash
|
||||
description: Lightweight 7B dense model for low-latency code completions.
|
||||
---
|
||||
|
||||
# zen-coder-flash
|
||||
# zen5-coder-flash
|
||||
|
||||
**Code**
|
||||
|
||||
@@ -13,12 +13,12 @@ A 7B dense transformer optimized for low-latency code completions. Designed for
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Model ID** | `zen-coder-flash` |
|
||||
| **Model ID** | `zen5-coder-flash` |
|
||||
| **Parameters** | 7B |
|
||||
| **Architecture** | Dense |
|
||||
| **Context Window** | 32K tokens |
|
||||
| **Status** | Available |
|
||||
| **HuggingFace** | [zenlm/zen-coder-flash](https://huggingface.co/zenlm/zen-coder-flash) |
|
||||
| **HuggingFace** | [zenlm/zen5-coder-flash](https://huggingface.co/zenlm/zen5-coder-flash) |
|
||||
|
||||
## Capabilities
|
||||
|
||||
@@ -40,8 +40,8 @@ pip install transformers torch
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("zenlm/zen-coder-flash")
|
||||
model = AutoModelForCausalLM.from_pretrained("zenlm/zen-coder-flash")
|
||||
tokenizer = AutoTokenizer.from_pretrained("zenlm/zen5-coder-flash")
|
||||
model = AutoModelForCausalLM.from_pretrained("zenlm/zen5-coder-flash")
|
||||
|
||||
inputs = tokenizer("def fibonacci(n):\n ", return_tensors="pt")
|
||||
outputs = model.generate(**inputs, max_new_tokens=128)
|
||||
@@ -56,7 +56,7 @@ from hanzoai import Hanzo
|
||||
client = Hanzo(api_key="hk-your-api-key")
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="zen-coder-flash",
|
||||
model="zen5-coder-flash",
|
||||
messages=[{"role": "user", "content": "Complete this function:\ndef binary_search(arr, target):\n "}],
|
||||
)
|
||||
print(response.choices[0].message.content)
|
||||
@@ -64,6 +64,6 @@ print(response.choices[0].message.content)
|
||||
|
||||
## See Also
|
||||
|
||||
- [zen-coder](/docs/models/zen-coder) -- 32B full code model
|
||||
- [zen5-coder](/docs/models/zen5-coder) -- 32B full code model
|
||||
- [zen-code](/docs/models/zen-code) -- 14B legacy code model
|
||||
- [zen4-coder-flash](/docs/models/zen4-coder-flash) -- 30B MoE fast code model
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
title: zen-coder
|
||||
title: zen5-coder
|
||||
description: 32B dense code model with 131K context for multi-language development.
|
||||
---
|
||||
|
||||
# zen-coder
|
||||
# zen5-coder
|
||||
|
||||
**Code**
|
||||
|
||||
@@ -13,12 +13,12 @@ A 32B dense transformer trained for software engineering. Supports multi-languag
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Model ID** | `zen-coder` |
|
||||
| **Model ID** | `zen5-coder` |
|
||||
| **Parameters** | 32B |
|
||||
| **Architecture** | Dense |
|
||||
| **Context Window** | 131K tokens |
|
||||
| **Status** | Available |
|
||||
| **HuggingFace** | [zenlm/zen-coder](https://huggingface.co/zenlm/zen-coder) |
|
||||
| **HuggingFace** | [zenlm/zen5-coder](https://huggingface.co/zenlm/zen5-coder) |
|
||||
|
||||
## Capabilities
|
||||
|
||||
@@ -40,8 +40,8 @@ pip install transformers torch
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("zenlm/zen-coder")
|
||||
model = AutoModelForCausalLM.from_pretrained("zenlm/zen-coder", device_map="auto")
|
||||
tokenizer = AutoTokenizer.from_pretrained("zenlm/zen5-coder")
|
||||
model = AutoModelForCausalLM.from_pretrained("zenlm/zen5-coder", device_map="auto")
|
||||
|
||||
inputs = tokenizer("Write a Python function to merge two sorted lists:", return_tensors="pt").to(model.device)
|
||||
outputs = model.generate(**inputs, max_new_tokens=256)
|
||||
@@ -56,7 +56,7 @@ from hanzoai import Hanzo
|
||||
client = Hanzo(api_key="hk-your-api-key")
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="zen-coder",
|
||||
model="zen5-coder",
|
||||
messages=[{"role": "user", "content": "Write a Go HTTP server with graceful shutdown."}],
|
||||
)
|
||||
print(response.choices[0].message.content)
|
||||
@@ -65,5 +65,5 @@ print(response.choices[0].message.content)
|
||||
## See Also
|
||||
|
||||
- [zen4-coder](/docs/models/zen4-coder) -- 480B MoE code model
|
||||
- [zen-coder-flash](/docs/models/zen-coder-flash) -- 7B low-latency code completions
|
||||
- [zen5-coder-flash](/docs/models/zen5-coder-flash) -- 7B low-latency code completions
|
||||
- [zen-code](/docs/models/zen-code) -- 14B legacy code model
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
title: zen-omni
|
||||
title: zen5
|
||||
description: 72B dense hypermodal model supporting text, vision, audio, and code.
|
||||
---
|
||||
|
||||
# zen-omni
|
||||
# zen5
|
||||
|
||||
**Hypermodal**
|
||||
|
||||
@@ -13,13 +13,13 @@ A 72B dense transformer that unifies text, vision, audio, and code in a single m
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Model ID** | `zen-omni` |
|
||||
| **Model ID** | `zen5` |
|
||||
| **Parameters** | 72B |
|
||||
| **Architecture** | Dense Multimodal |
|
||||
| **Context Window** | 131K tokens |
|
||||
| **Modalities** | Text, Vision, Audio, Code |
|
||||
| **Status** | Available |
|
||||
| **HuggingFace** | [zenlm/zen-omni](https://huggingface.co/zenlm/zen-omni) |
|
||||
| **HuggingFace** | [zenlm/zen5](https://huggingface.co/zenlm/zen5) |
|
||||
|
||||
## Capabilities
|
||||
|
||||
@@ -41,8 +41,8 @@ pip install transformers torch pillow
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("zenlm/zen-omni", trust_remote_code=True)
|
||||
model = AutoModelForCausalLM.from_pretrained("zenlm/zen-omni", trust_remote_code=True, device_map="auto")
|
||||
tokenizer = AutoTokenizer.from_pretrained("zenlm/zen5", trust_remote_code=True)
|
||||
model = AutoModelForCausalLM.from_pretrained("zenlm/zen5", trust_remote_code=True, device_map="auto")
|
||||
|
||||
inputs = tokenizer("Analyze this data and provide insights:", return_tensors="pt").to(model.device)
|
||||
outputs = model.generate(**inputs, max_new_tokens=512)
|
||||
@@ -57,7 +57,7 @@ from hanzoai import Hanzo
|
||||
client = Hanzo(api_key="hk-your-api-key")
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="zen-omni",
|
||||
model="zen5",
|
||||
messages=[{
|
||||
"role": "user",
|
||||
"content": [
|
||||
|
||||
@@ -54,4 +54,4 @@ response = client.chat.completions.create(
|
||||
|
||||
- [zen-director](/docs/models/zen-director) -- Text-to-video generation
|
||||
- [zen-video-i2v](/docs/models/zen-video-i2v) -- Image-to-video animation
|
||||
- [zen-omni](/docs/models/zen-omni) -- Hypermodal understanding
|
||||
- [zen5](/docs/models/zen5) -- Hypermodal understanding
|
||||
|
||||
@@ -76,5 +76,5 @@ print(response.choices[0].message.content)
|
||||
## See Also
|
||||
|
||||
- [zen3-vl](/docs/models/zen3-vl) -- 30B MoE vision-language model
|
||||
- [zen-omni](/docs/models/zen-omni) -- 72B hypermodal (text+vision+audio+code)
|
||||
- [zen5](/docs/models/zen5) -- 72B hypermodal (text+vision+audio+code)
|
||||
- [zen3-omni](/docs/models/zen3-omni) -- 200B multimodal model
|
||||
|
||||
@@ -54,4 +54,4 @@ response = client.chat.completions.create(
|
||||
|
||||
- [zen-3d](/docs/models/zen-3d) -- 3D asset generation
|
||||
- [zen-world](/docs/models/zen-world) -- World simulation
|
||||
- [zen-omni](/docs/models/zen-omni) -- Hypermodal understanding
|
||||
- [zen5](/docs/models/zen5) -- Hypermodal understanding
|
||||
|
||||
@@ -20,8 +20,8 @@ Training config at `training/configs/8xh200.yaml`:
|
||||
|
||||
```yaml
|
||||
# Model
|
||||
model_name: zenlm/zen-coder-flash
|
||||
output_dir: ./zen-coder-flash-lora
|
||||
model_name: zenlm/zen5-coder-flash
|
||||
output_dir: ./zen5-coder-flash-lora
|
||||
|
||||
# Hardware
|
||||
num_gpus: 8
|
||||
@@ -54,8 +54,8 @@ dataset: hanzoai/zen-agentic-dataset-private
|
||||
|
||||
```bash
|
||||
# Clone the repo
|
||||
git clone https://github.com/zenlm/zen-coder-flash
|
||||
cd zen-coder-flash
|
||||
git clone https://github.com/zenlm/zen5-coder-flash
|
||||
cd zen5-coder-flash
|
||||
|
||||
# Dry run
|
||||
python training/launch_training.py --dry-run
|
||||
@@ -73,7 +73,7 @@ The launcher generates a SLURM job script:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
#SBATCH --job-name=zen-coder-flash
|
||||
#SBATCH --job-name=zen5-coder-flash
|
||||
#SBATCH --nodes=1
|
||||
#SBATCH --ntasks-per-node=1
|
||||
#SBATCH --gpus-per-node=8
|
||||
|
||||
@@ -5,7 +5,7 @@ description: Train locally with NVIDIA GPUs
|
||||
|
||||
# CUDA Training (Local GPU)
|
||||
|
||||
Train zen-coder-flash on NVIDIA GPUs with QLoRA.
|
||||
Train zen5-coder-flash on NVIDIA GPUs with QLoRA.
|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -23,8 +23,8 @@ pip install torch transformers accelerate peft bitsandbytes datasets
|
||||
|
||||
```bash
|
||||
# Clone the repo
|
||||
git clone https://github.com/zenlm/zen-coder-flash
|
||||
cd zen-coder-flash
|
||||
git clone https://github.com/zenlm/zen5-coder-flash
|
||||
cd zen5-coder-flash
|
||||
|
||||
# Train with QLoRA
|
||||
python training/train_cuda.py
|
||||
|
||||
@@ -5,7 +5,7 @@ description: Train on Apple Silicon with MLX
|
||||
|
||||
# MLX Training (Apple Silicon)
|
||||
|
||||
Train zen-coder-flash on M1/M2/M3 Macs using MLX.
|
||||
Train zen5-coder-flash on M1/M2/M3 Macs using MLX.
|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -23,8 +23,8 @@ pip install mlx mlx-lm
|
||||
|
||||
```bash
|
||||
# Clone the repo
|
||||
git clone https://github.com/zenlm/zen-coder-flash
|
||||
cd zen-coder-flash
|
||||
git clone https://github.com/zenlm/zen5-coder-flash
|
||||
cd zen5-coder-flash
|
||||
|
||||
# Train with LoRA
|
||||
python training/train_mlx.py
|
||||
|
||||
@@ -32,7 +32,7 @@ Training is powered by [Zoo Gym](https://github.com/zooai/gym):
|
||||
## Repository Structure
|
||||
|
||||
```
|
||||
zen-coder-flash/
|
||||
zen5-coder-flash/
|
||||
├── training/
|
||||
│ ├── configs/
|
||||
│ │ └── 8xh200.yaml # Nebius 8x H200 config
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -55,7 +55,7 @@ import * as __fd_glob_73 from "../content/docs/models/zen-translator.mdx?collect
|
||||
import * as __fd_glob_72 from "../content/docs/models/zen-scribe.mdx?collection=docs"
|
||||
import * as __fd_glob_71 from "../content/docs/models/zen-reranker.mdx?collection=docs"
|
||||
import * as __fd_glob_70 from "../content/docs/models/zen-pro.mdx?collection=docs"
|
||||
import * as __fd_glob_69 from "../content/docs/models/zen-omni.mdx?collection=docs"
|
||||
import * as __fd_glob_69 from "../content/docs/models/zen5.mdx?collection=docs"
|
||||
import * as __fd_glob_68 from "../content/docs/models/zen-next.mdx?collection=docs"
|
||||
import * as __fd_glob_67 from "../content/docs/models/zen-nano.mdx?collection=docs"
|
||||
import * as __fd_glob_66 from "../content/docs/models/zen-musician.mdx?collection=docs"
|
||||
@@ -71,8 +71,8 @@ import * as __fd_glob_57 from "../content/docs/models/zen-dub.mdx?collection=doc
|
||||
import * as __fd_glob_56 from "../content/docs/models/zen-dub-live.mdx?collection=docs"
|
||||
import * as __fd_glob_55 from "../content/docs/models/zen-director.mdx?collection=docs"
|
||||
import * as __fd_glob_54 from "../content/docs/models/zen-designer.mdx?collection=docs"
|
||||
import * as __fd_glob_53 from "../content/docs/models/zen-coder.mdx?collection=docs"
|
||||
import * as __fd_glob_52 from "../content/docs/models/zen-coder-flash.mdx?collection=docs"
|
||||
import * as __fd_glob_53 from "../content/docs/models/zen5-coder.mdx?collection=docs"
|
||||
import * as __fd_glob_52 from "../content/docs/models/zen5-coder-flash.mdx?collection=docs"
|
||||
import * as __fd_glob_51 from "../content/docs/models/zen-code.mdx?collection=docs"
|
||||
import * as __fd_glob_50 from "../content/docs/models/zen-artist.mdx?collection=docs"
|
||||
import * as __fd_glob_49 from "../content/docs/models/zen-artist-edit.mdx?collection=docs"
|
||||
@@ -135,4 +135,4 @@ const create = server<typeof Config, import("@hanzo/docs-mdx/runtime/types").Int
|
||||
|
||||
export const blog = await create.docLazy("blog", "content/blog", {"7680-dim-embeddings.mdx": __fd_glob_0, "agent-nfts.mdx": __fd_glob_1, "bitdelta-behavioral-compression.mdx": __fd_glob_2, "case-for-decentralized-science.mdx": __fd_glob_3, "case-for-desci.mdx": __fd_glob_4, "chinese-clip.mdx": __fd_glob_5, "continual-learning-sure-opcm.mdx": __fd_glob_6, "decentralized-compute.mdx": __fd_glob_7, "drop-upcycling-zen-mode.mdx": __fd_glob_8, "embedding-spaces-7680-dimensions.mdx": __fd_glob_9, "experience-ledgers.mdx": __fd_glob_10, "federated-learning-without-compromise.mdx": __fd_glob_11, "federated-learning.mdx": __fd_glob_12, "future-of-open-ai.mdx": __fd_glob_13, "global-load-balance.mdx": __fd_glob_14, "grpo-group-relative-policy-optimization.mdx": __fd_glob_15, "grpo.mdx": __fd_glob_16, "gt-qlora-moe-abliteration.mdx": __fd_glob_17, "introducing-zen.mdx": __fd_glob_18, "ofa.mdx": __fd_glob_19, "ofasys.mdx": __fd_glob_20, "open-training-hanzo-network.mdx": __fd_glob_21, "open-weights-philosophy.mdx": __fd_glob_22, "proof-of-ai.mdx": __fd_glob_23, "training-gym.mdx": __fd_glob_24, "training-llms-collective-intelligence.mdx": __fd_glob_25, "zen-3.mdx": __fd_glob_26, "zen-collaboration.mdx": __fd_glob_27, "zen-lm-launch.mdx": __fd_glob_28, "zen-mode-architecture.mdx": __fd_glob_29, "zen-reranker.mdx": __fd_glob_30, "zen4-ultra.mdx": __fd_glob_31, "zen5-release.mdx": __fd_glob_32, "zips-governance.mdx": __fd_glob_33, "zoo-foundation-launch.mdx": __fd_glob_34, }, {"7680-dim-embeddings.mdx": () => import("../content/blog/7680-dim-embeddings.mdx?collection=blog"), "agent-nfts.mdx": () => import("../content/blog/agent-nfts.mdx?collection=blog"), "bitdelta-behavioral-compression.mdx": () => import("../content/blog/bitdelta-behavioral-compression.mdx?collection=blog"), "case-for-decentralized-science.mdx": () => import("../content/blog/case-for-decentralized-science.mdx?collection=blog"), "case-for-desci.mdx": () => import("../content/blog/case-for-desci.mdx?collection=blog"), "chinese-clip.mdx": () => import("../content/blog/chinese-clip.mdx?collection=blog"), "continual-learning-sure-opcm.mdx": () => import("../content/blog/continual-learning-sure-opcm.mdx?collection=blog"), "decentralized-compute.mdx": () => import("../content/blog/decentralized-compute.mdx?collection=blog"), "drop-upcycling-zen-mode.mdx": () => import("../content/blog/drop-upcycling-zen-mode.mdx?collection=blog"), "embedding-spaces-7680-dimensions.mdx": () => import("../content/blog/embedding-spaces-7680-dimensions.mdx?collection=blog"), "experience-ledgers.mdx": () => import("../content/blog/experience-ledgers.mdx?collection=blog"), "federated-learning-without-compromise.mdx": () => import("../content/blog/federated-learning-without-compromise.mdx?collection=blog"), "federated-learning.mdx": () => import("../content/blog/federated-learning.mdx?collection=blog"), "future-of-open-ai.mdx": () => import("../content/blog/future-of-open-ai.mdx?collection=blog"), "global-load-balance.mdx": () => import("../content/blog/global-load-balance.mdx?collection=blog"), "grpo-group-relative-policy-optimization.mdx": () => import("../content/blog/grpo-group-relative-policy-optimization.mdx?collection=blog"), "grpo.mdx": () => import("../content/blog/grpo.mdx?collection=blog"), "gt-qlora-moe-abliteration.mdx": () => import("../content/blog/gt-qlora-moe-abliteration.mdx?collection=blog"), "introducing-zen.mdx": () => import("../content/blog/introducing-zen.mdx?collection=blog"), "ofa.mdx": () => import("../content/blog/ofa.mdx?collection=blog"), "ofasys.mdx": () => import("../content/blog/ofasys.mdx?collection=blog"), "open-training-hanzo-network.mdx": () => import("../content/blog/open-training-hanzo-network.mdx?collection=blog"), "open-weights-philosophy.mdx": () => import("../content/blog/open-weights-philosophy.mdx?collection=blog"), "proof-of-ai.mdx": () => import("../content/blog/proof-of-ai.mdx?collection=blog"), "training-gym.mdx": () => import("../content/blog/training-gym.mdx?collection=blog"), "training-llms-collective-intelligence.mdx": () => import("../content/blog/training-llms-collective-intelligence.mdx?collection=blog"), "zen-3.mdx": () => import("../content/blog/zen-3.mdx?collection=blog"), "zen-collaboration.mdx": () => import("../content/blog/zen-collaboration.mdx?collection=blog"), "zen-lm-launch.mdx": () => import("../content/blog/zen-lm-launch.mdx?collection=blog"), "zen-mode-architecture.mdx": () => import("../content/blog/zen-mode-architecture.mdx?collection=blog"), "zen-reranker.mdx": () => import("../content/blog/zen-reranker.mdx?collection=blog"), "zen4-ultra.mdx": () => import("../content/blog/zen4-ultra.mdx?collection=blog"), "zen5-release.mdx": () => import("../content/blog/zen5-release.mdx?collection=blog"), "zips-governance.mdx": () => import("../content/blog/zips-governance.mdx?collection=blog"), "zoo-foundation-launch.mdx": () => import("../content/blog/zoo-foundation-launch.mdx?collection=blog"), });
|
||||
|
||||
export const docs = await create.docs("docs", "content/docs", {"meta.json": __fd_glob_125, }, {"datasets.mdx": __fd_glob_35, "index.mdx": __fd_glob_36, "models.mdx": __fd_glob_37, "training.mdx": __fd_glob_38, "api/chat-completions.mdx": __fd_glob_39, "api/embeddings.mdx": __fd_glob_40, "api/index.mdx": __fd_glob_41, "api/messages.mdx": __fd_glob_42, "api/models.mdx": __fd_glob_43, "api/pricing.mdx": __fd_glob_44, "getting-started/installation.mdx": __fd_glob_45, "getting-started/quickstart.mdx": __fd_glob_46, "models/zen-3d.mdx": __fd_glob_47, "models/zen-agent.mdx": __fd_glob_48, "models/zen-artist-edit.mdx": __fd_glob_49, "models/zen-artist.mdx": __fd_glob_50, "models/zen-code.mdx": __fd_glob_51, "models/zen-coder-flash.mdx": __fd_glob_52, "models/zen-coder.mdx": __fd_glob_53, "models/zen-designer.mdx": __fd_glob_54, "models/zen-director.mdx": __fd_glob_55, "models/zen-dub-live.mdx": __fd_glob_56, "models/zen-dub.mdx": __fd_glob_57, "models/zen-eco.mdx": __fd_glob_58, "models/zen-embedding.mdx": __fd_glob_59, "models/zen-foley.mdx": __fd_glob_60, "models/zen-guard-gen.mdx": __fd_glob_61, "models/zen-guard-stream.mdx": __fd_glob_62, "models/zen-guard.mdx": __fd_glob_63, "models/zen-live.mdx": __fd_glob_64, "models/zen-max.mdx": __fd_glob_65, "models/zen-musician.mdx": __fd_glob_66, "models/zen-nano.mdx": __fd_glob_67, "models/zen-next.mdx": __fd_glob_68, "models/zen-omni.mdx": __fd_glob_69, "models/zen-pro.mdx": __fd_glob_70, "models/zen-reranker.mdx": __fd_glob_71, "models/zen-scribe.mdx": __fd_glob_72, "models/zen-translator.mdx": __fd_glob_73, "models/zen-video-i2v.mdx": __fd_glob_74, "models/zen-video.mdx": __fd_glob_75, "models/zen-vl.mdx": __fd_glob_76, "models/zen-voyager.mdx": __fd_glob_77, "models/zen-world.mdx": __fd_glob_78, "models/zen.mdx": __fd_glob_79, "models/zen3-asr-v1.mdx": __fd_glob_80, "models/zen3-asr.mdx": __fd_glob_81, "models/zen3-audio-fast.mdx": __fd_glob_82, "models/zen3-audio.mdx": __fd_glob_83, "models/zen3-embedding-medium.mdx": __fd_glob_84, "models/zen3-embedding-small.mdx": __fd_glob_85, "models/zen3-embedding.mdx": __fd_glob_86, "models/zen3-guard.mdx": __fd_glob_87, "models/zen3-image-dev.mdx": __fd_glob_88, "models/zen3-image-fast.mdx": __fd_glob_89, "models/zen3-image-jp.mdx": __fd_glob_90, "models/zen3-image-max.mdx": __fd_glob_91, "models/zen3-image-playground.mdx": __fd_glob_92, "models/zen3-image-sdxl.mdx": __fd_glob_93, "models/zen3-image-ssd.mdx": __fd_glob_94, "models/zen3-image.mdx": __fd_glob_95, "models/zen3-nano.mdx": __fd_glob_96, "models/zen3-omni.mdx": __fd_glob_97, "models/zen3-reranker-medium.mdx": __fd_glob_98, "models/zen3-reranker-small.mdx": __fd_glob_99, "models/zen3-reranker.mdx": __fd_glob_100, "models/zen3-tts-fast.mdx": __fd_glob_101, "models/zen3-tts-hd.mdx": __fd_glob_102, "models/zen3-tts.mdx": __fd_glob_103, "models/zen3-vl.mdx": __fd_glob_104, "models/zen4-coder-flash.mdx": __fd_glob_105, "models/zen4-coder-pro.mdx": __fd_glob_106, "models/zen4-coder.mdx": __fd_glob_107, "models/zen4-max.mdx": __fd_glob_108, "models/zen4-mini.mdx": __fd_glob_109, "models/zen4-pro.mdx": __fd_glob_110, "models/zen4-thinking.mdx": __fd_glob_111, "models/zen4-ultra.mdx": __fd_glob_112, "models/zen4.1.mdx": __fd_glob_113, "models/zen4.mdx": __fd_glob_114, "models/zen5-coder.mdx": __fd_glob_115, "models/zen5-max.mdx": __fd_glob_116, "models/zen5-mini.mdx": __fd_glob_117, "models/zen5-pro.mdx": __fd_glob_118, "models/zen5-ultra.mdx": __fd_glob_119, "models/zen5.mdx": __fd_glob_120, "training/cloud.mdx": __fd_glob_121, "training/cuda.mdx": __fd_glob_122, "training/mlx.mdx": __fd_glob_123, "training/overview.mdx": __fd_glob_124, });
|
||||
export const docs = await create.docs("docs", "content/docs", {"meta.json": __fd_glob_125, }, {"datasets.mdx": __fd_glob_35, "index.mdx": __fd_glob_36, "models.mdx": __fd_glob_37, "training.mdx": __fd_glob_38, "api/chat-completions.mdx": __fd_glob_39, "api/embeddings.mdx": __fd_glob_40, "api/index.mdx": __fd_glob_41, "api/messages.mdx": __fd_glob_42, "api/models.mdx": __fd_glob_43, "api/pricing.mdx": __fd_glob_44, "getting-started/installation.mdx": __fd_glob_45, "getting-started/quickstart.mdx": __fd_glob_46, "models/zen-3d.mdx": __fd_glob_47, "models/zen-agent.mdx": __fd_glob_48, "models/zen-artist-edit.mdx": __fd_glob_49, "models/zen-artist.mdx": __fd_glob_50, "models/zen-code.mdx": __fd_glob_51, "models/zen5-coder-flash.mdx": __fd_glob_52, "models/zen5-coder.mdx": __fd_glob_53, "models/zen-designer.mdx": __fd_glob_54, "models/zen-director.mdx": __fd_glob_55, "models/zen-dub-live.mdx": __fd_glob_56, "models/zen-dub.mdx": __fd_glob_57, "models/zen-eco.mdx": __fd_glob_58, "models/zen-embedding.mdx": __fd_glob_59, "models/zen-foley.mdx": __fd_glob_60, "models/zen-guard-gen.mdx": __fd_glob_61, "models/zen-guard-stream.mdx": __fd_glob_62, "models/zen-guard.mdx": __fd_glob_63, "models/zen-live.mdx": __fd_glob_64, "models/zen-max.mdx": __fd_glob_65, "models/zen-musician.mdx": __fd_glob_66, "models/zen-nano.mdx": __fd_glob_67, "models/zen-next.mdx": __fd_glob_68, "models/zen5.mdx": __fd_glob_69, "models/zen-pro.mdx": __fd_glob_70, "models/zen-reranker.mdx": __fd_glob_71, "models/zen-scribe.mdx": __fd_glob_72, "models/zen-translator.mdx": __fd_glob_73, "models/zen-video-i2v.mdx": __fd_glob_74, "models/zen-video.mdx": __fd_glob_75, "models/zen-vl.mdx": __fd_glob_76, "models/zen-voyager.mdx": __fd_glob_77, "models/zen-world.mdx": __fd_glob_78, "models/zen.mdx": __fd_glob_79, "models/zen3-asr-v1.mdx": __fd_glob_80, "models/zen3-asr.mdx": __fd_glob_81, "models/zen3-audio-fast.mdx": __fd_glob_82, "models/zen3-audio.mdx": __fd_glob_83, "models/zen3-embedding-medium.mdx": __fd_glob_84, "models/zen3-embedding-small.mdx": __fd_glob_85, "models/zen3-embedding.mdx": __fd_glob_86, "models/zen3-guard.mdx": __fd_glob_87, "models/zen3-image-dev.mdx": __fd_glob_88, "models/zen3-image-fast.mdx": __fd_glob_89, "models/zen3-image-jp.mdx": __fd_glob_90, "models/zen3-image-max.mdx": __fd_glob_91, "models/zen3-image-playground.mdx": __fd_glob_92, "models/zen3-image-sdxl.mdx": __fd_glob_93, "models/zen3-image-ssd.mdx": __fd_glob_94, "models/zen3-image.mdx": __fd_glob_95, "models/zen3-nano.mdx": __fd_glob_96, "models/zen3-omni.mdx": __fd_glob_97, "models/zen3-reranker-medium.mdx": __fd_glob_98, "models/zen3-reranker-small.mdx": __fd_glob_99, "models/zen3-reranker.mdx": __fd_glob_100, "models/zen3-tts-fast.mdx": __fd_glob_101, "models/zen3-tts-hd.mdx": __fd_glob_102, "models/zen3-tts.mdx": __fd_glob_103, "models/zen3-vl.mdx": __fd_glob_104, "models/zen4-coder-flash.mdx": __fd_glob_105, "models/zen4-coder-pro.mdx": __fd_glob_106, "models/zen4-coder.mdx": __fd_glob_107, "models/zen4-max.mdx": __fd_glob_108, "models/zen4-mini.mdx": __fd_glob_109, "models/zen4-pro.mdx": __fd_glob_110, "models/zen4-thinking.mdx": __fd_glob_111, "models/zen4-ultra.mdx": __fd_glob_112, "models/zen4.1.mdx": __fd_glob_113, "models/zen4.mdx": __fd_glob_114, "models/zen5-coder.mdx": __fd_glob_115, "models/zen5-max.mdx": __fd_glob_116, "models/zen5-mini.mdx": __fd_glob_117, "models/zen5-pro.mdx": __fd_glob_118, "models/zen5-ultra.mdx": __fd_glob_119, "models/zen5.mdx": __fd_glob_120, "training/cloud.mdx": __fd_glob_121, "training/cuda.mdx": __fd_glob_122, "training/mlx.mdx": __fd_glob_123, "training/overview.mdx": __fd_glob_124, });
|
||||
@@ -24,7 +24,7 @@ export const families: ModelFamily[] = [
|
||||
name: 'Code',
|
||||
description: 'Specialized models for code generation, review, and debugging.',
|
||||
icon: 'Code',
|
||||
models: ['zen4-coder', 'zen4-coder-flash', 'zen4-coder-pro', 'zen-coder', 'zen-coder-flash', 'zen-code'],
|
||||
models: ['zen4-coder', 'zen4-coder-flash', 'zen4-coder-pro', 'zen5-coder', 'zen5-coder-flash', 'zen-code'],
|
||||
},
|
||||
{
|
||||
id: 'zen3',
|
||||
@@ -76,7 +76,7 @@ export const families: ModelFamily[] = [
|
||||
name: 'Vision (Open Weights)',
|
||||
description: 'Vision-language and multimodal open-weight models.',
|
||||
icon: 'Eye',
|
||||
models: ['zen-vl', 'zen-omni'],
|
||||
models: ['zen-vl', 'zen5'],
|
||||
},
|
||||
{
|
||||
id: 'safety',
|
||||
|
||||
@@ -1004,7 +1004,7 @@ export const zenNext: ZenModel = {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const zenCoder: ZenModel = {
|
||||
id: 'zen-coder',
|
||||
id: 'zen5-coder',
|
||||
name: 'Zen Coder',
|
||||
fullName: 'Zen Coder — Code Generation',
|
||||
description: 'Baseline code model for generation and completions.',
|
||||
@@ -1016,13 +1016,13 @@ export const zenCoder: ZenModel = {
|
||||
pricing: null,
|
||||
features: ['131K context', 'Multi-language'],
|
||||
status: 'available',
|
||||
huggingface: 'https://huggingface.co/zenlm/zen-coder',
|
||||
huggingface: 'https://huggingface.co/zenlm/zen5-coder',
|
||||
github: null,
|
||||
aliases: [],
|
||||
}
|
||||
|
||||
export const zenCoderFlash: ZenModel = {
|
||||
id: 'zen-coder-flash',
|
||||
id: 'zen5-coder-flash',
|
||||
name: 'Zen Coder Flash',
|
||||
fullName: 'Zen Coder Flash — Fast Code',
|
||||
description: 'Fast code model for inline completions and suggestions.',
|
||||
@@ -1034,7 +1034,7 @@ export const zenCoderFlash: ZenModel = {
|
||||
pricing: null,
|
||||
features: ['32K context', 'Low latency'],
|
||||
status: 'available',
|
||||
huggingface: 'https://huggingface.co/zenlm/zen-coder-flash',
|
||||
huggingface: 'https://huggingface.co/zenlm/zen5-coder-flash',
|
||||
github: null,
|
||||
aliases: [],
|
||||
}
|
||||
@@ -1080,7 +1080,7 @@ export const zenVl: ZenModel = {
|
||||
}
|
||||
|
||||
export const zenOmni: ZenModel = {
|
||||
id: 'zen-omni',
|
||||
id: 'zen5',
|
||||
name: 'Zen Omni',
|
||||
fullName: 'Zen Omni — Multimodal',
|
||||
description: 'Hypermodal model combining text, vision, audio, and code.',
|
||||
@@ -1092,7 +1092,7 @@ export const zenOmni: ZenModel = {
|
||||
pricing: null,
|
||||
features: ['131K context', 'Multimodal'],
|
||||
status: 'available',
|
||||
huggingface: 'https://huggingface.co/zenlm/zen-omni',
|
||||
huggingface: 'https://huggingface.co/zenlm/zen5',
|
||||
github: null,
|
||||
aliases: [],
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user