No accounts. No API keys. No credit cards. Just sats and inference.
Owlrun is in public beta. This is live software handling real Bitcoin. Known risks:
Only load sats you're willing to lose. Start small — 100 sats (~$0.07) is enough to test.
Owlrun Chat lets you talk to AI models and pay per prompt with Bitcoin ecash. No signup, no accounts — your sats are your session.
Your browser holds ecash proofs (digital cash tokens) in local storage. When you send a prompt, the browser attaches those proofs to the request. The gateway verifies them, runs inference on a GPU node, and returns the AI response along with your change.
The gateway never holds your funds. It claims your proofs at the moment of inference and returns change in the same response. Zero custody.
Minibits — recommended. Available on iOS and Android. Supports cashuA and cashuB token formats.
Use Minibits to:
Phoenix — recommended. Scan the Lightning invoice QR in the chat to top up your browser wallet.
Any Lightning wallet works for top-up:
Your ecash lives only in this browser tab. If you close it without withdrawing, your sats are lost forever. No recovery. Always click "Withdraw" and scan the QR with your Cashu wallet before leaving.
One HTTP header. No API keys, no accounts, no CAPTCHA. Your agent pays in sats and gets inference. OpenAI-compatible — swap your base URL and add X-Cashu.
curl -X POST https://api.owlrun.me/v1/chat/completions \
-H "Content-Type: application/json" \
-H "X-Cashu: cashuAeyJ0b2..." \
-d '{"model":"qwen2.5:0.5b","messages":[{"role":"user","content":"Hello"}],"stream":true}'
Attach ecash proofs in the X-Cashu header. No API key needed. Change returned in the SSE stream. That's it.
The X-Cashu header carries a cashuA token — base64url-encoded JSON containing ecash proofs from our mint (mint.owlrun.me).
| Header | Value | Required |
|---|---|---|
X-Cashu | cashuA... (ecash token) | Yes |
Content-Type | application/json | Yes |
Authorization | Bearer owlr_buy_... | No — optional, for volume tracking & better rates |
cashu_change SSE event at the end of the stream.Change arrives as the last SSE event after inference completes:
data: {"model":"qwen2.5:0.5b","message":{"content":"Hello!"},"done":false}
data: {"model":"qwen2.5:0.5b","message":{"content":""},"done":true,...}
data: {"type":"cashu_change","token":"cashuAeyJ0b2...","change_sats":48}
Critical: Your SSE parser must NOT stop at "done":true. Keep reading until the stream closes to catch the change event.
If inference fails before starting (no nodes available, node rejected), your proofs are returned via the X-Cashu-Change response header — not SSE (streaming hasn't started).
| Endpoint | Method | Description |
|---|---|---|
/v1/chat/completions | POST | OpenAI-compatible chat inference (streaming) |
/v1/completions | POST | Completion inference |
/v1/models | GET | List available models with pricing (USD per million tokens) |
/v1/oracle/rate | GET | Current BTC/USD rate, margins, pricing formula |
/v1/beta/signup | POST | Get an API key (optional — for volume tracking & better rates) |
/v1/broadcasts | GET | System announcements |
/healthz | GET | Gateway liveness check (returns {"status":"ok"}) |
| Status | Meaning | Action |
|---|---|---|
| 400 | Invalid X-Cashu token | Check token format (must start with cashuA) |
| 401 | No payment method | Add X-Cashu header with ecash, or a valid Authorization: Bearer key |
| 402 | Proofs spent or invalid | Mint fresh ecash |
| 503 | No nodes available | Check X-Cashu-Change header for refund, retry |
import requests
import json
API = "https://api.owlrun.me"
TOKEN = "cashuAeyJ0b2..." # your ecash token
resp = requests.post(f"{API}/v1/chat/completions",
headers={
"X-Cashu": TOKEN,
"Content-Type": "application/json",
},
json={
"model": "qwen2.5:0.5b",
"messages": [{"role": "user", "content": "What is Bitcoin?"}],
"stream": True,
},
stream=True,
)
change_token = None
for line in resp.iter_lines():
if not line:
continue
text = line.decode()
if text.startswith("data: "):
text = text[6:]
try:
data = json.loads(text)
if data.get("type") == "cashu_change":
change_token = data["token"]
print(f"\nChange: {data['change_sats']} sats")
elif data.get("message", {}).get("content"):
print(data["message"]["content"], end="", flush=True)
except json.JSONDecodeError:
pass
# change_token contains your remaining sats — save it for next request
const resp = await fetch("https://api.owlrun.me/v1/chat/completions", {
method: "POST",
headers: {
"X-Cashu": "cashuAeyJ0b2...",
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "qwen2.5:0.5b",
messages: [{ role: "user", content: "What is Bitcoin?" }],
stream: true,
}),
});
const reader = resp.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop();
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed) continue;
const data = trimmed.startsWith("data: ") ? trimmed.slice(6) : trimmed;
try {
const parsed = JSON.parse(data);
if (parsed.type === "cashu_change") {
console.log(`\nChange: ${parsed.change_sats} sats`);
// Save parsed.token for next request
} else if (parsed.message?.content) {
process.stdout.write(parsed.message.content);
}
} catch {}
}
}
curl -N https://api.owlrun.me/v1/chat/completions \
-H "X-Cashu: cashuAeyJ0b2..." \
-H "Content-Type: application/json" \
-d '{"model":"qwen2.5:0.5b","messages":[{"role":"user","content":"Hello"}],"stream":true}'
Every sat is accounted for. Check the live rate and formula at /v1/oracle/rate.
| Item | Value |
|---|---|
| Minimum per job | 2 sats — anti-spam floor (1 to provider, 1 to gateway). Every request costs real sats, preventing micro-prompt flood attacks. |
| Gateway margin | Under 10% (9% inference + ~1% FX) |
| Provider share | 90%+ of every job |
| BTC/USD rate | 24h average, published daily at midnight UTC |
| Lightning fees | Paid by the party withdrawing (not per-job) |
Use the Lightning top-up in chat.owlrun.me — scan the QR with any Lightning wallet. Or send ecash from Minibits.
Your ecash proofs live in your browser's local storage. If you close the tab without withdrawing, the proofs are lost. Always withdraw first.
Yes. The API is OpenAI-compatible. Add the X-Cashu header with ecash proofs and you're good. See the code examples above.
Check GET /v1/models for the current list with live pricing. During beta, availability depends on connected provider nodes.
curl https://api.owlrun.me/v1/models | jq
{
"object": "list",
"data": [
{
"id": "qwen2.5:0.5b",
"object": "model",
"owned_by": "owlrun",
"pricing": {
"per_m_input_usd": 0.02,
"per_m_output_usd": 0.06
}
}
]
}
No. The gateway never holds your funds. Your ecash proofs are in your browser (or your agent's memory). The gateway claims proofs at the moment of inference and returns change in the same response. Zero custody.
2 sats per job — an anti-spam floor. Even on micro-prompts, 1 sat goes to the provider and 1 sat to the gateway. This "pay to play" minimum makes DDoS-by-microprompt economically unviable while keeping real usage nearly free.
No. Ecash is the only credential you need — sats are the CAPTCHA. Just add the X-Cashu header with valid proofs. API keys are optional — they unlock volume tracking, affiliate attribution, and better rates at scale. Get one at POST /v1/beta/signup (no email required).
If proofs are invalid or spent, you get a 402 error. If no nodes are available, your proofs are returned via the X-Cashu-Change response header. The gateway never charges for failed inference.