Private, uncensored inference via x402.

Speakeasy Relay provides OpenAI-compatible streaming chat completions with pay-per-request USDC settlement on Base. No account required.

Endpoint · POST /v1/chat/completions Network · eip155:8453 Asset · USDC Discovery · /.well-known/x402

Private + Uncensored

Built for agents and developers who want fewer restrictions and direct paid inference access.

OpenAI-Compatible

Drop into existing chat-completions workflows with minimal integration friction.

On-Chain Settlement

Settlement path validated with tx receipt + USDC Transfer-event checks, not just stream success.

Quick Start

Fetch pricing
curl https://api.speakeasyrelay.com/v1/pricing
Unpaid probe (expect 402)
curl -X POST https://api.speakeasyrelay.com/v1/chat/completions \
  -H 'content-type: application/json' \
  -d '{"model":"venice-uncensored","messages":[{"role":"user","content":"Say hello."}],"max_tokens":64,"stream":true}'
Verify script (paste into a file)
cat > chat-in-60s.cjs <<'EOF'
const { privateKeyToAccount } = require("viem/accounts");
const { createPaymentHeader, selectPaymentRequirements } = require("x402/client");

async function main() {
  const PRIVATE_KEY = process.env.PRIVATE_KEY;
  const GATEWAY = process.env.GATEWAY_URL || "https://api.speakeasyrelay.com";
  if (!PRIVATE_KEY) throw new Error("Missing PRIVATE_KEY env var");

  const account = privateKeyToAccount(PRIVATE_KEY);
  const model = "venice-uncensored";

  const pricingRes = await fetch(`${GATEWAY}/v1/pricing`);
  const pricing = await pricingRes.json();
  const selected = selectPaymentRequirements(pricing.models[model].accepts, "base");

  const req = {
    ...selected,
    network: selected.network === "eip155:8453" ? "base" : selected.network,
    maxAmountRequired: selected.maxAmountRequired || selected.amount,
    resource: selected.resource || pricing.models[model].resource?.url || `${GATEWAY}/v1/chat/completions`,
  };

  const payment = await createPaymentHeader(account, pricing.models[model].x402Version, req);

  const body = {
    model,
    messages: [{ role: "user", content: "Say hello in one sentence." }],
    max_tokens: 64,
    stream: true,
  };

  const res = await fetch(`${GATEWAY}/v1/chat/completions`, {
    method: "POST",
    headers: {
      "content-type": "application/json",
      "payment-signature": payment,
      "x-payment": payment,
    },
    body: JSON.stringify(body),
  });

  console.log(`HTTP ${res.status}`);
  console.log(await res.text());
}

main().catch((err) => {
  console.error("❌", err.message || err);
  process.exit(1);
});
EOF

npm i x402 viem
PRIVATE_KEY=0xYOUR_PRIVATE_KEY node chat-in-60s.cjs
Local interactive chat (paste into a file)
cat > chat-local.cjs <<'EOF'
const readline = require("node:readline/promises");
const { stdin, stdout } = require("node:process");
const { privateKeyToAccount } = require("viem/accounts");
const { createPaymentHeader, selectPaymentRequirements } = require("x402/client");

const GATEWAY = process.env.GATEWAY_URL || "https://api.speakeasyrelay.com";
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const MODEL = process.env.MODEL || "venice-uncensored";
const MAX_TOKENS = Number(process.env.MAX_TOKENS || 256);

if (!PRIVATE_KEY) {
  console.error("❌ Missing PRIVATE_KEY env var");
  process.exit(1);
}

const account = privateKeyToAccount(PRIVATE_KEY);
const history = [{ role: "system", content: "You are helpful and concise." }];

function normalizeReq(selected, topResourceUrl) {
  return {
    ...selected,
    network: selected.network === "eip155:8453" ? "base" : selected.network,
    maxAmountRequired: selected.maxAmountRequired || selected.amount,
    resource: selected.resource || topResourceUrl || `${GATEWAY}/v1/chat/completions`,
  };
}

async function getPricingReq(model) {
  const pricingRes = await fetch(`${GATEWAY}/v1/pricing`);
  const pricing = await pricingRes.json();
  const modelInfo = pricing.models?.[model];
  if (!modelInfo) throw new Error(`Model not found: ${model}`);
  const selected = selectPaymentRequirements(modelInfo.accepts, "base");
  return { x402Version: modelInfo.x402Version, req: normalizeReq(selected, modelInfo.resource?.url) };
}

async function paidChatOnce(model) {
  const { x402Version, req } = await getPricingReq(model);
  const payment = await createPaymentHeader(account, x402Version, req);

  const res = await fetch(`${GATEWAY}/v1/chat/completions`, {
    method: "POST",
    headers: {
      "content-type": "application/json",
      "payment-signature": payment,
      "x-payment": payment,
    },
    body: JSON.stringify({ model, messages: history, max_tokens: MAX_TOKENS, stream: true }),
  });

  const raw = await res.text();
  const lines = raw.split("\n");
  let content = "";
  let settlement = null;
  let event = null;

  for (const line of lines) {
    if (line.startsWith("event: ")) { event = line.slice(7).trim(); continue; }
    if (!line.startsWith("data: ")) continue;
    const payload = line.slice(6).trim();
    if (!payload || payload === "[DONE]") continue;

    try {
      if (event === "payment_settlement") { settlement = JSON.parse(payload); event = null; continue; }
      const parsed = JSON.parse(payload);
      content += parsed?.choices?.[0]?.delta?.content || "";
      event = null;
    } catch { event = null; }
  }

  return { content: content.trim(), settlement };
}

(async () => {
  console.log(`🐦 Local paid chat\nGateway: ${GATEWAY}\nWallet: ${account.address}\nModel: ${MODEL}`);
  console.log("Type /exit to quit, /clear to reset conversation.\n");

  const rl = readline.createInterface({ input: stdin, output: stdout });
  while (true) {
    const input = (await rl.question("you> ")).trim();
    if (!input) continue;
    if (input === "/exit") break;
    if (input === "/clear") { history.length = 1; console.log("cleared.\n"); continue; }

    history.push({ role: "user", content: input });
    try {
      const { content, settlement } = await paidChatOnce(MODEL);
      history.push({ role: "assistant", content: content || "(no content)" });
      console.log(`assistant> ${content || "(no content)"}`);
      if (settlement) console.log(`settlement> ${settlement.settlement_status || "unknown"}`);
      console.log();
    } catch (err) {
      console.error(`❌ ${err.message || err}`);
      history.pop();
      console.log();
    }
  }
  rl.close();
})();
EOF

npm i x402 viem
PRIVATE_KEY=0xYOUR_PRIVATE_KEY node chat-local.cjs

These are self-contained scripts you can run locally against the live Speakeasy endpoint.