Files
zeekay 0c84acc0d8 about, analytics, affiliate, agents, api: the words go through @hanzo/i18n
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".
2026-10-22 18:13:04 -07:00

155 lines
6.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'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 &lt;your key&gt;</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>
)
}