PINTI Docs

Sponge Wallet

Spend policy enforcement for Sponge agent wallets and x402 payments.

Sponge Wallet gives AI agents autonomous crypto wallets — agents can hold USDC, make transfers, and pay for services via the x402 protocol (HTTP 402 Payment Required). PINTI sits between the agent's intent to pay and the actual wallet transfer, evaluating every spend against your configured policies.

Note

PINTI is not a wallet or payment method. It's a policy layer that decides whether a Sponge wallet should send funds. The wallet handles the actual crypto transfer — PINTI handles the permission.

How It Works

Agent → PINTI → Sponge Wallet
Agent discovers x402 service (HTTP 402 Payment Required)
    ↓
Agent wants to pay $5 USDC for API data
    ↓
PINTI evaluates against your policies
    ↓
┌──────────────────────────────────────────────┐
│ ALLOW  → Sponge Wallet sends USDC → get data │
│ DENY   → stop, wallet stays untouched        │
│ REQUIRE_APPROVAL → wait for human            │
└──────────────────────────────────────────────┘

Integration Example

Use @pinti/guard to check policy before calling Sponge's transfer method:

Policy check → Sponge transfer
import { PintiGuard } from "@pinti/guard";
import { SpongeWallet } from "@spongewallet/sdk";

const pinti = new PintiGuard({
  apiKey: process.env.PINTI_API_KEY!,
});
const wallet = await SpongeWallet.connect();

// 1. Check policy before spending
const result = await pinti.evaluateSpend({
  agentId: "research-agent",
  amountMinor: 500,       // $5.00
  unit: "USD",
  merchant: "data-api.example.com",
  category: "api",
  reason: "Fetch financial report via x402",
});

// 2. Only transfer if PINTI allows it
if (result.decision === "ALLOW") {
  await wallet.transfer({
    chain: "base",
    to: "0xServiceAddress...",
    amount: "5",
    currency: "USDC",
  });
}

// 3. Handle other decisions
if (result.decision === "DENY") {
  console.log("Blocked:", result.decisionReason);
}

if (result.decision === "REQUIRE_APPROVAL") {
  console.log("Awaiting human approval:", result.spendRequestId);
}

x402 Flow

The x402 protocol lets services charge per request using HTTP 402. When your agent hits a paid endpoint, the response includes payment details. Add PINTI as a guard before the agent pays:

x402 with PINTI guard
// Agent calls a paid API
const res = await fetch("https://data-api.example.com/report");

if (res.status === 402) {
  const paymentInfo = await res.json();
  // paymentInfo: { amount: "0.50", currency: "USDC", to: "0x..." }

  // Guard the payment with PINTI
  const check = await pinti.evaluateSpend({
    agentId: "research-agent",
    amountMinor: 50,          // $0.50
    unit: "USD",
    merchant: "data-api.example.com",
    category: "api",
    reason: "x402 payment for /report endpoint",
  });

  if (check.decision === "ALLOW") {
    await wallet.transfer({
      chain: paymentInfo.chain ?? "base",
      to: paymentInfo.to,
      amount: paymentInfo.amount,
      currency: paymentInfo.currency,
    });
    // Retry the original request after payment
    const data = await fetch("https://data-api.example.com/report");
  }
}

Why Use PINTI with Sponge?

Sponge gives agents the ability to pay. PINTI gives you control over what they pay for:

Without PINTIWith PINTI
Agent spends freely from walletEvery spend checked against your policy
No per-transaction limitsDaily/monthly caps, per-tx max, blocklists
No approval workflowHuman-in-the-loop for large transactions
Basic audit loggingFull audit trail with SAT cryptographic proof

Quick Start

Install
npm install pinti-sponge

The pinti-sponge package provides two patterns for integrating PINTI with Sponge Wallet:

beforeTransfer — hook pattern
import { beforeTransfer } from "pinti-sponge";

const check = await beforeTransfer({
  agentId: "research-agent",
  amountMinor: 500,
  unit: "USD",
  merchant: "data-api.example.com",
  category: "api",
  reason: "x402 payment for /report",
});

if (check.action === "continue") {
  await wallet.transfer({ /* ... */ });
}
// check.action === "block" → do not transfer
// check.action === "pause" → wait for human approval
guardedTransfer — wrap & execute
import { guardedTransfer } from "pinti-sponge";

const result = await guardedTransfer(
  {
    agentId: "research-agent",
    amountMinor: 500,
    unit: "USD",
    merchant: "data-api.example.com",
    category: "api",
    reason: "x402 payment for /report",
  },
  async () => {
    // Only runs if PINTI allows
    return await wallet.transfer({ chain: "base", to: "0x...", amount: "5", currency: "USDC" });
  }
);

result.executed // true if transfer ran
result.reason   // policy decision reason

Tip

pinti-sponge is live on npm. Set PINTI_API_KEY and PINTI_URL env vars and you're ready to go.