JOULE Compute
Pay-per-request AI inference. No API keys — just pay and query.
OpenAI-compatible POST /api/v1/chat/completions accepting USDC on Base and JOULE on Stellar via the x402 payment protocol.
Quick Start
Install the SDK and make your first paid inference request in 10 lines:
npm install joule-sdk
import { JouleClient } from "joule-sdk";
const client = new JouleClient({
secretKey: process.env.STELLAR_SECRET_KEY!, // S...
});
const response = await client.chat({
model: "meta-llama/Llama-3.3-70B-Instruct",
messages: [{ role: "user", content: "What is thermodynamic computing?" }],
});
console.log(response.choices[0].message.content);
console.log("Paid:", response._payment.amountPaid);Or pay with USDC on Base using @x402/fetch:
import { wrapFetch } from "@x402/fetch";
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const wallet = createWalletClient({ account, chain: base, transport: http() });
const fetchX402 = wrapFetch(fetch, wallet);
const res = await fetchX402("https://compute.lumenbro.com/api/v1/chat/completions", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "meta-llama/Llama-3.3-70B-Instruct",
messages: [{ role: "user", content: "Hello!" }],
}),
});
const data = await res.json();
console.log(data.choices[0].message.content);Payment Methods
| Method | Network | Asset | Min / Request | SDK |
|---|---|---|---|---|
| USDC | Base (mainnet) | 0x8335...2913 | $0.001 | @x402/fetch |
| JOULE | Stellar (testnet) | CBKI6...WXBMX | 0.10 JOULE | joule-sdk |
Both payment methods use the x402 protocol: the server returns 402 Payment Required with payment requirements, your client builds and signs a payment, then retries with the payment header.
API Reference
POST /api/v1/chat/completions
OpenAI-compatible chat completions endpoint. Requires payment via x402.
Request
POST https://compute.lumenbro.com/api/v1/chat/completions
Content-Type: application/json
{
"model": "meta-llama/Llama-3.3-70B-Instruct",
"messages": [
{ "role": "system", "content": "You are a helpful assistant." },
{ "role": "user", "content": "Explain x402 in one sentence." }
],
"max_tokens": 256,
"temperature": 0.7,
"stream": false
}| Field | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Model ID from /api/models |
messages | array | Yes | Array of {role, content} objects |
max_tokens | number | No | Max output tokens (default: model max) |
temperature | number | No | Sampling temperature 0-2 (default: 1) |
stream | boolean | No | Enable SSE streaming (default: false) |
Response (200 OK)
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1700000000,
"model": "meta-llama/Llama-3.3-70B-Instruct",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "x402 is a protocol that enables..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 24,
"completion_tokens": 42,
"total_tokens": 66
},
"_payment": {
"transaction": "abc123...def456",
"network": "stellar:testnet",
"payer": "GABCD...WXYZ",
"asset": "JOULE",
"amountPaid": "0.38 JOULE"
}
}402 Payment Required
Returned on first request (no payment header). The response body and headers contain payment requirements for both USDC and JOULE:
HTTP/1.1 402 Payment Required
PAYMENT-REQUIRED: <base64-encoded v2 requirements>
X-Payment: <base64-encoded v1 requirements>
{
"x402Version": 1,
"error": {
"type": "payment_required",
"message": "This endpoint requires payment. Cost: $0.0010 USDC or 0.38 JOULE"
},
"accepts": [
{
"scheme": "exact",
"network": "eip155:8453",
"maxAmountRequired": "1000",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"payTo": "0xA956311362f68Bd5291CED9C697998714bEEDA07"
},
{
"scheme": "exact",
"network": "stellar:testnet",
"maxAmountRequired": "3800000",
"asset": "CBKI6B65HBQNR4ESK3RQEJTYINVGCXVKMAMN7SMS4LBTP3IFNM6WXBMX",
"payTo": "GALK7SB3GGUKPPR6F7U4GORSIIITGATJKYUEAOKHBOXM5LSZT6Y3BITX"
}
]
}Other Endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/models | GET | List available models with pricing in JOULE and USDC |
/api/health | GET | Health check ({"status":"ok"}) |
/.well-known/x402 | GET | x402 discovery manifest |
Models & Pricing
Pricing is computed per-request based on input/output tokens. The table below shows costs for a typical request (~500 input tokens, max output tokens for the model).
| Model | Tier | USDC / req | JOULE / req | Max Output |
|---|---|---|---|---|
| Llama 3.2 3B | small | $0.001 | 0.10 | 4,096 |
| Mistral Small 24B | medium | $0.001 | 0.16 | 4,096 |
| Llama 4 Scout 17B | medium | $0.002 | 0.16 | 4,096 |
| Qwen 2.5 72B | medium | $0.002 | 0.16 | 4,096 |
| Llama 3.3 70B | medium | $0.002 | 0.16 | 4,096 |
| DeepSeek V3 | large | $0.009 | 0.96 | 8,192 |
| DeepSeek R1 | reasoning | $0.024 | 4.06 | 8,192 |
Prices include 20% margin over provider costs. JOULE pricing is based on estimated inference energy (1 JOULE = 1,000 Joules). Minimum charge: $0.001 USDC or 0.10 JOULE.
SDK Reference
npm install joule-sdk
JouleClient
import { JouleClient } from "joule-sdk";
const client = new JouleClient({
secretKey: string; // Stellar secret key (S...)
computeUrl?: string; // Default: "https://compute.lumenbro.com"
rpcUrl?: string; // Soroban RPC URL
network?: "testnet" | "mainnet"; // Default: "testnet"
});client.chat(request): Promise<ChatResponse>
Sends a chat completion request, automatically handling the x402 payment flow (402 → sign Soroban transfer → retry with payment header).
const response = await client.chat({
model: "meta-llama/Llama-3.3-70B-Instruct",
messages: [{ role: "user", content: "Hello!" }],
max_tokens: 256,
temperature: 0.7,
});
// response.choices[0].message.content — the AI response
// response._payment.transaction — Stellar tx hash
// response._payment.amountPaid — "0.38 JOULE"client.models(): Promise<any>
Fetches available models and their pricing.
buildSignedPayment(keypair, requirements, network, rpcUrl?)
Low-level function for building a signed Soroban transfer. Used internally by JouleClient but exported for custom integrations.
import { buildSignedPayment } from "joule-sdk";
import { Keypair } from "@stellar/stellar-sdk";
const keypair = Keypair.fromSecret("S...");
const payment = await buildSignedPayment(keypair, requirements, "testnet");
// payment.payload.signedTxXdr — signed XDR to submitTypes
// Exported from "joule-sdk"
interface JouleClientConfig {
secretKey: string;
computeUrl?: string;
rpcUrl?: string;
network?: "testnet" | "mainnet";
}
interface ChatRequest {
model: string;
messages: { role: "system" | "user" | "assistant"; content: string }[];
max_tokens?: number;
temperature?: number;
top_p?: number;
stream?: boolean;
stop?: string | string[];
}
interface ChatResponse {
id: string;
object: string;
created: number;
model: string;
choices: { index: number; message: { role: string; content: string }; finish_reason: string }[];
usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number };
_payment: { transaction: string; network: string; payer: string; joulesPaid: string };
}x402 Protocol Flow
The x402 protocol enables machine-to-machine payments over HTTP. Here is the full flow:
Agent Compute Server Facilitator
│ │ │
│ POST /chat/completions │ │
│ (no payment header) │ │
│ ──────────────────────────>│ │
│ │ │
│ 402 Payment Required │ │
│ { accepts: [USDC, JOULE] }│ │
│ <──────────────────────────│ │
│ │ │
│ Build + sign payment │ │
│ (Soroban transfer or │ │
│ EIP-3009 authorization) │ │
│ │ │
│ POST /chat/completions │ │
│ X-Payment: <signed tx> │ │
│ ──────────────────────────>│ │
│ │ POST /verify │
│ │ ────────────────────────>│
│ │ { isValid: true } │
│ │ <────────────────────────│
│ │ │
│ │ POST /settle │
│ │ ────────────────────────>│
│ │ { success: true, tx } │
│ │ <────────────────────────│
│ │ │
│ 200 OK │ │
│ { choices: [...], │ │
│ _payment: { tx, ... } } │ │
│ <──────────────────────────│ │
Payment Headers
| Header | Direction | Description |
|---|---|---|
PAYMENT-REQUIRED | Server → Client | Base64-encoded v2 payment requirements |
X-Payment | Client → Server | Base64-encoded signed payment (v1) |
PAYMENT-SIGNATURE | Client → Server | Base64-encoded signed payment (v2) |
PAYMENT-RESPONSE | Server → Client | Base64-encoded settlement receipt |
Network Info
Stellar (JOULE — testnet)
| JOULE Token | CBKI6B65HBQNR4ESK3RQEJTYINVGCXVKMAMN7SMS4LBTP3IFNM6WXBMX |
| Pay-to Address | GALK7SB3GGUKPPR6F7U4GORSIIITGATJKYUEAOKHBOXM5LSZT6Y3BITX |
| Facilitator | https://x402.lumenbro.com |
| Network ID | stellar:testnet |
| Soroban RPC | https://soroban-testnet.stellar.org |
| Decimals | 7 |
Base (USDC — mainnet)
| USDC Contract | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 |
| Pay-to Address | 0xA956311362f68Bd5291CED9C697998714bEEDA07 |
| Facilitator | https://facilitator.openx402.ai |
| Network ID | eip155:8453 |
| Decimals | 6 |
Agent Integration
USDC via @x402/fetch (any framework)
The @x402/fetch wrapper handles the 402 dance automatically for EVM wallets:
import { wrapFetch } from "@x402/fetch";
// Works with any viem WalletClient
const fetchX402 = wrapFetch(fetch, walletClient);
const res = await fetchX402("https://compute.lumenbro.com/api/v1/chat/completions", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "meta-llama/Llama-3.2-3B-Instruct",
messages: [{ role: "user", content: "Summarize this document." }],
}),
});JOULE via joule-sdk (Stellar)
import { JouleClient } from "joule-sdk";
const client = new JouleClient({ secretKey: process.env.STELLAR_SECRET_KEY! });
// Use in any agent loop
async function queryLLM(prompt: string): Promise<string> {
const res = await client.chat({
model: "meta-llama/Llama-3.3-70B-Instruct",
messages: [{ role: "user", content: prompt }],
});
return res.choices[0].message.content;
}Generic HTTP (manual 402 dance)
For languages without an SDK, implement the x402 flow manually:
# 1. Make initial request
curl -s -w "\n%{http_code}" \
-X POST https://compute.lumenbro.com/api/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"meta-llama/Llama-3.2-3B-Instruct","messages":[{"role":"user","content":"Hi"}]}'
# Returns 402 with payment requirements in body and headers
# 2. Build and sign payment (language-specific)
# 3. Retry with payment header:
curl -s -X POST https://compute.lumenbro.com/api/v1/chat/completions \
-H "Content-Type: application/json" \
-H "X-Payment: <base64-encoded-signed-payment>" \
-d '{"model":"meta-llama/Llama-3.2-3B-Instruct","messages":[{"role":"user","content":"Hi"}]}'Links
| npm | npmjs.com/package/joule-sdk |
| GitHub (SDK) | github.com/lumenbro/joule-sdk |
| x402 Protocol | x402.org |
| x402 Discovery | compute.lumenbro.com/.well-known/x402 |
| API Health | compute.lumenbro.com/api/health |
| Models | compute.lumenbro.com/api/models |
Built by LumenBro · Powered by x402 · JOULE is a prepaid AI compute credit, not a currency or investment