LLM Publisher Guide
Host your AI model and publish it as a Void App.
Publish an AI model as a Void App. One model per app, billed per token. Your server just needs to speak OpenAI-compatible POST /v1/chat/completions.
Quick start
Use any OpenAI-compatible server — vLLM, Ollama, or similar:
# Ollama
ollama pull smollm2:135m
curl http://localhost:11434/v1/chat/completions -H "Content-Type: application/json" \
-d '{"model":"smollm2:135m","messages":[{"role":"user","content":"hi"}],"stream":false}'
# vLLM
vllm serve HuggingFaceTB/SmolLM2-135M-Instruct --host 0.0.0.0 --port 9000 --served-model-name smollm2:135m
curl http://localhost:9000/v1/chat/completions -H "Content-Type: application/json" \
-d '{"model":"smollm2:135m","messages":[{"role":"user","content":"hi"}]}'Both return:
{"choices":[{"message":{"content":"Hello"}}],"usage":{"prompt_tokens":10,"completion_tokens":5,"total_tokens":15}}Publish (Voidnet Console)
- Verify a domain: Console → Domains → follow the verification steps.
- Connect payouts: Console → Payments → connect and activate your Stripe account. Every paid tier requires an active
stripe_transferscapability — publishing a paid tier without it is rejected, because earnings have no payout destination otherwise. - Go to Publish Apps → LLM and fill in:
- App Name — unique per publisher
a-z, 0-9, -, _(3–50 chars) - Model — the exact model ID your server serves (for example
HuggingFaceTB/SmolLM-135M-Instruct) - Server URL —
https://your-host/v1(must end with/v1; the gateway will call/chat/completionson it)
- App Name — unique per publisher
- Click Create Draft — you will receive a publisher API key. The gateway uses it to authenticate to your server, so your server should accept any
Authorization: Bearer <token>header. - In the overview click Publish to make your app live in the Marketplace.
You can configure free tiers, paid tiers, or both, with token limits and pricing during publishing.
Your server contract
Your server must expose a single endpoint:
POST {serverUrl}/v1/chat/completions
GET {serverUrl}/v1/models — expose your OpenAI models listing (vLLM and Ollama serve it natively). The gateway proxies it to buyers at GET /v1-beta/llm/{username}/{appname}/*models*, non-billable.**
Request — the gateway forwards the buyer's JSON verbatim:
{"model":"your-model-id","messages":[{"role":"user","content":"hi"}],"temperature":0.7,"max_tokens":64,"stream":false}model and messages are required. Multimodal content (image_url, audio, video) is rejected before reaching your server — TEXT only.
Streaming — supported, with one hard rule: stream:true requests reach your server as SSE. Your stream must end with a final data chunk carrying usage (OpenAI stream_options.include_usage shape) before [DONE]. The gateway injects stream_options.include_usage:true into buyer requests that lack it, but if your server drops it and never sends usage, the call fails 502 instead of going unbilled. vLLM always sends usage; Ollama needs the option.
Response — you must return valid OpenAI shape:
{
"id": "chatcmpl-...",
"object": "chat.completion",
"created": 123,
"model": "your-model-id",
"choices": [{"index":0,"message":{"role":"assistant","content":"Hello"},"finish_reason":"stop"}],
"usage": {"prompt_tokens":10,"completion_tokens":5,"total_tokens":15}
}total_tokens must be present and greater than zero — it is the billing input. Return 4xx/5xx with {"error":{"message":"..."}} on failure; the gateway maps your status range to publisher_client_error/publisher_server_error and preserves your body.
Auth: Accept any Authorization: Bearer <token> header.
Limits: Response must be under 16MB.
Tiers and billing
- Apps are metered per token (
total_tokensfrom your response). Your free and paid tier limits are token limits. - Paid LLM apps price per 1M tokens. Each buyer call deducts
total_tokens / 1M × pricefrom the buyer's wallet and credits your earnings in the same atomic step. Fixed-price tiers deduct the full price at purchase instead. - The platform fee defaults to 20% (
floor(gross × pct / 100)); founding publishers hold 85/15 per the Publisher Agreement. - Buyers on a free tier who upgrade to paid are moved automatically: the free purchase is revoked when the paid grant completes. One active tier per buyer per app.
Payouts
Wallet earnings accumulate in the platform ledger and pay out weekly on Fridays, one Stripe Transfer per publisher per week covering all your apps and sales, after a 7-day settlement hold. Track earnings, per-app breakdowns, and payout history (week, sales count, transfer id, status) in Console → Payments. Legacy Stripe-checkout earnings split automatically at charge time and never enter this ledger. There are no buyer-facing refunds; disputed charges are handled through Stripe.
Test via gateway
After your app is published and a buyer has purchased it (free or paid):
curl https://api.openvoidnet.com/v1-beta/llm/<publisher>/<app> \
-H "Authorization: Bearer vnb-sk-..." \
-H "Content-Type: application/json" \
-d '{"model":"your-model-id","messages":[{"role":"user","content":"hello"}]}'Or with the OpenAI SDK — just change the base_url:
from openai import OpenAI
client = OpenAI(base_url="https://api.openvoidnet.com/v1-beta/llm/<publisher>/<app>", api_key="vnb-sk-...")
response = client.chat.completions.create(model="your-model-id", messages=[{"role":"user","content":"hi"}])
print(response.choices[0].message.content, response.usage.total_tokens)Streaming test — expect SSE chunks plus a final usage chunk:
curl https://api.openvoidnet.com/v1-beta/llm/<publisher>/<app> \
-H "Authorization: Bearer vnb-sk-..." \
-H "Content-Type: application/json" \
-d '{"model":"your-model-id","messages":[{"role":"user","content":"hello"}],"stream":true}'Limits
TEXT only, single model per app, no embeddings. total_tokens present and greater than zero on every success. Full interactive reference: LLM API. See Buyer Guide (LLM).