Build on Kyklos.

One OpenAI-compatible API for text, image, and video generation, with a privacy posture you can audit instead of trusting. Everything on this page works with an API key and nothing else.

#Getting started

Kyklos is a drop-in replacement for the OpenAI API. If you have working OpenAI code, changing the base URL is the whole migration.

# base URL: everything lives under /v1 /v1

Three steps: create an account, generate an API key under API keys, load credits under Billing. Billing is usage-based: credits in, generations out, one auditable ledger. No monthly minimum.

# first request curl /v1/chat/completions \ -H "Authorization: Bearer kyk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "model": "llama-3.3-70b", "messages": [{"role": "user", "content": "hello"}] }'

#Authentication

A standard bearer header. Keys start with kyk_, are shown once at creation, and are stored server-side only as a hash. Revoke any key instantly from the console.

Authorization: Bearer kyk_your_api_key

Console logins use a separate session system that can never call the inference API. A leaked session token cannot spend your credits, and a leaked API key cannot change your account.

#Chat completions

POST /v1/chat/completions is the exact OpenAI shape, including streaming with "stream": true. The official OpenAI SDKs work unchanged:

# Python from openai import OpenAI client = OpenAI( base_url="/v1", api_key="kyk_your_api_key", ) r = client.chat.completions.create( model="llama-3.3-70b", messages=[{"role": "user", "content": "hello"}], ) print(r.choices[0].message.content)
// Node import OpenAI from "openai"; const client = new OpenAI({ baseURL: "/v1", apiKey: "kyk_your_api_key", }); const r = await client.chat.completions.create({ model: "llama-3.3-70b", messages: [{ role: "user", content: "hello" }], }); console.log(r.choices[0].message.content);

Text is billed per token at each model's listed input/output price. Every response includes exact token counts in usage, and the response headers carry your request id and remaining rate limit.

#Image generation

POST /v1/images/generations is OpenAI-shaped, so client.images.generate() works as-is. Billing is flat per image at the catalog price: no token meters, no surprises.

curl /v1/images/generations \ -H "Authorization: Bearer kyk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "model": "flux-2-dev", "prompt": "a lighthouse at dusk, film grain", "n": 1, "size": "1024x1024" }'
FieldTypeNotes
modelstringAny model with modality image in the catalog.
promptstringUp to 20,000 characters.
nint1–4 images. You are charged per image produced.
sizestringOptional, e.g. 1024x1024. Model default when omitted.

#Video generation

POST /v1/videos/generations: prompt in, video URL out, one flat price per clip. This endpoint is Kyklos-specific: there is no industry-standard video API yet, so we kept it as small as possible.

curl /v1/videos/generations \ -H "Authorization: Bearer kyk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "model": "fastwan-qad-fp8-1.3b", "prompt": "waves rolling onto a beach at golden hour" }' # response { "data": [{ "url": "https://…" }], "kyklos": { "cost_micro_usd": 120000 } }
Timeouts are honest Generation runs synchronously with a 110-second ceiling. A model that can't answer in time returns upstream_timeout and nothing is charged. You only ever pay for a URL you received.

#Models & pricing

The catalog is a public endpoint. Anyone can audit every price without an account:

curl /v1/models

Prices are per million tokens for text, per image for image models, and per clip for video models; the response says which (input_usd_per_mtok / usd_per_image / usd_per_video). The live catalog is browsable with search and filters at /app#models.

Models never disappear silently: a removal gets a published deprecate_on date in the API at least 30 days ahead.

#Errors

Every error is { "error": { "code", "type", "request_id" } }: a code and a request id, never an echo of your request.

HTTPCodeMeaning
400bad_requestMalformed body or parameters.
401unauthorizedMissing, wrong, or revoked API key.
402insufficient_creditsBalance too low. Nothing was charged.
404model_not_foundNo such model in the catalog.
410model_retiredModel passed its published removal date.
429rate_limitedOver your plan's requests/minute. Keyed to your account, never your IP.
503no_route_availableModel exists but nothing healthy can serve it right now. Retryable.
502 / 504upstream_error / upstream_timeoutThe serving side failed or timed out. Nothing charged.

#Paying with USDC

Credits can be bought by card, or with USDC on Arc, Circle's USDC-native chain (chain id 5042). No card, no billing account, no extra token for gas: fees on Arc are paid in USDC and transfers settle in under a second.

The flow, from the console's Billing page:

  1. Pick an amount. The console opens a deposit and shows our treasury address plus an exact amount: your amount plus a few random millionths of a dollar.
  2. Send exactly that amount of USDC on Arc, from any wallet or exchange that supports the network.
  3. Our watcher sees the transfer and credits your balance, usually within ten seconds. The transaction hash lands in your ledger; the receipt is the chain itself.

The unique amount is the matching mechanism: it attributes a transfer on a public chain to your account without per-user deposit addresses or any personal information. A deposit window stays open for an hour; if it expires unused, nothing is lost.

You can also sign in with a wallet instead of an email: the console asks your wallet to sign a one-time message (free, no transaction), and the signature is the login. An account created this way has no email and no password at all.

