// DOCUMENTATION
PHANTOM API
OpenAI-compatible. Anonymous payment. Hardware-attested inference.
// CONNECTION
| Base URL | https://phantom.codes/v1 |
| Tor (.onion) | http://jzqvbfmrlt5ye467joz75dg6xdurc6bniozautqlil5b3tbf777zmsid.onion/v1 |
| Auth header | Authorization: Bearer sk-... |
| Get a key | Buy credit at phantom.codes. Pay XMR / BTC / ETH / USDT / USDC / LTC / SOL / DOGE. Receive sk-... once. |
| Compatibility | Drop-in OpenAI replacement. Point any OpenAI SDK at the Base URL above. |
// 01
Quick start
▸ curl
$ curl https://phantom.codes/v1/chat/completions \
-H "Authorization: Bearer YOUR_PHANTOM_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "phantom/qwen3-32b",
"messages": [{"role":"user","content":"Hello"}]
}'
▸ Python
from openai import OpenAI
client = OpenAI(
api_key="YOUR_PHANTOM_KEY",
base_url="https://phantom.codes/v1",
)
r = client.chat.completions.create(
model="phantom/deepseek-v4-flash",
messages=[{"role": "user", "content": "Hello"}],
)
print(r.choices[0].message.content)
▸ Node
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "YOUR_PHANTOM_KEY",
baseURL: "https://phantom.codes/v1",
});
const r = await client.chat.completions.create({
model: "phantom/qwen3.5-122b-a10b",
messages: [{ role: "user", content: "Hello" }],
});
console.log(r.choices[0].message.content);
Need crypto? See /#pricing for accepted coins and how to acquire them.
// 02
Endpoints
| METHOD | PATH | AUTH | PURPOSE |
|---|---|---|---|
POST | /v1/chat/completions | Bearer | OpenAI-compatible chat. Streams. Vision via phantom/qwen3.6-27b using image_url parts. |
POST | /v1/embeddings | Bearer | OpenAI-compatible embeddings. |
POST | /v1/images/generations | Bearer | Image generation. Flat per-image billing. |
GET | /v1/models | none | List models + live pricing (markup included). |
POST | /v1/purchase | none | Body: {"bundle":"small"} OR {"amount_usd":7.5}. |
GET | /v1/purchase/{id}/status | none | Poll payment. Returns plaintext key once on completion. |
GET | /v1/key/balance | Bearer | Remaining credit + expiry. |
POST | /v1/key/rotate | Bearer | Issue new key, carry credit, deactivate old. |
GET | /v1/signature/{id} | Bearer | Per-response signature. Step 2 of attestation. |
GET | /v1/inference-attest | Bearer | TDX + NVIDIA CC report. Step 3 of attestation. |
GET | /health | none | Liveness. |
▸ Check balance
$ curl https://phantom.codes/v1/key/balance \
-H "Authorization: Bearer YOUR_PHANTOM_KEY"
{"balance_usd": 9.7421, "expires_at": "2026-08-25T18:00:00+00:00"}
▸ Rotate key
$ curl -X POST https://phantom.codes/v1/key/rotate \
-H "Authorization: Bearer YOUR_PHANTOM_KEY"
{"api_key": "sk-...", "balance_usd": 9.7421}
Old key dies instantly. Plaintext returned exactly once. Store it.
// 03
Streaming
Pass "stream": true. SSE-compatible. Each chunk arrives as data: {...} followed by a blank line. Final chunk before data: [DONE] carries the usage block used for billing.
$ curl -N https://phantom.codes/v1/chat/completions \
-H "Authorization: Bearer YOUR_PHANTOM_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "phantom/qwen3.5-122b-a10b",
"stream": true,
"messages": [{"role":"user","content":"Hi"}]
}'
data: {"id":"chatcmpl-...","choices":[{"delta":{"content":"He"}}]}
data: {"id":"chatcmpl-...","choices":[{"delta":{"content":"llo"}}]}
data: {"id":"chatcmpl-...","choices":[{"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":8,"completion_tokens":2,"total_tokens":10}}
data: [DONE]
Abort mid-stream: phantom bills for tokens already generated. If upstream sent no bytes, no charge. Intentional aborts before max_tokens finishes are still billed.
// 04
Image generation
OpenAI-compatible. Flat-rate per image. Upstream URLs live ~1 hour. Download them.
$ curl https://phantom.codes/v1/images/generations \
-H "Authorization: Bearer YOUR_PHANTOM_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "stability/stable-diffusion-3-5-large",
"prompt": "A misty cyberpunk alley at dawn",
"n": 1,
"size": "1024x1024",
"quality": "standard"
}'
Parameters: model, prompt (max 4000 chars), n (1-10), size (256/512/1024/1536/2048 square), quality (standard | hd), response_format (url | b64_json). Per-model pricing in /v1/models under image_pricing_usd_user.
// PRIVACY NOTE
All image models are tier PROXY. Gateway runs in TDX but the model itself runs on the vendor's infra. They see your prompt content. Phantom hides only your identity.
// 05
Attestation
Bind each response to verified TEE hardware in three steps.
1. Run any chat completion. Capture response.id.
2. GET /v1/signature/{id}?model=... → returns signature + signing_address.
3. GET /v1/inference-attest?model=...&nonce=$(openssl rand -hex 32)&signing_address=... → returns Intel TDX quote + NVIDIA CC payload.
Verify offline:
- TDX quote →
POST https://phantom.codes/v1/verify/tdx - NVIDIA payload →
POST https://phantom.codes/v1/verify/gpu - Signature → recover pubkey, confirm matches
signing_address
Chain: response → signature → TEE quote.
// 06
Integrations
Dedicated coding-agents page with full setups: /code.html.
Anything that takes base_url + api_key works. Set:
$ export OPENAI_BASE_URL=https://phantom.codes/v1
$ export OPENAI_API_KEY=sk-your-phantom-key
Picks up automatically in: LangChain, LlamaIndex, Vercel AI SDK, Pydantic-AI, llm, mods, aichat, shell-gpt, tgpt, chatblade.
▸ Tool-by-tool config
Aider:
aider --openai-api-base https://phantom.codes/v1 \
--openai-api-key sk-your-phantom-key \
--model openai/phantom/deepseek-v4-flash
OpenHands:
export LLM_API_KEY=sk-your-phantom-key
export LLM_BASE_URL=https://phantom.codes/v1
export LLM_MODEL=openai/phantom/deepseek-v4-flash
opencode · ~/.config/opencode/opencode.json:
{
"provider": {
"phantom": {
"npm": "@ai-sdk/openai-compatible",
"options": {
"baseURL": "https://phantom.codes/v1",
"apiKey": "{env:OPENAI_API_KEY}"
},
"models": {
"phantom/deepseek-v4-flash": {"name": "DeepSeek V4 Flash"}
}
}
}
}
Crush · ./crush.json:
{
"$schema": "https://charm.land/crush.json",
"providers": {
"phantom": {
"type": "openai-compat",
"base_url": "https://phantom.codes/v1",
"api_key": "$OPENAI_API_KEY",
"models": [
{
"id": "phantom/deepseek-v4-flash",
"name": "DeepSeek V4 Flash",
"context_window": 1048576,
"default_max_tokens": 8192
}
]
}
}
}
type must be "openai-compat" — "openai" is reserved for OpenAI itself. Leave models empty and Crush pulls the whole catalog from /v1/models.
Continue.dev · ~/.continue/config.json:
{
"models": [{
"title": "Phantom DeepSeek",
"provider": "openai",
"model": "phantom/deepseek-v4-flash",
"apiKey": "sk-your-phantom-key",
"apiBase": "https://phantom.codes/v1"
}]
}
Cline / Cursor / OpenWebUI: pick "OpenAI Compatible" in settings. Base URL = https://phantom.codes/v1, API Key = your sk-..., Model = any from /v1/models.
// FUNCTION-CALLING
For agents that lean on tools, pick a capable model: phantom/deepseek-v4-pro, phantom/glm-5.2 (strong), phantom/deepseek-v4-flash, phantom/qwen3.5-122b-a10b (decent). OpenAI-shape tools[] works as-is:
{
"model": "phantom/deepseek-v4-flash",
"messages": [{"role": "user", "content": "Weather in Tokyo?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Current weather for a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
}
}],
"tool_choice": "auto"
}
Model returns tool_calls in choices[0].message. Send back a {"role":"tool","tool_call_id":"...","content":"..."} message in the next turn.
// 07
Rate limits
| ENDPOINT | PER-KEY | PER-IP |
|---|---|---|
/v1/chat/completions | 60/min | 300/min |
/v1/embeddings | 60/min | 300/min |
/v1/images/generations | 30/min | 60/min |
/v1/key/rotate | 5/hour | 30/hour |
/v1/purchase | n/a | 10/min |
Hashed in memory. Never logged, never persisted.
// 08
FAQ
▸ I lost my key.
If you have your payment ID, recover anytime at /recover.html. Your key was AES-GCM-encrypted under HKDF(payment_id) at issuance. Phantom holds ciphertext only. No payment ID → no recovery. Same SHA-256 hash of the key still gates auth.
▸ Refunds?
Crypto refunds need a return address we don't store. Buy small first.
▸ Can you see my prompts?
In flight, the proxy holds the prompt in RAM. Not logged, not persisted. Hosting provider could in principle dump memory. See trust boundaries.
▸ How long does payment take?
Hosted crypto checkout. Typical drop: ~2-20 min depending on coin and network. BTC needs ~3 confirms (~30 min). ETH ~30 confirms (~7 min). XMR ~10 confirms (~20 min). USDT/USDC on TRC-20 fastest (~1 min). Key drops on next /v1/purchase/{id}/status poll.
▸ Which coin? No crypto yet?
XMR for max privacy. BTC / ETH / USDT / USDC / LTC / SOL / DOGE if XMR isn't convenient. Phantom hides your identity either way. Non-XMR txs sit on a public ledger forever.
No crypto yet? Three-minute path: install any Monero wallet, or any multi-asset crypto wallet for BTC/ETH/USDT/USDC. Fund via any major exchange or a card-to-crypto DEX. Send to the address Phantom shows at checkout. Done.
▸ Why no /v1/usage history?
Exposing it would let attackers enumerate when a key is active. /v1/key/balance gives the only thing you need: remaining credit.
▸ How does this compare to OpenAI / Anthropic / going direct?
| vendor | account | payment | logs prompts | TEE |
|---|---|---|---|---|
| OpenAI / Anthropic / Google | required + KYC | credit card | yes (30d default) | no |
| TEE provider direct | email account | card / crypto | no | yes |
| Phantom | none | any major crypto | no | yes |
Markup: +30% on TEE-attested models, +50% on closed-weight proxy (Claude/GPT/Gemini). Flat price on every coin. Cost of the no-account, no-card, no-IP layer.
▸ What happens at $0 credit?
HTTP 402 "insufficient credit or expired key". Buy a new bundle or top up.
▸ Contact / abuse?
Encrypted only. PGP key at /pgp.txt (fingerprint 09654A79076956E6042D11946296DEC4E954FC76).