Documentation

Everything you need to build.

Silicon Network speaks the OpenAI wire format. If you already call an OpenAI-compatible API, you are a base URL away from running on a distributed network of open models.

Quickstart

Create an API key in the dashboard, then point your client at the Silicon Network base URL.

quickstart.py
from openai import OpenAI

client = OpenAI(
    base_url="https://api.fabriqnetwork.com/v1",
    api_key="fbq_live_...",
)

resp = client.chat.completions.create(
    model="llama-3.2-3b",
    messages=[{"role": "user", "content": "Say hello in one line."}],
)
print(resp.choices[0].message.content)

Or with curl:

silicon - zsh
curl https://api.fabriqnetwork.com/v1/chat/completions \
  -H "Authorization: Bearer fbq_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "llama-3.2-3b",
    "messages": [{"role": "user", "content": "Hello"}]
  }'

Authentication

Every request carries an API key as a bearer token. Keys are created in the dashboard and shown once at creation, so store them somewhere safe. Use a live key in production and a test key while you build. Revoke a key any time and it stops working immediately.

Authorization: Bearer fbq_live_xxxxxxxxxxxxxxxx

Chat completions

POST /v1/chat/completions takes the same shape you already know. Set "stream": true for server-sent events, and pass tools and image content on models that support them.

response.json
{
  "id": "chatcmpl_...",
  "object": "chat.completion",
  "model": "llama-3.2-3b",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "Hello." },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 9, "completion_tokens": 2, "total_tokens": 11 }
}

Parameters that work

messages, stream, stream_options, max_tokens and max_completion_tokens, temperature, top_p, top_k, min_p, stop, seed, frequency_penalty, presence_penalty, repetition_penalty, logprobs, top_logprobs, tools, and enable_thinking (chain-of-thought on thinking models, returned separately as reasoning_content). An explicitly requested output length above 8,192 tokens is clamped down to 8,192 so a single call cannot run up an unbounded charge. Streaming requests get a final chunk carrying usage.

Parameters that do not

response_format (there is no JSON mode and no constrained decoding), tool_choice, parallel_tool_calls, logit_bias, and n (you always get one choice). Nothing below the gateway reads them, so rather than hand you prose where you asked for JSON with no error, a request that depends on one is refused with 400 naming the parameter. Sending the value that matches what already happens is fine and is not refused: n: 1, tool_choice: "auto", response_format: { "type": "text" }, an empty logit_bias, parallel_tool_calls: true. Frameworks send those explicitly and they describe the behaviour you get.

Logprobs

Set logprobs: true and every generated token comes back with its log-probability and the most likely alternatives at that position. It works on the public endpoint, streaming and non-streaming, on every text model. Useful for classification, confidence thresholds, and eval harnesses that score tokens rather than parse text.

logprobs.py
from openai import OpenAI

client = OpenAI(
    base_url="https://api.fabriqnetwork.com/v1",
    api_key="fbq_live_...",
)

resp = client.chat.completions.create(
    model="llama-3.2-3b",
    messages=[{"role": "user", "content": "Answer with one word: is 97 prime?"}],
    max_tokens=1,
    logprobs=True,
    top_logprobs=5,
)

first = resp.choices[0].logprobs.content[0]
print(first.token, first.logprob)
for alt in first.top_logprobs:
    print(alt.token, alt.logprob)

top_logprobs is honoured up to 20; ask for more and you get 20. Omit it while logprobs is true and you get five alternatives per token. Each entry carries token and logprob, and every alternative also carries its UTF-8 bytes. When you stream, each chunk carries the logprobs for the token in that chunk.

Vision

qwen3-vl-4b accepts images in the standard OpenAI content-parts shape. Pass a data URL, or an https:// URL that the serving node can reach; the node fetches the URL itself, so a link only your machine can see will fail. Several images in one message are fine.

vision.py
import base64
from openai import OpenAI

client = OpenAI(
    base_url="https://api.fabriqnetwork.com/v1",
    api_key="fbq_live_...",
)

with open("chart.png", "rb") as fh:
    data_url = "data:image/png;base64," + base64.b64encode(fh.read()).decode()

resp = client.chat.completions.create(
    model="qwen3-vl-4b",
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "What does this chart show?"},
                {"type": "image_url", "image_url": {"url": data_url}},
            ],
        }
    ],
)
print(resp.choices[0].message.content)

Wire formats

Same models, four request shapes: OpenAI Chat Completions at /v1/chat/completions, OpenAI Responses at /v1/responses, Anthropic Messages at /v1/messages, and Ollama at /ollama/api/chat and /ollama/api/generate. The bodies are the ones those APIs define; the one thing that never changes is auth: Silicon Network reads Authorization: Bearer and nothing else, so an SDK that authenticates with x-api-key needs that header set explicitly.

silicon - zsh
# Anthropic Messages shape, Silicon Network model, Silicon Network key
curl https://api.fabriqnetwork.com/v1/messages \
  -H "Authorization: Bearer fbq_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "llama-3.2-3b",
    "max_tokens": 256,
    "messages": [{"role": "user", "content": "Hello"}]
  }'

For Ollama-native clients the base URL is https://api.fabriqnetwork.com/ollama. Discovery (the root probe, /api/version, /api/tags, /api/ps) needs no key and lists the models loaded right now, so a client's model picker only ever shows ids that serve. Chat still needs your key, so use a client that lets you set an Authorization header.

There is no legacy /v1/completions, no /v1/embeddings, and no image endpoint on the managed API. A client that needs one of those will not work by swapping the base URL, so pick a chat path.

Framework recipes

Every one of these is a base URL swap. They all speak /v1/chat/completions, which is what Silicon Network serves.

