Integrate15
SDK
@complir/sdk is a small TypeScript client that pays for you. On a 402 it reads the requirements, signs an EIP-3009 TransferWithAuthorization with a viem account, retries once with PAYMENT-SIGNATURE, and exposes the settle receipt. Verification of an attestation needs no network at all.
Install
The package lives in packages/sdk of the repository and depends only on viem. It is not published to npm yet; install it from the repo (npm install ./packages/sdk or a workspace link; it ships TypeScript sources, main: ./src/index.ts). Node 20+ or any runtime with fetch, crypto.getRandomValues and btoa.
Usage
import { CompliR, CompliRPaymentError } from "@complir/sdk";
import { privateKeyToAccount } from "viem/accounts";
const c = new CompliR({
baseUrl: "https://trycomplir.xyz",
account: privateKeyToAccount(process.env.PAYER_KEY as `0x${string}`), // any viem LocalAccount: holds USDC on Arc
maxPriceUsdc: 0.05, // refuse to sign above this per call (default 1)
network: "eip155:5042", // only accept requirements on Arc mainnet (default: any eip155:*)
});
try {
const v = await c.screen("0xPayee", { amountUsdc: 120, name: "Lela Design", payeeBook: myPayees, clientId: "treasury-7" });
if (v.tier === "HIGH") hold(v.rationale);
else pay(Math.min(120, v.recommendedLimits.maxPerTxUsdc));
console.log(c.lastPayment); // settle receipt from PAYMENT-RESPONSE: { transaction, payer, amount, network }
await c.watch("0xPayee", { webhookUrl: "https://treasury.example/complir", clientId: "treasury-7" });
const att = await c.attestation("0xPayee"); // free; null on 404
const ok = await CompliR.verifyAttestation(v.attestation, { expectedChainId: 5042 });
} catch (e) {
if (e instanceof CompliRPaymentError) console.error(e.requirements, e.receipt); // 402 after signing
}API
| Member | Does |
|---|---|
new CompliR({ baseUrl, account, maxPriceUsdc?, network?, authorizationSlackSeconds?, fetch? }) | baseUrl and a viem account with signTypedData are required. Slack (default 540 s) is added to the server's maxTimeoutSeconds for the authorization's validBefore. |
screen(address, { name?, amountUsdc?, payeeBook?, clientId?, depth? }) | POST /api/v1/screen → Verdict |
watch(address, { webhookUrl, clientId?, payeeBook? }) | POST /api/v1/watch → Watch |
attestation(address) | GET /api/v1/attestation/:address → Attestation | null |
verifyAttestation(att, opts?) | static and instance: offline EIP-712 check; never throws, returns boolean. opts: now, ignoreExpiry, expectedAttester, expectedChainId, expectedVerifyingContract |
paidFetch(path, init?) | fetch with the 402 → sign → retry loop; path relative to baseUrl or absolute |
lastPayment | PaymentReceipt from the most recent paid call, or null |
CompliRError / CompliRPaymentError | status, code, body; payment errors add requirements and receipt |
// Any paid route, the x402 dance handled for you (bodies must be re-sendable strings).
const res = await c.paidFetch("/api/v1/screen", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ address }) });
// Pieces, if you bring your own HTTP client:
import { readPaymentRequired, readReceipt, usdcToAtomic, atomicToUsdc, tierForScore } from "@complir/sdk";How a payment is signed
- Requirement
- the first accepts[] entry with scheme exact on an eip155:* network (or the configured one); amount ≤ maxPriceUsdc or CompliRPaymentError
- Domain
- { name: extra.name ?? "USDC", version: extra.version ?? "2", chainId from the CAIP-2 network, verifyingContract: asset }
- Authorization
- from = account, to = payTo, value = amount, validAfter 0, validBefore = now + maxTimeoutSeconds + slack, nonce = 32 random bytes
- Retry
- exactly one, with PAYMENT-SIGNATURE = base64 { x402Version: 2, resource, accepted, payload: { signature, authorization } }
- Second 402
- throws CompliRPaymentError with the server's error (settlement pending, mismatch …) and the receipt when present
Types
Verdict, Attestation, AttestationTypedData, Reason, Watch, PayeeBookEntry, PaymentRequired, PaymentRequirements, PaymentReceipt mirror src/lib/types.ts (the SDK types evidence as unknown). Field meanings are on Screening & verdicts. The MCP server uses this SDK for its paid tools.