Honesty note: Arc is a public ledger. Amounts, addresses, and timing of your deposits are visible on-chain to anyone (pseudonymous, not anonymous). If your threat model includes payment metadata, a card via Stripe reveals it to fewer observers; we'll adopt Arc's confidential transfers when they go live. What you buy stays off every ledger either way: usage is metered as token counts, never content.

Providers are paid the same way: set a payout address on the Provider page and revenue share arrives as USDC on Arc, each payout carrying a transaction hash you can verify on the explorer.

#Privacy architecture

Privacy at Kyklos is enforced by what the system cannot store, not by a policy PDF. The database schema has no columns for prompts, completions, IP addresses, user agents, or fingerprints; usage rows carry token counts and cost against an account id, nothing else. Rate limiting is keyed to your account, never your IP.

TierStatusWhat it means
anonymous live Private by policy. Requests are rebuilt field-by-field before routing, so tracking headers and metadata never reach a provider. No prompt logging anywhere in the path.
tee live Served only by nodes that prove, with an Intel TDX quote verified against a pinned Intel root, that they boot the published inference image on confidential-computing hardware. Every response names the node and measurement that served it. Live today on an NVIDIA H200 in confidential-compute mode.
e2ee hardware pilot Your client seals the prompt to one attested node's X25519 key before it leaves your machine. The gateway relays ciphertext it cannot open and bills from the node's signed receipt.
Straight answer on the attested tiers The tee tier is live: real Intel TDX hardware, quotes verified against a pinned Intel root, measurements whitelisted, fail-closed routing. What it proves: the machine booted exactly the published inference image, which contains no logging of request content. What it does not prove: that Intel, NVIDIA, or the metadata layer (billing counters exist) are beyond trust. No honest system claims "nobody can read it". The e2ee tier (client-side sealing) is built but not yet live.

Attestation discovery is already public API: GET /v1/models/:slug/attestation returns the ready nodes and sealing keys for any attested model, so clients can verify before sending a byte.

#Run a provider node

You can put your own GPU on the network. A node is not vetted by a form; it is admitted by hardware evidence. On boot, the node agent generates its keys inside the enclave, asks the gateway for a one-shot challenge, and has the CPU sign a TDX quote binding those keys to that challenge. The gateway verifies the quote against a pinned Intel root and an approved image measurement. Pass and it serves traffic; fail and it does not exist.

The flow, end to end:

1. Create an account and a provider key. Any API key works; the console has a Provider page that creates one and generates the full config for you. The key ties the node to your account so it appears on your dashboard with its served usage.

2. Run the node on your machine. Requirements today: an Intel TDX host with a confidential-compute GPU (validated on an NVIDIA H200 in a Phala dstack CVM). One compose file runs the inference engine and the node agent:

# docker-compose.yml: reference provider node (TDX CVM, 1x H200) services: vllm: image: vllm/vllm-openai:latest restart: unless-stopped runtime: nvidia environment: NVIDIA_VISIBLE_DEVICES: all # required under NVIDIA Confidential Computing mode VLLM_USE_V2_MODEL_RUNNER: "0" command: > --model Qwen/Qwen3-32B --served-model-name qwen3-32b --max-model-len 16384 --gpu-memory-utilization 0.92 volumes: [hf-cache:/root/.cache/huggingface] shm_size: "16gb" kyklos-node: image: node:22-slim restart: unless-stopped command: ["npx", "-y", "kyklos-node@0.1.5", "run"] environment: KYKLOS_GATEWAY_URL: "" KYKLOS_ENCLAVE_BACKEND: "vllm" VLLM_URL: "http://vllm:8000" # our public key — the enclave refuses traffic not signed by the gateway KYKLOS_GATEWAY_PUBLIC_KEY: "MCowBQYDK2VwAyEALBJzwxxksYwzgP3ZAOY0FMQxswA8JFUjMZt8_uCaN3c" KYKLOS_PROVIDER_KEY: "kyk_your_provider_key" KYKLOS_NODE_ENDPOINT: "https://your-public-endpoint:8899" KYKLOS_NODE_MODELS: "qwen3-32b-tee" KYKLOS_NODE_LABEL: "my-h200-1" ports: ["8899:8899"] volumes: [/var/run/dstack.sock:/var/run/dstack.sock] depends_on: [vllm] volumes: hf-cache:

3. The machine proves itself. No manual step. The agent logs the quote collection and the enrollment result; the gateway's decision is final and fail-closed. Because the measurement covers the whole booted image, a modified image (say, one that logs prompts) produces a different measurement and is refused.

4. Serve and get paid. The node appears on your console Provider page with status, attestation, and 30-day served usage. Heartbeats are signed by the attested key; a node that stops heartbeating stops receiving traffic within minutes.

Pilot honesty Enrollment is currently limited to image measurements we have published (the reference compose above). Different hardware or a custom image needs its measurement reviewed first; contact us. Served usage is metered per node from day one; automated payouts are not built yet, so pilot revenue share is settled manually.