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

MethodNetworkAssetMin / RequestSDK
USDCBase (mainnet)0x8335...2913$0.001@x402/fetch
JOULEStellar (testnet)CBKI6...WXBMX0.10 JOULEjoule-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
}
FieldTypeRequiredDescription
modelstringYesModel ID from /api/models
messagesarrayYesArray of {role, content} objects
max_tokensnumberNoMax output tokens (default: model max)
temperaturenumberNoSampling temperature 0-2 (default: 1)
streambooleanNoEnable 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

EndpointMethodDescription
/api/modelsGETList available models with pricing in JOULE and USDC
/api/healthGETHealth check ({"status":"ok"})
/.well-known/x402GETx402 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).

ModelTierUSDC / reqJOULE / reqMax Output
Llama 3.2 3Bsmall$0.0010.104,096
Mistral Small 24Bmedium$0.0010.164,096
Llama 4 Scout 17Bmedium$0.0020.164,096
Qwen 2.5 72Bmedium$0.0020.164,096
Llama 3.3 70Bmedium$0.0020.164,096
DeepSeek V3large$0.0090.968,192
DeepSeek R1reasoning$0.0244.068,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 submit

Types

// 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

HeaderDirectionDescription
PAYMENT-REQUIREDServer → ClientBase64-encoded v2 payment requirements
X-PaymentClient → ServerBase64-encoded signed payment (v1)
PAYMENT-SIGNATUREClient → ServerBase64-encoded signed payment (v2)
PAYMENT-RESPONSEServer → ClientBase64-encoded settlement receipt

Network Info

Stellar (JOULE — testnet)

JOULE TokenCBKI6B65HBQNR4ESK3RQEJTYINVGCXVKMAMN7SMS4LBTP3IFNM6WXBMX
Pay-to AddressGALK7SB3GGUKPPR6F7U4GORSIIITGATJKYUEAOKHBOXM5LSZT6Y3BITX
Facilitatorhttps://x402.lumenbro.com
Network IDstellar:testnet
Soroban RPChttps://soroban-testnet.stellar.org
Decimals7

Base (USDC — mainnet)

USDC Contract0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
Pay-to Address0xA956311362f68Bd5291CED9C697998714bEEDA07
Facilitatorhttps://facilitator.openx402.ai
Network IDeip155:8453
Decimals6

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"}]}'
npmnpmjs.com/package/joule-sdk
GitHub (SDK)github.com/lumenbro/joule-sdk
x402 Protocolx402.org
x402 Discoverycompute.lumenbro.com/.well-known/x402
API Healthcompute.lumenbro.com/api/health
Modelscompute.lumenbro.com/api/models

Built by LumenBro · Powered by x402 · JOULE is a prepaid AI compute credit, not a currency or investment