# Transcribe audio files with Darkbloom's API
Source: https://docs.darkbloom.dev/api/audio-transcription
POST /v1/audio/transcriptions transcribes audio to text using the OpenAI-compatible Whisper endpoint, served by attested Apple Silicon providers.
`POST /v1/audio/transcriptions` transcribes an audio file to text. The endpoint is compatible with the OpenAI Whisper API — you submit audio as a multipart form upload and receive a JSON response containing the transcript. Providers serving transcription run Whisper on Apple Silicon via the same hardened inference process used for text models.
## Request
The request must be sent as `multipart/form-data`.
The audio file to transcribe. Common formats include MP3, MP4, MPEG, MPGA, M4A, WAV, and WEBM.
The transcription model to use. Pass `whisper-1` to use the default Whisper model available on the network.
## Example
```bash curl theme={null}
curl https://api.darkbloom.dev/v1/audio/transcriptions \
-H "Authorization: Bearer eigeninference-your-key-here" \
-F "file=@recording.mp3" \
-F "model=whisper-1"
```
## Response
```json theme={null}
{
"text": "The transcript of the audio file appears here as a single string."
}
```
The transcribed text from the audio file.
Transcription requests are routed to providers that have a Whisper model loaded. If no transcription providers are currently online, the request will queue and retry up to three times before returning an error.
# Authenticate requests to the Darkbloom API
Source: https://docs.darkbloom.dev/api/authentication
Create and manage API keys for the Darkbloom inference API. Keys start with eigeninference- and are passed as Authorization: Bearer tokens on every request.
Every request to the Darkbloom API requires an API key. You pass the key in the `Authorization` header as a Bearer token. Keys are prefixed with `eigeninference-` so they are easy to identify and rotate if they appear in logs or source control.
## Getting an API key
Create an account at [darkbloom.dev](https://darkbloom.dev). Darkbloom uses Privy for authentication — you can sign in with email or a connected wallet.
Navigate to **Settings → API Keys** in the console dashboard.
Click **New API Key**. Copy the key immediately — it is shown only once. The key will look like:
```
eigeninference-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```
API calls are metered. Add credits from the **Billing** section before sending inference requests. Requests return `403` when your balance reaches zero.
Store your API key in an environment variable or secrets manager. Never commit it to source control or expose it in client-side code.
## Sending the key
Include the key in the `Authorization` header on every request:
```
Authorization: Bearer eigeninference-your-key-here
```
```bash curl theme={null}
curl https://api.darkbloom.dev/v1/models \
-H "Authorization: Bearer eigeninference-your-key-here"
```
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
base_url="https://api.darkbloom.dev/v1",
api_key="eigeninference-your-key-here",
)
```
```javascript Node.js theme={null}
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.darkbloom.dev/v1",
apiKey: "eigeninference-your-key-here",
});
```
Use the `OPENAI_API_KEY` and `OPENAI_BASE_URL` environment variables when working with the OpenAI SDK. Many tools and scripts already read from these variables automatically.
```bash theme={null}
export OPENAI_BASE_URL="https://api.darkbloom.dev/v1"
export OPENAI_API_KEY="eigeninference-your-key-here"
```
## Key management
You can create and revoke keys programmatically. Key creation and revocation require an active Privy session (interactive login) — API keys cannot be used to create or revoke other API keys.
### Create a key
```bash theme={null}
POST /v1/auth/keys
```
### Revoke a key
```bash theme={null}
DELETE /v1/auth/keys
```
Pass the key you want to revoke in the request body as `{"key": "eigeninference-..."}`.
## Authentication errors
The `Authorization` header is missing or the key is invalid. Check that you are passing the full key value including the `eigeninference-` prefix.
Your account has insufficient balance to complete the request. Add credits in the console under **Billing → Add Credits**.
# Send chat completions with the Darkbloom API
Source: https://docs.darkbloom.dev/api/chat-completions
Use POST /v1/chat/completions to run multi-turn conversations on Darkbloom. Fully OpenAI-compatible, with streaming, system prompts, and trust headers.
`POST /v1/chat/completions` is the primary inference endpoint. It is fully compatible with the OpenAI Chat Completions API, so you can point any OpenAI SDK at Darkbloom by changing the base URL — no other code changes required. The endpoint supports both streaming (server-sent events) and non-streaming responses.
## Request parameters
The model ID to use for this request. See [Models](/api/models) for the full list of available IDs.
The conversation history as an array of message objects. Each message has a `role` (`system`, `user`, or `assistant`) and a `content` string.
When `true`, the response is delivered as a stream of server-sent events. Each event contains a delta chunk in the standard OpenAI SSE format, ending with `data: [DONE]`.
Maximum number of tokens to generate. If you do not set this, the coordinator injects a default of 8192 to bound the worst-case cost and ensure the pre-flight balance reservation covers the full generation.
Sampling temperature between 0 and 2. Lower values produce more deterministic output.
## Examples
### Basic request
```bash curl theme={null}
curl https://api.darkbloom.dev/v1/chat/completions \
-H "Authorization: Bearer eigeninference-your-key-here" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.5-27b-claude-opus-8bit",
"messages": [
{"role": "user", "content": "Explain gradient descent in one paragraph."}
]
}'
```
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
base_url="https://api.darkbloom.dev/v1",
api_key="eigeninference-your-key-here",
)
response = client.chat.completions.create(
model="qwen3.5-27b-claude-opus-8bit",
messages=[
{"role": "user", "content": "Explain gradient descent in one paragraph."}
],
)
print(response.choices[0].message.content)
```
```javascript Node.js theme={null}
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.darkbloom.dev/v1",
apiKey: "eigeninference-your-key-here",
});
const response = await client.chat.completions.create({
model: "qwen3.5-27b-claude-opus-8bit",
messages: [
{ role: "user", content: "Explain gradient descent in one paragraph." },
],
});
console.log(response.choices[0].message.content);
```
### Streaming
```bash curl theme={null}
curl https://api.darkbloom.dev/v1/chat/completions \
-H "Authorization: Bearer eigeninference-your-key-here" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.5-27b-claude-opus-8bit",
"messages": [
{"role": "user", "content": "Write a haiku about distributed systems."}
],
"stream": true
}'
```
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
base_url="https://api.darkbloom.dev/v1",
api_key="eigeninference-your-key-here",
)
stream = client.chat.completions.create(
model="qwen3.5-27b-claude-opus-8bit",
messages=[
{"role": "user", "content": "Write a haiku about distributed systems."}
],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content or ""
print(delta, end="", flush=True)
```
```javascript Node.js theme={null}
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.darkbloom.dev/v1",
apiKey: "eigeninference-your-key-here",
});
const stream = await client.chat.completions.create({
model: "qwen3.5-27b-claude-opus-8bit",
messages: [
{ role: "user", content: "Write a haiku about distributed systems." },
],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
```
### With a system prompt
```bash curl theme={null}
curl https://api.darkbloom.dev/v1/chat/completions \
-H "Authorization: Bearer eigeninference-your-key-here" \
-H "Content-Type: application/json" \
-d '{
"model": "mlx-community/Qwen3.5-122B-A10B-8bit",
"messages": [
{"role": "system", "content": "You are a concise technical assistant. Answer in bullet points only."},
{"role": "user", "content": "What are the trade-offs of using SSE vs WebSockets?"}
],
"max_tokens": 512,
"temperature": 0.3
}'
```
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
base_url="https://api.darkbloom.dev/v1",
api_key="eigeninference-your-key-here",
)
response = client.chat.completions.create(
model="mlx-community/Qwen3.5-122B-A10B-8bit",
messages=[
{
"role": "system",
"content": "You are a concise technical assistant. Answer in bullet points only.",
},
{
"role": "user",
"content": "What are the trade-offs of using SSE vs WebSockets?",
},
],
max_tokens=512,
temperature=0.3,
)
print(response.choices[0].message.content)
```
## Response headers
Every response from the inference endpoint includes trust metadata headers that let you verify which provider handled the request and inspect their attestation status.
| Header | Description |
| ------------------------ | ------------------------------------------------------------------------ |
| `x-provider-attested` | `true` if the provider passed the most recent attestation challenge |
| `x-provider-trust-level` | `self_signed` or `hardware` — see [Trust levels](/security/trust-levels) |
| `x-provider-chip` | Apple Silicon chip model (e.g. `M3 Ultra`) |
| `x-provider-serial` | Provider machine serial number |
| `x-se-signature` | Secure Enclave signature over the response hash |
| `x-response-hash` | SHA-256 hash of the response body, signed by the Secure Enclave |
You can use `x-provider-serial` to pin requests to a specific provider machine you have independently verified. Pass it as `provider_serial` in the request body and the coordinator will route only to that machine.
## Related endpoints
**`POST /v1/responses`** — OpenAI Responses API alias. The coordinator auto-detects the `input` vs `messages` field shape and routes to the same underlying handler.
**`POST /v1/completions`** — Legacy text completions endpoint. Accepts a `prompt` string instead of a `messages` array. This is the older OpenAI `/v1/completions` format, not recommended for new integrations.
**`POST /v1/messages`** — Anthropic Messages API compatible endpoint. Use this if you are working with the Anthropic Python or TypeScript SDK. See the note below.
To use the Anthropic SDK, set `base_url="https://api.darkbloom.dev"` (without `/v1`) and pass your Darkbloom API key as `api_key`. The Anthropic SDK appends `/v1/messages` automatically.
## Thinking tags
Some models emit extended thinking wrapped in `...` tags. These tags are stripped from responses by default before the content reaches you. The final `content` field contains only the model's visible output.
# Generate images from text with Darkbloom's API
Source: https://docs.darkbloom.dev/api/image-generation
POST /v1/images/generations generates images from a text prompt using the OpenAI-compatible image endpoint, served by attested Apple Silicon providers.
`POST /v1/images/generations` generates images from a text prompt. The endpoint follows the OpenAI Images API format — you send a prompt and receive a response containing the generated image. Providers serving image generation run the image backend on Apple Silicon alongside the text inference process.
## Request parameters
A text description of the image you want to generate.
The number of images to generate. Currently `1` is recommended.
The dimensions of the generated image. Supported values depend on the provider's image backend configuration.
## Examples
```bash curl theme={null}
curl https://api.darkbloom.dev/v1/images/generations \
-H "Authorization: Bearer eigeninference-your-key-here" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A neon-lit Apple Silicon chip floating in a dark ocean, cinematic, dramatic lighting",
"n": 1,
"size": "1024x1024"
}'
```
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
base_url="https://api.darkbloom.dev/v1",
api_key="eigeninference-your-key-here",
)
response = client.images.generate(
prompt="A neon-lit Apple Silicon chip floating in a dark ocean, cinematic, dramatic lighting",
n=1,
size="1024x1024",
)
print(response.data[0].url)
```
## Response
```json theme={null}
{
"created": 1714500000,
"data": [
{
"url": "https://..."
}
]
}
```
Unix timestamp for when the image was generated.
Array of generated image objects.
URL to the generated image. The URL is temporary — download the image promptly if you need to persist it.
Image generation is served by providers that have opted into running the image backend. Availability may be more limited than text inference. If no image providers are online, the request will queue and retry before returning an error.
# Browse and select Darkbloom inference models
Source: https://docs.darkbloom.dev/api/models
Use GET /v1/models to see which models are online, compare capabilities and pricing, and choose the right model for your workload and budget.
`GET /v1/models` returns the list of models currently available on the Darkbloom network. The response follows the OpenAI models list format, with additional fields for trust level, provider count, and hardware metadata. All listed models have been verified by the coordinator and have at least one active provider online.
## Request
```bash curl theme={null}
curl https://api.darkbloom.dev/v1/models \
-H "Authorization: Bearer eigeninference-your-key-here"
```
## Response format
Always `"list"`.
Array of model objects.
The model ID to pass in inference requests.
Always `"model"`.
The organization that released the model weights.
Number of active providers currently serving this model.
Highest trust level among active providers: `self_signed` or `hardware`.
`true` if at least one provider serving this model has passed recent attestation.
Human-readable model name for display purposes.
## Available models
The catalog currently includes the following models. All are quantized to 8-bit for efficient Apple Silicon inference.
### Qwen3.5 27B Claude Opus 8-bit
**Model ID:** `qwen3.5-27b-claude-opus-8bit`
A 27-billion-parameter dense model distilled from Claude Opus. Delivers frontier-quality reasoning at a fraction of the compute cost of the full Opus model. Well-suited for complex reasoning, analysis, and code generation tasks that benefit from extended thinking.
| Property | Value |
| ---------------- | ------------------ |
| Architecture | 27B dense |
| Quantization | 8-bit |
| Min provider RAM | 36 GB |
| Input price | \$0.10 / 1M tokens |
| Output price | \$0.78 / 1M tokens |
### Gemma 4 26B 8-bit
**Model ID:** `mlx-community/gemma-4-26b-a4b-it-8bit`
Google's Gemma 4 in a 26-billion-parameter mixture-of-experts configuration with only 4 billion parameters active per forward pass. Fast and memory-efficient, with multimodal instruction following. A good default for general-purpose tasks where cost and latency matter.
| Property | Value |
| ---------------- | ------------------- |
| Architecture | 26B MoE, 4B active |
| Quantization | 8-bit |
| Min provider RAM | 36 GB |
| Input price | \$0.065 / 1M tokens |
| Output price | \$0.20 / 1M tokens |
### Trinity Mini 8-bit
**Model ID:** `mlx-community/Trinity-Mini-8bit`
A 27-billion-parameter adaptive mixture-of-experts model optimized for agentic use cases — tool use, multi-step reasoning, and long-context tasks. The adaptive routing keeps active parameter count low while maintaining quality on structured tasks.
| Property | Value |
| ---------------- | ---------------- |
| Architecture | 27B Adaptive MoE |
| Quantization | 8-bit |
| Min provider RAM | 48 GB |
### Qwen3.5 122B MoE 8-bit
**Model ID:** `mlx-community/Qwen3.5-122B-A10B-8bit`
The highest-quality model in the catalog. 122 billion total parameters with 10 billion active per token — delivering near-full-model quality at significantly reduced inference cost. Best for tasks where output quality is the primary constraint.
| Property | Value |
| ---------------- | -------------------- |
| Architecture | 122B MoE, 10B active |
| Quantization | 8-bit |
| Min provider RAM | 128 GB |
| Input price | \$0.13 / 1M tokens |
| Output price | \$1.04 / 1M tokens |
### MiniMax M2.5 8-bit
**Model ID:** `mlx-community/MiniMax-M2.5-8bit`
A state-of-the-art coding and reasoning model with 239 billion total parameters and 11 billion active per token. Achieves approximately 100 tokens per second on Apple Silicon, making it competitive with much smaller models on throughput while delivering top-tier coding quality.
| Property | Value |
| ---------------- | -------------------- |
| Architecture | 239B MoE, 11B active |
| Quantization | 8-bit |
| Min provider RAM | 256 GB |
| Input price | \$0.06 / 1M tokens |
| Output price | \$0.50 / 1M tokens |
## Choosing a model
Start with `mlx-community/gemma-4-26b-a4b-it-8bit`. It has the lowest output cost, runs on the widest range of provider hardware (36 GB+), and is fast enough for interactive use.
Use `qwen3.5-27b-claude-opus-8bit` for tasks requiring multi-step logic, careful analysis, or nuanced writing. The Claude Opus distillation gives it reasoning depth beyond its parameter count.
Use `mlx-community/Qwen3.5-122B-A10B-8bit`. With 122B total parameters, it produces the highest quality output in the catalog across most benchmarks.
Use `mlx-community/MiniMax-M2.5-8bit`. It was trained for coding tasks and achieves approximately 100 tokens per second, which makes it practical for long code generation.
Use `mlx-community/Trinity-Mini-8bit`. Its adaptive MoE routing is tuned for the structured reasoning patterns that appear in tool-use and multi-step agent loops.
The `provider_count` field tells you how many providers are currently online for each model. A count of zero means the model is in the catalog but no providers are serving it right now — your request will queue. The coordinator retries up to three times before returning an error.
# Add credits to your Darkbloom account
Source: https://docs.darkbloom.dev/billing/add-credits
Load a prepaid credit balance using a credit or debit card through Stripe. Credits apply immediately after payment and never expire.
Darkbloom uses a prepaid credit model: you add funds to your account before making inference requests, and costs are deducted per request. Credits are loaded through the web console at [darkbloom.dev](https://darkbloom.dev) using a credit or debit card via Stripe. This page walks through how the process works.
## How to add credits
Go to [darkbloom.dev](https://darkbloom.dev) and sign in to your account.
Navigate to the **Billing** section from the sidebar.
Enter the amount you want to add. The minimum deposit is **\$0.50**.
You will be redirected to a Stripe-hosted checkout page. Enter your credit or debit card details and confirm the payment.
Once Stripe confirms the payment, your balance is updated automatically. You can start making inference requests immediately.
Credits are non-refundable. Unused credits remain in your account and do not expire.
## Payment details
* **Payment method:** Credit card or debit card via Stripe
* **Minimum deposit:** \$0.50
* **Currency:** USD
* **Processing:** Credits are applied automatically after Stripe confirms payment. There is no manual review step.
Do not close the Stripe checkout tab before the payment completes. If you do and the payment goes through, your credits will still be applied — but it may take a few seconds for the webhook confirmation to arrive.
## Checking your balance after deposit
Once your credits are applied, you can verify your balance from the console or via the API:
```bash theme={null}
curl https://api.darkbloom.dev/v1/payments/balance \
-H "Authorization: Bearer $DARKBLOOM_API_KEY"
```
See [Pricing](/billing/pricing) for more on how credits are consumed per request.
# Darkbloom pricing: per-token rates for every model
Source: https://docs.darkbloom.dev/billing/pricing
Token pricing for every model on Darkbloom, how the prepaid credit balance works, and how to check your current rates and usage programmatically.
Darkbloom charges per token, deducted from a prepaid credit balance you load in advance. There are no subscription fees, seat fees, or platform markups — providers keep 100% of the token revenue. You pay only for what you use, and unused credits remain in your account indefinitely.
## Pricing table
Prices are per 1 million tokens.
Pricing may change. Fetch current rates programmatically at any time with `GET /v1/pricing` — no authentication required.
| Model | Input (per 1M tokens) | Output (per 1M tokens) |
| ------------ | --------------------- | ---------------------- |
| Gemma 4 26B | \$0.065 | \$0.20 |
| Qwen3.5 27B | \$0.10 | \$0.78 |
| Qwen3.5 122B | \$0.13 | \$1.04 |
| MiniMax M2.5 | \$0.06 | \$0.50 |
**0% platform fee.** Every dollar you spend goes directly to the providers running inference.
## How billing works
Your account holds a credit balance denominated in USD. When you make an inference request:
1. The coordinator tallies your input and output tokens after the response completes.
2. The cost is deducted from your balance at the rates above.
3. If your balance reaches zero, requests will be rejected until you add more credits.
There are no trailing charges or invoices. You add credits before you use them.
## Fetch current pricing
```bash theme={null}
curl https://api.darkbloom.dev/v1/pricing
```
This endpoint is public — no API key required. It returns the current per-token rates for every model on the network.
## Check your balance
```bash theme={null}
curl https://api.darkbloom.dev/v1/payments/balance \
-H "Authorization: Bearer $DARKBLOOM_API_KEY"
```
The response includes your total balance and the withdrawable amount (relevant for providers):
```json theme={null}
{
"balance_micro_usd": 5000000,
"balance_usd": 5.00,
"withdrawable_micro_usd": 0,
"withdrawable_usd": 0.00
}
```
## Check usage history
```bash theme={null}
curl https://api.darkbloom.dev/v1/payments/usage \
-H "Authorization: Bearer $DARKBLOOM_API_KEY"
```
Each entry in the response shows a single request's model, token counts, cost, and timestamp:
```json theme={null}
[
{
"request_id": "req_01abc...",
"model": "qwen3.5-27b-claude-opus-8bit",
"prompt_tokens": 412,
"completion_tokens": 187,
"cost_micro_usd": 187400,
"timestamp": "2026-04-30T14:22:01Z"
}
]
```
`cost_micro_usd` is the cost in millionths of a dollar. Divide by 1,000,000 for the USD value.
# Darkbloom: Private AI Inference on Idle Macs
Source: https://docs.darkbloom.dev/introduction
Darkbloom routes AI to idle Apple Silicon Macs. Get an OpenAI-compatible API with hardware-level privacy, or earn by sharing your Mac's compute.
Darkbloom is a decentralized inference network that connects AI consumers with Mac owners running idle Apple Silicon hardware. As a consumer, you get access to frontier-quality models through an OpenAI-compatible API — with end-to-end encryption ensuring your prompts stay private. As a provider, you earn by running inference on your Mac during idle hours.
Make your first inference request in under 5 minutes using any OpenAI SDK.
Install the provider agent on your Apple Silicon Mac and start earning.
Full reference for all inference, account, and network endpoints.
Learn how Darkbloom ensures your prompts are never visible to providers.
## How it works
Darkbloom runs on a three-layer architecture: your requests go to a coordinator running in a Confidential VM, which routes them to attested provider machines running hardened inference processes on Apple Silicon.
```text theme={null}
Consumer (SDK / Web UI / curl)
│
│ HTTPS, OpenAI-compatible API
▼
Coordinator (Confidential VM, encrypted memory)
│
│ WebSocket — request re-encrypted to provider's key
▼
Provider (hardened process on Apple Silicon)
│
│ inference engine
▼
Apple Silicon GPU
```
The coordinator encrypts each request with the destination provider's public key before forwarding it. Only the hardened provider process — running with debugger attachment blocked and memory-reading APIs disabled — can decrypt and process the request.
## Available models
| Model | Size | Min RAM | Best for |
| ----------------------------- | -------------------- | ------- | -------------------------- |
| Gemma 4 26B 8-bit | 26B MoE, 4B active | 36 GB | Fast multimodal requests |
| Qwen3.5 27B Claude Opus 8-bit | 27B dense | 36 GB | Frontier-quality reasoning |
| Trinity Mini 8-bit | 27B Adaptive MoE | 48 GB | Fast agentic inference |
| Qwen3.5 122B MoE 8-bit | 122B MoE, 10B active | 128 GB | Best quality reasoning |
| MiniMax M2.5 8-bit | 239B MoE, 11B active | 256 GB | SOTA coding, \~100 tok/s |
Darkbloom is an experimental research prototype under active development. Expect rough edges and breaking changes. Do not use in production.
# darkbloom CLI: complete command reference
Source: https://docs.darkbloom.dev/provider/cli-reference
Complete reference for every darkbloom subcommand — serve, start, stop, status, doctor, models, earnings, login, and more — with flags and usage examples.
The `darkbloom` binary is the provider agent CLI. Every operation — starting and stopping the provider, checking status, managing models, viewing earnings, and updating the agent — goes through this command. All subcommands support the `-v` / `--verbose` flag for more detailed log output.
```bash theme={null}
darkbloom [--verbose] [options]
```
***
## serve
Start the provider in the foreground. The provider connects to the coordinator, begins serving inference requests, and logs to stdout. Press `Ctrl+C` to stop.
```bash theme={null}
darkbloom serve [options]
```
| Flag | Default | Description |
| ----------------------- | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `--model ` | largest downloaded model | Model to serve. Can be specified multiple times to serve more than one model simultaneously. |
| `--all-models` | off | Serve all downloaded models that fit in memory. |
| `--port ` | `8000` | Port for the local API server. |
| `--backend-port ` | `8100` (from config) | Port for the inference backend process. |
| `--coordinator ` | `wss://api.darkbloom.dev/ws/provider` | Coordinator WebSocket URL. |
| `--local` | off | Run in local-only mode with no coordinator connection. |
| `--idle-timeout ` | `60` (from config) | Minutes of inactivity before the backend shuts down to free GPU memory. Set to `0` to keep the backend running indefinitely. |
| `--no-auto-update` | off | Disable the automatic update check at startup. |
```bash theme={null}
# Serve with the default model
darkbloom serve
# Serve a specific model
darkbloom serve --model qwen3.5-27b-claude-opus-8bit
# Serve multiple models
darkbloom serve --model qwen3.5-27b-claude-opus-8bit --model mlx-community/gemma-4-26b-a4b-it-8bit
# Keep the backend running even when idle
darkbloom serve --idle-timeout 0
```
***
## start
Start the provider as a background daemon. The process is registered with launchd, persists across reboots, and auto-restarts if it crashes. Equivalent to `darkbloom serve` but daemonised.
```bash theme={null}
darkbloom start [options]
```
| Flag | Default | Description |
| ----------------------- | ------------------------------------- | ----------------------------------------------------------------------- |
| `--model ` | value from config | Model to serve. |
| `--coordinator ` | `wss://api.darkbloom.dev/ws/provider` | Coordinator WebSocket URL. |
| `--idle-timeout ` | `60` (from config) | Minutes of inactivity before the backend shuts down to free GPU memory. |
```bash theme={null}
# Start with config defaults
darkbloom start
# Start with a specific model
darkbloom start --model mlx-community/Qwen3.5-122B-A10B-8bit
```
***
## stop
Stop the background daemon gracefully. Sends a termination signal to the running provider process and waits for it to exit cleanly.
```bash theme={null}
darkbloom stop
```
***
## status
Print hardware information, connection status, and the current serving configuration.
```bash theme={null}
darkbloom status
```
The output includes your Apple Silicon chip model, memory size, GPU core count, and memory bandwidth, along with whether the provider is connected to the coordinator and which model is active.
***
## doctor
Run a full diagnostic check and report any problems. Use this when the provider fails to start or connect, or after installing the agent for the first time.
```bash theme={null}
darkbloom doctor [--coordinator ]
```
Doctor checks the following in order:
1. Hardware detection (chip model, memory, GPU cores)
2. System Integrity Protection (SIP) — must be enabled
3. Secure Enclave (`eigeninference-enclave` binary availability)
4. MDM enrollment status
5. Inference runtime (vllm-mlx / mlx-lm import and version)
6. Downloaded models
7. Coordinator connectivity
Each check is marked pass or fail. For any failures, doctor prints the specific remediation steps.
Run `darkbloom doctor` before you run `darkbloom serve` for the first time. It will catch configuration problems before they show up as cryptic errors during startup.
***
## models list
List the models you have downloaded locally, along with their estimated memory usage.
```bash theme={null}
darkbloom models list [--coordinator ]
```
Pass `--coordinator` to also fetch the full catalog from the network and show which additional models your hardware could run.
To download a model interactively:
```bash theme={null}
darkbloom models download
```
To download a specific model without the interactive picker:
```bash theme={null}
darkbloom models download --model
```
***
## earnings
Show your current balance, total earnings, and recent payout history.
```bash theme={null}
darkbloom earnings [--coordinator ]
```
The output shows:
* **Balance** — amount available for withdrawal
* **Total earned** — cumulative lifetime earnings
* **Jobs served** — total number of inference requests completed
* **Recent payouts** — last five individual request payouts with model and amount
For full earnings details and withdrawal options, use the web console or see the [earnings guide](/provider/earnings).
***
## update
Check for a newer version of the provider agent and install it if one is available.
```bash theme={null}
darkbloom update [--coordinator ] [--force]
```
| Flag | Description |
| --------- | ---------------------------------------------------------------------- |
| `--force` | Re-download and install even if you are already on the latest version. |
The provider also checks for updates automatically at startup and prints a notification if a newer version is available. Auto-updates in the background can be managed with `darkbloom autoupdate`.
***
## login
Link this machine to your Darkbloom account using a device code flow. Running `darkbloom login` opens your browser to the account linking page and displays a short code in the terminal. After you approve the link in the browser, the provider saves an auth token and uses it for all subsequent connections.
```bash theme={null}
darkbloom login [--coordinator ]
```
If the machine is already linked, the command prints the current status and exits without re-linking. Run `darkbloom logout` first if you need to switch accounts.
***
## logout
Unlink this machine from your Darkbloom account. The locally stored auth token is deleted. The provider will continue to run and serve requests, but earnings will not be credited to your account until you run `darkbloom login` again.
```bash theme={null}
darkbloom logout
```
***
## logs
View provider logs.
```bash theme={null}
darkbloom logs [--lines ] [--watch]
```
| Flag | Default | Description |
| ---------------- | ------- | --------------------------------------------------- |
| `--lines ` | `50` | Number of recent log lines to show. |
| `-w` / `--watch` | off | Follow logs in real time (equivalent to `tail -f`). |
***
## autoupdate
Enable or disable automatic background updates.
```bash theme={null}
darkbloom autoupdate
```
When enabled (the default), the provider checks for updates every 30 minutes while running and installs them automatically. When disabled, you manage updates manually with `darkbloom update`.
```bash theme={null}
# Check current setting
darkbloom autoupdate status
# Disable automatic updates
darkbloom autoupdate disable
# Re-enable automatic updates
darkbloom autoupdate enable
```
***
## Global flags
| Flag | Description |
| ------------------ | --------------------------------------------------- |
| `-v` / `--verbose` | Enable debug-level logging for the current command. |
| `--version` | Print the installed version and exit. |
| `--help` | Print usage for any command or subcommand. |
# Understanding and withdrawing your earnings
Source: https://docs.darkbloom.dev/provider/earnings
How provider earnings are calculated per model, how to check your balance via CLI or web console, and how to withdraw via Stripe Connect.
Every token your Mac generates for a consumer request earns you a share of that request's billing. Darkbloom charges consumers per million tokens — input and output priced separately — and credits the full amount to your account. There is no platform fee deducted from provider earnings.
## How pricing works
Billing is per token and varies by model. Larger, higher-quality models command higher rates. The current rates for the models available on the network are:
| Model | Input | Output |
| ----------------------------- | ------------------- | ------------------ |
| Gemma 4 26B 8-bit | \$0.065 / 1M tokens | \$0.20 / 1M tokens |
| Qwen3.5 27B Claude Opus 8-bit | \$0.10 / 1M tokens | \$0.78 / 1M tokens |
| Qwen3.5 122B MoE 8-bit | \$0.13 / 1M tokens | \$1.04 / 1M tokens |
| MiniMax M2.5 8-bit | \$0.06 / 1M tokens | \$0.50 / 1M tokens |
The coordinator credits your account after each completed request. Earnings accumulate in real time as your Mac serves.
## Checking your earnings
### From the CLI
```bash theme={null}
darkbloom earnings
```
This shows your current balance, total lifetime earnings, total jobs served, and a list of recent individual payouts with the model and amount for each.
Example output:
```
Darkbloom Earnings
Coordinator: online (14 providers connected)
Earnings:
Balance: $4.821200
Total earned: $12.340000
Jobs served: 8423
Recent payouts:
$0.000182 qwen3.5-27b-claude-opus-8bit
$0.000094 mlx-community/gemma-4-26b-a4b-it-8bit
$0.000341 qwen3.5-27b-claude-opus-8bit
$0.000076 mlx-community/gemma-4-26b-a4b-it-8bit
$0.000217 qwen3.5-27b-claude-opus-8bit
```
### From the web console
Log in at [darkbloom.dev](https://darkbloom.dev) and navigate to the **Earn** section. The dashboard shows your balance, a usage graph over time, and the full payout history with filtering by date and model.
### From the leaderboard API
The network publishes a public leaderboard of provider earnings:
```bash theme={null}
GET /v1/leaderboard
```
This endpoint returns providers ranked by total earnings. It is publicly accessible — no authentication required.
## Withdrawing your earnings
Darkbloom uses [Stripe Connect](https://stripe.com/connect) for payouts. To set up withdrawals:
Go to the **Earn** section of the web console and click **Set up payouts**. This opens the Stripe Connect onboarding flow where you can link a bank account or debit card.
Once your payout method is connected, click **Withdraw** and enter the amount. Stripe processes the transfer to your bank account or card.
Transfer times vary by payout method and region. Bank transfers typically arrive within 1-3 business days.
Withdrawals require your device to be linked to your account. If you have not run `darkbloom login`, earnings are tracked locally but cannot be withdrawn until the machine is linked.
## Maximising earnings
A few factors affect how much your machine earns:
* **Uptime** — the more hours your provider is running and connected, the more requests it can serve. Consider using [scheduling](/provider/scheduling) to serve during hours when your Mac would otherwise be idle.
* **Model choice** — higher-value models (like Qwen3.5 122B or MiniMax M2.5) earn more per token. If your hardware has the memory headroom, serving a larger model can significantly increase earnings per request.
* **Hardware** — Macs with more unified memory and higher memory bandwidth serve requests faster, which means higher throughput and more tokens per hour.
# Installing and setting up the provider agent
Source: https://docs.darkbloom.dev/provider/install
Install the Darkbloom provider agent on your Apple Silicon Mac, link your account, pick a model, and start earning in a few minutes.
Getting started as a provider takes a single terminal command. The installer handles everything — the provider binary, a bundled Python 3.12 runtime, the vllm-mlx inference engine, and the Secure Enclave tooling needed for attestation. You do not need to install Python, set up a virtual environment, or configure anything manually before running the installer.
## Install the provider agent
Open Terminal and run:
```bash theme={null}
curl -fsSL https://api.darkbloom.dev/install.sh | bash
```
The installer will:
1. Download and verify the provider binary (`darkbloom`)
2. Install a bundled Python 3.12 runtime to `~/.darkbloom/python/`
3. Install vllm-mlx and its dependencies into the bundled Python environment
4. Install the Secure Enclave helper (`eigeninference-enclave`)
5. Walk you through model selection and account linking
6. Start the provider as a background launchd service
The installer verifies SHA-256 hashes and code signatures for all downloaded components. If any check fails, installation is aborted.
## What gets installed
The provider agent itself — a Rust binary that manages the inference backend, maintains the WebSocket connection to the coordinator, handles attestation, and exposes the CLI. Installed to a location on your `PATH` so you can run `darkbloom` from any terminal.
A self-contained Python 3.12 installation in `~/.darkbloom/python/`. It is completely separate from any system Python or Homebrew Python you already have and will not interfere with them.
The inference engine that runs models on Apple Silicon's GPU via Metal. Installed into the bundled Python environment. The provider agent verifies the hash of the installed packages against the coordinator's runtime manifest on every startup and updates them automatically if they drift.
The `eigeninference-enclave` binary, which the provider uses to generate hardware-bound attestation blobs from your Mac's Secure Enclave. These proofs bind your machine's identity to the inference keys used in the current session.
## Link your account
Your machine needs to be linked to your Darkbloom account for earnings to be credited to you. The setup wizard that runs after installation will prompt you to do this, but you can also run it manually at any time:
```bash theme={null}
darkbloom login
```
This opens a browser window and displays a short code in your terminal. Sign in to your Darkbloom account in the browser, enter the code when prompted, and the link is made. The provider stores an auth token locally and uses it on subsequent connections.
If you skip account linking, your provider will still serve requests but earnings will not be credited to your account. Run `darkbloom login` to link at any time.
## Pick a model
During setup, the installer shows you which models your hardware can run based on detected memory. You can also browse and download models manually:
```bash theme={null}
darkbloom models list
```
The models available on the network, along with their memory requirements, are:
| Model | Size | Min RAM | Notes |
| ----------------------------- | ------ | ------- | -------------------------- |
| Gemma 4 26B 8-bit | 28 GB | 36 GB | Fast multimodal MoE |
| Qwen3.5 27B Claude Opus 8-bit | 27 GB | 36 GB | Frontier-quality reasoning |
| Trinity Mini 8-bit | 26 GB | 48 GB | Fast agentic inference |
| Qwen3.5 122B MoE 8-bit | 122 GB | 128 GB | Best quality reasoning |
| MiniMax M2.5 8-bit | 243 GB | 256 GB | SOTA coding, \~100 tok/s |
Model weights are downloaded to your HuggingFace cache (`~/.cache/huggingface/hub/`) and are only fetched once. If you already have a model downloaded, the provider uses the existing copy.
## Start serving
Once a model is downloaded and your account is linked, start the provider:
```bash Background (recommended) theme={null}
darkbloom start
```
```bash Foreground theme={null}
darkbloom serve
```
`darkbloom start` runs the provider as a background daemon that persists across reboots. `darkbloom serve` keeps the process in your current terminal session — useful when you want to watch the logs directly.
Once running, check that everything is connected:
```bash theme={null}
darkbloom status
```
You should see your hardware detected, your model loaded, and the coordinator connection shown as active.
## Configuration file
The provider writes its configuration to `~/.config/eigeninference/provider.toml`. You can edit this file directly to adjust settings without using the CLI. Changes take effect the next time you run `darkbloom start` or `darkbloom serve`.
See the [CLI reference](/provider/cli-reference) for all available commands, or the [scheduling guide](/provider/scheduling) to configure when your Mac serves requests.
# Manage your provider with the Darkbloom Mac app
Source: https://docs.darkbloom.dev/provider/macos-app
The native macOS menu bar app lets you start and stop your provider, monitor throughput, view earnings, configure scheduling, and enable idle detection.
The Darkbloom macOS app lives in your menu bar and gives you a native interface for managing your provider without touching the terminal. It wraps the same `darkbloom` CLI under the hood, so everything you can do in the app you can also do from the command line — the two are fully equivalent.
## Features
Start or stop your provider from the menu bar with a single click. No need to open a terminal.
See tokens per second and active request counts update live as your Mac serves inference requests.
The app monitors whether you are actively using your Mac. When it detects activity, it pauses the provider so inference does not compete with your own work. Serving resumes automatically when the Mac goes idle again.
Set specific hours and days when your Mac should serve. Outside those windows, the provider disconnects and the backend shuts down to free GPU memory.
View your balance and recent earnings history without leaving the app.
Optionally start the provider automatically when you log in to your Mac, so your machine earns whenever it is on and idle.
## Accessing settings
Click the Darkbloom icon in the menu bar to open the status panel. From there, click **Settings** to access the full configuration view, where you can:
* Choose which model to serve
* Configure scheduling windows
* Enable or disable auto-start at login
* Enable or disable automatic updates
## Idle detection
Idle detection watches for keyboard, mouse, and other user activity signals from macOS. When you start using your Mac — opening applications, typing, moving the mouse — the provider pauses so the GPU is available for your own work. When your Mac goes idle again, the provider resumes automatically.
This happens transparently. You do not need to manually stop and start the provider around your work sessions.
Idle detection is separate from [scheduling](/provider/scheduling). Scheduling defines fixed time windows when the provider is allowed to run. Idle detection operates within those windows and further pauses serving when you are actively using the machine.
## Earnings display
The menu bar panel shows your current balance and a summary of recent earnings. For a full breakdown with per-request detail and withdrawal options, use the web console at [darkbloom.dev](https://darkbloom.dev) or run `darkbloom earnings` in the terminal.
## Setup wizard
When you launch the app for the first time, a setup wizard walks you through:
1. Detecting your hardware
2. Downloading a model matched to your machine's memory
3. Linking your Darkbloom account
4. Starting the provider
If you have already installed and configured the provider via the CLI, the app connects to the existing configuration and launchd service automatically.
# Earn by sharing your Mac's compute on Darkbloom
Source: https://docs.darkbloom.dev/provider/overview
Run AI inference on your idle Apple Silicon Mac and earn 100% of the revenue. No platform fee, no port forwarding, and consumers cannot read your data.
Darkbloom turns your Mac's idle GPU cycles into income. When you run the provider agent, your machine connects to the Darkbloom network and serves inference requests from consumers using the API. You earn for every token your Mac generates, and the payout is direct: Darkbloom takes a 0% platform fee, so 100% of the revenue your hardware earns goes to you.
## System requirements
You need an Apple Silicon Mac to run the provider agent. The inference engine is built on Metal and vllm-mlx, which require Apple's unified memory architecture.
Apple Silicon M1 or later (M1, M2, M3, M4 and their Pro / Max / Ultra variants)
macOS 14 Sonoma or later
16 GB unified memory minimum; 36 GB or more recommended to serve the smallest catalog model
Outbound internet access only — no port forwarding or firewall changes needed
The minimum 16 GB figure covers installation and the agent itself. To actually serve a model, your Mac needs at least 36 GB of unified memory. The full model catalog and their RAM requirements are listed in the [install guide](/provider/install).
## How earning works
Consumers pay per token when they call the API. Pricing varies by model — smaller models cost less, larger reasoning models cost more. Every dollar billed to a consumer for requests your machine handles flows directly to your account. There is no platform cut.
Earnings are paid out via [Stripe Connect](/provider/earnings). You can withdraw to a bank account or debit card once your balance meets the payout threshold.
The network runs a public earnings leaderboard at `GET /v1/leaderboard` so you can see how your machine ranks against other providers.
## Privacy: what you can and cannot see
Darkbloom is designed so that neither you nor any other party outside the requesting consumer can read the content of inference requests. The coordinator (Darkbloom's routing server) encrypts each request with your provider's X25519 public key before forwarding it over WebSocket. Only your provider process can decrypt and process the request.
Several layers enforce this at the OS level:
* Debugger attachment is blocked at the kernel level (`PT_DENY_ATTACH`)
* Memory-reading APIs are disabled by Hardened Runtime
* Core dumps are disabled before any inference data enters the process
* System Integrity Protection (SIP) must be enabled — the provider refuses to serve if SIP is off
The same guarantee applies in reverse: consumers cannot read data from your machine outside the inference response they receive.
## Attestation
When your provider connects to the network, it generates a cryptographic attestation using your Mac's Secure Enclave. This attestation proves to the coordinator — and to any consumer who wants to verify — that your machine is running an unmodified, blessed version of the provider agent with all security controls intact.
The coordinator re-checks this every five minutes via a challenge-response mechanism. If your machine's security posture changes (for example, if SIP is disabled), the coordinator stops routing requests to it.
Attestation data for all active providers is publicly verifiable at `GET /v1/providers/attestation`.
Run `darkbloom doctor` at any time to check whether your machine passes all security and connectivity checks before you start serving.
# Schedule when your Mac serves inference requests
Source: https://docs.darkbloom.dev/provider/scheduling
Set specific days and hours when your Mac serves requests. Outside scheduled windows, the provider disconnects and frees GPU memory for your own use.
By default, the provider runs whenever you start it and keeps running until you stop it. Scheduling lets you define time windows — specific days and hours — when your Mac should actively serve requests. Outside those windows, the provider disconnects from the coordinator and shuts down the inference backend, freeing GPU memory for other uses.
This is particularly useful if you want your Mac to serve overnight or during work hours when you are away from your desk, without having to remember to start and stop the provider manually.
## How scheduling works
When scheduling is enabled, the provider evaluates your configured windows each time it checks whether to serve. If the current local time falls inside a window, the provider connects and serves normally. If the current time falls outside all windows, the provider disconnects and stops the backend process.
Windows are defined in local time. Overnight windows are supported: if the end time is earlier than the start time (for example, `22:00` to `08:00`), the provider treats it as a window that spans midnight.
## Configuring via the macOS app
Open the Darkbloom menu bar app and click **Settings**. Under **Scheduling**, enable scheduling and add one or more time windows. Each window lets you pick the days of the week and a start and end time using a time picker.
Changes take effect immediately — the provider re-evaluates its schedule the next time the check interval fires.
## Configuring via provider.toml
You can also configure scheduling directly in the config file at `~/.config/eigeninference/provider.toml`. Add a `[schedule]` section with one or more `[[schedule.windows]]` entries.
### Basic example: weeknight serving
Serve every weeknight from 10 pm to 8 am the following morning:
```toml theme={null}
[schedule]
enabled = true
[[schedule.windows]]
days = ["mon", "tue", "wed", "thu", "fri"]
start = "22:00"
end = "08:00"
```
### Example: weeknights and full weekends
```toml theme={null}
[schedule]
enabled = true
[[schedule.windows]]
days = ["mon", "tue", "wed", "thu", "fri"]
start = "22:00"
end = "08:00"
[[schedule.windows]]
days = ["sat", "sun"]
start = "00:00"
end = "23:59"
```
### Disabling scheduling
Set `enabled = false` to disable scheduling without removing your configured windows. The provider will run continuously whenever it is started.
```toml theme={null}
[schedule]
enabled = false
```
## Window reference
Each `[[schedule.windows]]` entry accepts the following fields:
| Field | Type | Description |
| ------- | ---------------- | ----------------------------------------------------------------------------------------------- |
| `days` | array of strings | Days the window applies to. See day values below. |
| `start` | string | Window start time in 24-hour `HH:MM` format. |
| `end` | string | Window end time in 24-hour `HH:MM` format. If earlier than `start`, the window wraps overnight. |
**Day values:** `"mon"`, `"tue"`, `"wed"`, `"thu"`, `"fri"`, `"sat"`, `"sun"`
Times are in your Mac's local timezone. The provider reads the system clock to evaluate windows, so changing your Mac's timezone will shift when windows activate.
## Multiple windows
You can define as many `[[schedule.windows]]` entries as you like. The provider is active whenever the current time falls inside any one of them. Windows do not need to be contiguous or non-overlapping.
## Applying config changes
After editing `provider.toml` directly, restart the provider for changes to take effect:
```bash theme={null}
darkbloom stop
darkbloom start
```
If you are using the macOS app, changes made in **Settings** are applied to the config file automatically and do not require a manual restart.
# Quickstart: call the Darkbloom API in 5 minutes
Source: https://docs.darkbloom.dev/quickstart-consumer
Get an API key, send your first chat completion, and list available models using any OpenAI-compatible SDK. Works with Python, Node.js, and curl.
Darkbloom exposes an OpenAI-compatible API at `https://api.darkbloom.dev/v1`. If you've used the OpenAI SDK before, the only change is the base URL and your API key — everything else works the same way. This guide walks you through getting a key, making your first request, and exploring what's available.
Go to [darkbloom.dev](https://darkbloom.dev) and sign up for an account. Once you're logged in, open the console and create an API key. Your key will start with `eigeninference-`.
Store your API key somewhere safe. You won't be able to view it again after closing the creation dialog.
Point any OpenAI-compatible SDK at `https://api.darkbloom.dev/v1` and pass your API key. The request format is identical to the OpenAI Chat Completions API.
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
base_url="https://api.darkbloom.dev/v1",
api_key="eigeninference-..." # replace with your key
)
response = client.chat.completions.create(
model="qwen3.5-27b-claude-opus-8bit",
messages=[
{"role": "user", "content": "Explain the difference between a mutex and a semaphore."}
]
)
print(response.choices[0].message.content)
```
```javascript Node.js theme={null}
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.darkbloom.dev/v1",
apiKey: "eigeninference-...", // replace with your key
});
const response = await client.chat.completions.create({
model: "qwen3.5-27b-claude-opus-8bit",
messages: [
{ role: "user", content: "Explain the difference between a mutex and a semaphore." }
],
});
console.log(response.choices[0].message.content);
```
```bash curl theme={null}
curl https://api.darkbloom.dev/v1/chat/completions \
-H "Authorization: Bearer eigeninference-..." \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.5-27b-claude-opus-8bit",
"messages": [
{"role": "user", "content": "Explain the difference between a mutex and a semaphore."}
]
}'
```
`qwen3.5-27b-claude-opus-8bit` is a good general-purpose starting point — it's a frontier-quality reasoning model distilled from Claude Opus. See [available models](#list-available-models) below for the full catalog.
To see which models are currently online and accepting requests, call `GET /v1/models`.
```python Python theme={null}
models = client.models.list()
for model in models.data:
print(model.id)
```
```javascript Node.js theme={null}
const models = await client.models.list();
for (const model of models.data) {
console.log(model.id);
}
```
```bash curl theme={null}
curl https://api.darkbloom.dev/v1/models \
-H "Authorization: Bearer eigeninference-..."
```
The response lists only models that have at least one provider currently online. If a model isn't in the list, no provider is serving it right now.
| Model ID | Best for |
| --------------------------------------- | ----------------------------------------- |
| `qwen3.5-27b-claude-opus-8bit` | Frontier reasoning, Claude Opus distilled |
| `mlx-community/gemma-4-26b-a4b-it-8bit` | Fast multimodal requests |
| `mlx-community/Trinity-Mini-8bit` | Fast agentic inference |
| `mlx-community/Qwen3.5-122B-A10B-8bit` | Highest quality reasoning |
| `mlx-community/MiniMax-M2.5-8bit` | State-of-the-art coding, \~100 tok/s |
Add `stream=True` (Python) or `stream: true` (Node.js) to receive tokens as they're generated instead of waiting for the full response.
```python Python theme={null}
stream = client.chat.completions.create(
model="qwen3.5-27b-claude-opus-8bit",
messages=[
{"role": "user", "content": "Write a haiku about distributed systems."}
],
stream=True
)
for chunk in stream:
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="", flush=True)
```
```javascript Node.js theme={null}
const stream = await client.chat.completions.create({
model: "qwen3.5-27b-claude-opus-8bit",
messages: [
{ role: "user", content: "Write a haiku about distributed systems." }
],
stream: true,
});
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta?.content;
if (delta) process.stdout.write(delta);
}
```
```bash curl theme={null}
curl https://api.darkbloom.dev/v1/chat/completions \
-H "Authorization: Bearer eigeninference-..." \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.5-27b-claude-opus-8bit",
"messages": [
{"role": "user", "content": "Write a haiku about distributed systems."}
],
"stream": true
}'
```
The streaming response uses server-sent events, the same format as the OpenAI API. Each line is prefixed with `data:` and the stream ends with `data: [DONE]`.
## Using the Anthropic Messages API
Darkbloom also supports the Anthropic Messages API format at `/v1/messages`. Use this if your code is already written for the Anthropic SDK or if you prefer the `system` parameter as a top-level field.
```bash theme={null}
curl https://api.darkbloom.dev/v1/messages \
-H "Authorization: Bearer eigeninference-..." \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.5-27b-claude-opus-8bit",
"max_tokens": 1024,
"messages": [
{"role": "user", "content": "What is the capital of France?"}
]
}'
```
Darkbloom is an experimental research prototype. Do not use it in production applications.
# Quickstart: become a Darkbloom inference provider
Source: https://docs.darkbloom.dev/quickstart-provider
Turn your idle Apple Silicon Mac into a Darkbloom provider. Install the agent, link your account, pick a model, and start earning in about 10 minutes.
If you have an Apple Silicon Mac sitting idle for part of the day, you can put its unified memory and GPU to work serving AI inference requests. Darkbloom's provider agent connects outbound over WebSocket — no port forwarding or firewall changes needed — and your prompts are cryptographically isolated from your own process. This guide covers everything from installation to your first confirmed earnings.
The provider agent requires Apple Silicon and enough unified memory to hold the model you want to serve.
| Requirement | Minimum |
| -------------- | ----------------------------------------- |
| Chip | Apple Silicon M1 or later |
| macOS | 26 Tahoe (preferred) |
| Unified memory | 16 GB (36 GB recommended for most models) |
Run this command to confirm your chip:
```bash theme={null}
system_profiler SPHardwareDataType | grep "Chip\|Memory:"
```
You should see something like `Chip: Apple M2 Pro` and `Memory: 32 GB`. If your chip says "Intel", the provider agent won't run on your machine.
The minimum RAM required varies by model. Most models in the catalog need at least 36 GB. Check the [model catalog](/introduction#available-models) before downloading.
Run the one-line installer. It downloads and installs the `darkbloom` binary, a bundled Python 3.12 runtime, vllm-mlx, and the Secure Enclave tooling. No prerequisites required.
```bash theme={null}
curl -fsSL https://api.darkbloom.dev/install.sh | bash
```
The installer places the `darkbloom` binary on your `PATH`. Once it finishes, confirm the installation worked:
```bash theme={null}
darkbloom --version
```
Your Mac needs to be associated with your Darkbloom account so earnings can be credited to you. Run the login command, which starts a device authorization flow:
```bash theme={null}
darkbloom login
```
You'll see a short code and a URL. Open the URL in your browser, sign in to your Darkbloom account, and approve the device. The CLI polls for confirmation and exits once the link is established.
If you don't have a Darkbloom account yet, go to [darkbloom.dev](https://darkbloom.dev) and sign up first.
List the models available to download based on your hardware:
```bash theme={null}
darkbloom models list
```
The output shows each model's RAM requirement alongside your available unified memory. Pick a model your Mac can fit, then start serving. The first run downloads the model weights — expect this to take several minutes depending on your connection.
```bash theme={null}
darkbloom serve
```
`darkbloom serve` runs in the foreground and prints connection status and request throughput. To run as a background daemon instead:
```bash theme={null}
darkbloom start
```
On a 36 GB Mac, `qwen3.5-27b-claude-opus-8bit` (27 GB) or `mlx-community/gemma-4-26b-a4b-it-8bit` (28 GB) are good fits. On a 128 GB Mac, `mlx-community/Qwen3.5-122B-A10B-8bit` unlocks the highest-quality tier.
Once the provider is running, use these commands to monitor it.
**Connection and hardware status:**
```bash theme={null}
darkbloom status
```
This shows your chip, available memory, current model, and whether you're connected to the coordinator.
**Earnings:**
```bash theme={null}
darkbloom earnings
```
This shows your total earnings and a breakdown by session.
**Diagnose problems:**
```bash theme={null}
darkbloom doctor
```
`darkbloom doctor` runs a series of checks — SIP status, Secure Boot, memory, network connectivity — and reports any issues that would prevent the provider from attesting correctly.
## Managing the daemon
```bash theme={null}
darkbloom start # start as background daemon
darkbloom stop # stop the daemon
darkbloom status # hardware and connection info
darkbloom update # check for and apply updates
```
## Scheduling availability windows
By default the provider runs whenever `darkbloom start` is active. You can restrict it to specific hours so it only serves during times you're not using your Mac. Edit `~/.config/eigeninference/provider.toml`:
```toml theme={null}
[schedule]
enabled = true
[[schedule.windows]]
days = ["mon", "tue", "wed", "thu", "fri"]
start = "22:00"
end = "08:00"
```
Outside the scheduled windows, the provider disconnects and shuts down the inference backend, freeing GPU memory for your own use.
## macOS menu bar app
A native SwiftUI menu bar app is also available if you prefer a GUI. It provides one-click start/stop, a live throughput display, idle detection (pauses automatically when you're actively using your Mac), and an earnings dashboard. You can download it from [darkbloom.dev](https://darkbloom.dev).
Darkbloom is an experimental research prototype. Provider software may have breaking changes between releases. Run `darkbloom update` regularly to stay current.
# API key management — POST and DELETE /v1/auth/keys
Source: https://docs.darkbloom.dev/reference/api-keys
POST /v1/auth/keys creates a new API key; DELETE /v1/auth/keys revokes one. Both require an interactive Privy browser session — API key auth is not accepted.
These endpoints create and revoke Darkbloom API keys. Both operations require an interactive Privy session, which means they must be performed through a browser-based login flow. You cannot use an existing API key to create or revoke other keys.
API key creation requires browser-based authentication via Privy. You cannot create API keys programmatically using an existing API key — this restriction prevents a leaked key from minting new long-lived credentials.
## Creating API keys
The recommended way to create an API key is through the Darkbloom web console at [darkbloom.dev](https://darkbloom.dev). Log in with your Privy account, navigate to Settings, and generate a new key there.
### POST /v1/auth/keys
Creates a new API key linked to the authenticated Privy account. All inference requests made with the returned key are billed to the same account.
**Authentication:** Privy session token (browser login). API key auth is rejected.
#### Response
The new API key. Keys always start with `eigeninference-`. Store it securely — it is not shown again.
The account ID the key is linked to.
## Revoking API keys
### DELETE /v1/auth/keys
Revokes an existing API key. You can only revoke keys that belong to your own account. A revoked key is immediately invalidated — in-flight requests using it will fail.
**Authentication:** Privy session token (browser login). API key auth is rejected.
#### Request body
The API key to revoke, e.g. `"eigeninference-..."`.
#### Response
Always `"revoked"` on success.
## Example (web console)
Sign in at [darkbloom.dev](https://darkbloom.dev) and navigate to **Settings → API Keys** to create or revoke keys interactively.
# Provider attestation — GET /v1/providers/attestation
Source: https://docs.darkbloom.dev/reference/attestation
GET /v1/providers/attestation — public attestation data. No auth required. Returns trust level, SE public key, and MDA chain for independent verification.
The attestation endpoint returns cryptographic attestation data for every provider currently connected to the network. No authentication is required — this data is intentionally public so that any third party can independently verify the hardware and security posture of the providers that are serving inference requests.
For hardware-attested providers, the response includes the full Apple Managed Device Attestation (MDA) certificate chain. You can verify this chain against Apple's Enterprise Attestation Root CA to confirm that Apple has certified the device properties independently of Darkbloom.
## Authentication
Not required. This endpoint is public.
## Response
Array of attestation records, one per connected provider.
Internal provider identifier.
The verified trust level for this provider.
* `"self_signed"` — Secure Enclave signature and periodic challenge-response verified. The coordinator confirms the device is running an unmodified binary with SIP and Secure Boot active.
* `"hardware"` — All of the above, plus Apple MDM cross-verification and an Apple MDA certificate chain signed by Apple's Enterprise Attestation Root CA.
Current provider status. `"online"` when the provider is accepting requests.
Apple Silicon chip name as reported during attestation, e.g. `"Apple M3 Max"`.
Mac hardware model identifier, e.g. `"Mac14,6"`.
Device serial number from the Secure Enclave attestation.
Unified memory size in GB.
GPU core count.
Model IDs this provider is currently serving.
Whether the Secure Enclave is present and was used during attestation.
Whether System Integrity Protection was verified as enabled at attestation time.
Whether Secure Boot was verified as enabled.
Whether Authenticated Root (sealed system volume) was verified as enabled.
The provider's Secure Enclave P-256 public key in base64. Use this to verify the `x-se-signature` and `x-response-hash` values from inference responses, confirming that the response was produced by this specific device.
Whether Apple MDM SecurityInfo cross-checked this device's hardware integrity (SIP, Secure Boot, FileVault).
Whether the ACME device-attest-01 challenge proved the Secure Enclave key belongs to a genuine Apple device.
Whether Apple Managed Device Attestation was verified with a certificate chain from Apple's Enterprise Attestation Root CA.
DER-encoded certificates in the MDA chain, each base64-encoded. Present only for `mda_verified: true` providers. Decode each entry from base64 to DER, then verify the chain against Apple's Enterprise Attestation Root CA (see below).
Device serial number from the MDA certificate. Should match `serial_number`.
Device UDID from the MDA certificate.
macOS version reported in the MDA certificate.
Secure Enclave OS version reported in the MDA certificate.
URL to Apple's Certificate Authority page where you can download the Enterprise Attestation Root CA.
Name of the CA to verify against: `"Apple Enterprise Attestation Root CA"`.
Human-readable instructions for verifying the MDA certificate chain.
## Independent verification
To verify a hardware-attested provider using the MDA certificate chain:
1. Fetch the attestation data from `GET /v1/providers/attestation`.
2. For each provider with `mda_verified: true`, take the `mda_cert_chain_b64` array.
3. Decode each element from base64 to its raw DER bytes.
4. Download the Apple Enterprise Attestation Root CA from [apple.com/certificateauthority](https://www.apple.com/certificateauthority/).
5. Verify the DER chain against the root CA using any standard X.509 library.
If verification passes, Apple has independently confirmed that the device is a genuine Apple device with the attested hardware properties.
## Example
```bash cURL theme={null}
curl https://api.darkbloom.dev/v1/providers/attestation
```
### Example response
```json theme={null}
{
"providers": [
{
"provider_id": "prov_a1b2c3d4",
"trust_level": "hardware",
"status": "online",
"chip_name": "Apple M3 Max",
"hardware_model": "Mac14,6",
"serial_number": "FVFXYZ123456",
"memory_gb": 128,
"gpu_cores": 40,
"models": ["qwen3.5-27b-claude-opus-8bit"],
"secure_enclave": true,
"sip_enabled": true,
"secure_boot_enabled": true,
"authenticated_root_enabled": true,
"se_public_key": "BHv9k2...base64...",
"mdm_verified": true,
"acme_verified": true,
"mda_verified": true,
"mda_cert_chain_b64": [
"MIIBxTCCAW...base64...",
"MIICSzCCAd...base64..."
],
"mda_serial": "FVFXYZ123456",
"mda_udid": "00001234-000A1234B1234567",
"mda_os_version": "14.5",
"mda_sepos_version": "20.100.5"
},
{
"provider_id": "prov_e5f6g7h8",
"trust_level": "self_signed",
"status": "online",
"chip_name": "Apple M2",
"hardware_model": "Mac13,2",
"serial_number": "C02XY1234567",
"memory_gb": 32,
"gpu_cores": 19,
"models": ["mlx-community/gemma-4-26b-a4b-it-8bit"],
"secure_enclave": true,
"sip_enabled": true,
"secure_boot_enabled": true,
"authenticated_root_enabled": true,
"se_public_key": "BKm3p7...base64...",
"mdm_verified": false,
"acme_verified": false,
"mda_verified": false
}
],
"apple_root_ca_url": "https://www.apple.com/certificateauthority/",
"apple_enterprise_root_ca": "Apple Enterprise Attestation Root CA",
"verification_instructions": "Download each provider's mda_cert_chain_b64, decode from base64 to DER, then verify the certificate chain against Apple's Enterprise Attestation Root CA. If verification passes, Apple has confirmed this is a real Apple device with the attested properties."
}
```
# Account balance — GET /v1/payments/balance
Source: https://docs.darkbloom.dev/reference/balance
GET /v1/payments/balance — returns your current account balance. Returns balance_micro_usd, balance_usd, withdrawable_micro_usd, and withdrawable_usd.
The balance endpoint returns your current account balance in both micro-USD (integer) and USD (string). Balances are credited when you deposit via the Darkbloom console and debited after each inference request completes.
`balance_micro_usd` is the canonical value — all internal billing uses micro-USD to avoid floating-point rounding errors. The `balance_usd` string is a human-readable convenience field formatted to six decimal places.
`withdrawable_micro_usd` reflects funds that can be withdrawn (for provider earnings). This will be zero for consumer-only accounts.
## Authentication
This endpoint requires a Bearer token:
```
Authorization: Bearer eigeninference-...
```
## Response
Your current balance in micro-USD (1 USD = 1,000,000 micro-USD). Use this value for precise balance comparisons and cost calculations.
Your current balance as a USD string formatted to six decimal places, e.g. `"1.250000"`.
The portion of your balance available for withdrawal, in micro-USD. For consumer accounts this is typically `0`.
Withdrawable balance as a USD string formatted to six decimal places.
## Example
```bash cURL theme={null}
curl https://api.darkbloom.dev/v1/payments/balance \
-H "Authorization: Bearer eigeninference-..."
```
### Example response
```json theme={null}
{
"balance_micro_usd": 4750000,
"balance_usd": "4.750000",
"withdrawable_micro_usd": 0,
"withdrawable_usd": "0.000000"
}
```
# Chat completions — POST /v1/chat/completions
Source: https://docs.darkbloom.dev/reference/chat-completions
POST /v1/chat/completions — generates replies from a message history. Accepts model, messages, stream, temperature. Returns a chat completion or SSE stream.
The chat completions endpoint is the primary way to run inference on Darkbloom. It is fully compatible with the OpenAI Chat Completions API, so any OpenAI SDK works by setting the base URL to `https://api.darkbloom.dev/v1`. The coordinator routes your request to a hardware-attested Apple Silicon provider, encrypts the request body with the provider's X25519 key before forwarding it, and returns the response through the standard OpenAI response shape.
Every response includes provider attestation headers so you can independently verify the hardware that served your request.
`POST /v1/responses` is an alias for the [OpenAI Responses API](https://platform.openai.com/docs/api-reference/responses). The coordinator auto-detects whether the body uses `input` (Responses format) or `messages` (Chat Completions format) and routes through the same handler.
## Authentication
All inference endpoints require a Bearer token. Pass your API key in the `Authorization` header:
```
Authorization: Bearer eigeninference-...
```
Get your API key from the [Darkbloom console](https://darkbloom.dev).
## Request
The model ID to use for this request. See [Models](/reference/models) for the list of available model IDs.
Example: `"qwen3.5-27b-claude-opus-8bit"`
The conversation history as an array of message objects. Each object must have a `role` and a `content` field.
* `role` — `"system"`, `"user"`, or `"assistant"`
* `content` — the message text (string)
When `true`, the response is delivered as a stream of Server-Sent Events (SSE). Each event carries a `data:` field with a JSON chunk. The stream ends with `data: [DONE]`.
Maximum number of tokens to generate. If not set, the coordinator injects a default of 8192 to bound the worst-case cost. Set this explicitly if you need longer generations.
Sampling temperature between 0 and 2. Higher values make output more random; lower values make it more deterministic.
Nucleus sampling parameter. The model considers only the tokens comprising the top `top_p` probability mass.
One or more sequences at which generation stops. The stop sequence itself is not included in the output.
Fixed random seed for reproducible outputs. Two requests with the same seed and parameters will produce identical results when served by the same provider.
## Response (non-streaming)
Unique identifier for the request.
Always `"chat.completion"` for non-streaming responses.
Array of completion choices. Standard requests return exactly one choice.
The generated message.
Always `"assistant"`.
The generated text.
Why generation stopped. `"stop"` means the model reached a natural end; `"length"` means `max_tokens` was reached.
Token counts for the request.
Tokens consumed by the input messages.
Tokens generated in the response.
Sum of prompt and completion tokens.
## Streaming
When `stream: true`, the response is a sequence of SSE events:
```
data: {"id":"...","object":"chat.completion.chunk","choices":[{"delta":{"content":"Hello"},"finish_reason":null}]}
data: {"id":"...","object":"chat.completion.chunk","choices":[{"delta":{"content":" world"},"finish_reason":null}]}
data: [DONE]
```
Just before `[DONE]`, the coordinator may emit a final event carrying the provider's Secure Enclave signature over the response hash:
```json theme={null}
{"choices":[],"se_signature":"","response_hash":""}
```
## Response headers
Every response (streaming and non-streaming) includes attestation headers that describe the provider that served the request.
| Header | Description |
| ----------------------------- | ------------------------------------------------------------------------------------- |
| `X-Provider-Attested` | `"true"` if the provider passed the most recent challenge-response attestation cycle |
| `X-Provider-Trust-Level` | `"self_signed"` or `"hardware"` — the provider's verified trust level |
| `X-Provider-Chip` | Apple Silicon chip name, e.g. `"Apple M3 Max"` |
| `X-Provider-Id` | Internal provider identifier |
| `X-Provider-Model` | Mac hardware model identifier |
| `X-Provider-Serial` | Provider device serial number |
| `X-Provider-Secure-Enclave` | `"true"` if the provider has a Secure Enclave |
| `X-Provider-Mda-Verified` | `"true"` if Apple MDA hardware attestation was verified |
| `X-Attestation-Se-Public-Key` | Provider's Secure Enclave P-256 public key (base64) |
| `X-Attestation-Device-Serial` | Device serial matching the attestation record |
| `X-Inference-Job-ID` | Job UUID for this request, useful for correlating with usage records (streaming only) |
## Examples
```bash cURL (non-streaming) theme={null}
curl https://api.darkbloom.dev/v1/chat/completions \
-H "Authorization: Bearer eigeninference-..." \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.5-27b-claude-opus-8bit",
"messages": [
{"role": "user", "content": "Explain what a Merkle tree is."}
],
"max_tokens": 512
}'
```
```bash cURL (streaming) theme={null}
curl https://api.darkbloom.dev/v1/chat/completions \
-H "Authorization: Bearer eigeninference-..." \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.5-27b-claude-opus-8bit",
"messages": [
{"role": "user", "content": "Explain what a Merkle tree is."}
],
"stream": true
}'
```
```python Python (OpenAI SDK) theme={null}
from openai import OpenAI
client = OpenAI(
base_url="https://api.darkbloom.dev/v1",
api_key="eigeninference-..."
)
response = client.chat.completions.create(
model="qwen3.5-27b-claude-opus-8bit",
messages=[
{"role": "user", "content": "Explain what a Merkle tree is."}
],
max_tokens=512,
)
print(response.choices[0].message.content)
```
```python Python (streaming) theme={null}
from openai import OpenAI
client = OpenAI(
base_url="https://api.darkbloom.dev/v1",
api_key="eigeninference-..."
)
stream = client.chat.completions.create(
model="qwen3.5-27b-claude-opus-8bit",
messages=[
{"role": "user", "content": "Explain what a Merkle tree is."}
],
stream=True,
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
```
```javascript Node.js (OpenAI SDK) theme={null}
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.darkbloom.dev/v1",
apiKey: "eigeninference-...",
});
const response = await client.chat.completions.create({
model: "qwen3.5-27b-claude-opus-8bit",
messages: [
{ role: "user", content: "Explain what a Merkle tree is." },
],
max_tokens: 512,
});
console.log(response.choices[0].message.content);
```
```javascript Node.js (streaming) theme={null}
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.darkbloom.dev/v1",
apiKey: "eigeninference-...",
});
const stream = await client.chat.completions.create({
model: "qwen3.5-27b-claude-opus-8bit",
messages: [
{ role: "user", content: "Explain what a Merkle tree is." },
],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
```
### Example response
```json theme={null}
{
"id": "a3f1c2e7-84bb-4d9a-91f3-2b7e6d4a0c18",
"object": "chat.completion",
"choices": [
{
"message": {
"role": "assistant",
"content": "A Merkle tree is a hash-based data structure where every leaf node contains the hash of a data block, and every non-leaf node contains the hash of its child nodes..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 14,
"completion_tokens": 87,
"total_tokens": 101
}
}
```
# Text completions — POST /v1/completions
Source: https://docs.darkbloom.dev/reference/completions
POST /v1/completions — legacy text completion endpoint. Accepts model, prompt, max_tokens, temperature, and stream. Returns a completion object or SSE stream.
The text completions endpoint is a legacy OpenAI-compatible endpoint that generates a continuation of a raw text prompt rather than a structured message history. It is routed through the same provider dispatch pipeline as [chat completions](/reference/chat-completions), so the same attestation headers and streaming format apply.
For most use cases, prefer [POST /v1/chat/completions](/reference/chat-completions), which is the actively developed endpoint with full tool-call and response-format support.
## Authentication
All inference endpoints require a Bearer token:
```
Authorization: Bearer eigeninference-...
```
## Request
The model ID to use. See [Models](/reference/models) for the list of available IDs.
The input text to complete.
Maximum number of tokens to generate. Defaults to 8192 if not set.
Sampling temperature between 0 and 2.
When `true`, returns the response as SSE chunks ending with `data: [DONE]`.
## Example
```bash cURL theme={null}
curl https://api.darkbloom.dev/v1/completions \
-H "Authorization: Bearer eigeninference-..." \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.5-27b-claude-opus-8bit",
"prompt": "The capital of France is",
"max_tokens": 16
}'
```
# Anthropic Messages API — POST /v1/messages
Source: https://docs.darkbloom.dev/reference/messages
POST /v1/messages — Anthropic-compatible endpoint. Accepts model, messages, max_tokens, and system. Returns an Anthropic-format content array response.
The messages endpoint implements the Anthropic Messages API format, letting you use the official Anthropic SDK with Darkbloom by pointing it at `https://api.darkbloom.dev`. The request and response shapes follow the Anthropic API specification; the coordinator routes the request through the same provider dispatch and attestation pipeline as all other inference endpoints.
## Authentication
All inference endpoints require a Bearer token:
```
Authorization: Bearer eigeninference-...
```
When using the Anthropic SDK, pass your Darkbloom API key as the `api_key` argument alongside the custom `base_url`.
## Request
The model ID to use. See [Models](/reference/models) for the list of available IDs.
The conversation as an array of message objects. Each object must have:
* `role` — `"user"` or `"assistant"`
* `content` — the message text (string)
Maximum number of tokens to generate. Required in Anthropic format.
An optional system prompt that sets context or persona for the assistant.
## Response
The response follows the Anthropic response shape with a `content` array.
Unique identifier for the request.
Always `"message"`.
Always `"assistant"`.
Array of content blocks. Text responses contain a single block with `type: "text"`.
Content block type. `"text"` for standard responses.
The generated text (present when `type` is `"text"`).
Why generation stopped. `"end_turn"` for natural completion; `"max_tokens"` if the token limit was reached.
Tokens consumed by the input.
Tokens generated in the response.
## Examples
```python Python (Anthropic SDK) theme={null}
import anthropic
client = anthropic.Anthropic(
base_url="https://api.darkbloom.dev",
api_key="eigeninference-...",
)
message = client.messages.create(
model="qwen3.5-27b-claude-opus-8bit",
max_tokens=512,
system="You are a helpful assistant.",
messages=[
{"role": "user", "content": "What is the difference between a process and a thread?"}
],
)
print(message.content[0].text)
```
```bash cURL theme={null}
curl https://api.darkbloom.dev/v1/messages \
-H "Authorization: Bearer eigeninference-..." \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.5-27b-claude-opus-8bit",
"max_tokens": 512,
"system": "You are a helpful assistant.",
"messages": [
{"role": "user", "content": "What is the difference between a process and a thread?"}
]
}'
```
### Example response
```json theme={null}
{
"id": "msg_01XFDUDYJgAACTvhG8fDDBEc",
"type": "message",
"role": "assistant",
"content": [
{
"type": "text",
"text": "A process is an independent program with its own memory space..."
}
],
"stop_reason": "end_turn",
"usage": {
"input_tokens": 22,
"output_tokens": 94
}
}
```
# Available models — GET /v1/models
Source: https://docs.darkbloom.dev/reference/models
GET /v1/models — returns available inference models with provider count, attestation status, and trust level. Compatible with OpenAI's model list format.
The models endpoint returns the set of models currently available across the Darkbloom provider network. The response extends the OpenAI model list format with Darkbloom-specific metadata: how many providers are serving each model, whether any of those providers are attested, and their aggregate trust level.
Use this endpoint to discover which model IDs are valid for inference requests and to check real-time network availability before sending a request.
## Authentication
This endpoint requires a Bearer token:
```
Authorization: Bearer eigeninference-...
```
## Response
Always `"list"`.
Array of model objects.
The model ID to use in inference requests. Pass this value as the `model` field in [chat completions](/reference/chat-completions) and other inference endpoints.
Always `"model"`.
Always `"eigeninference"`.
Darkbloom-specific metadata for the model.
The model category. `"text"` for language models.
The quantization format in use, e.g. `"8bit"`.
Number of providers currently connected and serving this model.
Number of providers for this model that have passed attestation.
The highest trust level across all providers for this model. `"self_signed"` or `"hardware"`.
Human-readable model name.
## Available models
| Model ID | Display name | Architecture |
| --------------------------------------- | ----------------------------- | -------------------------------- |
| `qwen3.5-27b-claude-opus-8bit` | Qwen3.5 27B Claude Opus 8-bit | 27B dense, Claude Opus distilled |
| `mlx-community/gemma-4-26b-a4b-it-8bit` | Gemma 4 26B 8-bit | 26B MoE, 4B active |
| `mlx-community/Trinity-Mini-8bit` | Trinity Mini 8-bit | 27B Adaptive MoE |
| `mlx-community/Qwen3.5-122B-A10B-8bit` | Qwen3.5 122B MoE 8-bit | 122B MoE, 10B active |
| `mlx-community/MiniMax-M2.5-8bit` | MiniMax M2.5 8-bit | 239B MoE, 11B active |
## Example
```bash cURL theme={null}
curl https://api.darkbloom.dev/v1/models \
-H "Authorization: Bearer eigeninference-..."
```
### Example response
```json theme={null}
{
"object": "list",
"data": [
{
"id": "qwen3.5-27b-claude-opus-8bit",
"object": "model",
"created": 0,
"owned_by": "eigeninference",
"metadata": {
"model_type": "text",
"quantization": "8bit",
"provider_count": 3,
"attested_providers": 2,
"trust_level": "hardware",
"display_name": "Qwen3.5 27B Claude Opus 8-bit"
}
},
{
"id": "mlx-community/gemma-4-26b-a4b-it-8bit",
"object": "model",
"created": 0,
"owned_by": "eigeninference",
"metadata": {
"model_type": "text",
"quantization": "8bit",
"provider_count": 5,
"attested_providers": 5,
"trust_level": "hardware",
"display_name": "Gemma 4 26B 8-bit"
}
},
{
"id": "mlx-community/Qwen3.5-122B-A10B-8bit",
"object": "model",
"created": 0,
"owned_by": "eigeninference",
"metadata": {
"model_type": "text",
"quantization": "8bit",
"provider_count": 1,
"attested_providers": 1,
"trust_level": "hardware",
"display_name": "Qwen3.5 122B MoE 8-bit"
}
}
]
}
```
# Network stats — /v1/stats, /v1/leaderboard
Source: https://docs.darkbloom.dev/reference/stats
Public endpoints for Darkbloom network statistics. No auth required. Returns active providers, token totals, leaderboard rankings, and network-wide totals.
These three endpoints expose public, read-only statistics about the Darkbloom network. No authentication is required. They power the network dashboard on [darkbloom.dev](https://darkbloom.dev) and are suitable for building external monitoring tools or status pages.
## GET /v1/stats
Returns aggregate platform statistics for all currently connected providers, including hardware totals, token counts, and a 30-minute time series. Cached for 60 seconds.
### Response
Cumulative number of inference requests served across the network lifetime.
Cumulative input tokens consumed across all requests.
Cumulative output tokens generated across all requests.
Sum of prompt and completion tokens.
Average token count per request.
Number of providers currently connected.
Total GPU cores across all connected providers.
Total CPU cores across all connected providers.
Total unified memory in GB across all connected providers.
Total memory bandwidth in GB/s across all connected providers.
Array of per-provider hardware and stats snapshots.
Internal provider identifier.
Apple Silicon chip name, e.g. `"Apple M3 Max"`.
Chip family, e.g. `"M3"`.
Unified memory size in GB.
GPU core count.
Provider status. `"online"` when available for requests.
Attestation trust level: `"self_signed"` or `"hardware"`.
Most recently observed decode throughput in tokens per second.
Requests served by this provider in the current session.
Tokens generated by this provider in the current session.
Model IDs this provider is serving.
The model currently loaded on this provider.
Aggregated per-model provider counts.
Model ID.
Number of providers currently serving this model.
Per-minute request and token counts for the last 30 minutes.
ISO 8601 UTC timestamp for the minute bucket.
Requests completed in this minute.
Input tokens consumed in this minute.
Output tokens generated in this minute.
Total tokens in this minute.
***
## GET /v1/leaderboard
Returns the top providers ranked by earnings, tokens generated, or jobs completed. Provider identities are pseudonymized — raw account IDs are never exposed. Cached for 5 minutes.
### Query parameters
The ranking metric. One of `"earnings"`, `"tokens"`, or `"jobs"`.
The time window for rankings. One of `"24h"`, `"7d"`, `"30d"`, or `"all"`.
Maximum number of entries to return. Between 1 and 200.
### Response
The metric used for ranking.
The time window used.
Ranked list of providers.
Position in the leaderboard (1-indexed).
Pseudonymized provider identifier derived deterministically from the account ID.
Total earnings in micro-USD for the selected window.
Total tokens generated for the selected window.
Total inference jobs completed for the selected window.
ISO 8601 timestamp of when this response was generated.
***
## GET /v1/network/totals
Returns aggregate network metrics (earnings, tokens, jobs, active accounts) for a given time window. Cached for 1 minute.
### Query parameters
The time window. One of `"24h"`, `"7d"`, `"30d"`, or `"all"`.
### Response
The time window used.
Total provider earnings in micro-USD for the window.
Total tokens generated for the window.
Total inference jobs completed for the window.
Number of distinct accounts active in the window.
ISO 8601 timestamp of when this response was generated.
## Examples
```bash GET /v1/stats theme={null}
curl https://api.darkbloom.dev/v1/stats
```
```bash GET /v1/leaderboard theme={null}
curl "https://api.darkbloom.dev/v1/leaderboard?metric=earnings&window=7d&limit=10"
```
```bash GET /v1/network/totals theme={null}
curl "https://api.darkbloom.dev/v1/network/totals?window=24h"
```
### Example /v1/stats response
```json theme={null}
{
"total_requests": 142893,
"total_prompt_tokens": 89234120,
"total_completion_tokens": 31047880,
"total_tokens": 120282000,
"avg_tokens_per_request": 841.7,
"active_providers": 12,
"total_gpu_cores": 480,
"total_cpu_cores": 192,
"total_memory_gb": 768,
"total_bandwidth_gbs": 9828.0,
"providers": [...],
"models": [
{"id": "qwen3.5-27b-claude-opus-8bit", "providers": 4},
{"id": "mlx-community/gemma-4-26b-a4b-it-8bit", "providers": 5}
],
"time_series": [...]
}
```
### Example /v1/leaderboard response
```json theme={null}
{
"metric": "earnings",
"window": "7d",
"entries": [
{
"rank": 1,
"pseudonym": "SwiftFalcon",
"earnings_micro_usd": 8420000,
"tokens": 91234567,
"jobs": 4821
},
{
"rank": 2,
"pseudonym": "IronHawk",
"earnings_micro_usd": 6150000,
"tokens": 67012345,
"jobs": 3640
}
],
"updated_at": "2025-04-30T15:00:00Z"
}
```
### Example /v1/network/totals response
```json theme={null}
{
"window": "24h",
"earnings_micro_usd": 12480000,
"tokens": 148203450,
"jobs": 7923,
"active_accounts": 38,
"updated_at": "2025-04-30T15:01:00Z"
}
```
# Usage history — GET /v1/payments/usage
Source: https://docs.darkbloom.dev/reference/usage
GET /v1/payments/usage — returns your inference usage history. Each entry includes model, token counts, cost in micro-USD, and a timestamp.
The usage endpoint returns your inference usage history as an array of per-request records. Each record shows the model used, the token counts, the cost charged, and the timestamp of the request. This data is useful for auditing your spending, tracking usage patterns by model, and reconciling costs.
## Authentication
This endpoint requires a Bearer token:
```
Authorization: Bearer eigeninference-...
```
## Response
Array of usage entries, most recent first.
The internal job UUID for this inference request. Matches the `X-Inference-Job-ID` header returned on streaming responses.
The model ID used for this request.
Number of input tokens consumed.
Number of output tokens generated.
The cost charged for this request in micro-USD.
ISO 8601 timestamp of when the request was completed.
## Example
```bash cURL theme={null}
curl https://api.darkbloom.dev/v1/payments/usage \
-H "Authorization: Bearer eigeninference-..."
```
### Example response
```json theme={null}
{
"usage": [
{
"request_id": "a3f1c2e7-84bb-4d9a-91f3-2b7e6d4a0c18",
"model": "qwen3.5-27b-claude-opus-8bit",
"prompt_tokens": 14,
"completion_tokens": 87,
"cost_micro_usd": 72,
"timestamp": "2025-04-30T14:22:07Z"
},
{
"request_id": "b7d3e9f1-21cc-4a8b-85e2-9c4d1a7f3b22",
"model": "mlx-community/gemma-4-26b-a4b-it-8bit",
"prompt_tokens": 32,
"completion_tokens": 210,
"cost_micro_usd": 44,
"timestamp": "2025-04-30T13:05:41Z"
}
]
}
```
# Verifying provider attestation on Darkbloom
Source: https://docs.darkbloom.dev/security/attestation
Darkbloom's four-layer attestation proves every provider's security posture is intact. Learn how to verify attestation data and read per-request trust headers.
Attestation is the mechanism by which Darkbloom proves, cryptographically, that a provider Mac has not been tampered with before your request is routed to it. Rather than asking you to trust that a provider has the right security configuration, the system produces machine-verifiable evidence that is checked before every session and refreshed continuously while inference runs. This page explains what that evidence consists of, how it is verified, and how you can inspect it yourself.
## What attestation proves
A fully attested provider has demonstrated all of the following to the coordinator:
1. It is running a **blessed binary** — a provider build whose SHA-256 hash matches a coordinator-approved release.
2. Its **Secure Enclave** has produced a hardware-bound P-256 keypair and a signed attestation blob tied to that specific piece of hardware.
3. **MDM SecurityInfo** has been cross-checked via Apple MDM to confirm SIP, Secure Boot, and FileVault are all enabled on the machine.
4. An **Apple Managed Device Attestation (MDA)** certificate chain — rooted at Apple's Enterprise Attestation Root CA — has been verified, meaning Apple has independently vouched for the device's hardware integrity.
## Four layers of verification
Every provider generates a hardware-bound P-256 identity inside the Secure Enclave — a dedicated security processor that is isolated from the main CPU and operating system. The private key never leaves the enclave. The coordinator uses the corresponding public key to verify attestation blobs that only that specific Mac can produce.
Providers enroll in an MDM profile. The coordinator uses Apple's MDM SecurityInfo API to independently check that SIP (System Integrity Protection), Secure Boot, and FileVault are all enabled. This check runs from outside the provider process, so the provider cannot manipulate the result.
For hardware-attested providers, the coordinator verifies a certificate chain issued through Apple's Managed Device Attestation program and rooted at the Apple Enterprise Attestation Root CA. This means Apple itself has cryptographically vouched for the device's hardware. See [Trust levels](/security/trust-levels) for what this means for your requests.
Attestation is not a one-time check at startup. The coordinator sends a fresh challenge to every connected provider every 5 minutes. The provider must re-demonstrate its SIP and Secure Boot status. If a provider's security posture changes — for example if someone rebooted into recovery mode and disabled SIP — it would fail the next challenge and be removed from the routing pool.
## Verifying attestation yourself
Attestation data for all active providers is publicly accessible with no authentication required:
```bash theme={null}
curl https://api.darkbloom.dev/v1/providers/attestation
```
The response contains the attestation blobs, public keys, and certificate chains for each provider. You can independently verify the Apple MDA certificate chain against Apple's published root CA.
## Per-request trust headers
Every API response from Darkbloom includes headers that tell you exactly which provider served your request and what its trust level was at the time:
| Header | Description |
| ------------------------ | --------------------------------------------------------- |
| `x-provider-attested` | `true` if the provider was attested when your request ran |
| `x-provider-trust-level` | Trust level: `self_signed` or `hardware` |
| `x-se-signature` | Secure Enclave signature over the response |
| `x-response-hash` | SHA-256 hash of the response body |
| `x-se-public-key` | The provider's Secure Enclave public key |
### Reading trust headers from a response
```bash curl theme={null}
curl -i https://api.darkbloom.dev/v1/chat/completions \
-H "Authorization: Bearer $DARKBLOOM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"mlx-community/gemma-4-26b-a4b-it-8bit","messages":[{"role":"user","content":"Hello"}]}'
```
```python Python theme={null}
import httpx
response = httpx.post(
"https://api.darkbloom.dev/v1/chat/completions",
headers={"Authorization": "Bearer eigeninference-your-key-here"},
json={
"model": "mlx-community/gemma-4-26b-a4b-it-8bit",
"messages": [{"role": "user", "content": "Hello"}],
},
)
print(response.headers.get("x-provider-trust-level"))
print(response.headers.get("x-provider-attested"))
print(response.headers.get("x-se-signature"))
```
An example response header set looks like:
```
x-provider-attested: true
x-provider-trust-level: hardware
x-se-signature: MEUCIQD...
x-response-hash: sha256:a3f1...
x-se-public-key: MFkwEwYHKoZIzj0C...
```
The `x-se-signature` is a Secure Enclave signature over the response hash. You can verify it against the provider's `x-se-public-key` using standard P-256 ECDSA verification.
# How Darkbloom keeps your prompts private
Source: https://docs.darkbloom.dev/security/overview
Darkbloom uses E2E encryption, macOS Hardened Runtime, and Secure Enclave attestation so Mac owners running inference cannot read your prompts.
When you send a prompt to Darkbloom, it travels through a Mac you don't own, operated by someone with full root access and physical custody of the hardware. The core privacy guarantee of Darkbloom is that this person cannot read what you sent — not through software, not through the operating system, and not through attached debugging tools. This page explains how that guarantee is constructed and what it means for you in practice.
## The threat model
The machine owner has administrator privileges on their Mac. Without protections, they could in principle attach a debugger to the inference process, read process memory, or intercept data as it arrives over the network. Darkbloom closes every one of those software paths:
* **Debugger attachment** is refused at the kernel level via `PT_DENY_ATTACH`. No process — not even root — can attach.
* **Memory inspection** is blocked by macOS Hardened Runtime, which prevents memory-reading APIs from returning inference process data.
* **Code injection** into the provider process is blocked by the same Hardened Runtime entitlements.
* **SIP (System Integrity Protection)** makes these protections immutable for the lifetime of the process. Disabling SIP requires a reboot, which terminates the provider process. There is no way to weaken the protections while inference is running.
The only remaining attack against a Darkbloom provider is physically probing the memory chips soldered into the Apple SoC package. This is the same residual threat model Apple accepts for Private Cloud Compute (Siri and Apple Intelligence).
## End-to-end encryption
Your request never travels to the provider in plaintext. Before the coordinator forwards any request, it re-encrypts the payload with the provider's **X25519 public key**. Only the hardened provider process holds the corresponding private key — so only that process can decrypt and run your prompt.
This means even if someone intercepted traffic between the coordinator and the provider, they would see ciphertext they cannot decrypt without the provider's private key, which never leaves the secured process.
## The coordinator runs in a Confidential VM
The Darkbloom coordinator — the routing and authentication layer your API requests first reach — runs inside a **Confidential VM using AMD SEV-SNP**. SEV-SNP encrypts the VM's memory so that even the hypervisor host cannot read coordinator state. This protects your request in transit before it is forwarded to the provider.
## Logs never contain prompt content
Coordinator logs record metadata — request IDs, model names, token counts, timestamps — but never prompt text or response content. You can verify the attestation of any provider at any time without authenticating (see [Attestation](/security/attestation)).
## Verifying security yourself
Every aspect of this security model is independently verifiable:
* **Attestation data** is public at `GET /v1/providers/attestation` — no API key required.
* **Per-request trust headers** on every API response let you confirm the provider that served your request was attested at the time it ran.
* **The binary hash** of every provider binary is verified by the coordinator before routing begins. Providers cannot run modified code.
For a deeper look at the cryptographic proof behind each provider's security claims, see [Attestation](/security/attestation) and [Trust levels](/security/trust-levels).
# Understanding provider trust levels on Darkbloom
Source: https://docs.darkbloom.dev/security/trust-levels
What self_signed and hardware trust levels mean for your privacy, how each is verified, and how to check the trust level of any inference response.
Not all providers on the Darkbloom network carry the same level of cryptographic assurance. The trust level attached to a provider tells you what verification has been performed on its hardware and security configuration — and therefore how strong the privacy guarantee is for requests routed to it. This page explains the two trust levels, how they differ, and what each means for your prompts.
## Trust levels at a glance
Verified by Secure Enclave attestation and periodic challenge-response. The provider's hardware identity is established and its security posture is re-checked every 5 minutes.
All `self_signed` checks, plus an Apple Managed Device Attestation certificate chain rooted at Apple's Enterprise Attestation Root CA. Apple has independently vouched for the device's integrity.
## self\_signed
A `self_signed` provider has passed the following verification:
* Its **Secure Enclave** has produced a hardware-bound P-256 identity and signed an attestation blob. The private key never leaves the enclave and is bound to that specific Mac's hardware.
* The coordinator has verified that the provider is running a **blessed binary** — a build whose SHA-256 hash matches a coordinator-approved release.
* A **periodic challenge-response** re-confirms SIP (System Integrity Protection) and Secure Boot status every 5 minutes. If the provider's security configuration changes, it is removed from routing.
This level provides strong assurance that the provider process cannot be debugged, its memory cannot be read by the Mac owner, and it is running unmodified code. The attestation is self-generated — meaning the cryptographic evidence originates from the device itself rather than from Apple.
## hardware
A `hardware` provider has passed all `self_signed` verification, and additionally:
* An **Apple Managed Device Attestation (MDA)** certificate chain has been verified, rooted at the **Apple Enterprise Attestation Root CA**. This certificate chain is issued by Apple and proves that Apple's infrastructure has independently verified the device's hardware identity and security posture.
This is the strongest trust level available. The difference from `self_signed` is that Apple — not just the device itself — has cryptographically vouched for the machine's integrity. An attacker who somehow compromised the provider binary or the attestation process would also need to forge an Apple-signed certificate chain to appear hardware-attested.
## What the trust level means for your privacy
Both trust levels provide the same runtime protections for your prompts: E2E encryption, Hardened Runtime, SIP-enforced anti-debugging, and binary hash verification. The trust level affects the **strength of the attestation evidence** backing those claims:
| | self\_signed | hardware |
| ------------------------------ | ------------ | -------- |
| Secure Enclave identity | Yes | Yes |
| Binary hash verified | Yes | Yes |
| Challenge-response every 5 min | Yes | Yes |
| MDM SecurityInfo check | Yes | Yes |
| Apple MDA certificate chain | No | Yes |
| Apple Enterprise Root CA | No | Yes |
You can check the trust level of the provider that served any request using the `x-provider-trust-level` response header. See [Attestation](/security/attestation) for the full list of per-request trust headers.
`self_signed` providers still provide meaningful privacy protection. The Secure Enclave and periodic challenge-response together make it cryptographically difficult — though not impossible — to mount an attestation forgery. `hardware` providers add Apple's independent verification on top of this.