SQUIID
DOCS
01 · QUICK START

Every request is authenticated with your Squiid key. Base URL is https://api.squiid.io/v1. Cost comes back on every response.

import OpenAI from "openai";

const ai = new OpenAI({
  baseURL: "https://api.squiid.io/v1/ai",
  apiKey: process.env.SQUIID_API_KEY,
});

const res = await ai.chat.completions.create({
  model: "anthropic/claude-sonnet-5",
  messages: [{ role: "user", content: "hi" }],
});
02 · UNIFIED AI ENDPOINT

OpenAI-compatible. Any model as provider/model. Streaming, tools, JSON mode and vision pass through. Coming from OpenRouter? Only the base URL changes.

const stream = await ai.chat.completions.create({
  model: "openai/gpt-5",      // or google/gemini-flash, anthropic/claude-sonnet-5 …
  stream: true,
  messages,
});
for await (const chunk of stream) process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
03 · RAW PASSTHROUGH

Every catalog service is reachable at /v1/{service}/… with the provider’s own request and response shapes. Provider SDKs work by overriding their base URL.

import Anthropic from "@anthropic-ai/sdk";

const anthropic = new Anthropic({
  baseURL: "https://api.squiid.io/v1/anthropic",
  apiKey: process.env.SQUIID_API_KEY,
});

const msg = await anthropic.messages.create({
  model: "claude-sonnet-5",
  max_tokens: 1024,
  messages: [{ role: "user", content: "hi" }],
});
04 · PROVISIONING

Create isolated resources under Squiid’s provider accounts. Credentials come back once, named SQ_*; usage is billed to your balance daily.

import { Squiid } from "@squiid/sdk";
const sq = new Squiid();

const db = await sq.resources.create({ service: "neon", name: "my-app-db", region: "us-east-1" });
await db.ready();
const { SQ_DATABASE_URL } = db.credentials;

// or a pre-configured client for a resource
const supabase = await sq.supabase("res_8h2k");
05 · MCP SERVER

Exposes list_services, provision, get_credentials and usage so an agent can set up infrastructure mid-task. Use a key with the “may provision” scope and a spend cap.

claude mcp add squiid -e SQUIID_API_KEY=sq_live_… -- npx @squiid/mcp
06 · AGENT SETUP

GET /v1/me/instructions returns a Markdown block, wrapped in <!-- squiid:begin --> and <!-- squiid:end -->, that an agent splices into AGENTS.md so every later run knows which services this key reaches. x-sq-instructions-hash is the sha256 of the body, so a rewrite is skipped when nothing changed. If Squiid does not carry a service yet, POST /v1/service-requests asks for it and answers whether we already know the name.

const res = await fetch("https://api.squiid.io/v1/me/instructions", {
  headers: { Authorization: `Bearer ${process.env.SQUIID_API_KEY}` },
});
const block = await res.text();          // between <!-- squiid:begin --> and <!-- squiid:end -->
const hash = res.headers.get("x-sq-instructions-hash"); // skip the rewrite when unchanged

await fetch("https://api.squiid.io/v1/service-requests", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SQUIID_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ service: "clerk", note: "auth for the console" }),
});
07 · RESPONSE HEADERS
x-sq-request-idUnique id. Quote it to support; find it in the ledger.
x-sq-costCost of this request in USD, e.g. 0.004120. On streams it is not a header: the last SSE line is a comment, : sq-cost=0.004120 sq-balance=142.18, which every parser ignores — or read it back from GET /v1/requests/:id.
x-sq-balanceRemaining balance after this request.
x-sq-provider-msTime spent waiting on the provider, so you can separate our latency from theirs.
08 · ERRORS
401Missing or revoked key.
402Insufficient balance, or the key's cap is reached. The body includes topup_url.
403Key isn't scoped to this service or resource.
429Your rate limit or the provider's — x-sq-limit-source says which.
5xxProvider errors pass through unchanged and are never billed.

Every error body is { error: { type, message, request_id } }, with topup_url on a 402.