mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-30 14:58:08 +00:00
The about sections, the analytics page and its demo's labels, the affiliate and agents pages, the API page and the account forwards wrap their copy. Copy handed to a shared component from a client page is translated at the call site; arrays written outside a component are marked with phrase(). Commands and figures inside a sentence are values, the mock dashboard's sample rows stay as they are, and the forward arrows mirror under dir="rtl".
155 lines
6.0 KiB
TypeScript
155 lines
6.0 KiB
TypeScript
'use client'
|
||
|
||
import { Code2, MessageSquare, Boxes, Binary, Waypoints, ShieldCheck } from 'lucide-react'
|
||
import { Page, PageHero, Section, CardGrid, Prose, Cta, type CardItem } from '@/components/marketing/page-kit'
|
||
import { AgentPrompt } from '@/components/product/AgentPrompt'
|
||
import { Related } from '@/components/product/Related'
|
||
import { product } from '@/lib/product'
|
||
import { KEYS } from '@/components/home/nav-data'
|
||
import { phrase } from '@hanzo/i18n'
|
||
import { useI18n } from '@hanzo/i18n/react'
|
||
|
||
/** What the agent prompt and the closing block read, off the one table that
|
||
* holds a product's name, route, audited command and docs page. */
|
||
const PRODUCT = product('api')
|
||
|
||
const ENDPOINTS: CardItem[] = [
|
||
{
|
||
title: '/v1/chat/completions',
|
||
meta: 'POST',
|
||
description: phrase(
|
||
'A completion from any model your organization can reach, streamed or buffered. Model ids come from the catalog, so the list is a request rather than a page in the docs.',
|
||
),
|
||
},
|
||
{
|
||
title: '/v1/models',
|
||
meta: 'GET',
|
||
description: phrase(
|
||
'What your organization may call right now — the models we serve plus any provider account you have connected, with their identifiers.',
|
||
),
|
||
},
|
||
{
|
||
title: '/v1/embeddings',
|
||
meta: 'POST',
|
||
description: phrase('Vectors for search, retrieval and clustering, from the same key and the same bill as generation.'),
|
||
},
|
||
{
|
||
title: '/v1/agents',
|
||
meta: 'GET · POST',
|
||
description: phrase(
|
||
'Define an agent once, run it by reference, and read its runs afterwards. The definition lives here, so everything that runs it runs the same one.',
|
||
),
|
||
},
|
||
{
|
||
title: '/v1/billing/balance · /v1/billing/usage',
|
||
meta: 'GET',
|
||
description: phrase(
|
||
'What is left, and what was spent. Usage is recorded per call and attributed to the organization on the token, so a bill can be traced back to the request that caused it.',
|
||
),
|
||
},
|
||
{
|
||
title: '/v1/tools',
|
||
meta: 'GET',
|
||
description: phrase(
|
||
'The tools your organization can call. An agent picks from this list, and so can you — it is the same catalog either way.',
|
||
),
|
||
},
|
||
]
|
||
|
||
const CONCEPTS: CardItem[] = [
|
||
{
|
||
icon: ShieldCheck,
|
||
title: phrase('One key, one bill'),
|
||
description: phrase(
|
||
'A single key authenticates every endpoint, and usage meters to the organization it belongs to. Spend is attributed in one place instead of once per service.',
|
||
),
|
||
},
|
||
{
|
||
icon: Waypoints,
|
||
title: phrase('Identity is the gateway’s to state'),
|
||
description: phrase(
|
||
'Every request passes a gateway that throws away the identity headers a client sent and writes them again from the verified token. Nothing downstream has to wonder whether an org id came from a token or from a curl flag.',
|
||
),
|
||
},
|
||
{
|
||
icon: Binary,
|
||
title: phrase('Generated, not hand-written'),
|
||
description: phrase(
|
||
'The clients come from the OpenAPI document this API serves, and their method names are its operation ids. A client is checkable against a release rather than against somebody’s memory.',
|
||
),
|
||
},
|
||
]
|
||
|
||
export default function ApiPage() {
|
||
const { t } = useI18n()
|
||
return (
|
||
<Page>
|
||
<PageHero
|
||
eyebrow="API"
|
||
icon={Code2}
|
||
title={t('One API for models, agents and tools')}
|
||
lede={t('Every Hanzo capability answers under one base URL, behind one key. There is no per-service host to look up and no second version to migrate to later.')}
|
||
>
|
||
<Cta href={KEYS}>{t('Get API key')}</Cta>
|
||
<Cta href="https://docs.hanzo.ai/docs/openapi/">{t('OpenAPI Reference ↗')}</Cta>
|
||
</PageHero>
|
||
|
||
{PRODUCT && <AgentPrompt product={PRODUCT} />}
|
||
|
||
<Section title={t('Base URL')}>
|
||
<Prose>
|
||
<p>
|
||
<strong>https://api.hanzo.ai/v1</strong>
|
||
</p>
|
||
<p>
|
||
{t('Authenticate with a bearer token: {header}. Keys are created and revoked in the {console}, and revoking one there is what stops it working.', {
|
||
header: <strong>Authorization: Bearer <your key></strong>,
|
||
console: <a href={KEYS}>{t('console')}</a>,
|
||
})}
|
||
</p>
|
||
<p>
|
||
{t('Every route lives under {v1}, and every service answers on the same host — there is no second base URL to configure and no v2 waiting to break the first one. Rate limits are applied per caller and across the edge as a whole; a rejected request comes back as a {status} with a {retry} rather than a dropped connection.', {
|
||
v1: <strong>/v1</strong>,
|
||
status: <strong>429</strong>,
|
||
retry: <strong>Retry-After</strong>,
|
||
})}
|
||
</p>
|
||
</Prose>
|
||
</Section>
|
||
|
||
<Section title={t('Core endpoints')} lede={t('A few of the ones people reach for first. Every parameter and error shape is in the reference.')}>
|
||
{/* An endpoint's path and method stay as written; what it does is read in the reader's language. */}
|
||
<CardGrid items={ENDPOINTS.map((e) => ({ ...e, description: t(e.description) }))} columns={2} />
|
||
</Section>
|
||
|
||
<Section title={t('How it fits together')}>
|
||
<CardGrid items={CONCEPTS.map((c) => ({ ...c, title: t(c.title), description: t(c.description) }))} columns={3} />
|
||
</Section>
|
||
|
||
<Section title={t('Next')}>
|
||
<CardGrid
|
||
columns={2}
|
||
items={[
|
||
{
|
||
icon: MessageSquare,
|
||
title: t('API reference'),
|
||
description: t('Every endpoint, parameter and response shape.'),
|
||
// `/docs/api` answers 200 as a `Moved` stub — noindex, meta
|
||
// refresh — so the link goes where its canonical points.
|
||
href: 'https://docs.hanzo.ai/docs/openapi/',
|
||
},
|
||
{
|
||
icon: Boxes,
|
||
title: t('Getting started'),
|
||
description: t('An empty project to a first call that works.'),
|
||
href: 'https://docs.hanzo.ai/docs/quickstart',
|
||
},
|
||
]}
|
||
/>
|
||
</Section>
|
||
|
||
{PRODUCT && <Related product={PRODUCT} />}
|
||
</Page>
|
||
)
|
||
}
|