OpenAI SDK (Node)

quickstart.ts
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.fabriqnetwork.com/v1",
  apiKey: process.env.SILICON_API_KEY,
});

const res = await client.chat.completions.create({
  model: "llama-3.2-3b",
  messages: [{ role: "user", content: "Hello" }],
});
console.log(res.choices[0].message.content);

LangChain

langchain.py
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="llama-3.2-3b",
    base_url="https://api.fabriqnetwork.com/v1",
    api_key="fbq_live_...",
)
print(llm.invoke("Hello").content)

LlamaIndex

llamaindex.py
from llama_index.llms.openai_like import OpenAILike

# is_chat_model=True is required: without it the client calls the legacy
# /v1/completions route, which Silicon Network does not serve.
llm = OpenAILike(
    model="llama-3.2-3b",
    api_base="https://api.fabriqnetwork.com/v1",
    api_key="fbq_live_...",
    is_chat_model=True,
)
print(llm.complete("Hello"))

Vercel AI SDK

ai-sdk.ts
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { generateText } from "ai";

const fabriq = createOpenAICompatible({
  name: "fabriq",
  baseURL: "https://api.fabriqnetwork.com/v1",
  apiKey: process.env.SILICON_API_KEY,
});

const { text } = await generateText({
  model: fabriq("llama-3.2-3b"),
  prompt: "Hello",
});
console.log(text);

If you would rather use @ai-sdk/openai, take the chat model explicitly (openai.chat("llama-3.2-3b")) because that provider's default model call targets OpenAI's Responses format.

Continue / Cursor

config.yaml
# Continue: ~/.continue/config.yaml
models:
  - name: Silicon Network
    provider: openai
    model: llama-3.2-3b
    apiBase: https://api.fabriqnetwork.com/v1
    apiKey: fbq_live_...

Cursor: Settings → Models, add your Silicon Network key, override the OpenAI base URL with https://api.fabriqnetwork.com/v1, and add a model id from the table below by hand.

Aider

silicon - zsh
export OPENAI_API_BASE=https://api.fabriqnetwork.com/v1
export OPENAI_API_KEY=fbq_live_...
aider --model openai/llama-3.2-3b

Open WebUI

Settings → Connections → add an OpenAI API connection with the URL https://api.fabriqnetwork.com/v1 and your Silicon Network key. Open WebUI fills its model picker from GET /v1/models, so it lists exactly the models loaded right now. An Ollama connection works too: point it at https://api.fabriqnetwork.com/ollama, as in the previous section.

Models

Pass the model id in the model field. Every id below resolves at the gateway, but only a few are loaded into memory at any one time: the network is machines, not a warm datacenter, and loading a large model takes minutes. Ask for one that is not loaded and you get a 404 that names what is being served.

GET /v1/models is the only live answer to "what can I call right now"; an id it returns always serves. Add ?all=true for the full catalog a node could load.

Models
llama-3.2-1bLlamaText
llama-3.2-3bLlamaText
llama-3.1-8bLlamaText
llama-3.1-70bLlamaText
llama-3.3-70bLlamaText
deepseek-v3.1DeepSeekText
deepseek-v3.2DeepSeekText
qwen3-235bQwenText
qwen3-vl-4bQwenVision
kimi-k2-thinkingKimiReasoning
glm-4.7GLMText
gpt-ossOpenAI OSSText
gpt-oss-20bOpenAI OSSText
gpt-oss-120bOpenAI OSSText

Run a node

A node runs the Silicon Network engine on Apple Silicon or a GPU host. It loads models, shards large ones across peers, and registers with the network. Your node accrues credit for the compute it serves (operator payouts enable as verification rolls out).

silicon - zsh
# Apple Silicon, from the engine source
uv sync
uv run fabriq

Running the engine needs real hardware and is rolling out to operators. Want in early? See the litepaper for how the network fits together.

Pricing

Pricing is usage-based. You pay per token for the model you actually call, metered from real requests. There are no seats and no idle clusters to rent, so the meter only runs when you do. Node operators accrue credit for the compute they serve on the same ledger (payouts enable as verification rolls out).

Per-model rates are published as models come online.

Architecture

Three parts: the engine on each node, the gateway that authenticates and routes requests, and the control plane that holds accounts, keys, usage, and node state. The full design is in the litepaper.

Privacy

Requests run on an operator's machine, so that node necessarily processes your prompt, and today it also retains it. Here is exactly who stores what.

The serving node stores prompts and completions. The engine appends every cluster event to a log on the operator's disk, and those events include the messages you sent and every token generated back. The engine also serves that whole log over its own API (GET /events on port 52415), which is open unless the operator sets a node key. Assume anything you send to a node is readable on that machine until the log rotates away.

The control plane stores no content. A served request records org, key, model id, token counts, latency, status, region, and a timestamp. There is no column for prompt or completion text.

The gateway does not persist bodies. It holds the request in memory to check your key, resolve the model id, and meter the result. Two things can widen that and are off unless we turn them on: content moderation, which sends prompt text to a moderation service before serving, and verification sampling, which re-runs a sampled request on our own engine to score the node that served it.

Only operators we have approved can register a node into the routable pool.

X-Silicon Network-No-Retention

Send X-Silicon Network-No-Retention: true and the gateway skips verification sampling for that request, so your prompt is never buffered and re-sent to a second engine, and forwards the header to the serving node. The node does not act on it yet: the engine has no handler for the header, so it still writes the prompt and the completion to its event log. Treat the header as enforced at the gateway and ignored at the node until we say otherwise. For confidentiality that does not depend on someone else's machine, run your own node; a local node is the whole data path.