SDK
@himitsu/sdk for buyer and seller agents: verify, open, prove, claim, decrypt, and x402 on both sides.
@himitsu/sdk is what the app and the live x402 endpoint run, packaged for agents. It proves and verifies deliveries, opens and claims orders on the escrow, and pays or sells over x402.
Install
npm i https://himitsuprivacy.xyz/sdk/himitsu-sdk-0.1.0.tgz
The package is served from this site (/sdk/latest.tgz always points at the newest version). Node 20+ or any modern browser with a bundler. ESM only.
Buyer
import { Himitsu } from "@himitsu/sdk";
const himitsu = new Himitsu({ privateKey: process.env.AGENT_PK });
// The seller sent a delivery package: ciphertext + Groth16 proof.
if (!(await himitsu.verify(offer.package))) throw new Error("unproven delivery");
const order = await himitsu.open({
seller: "0x5E11...b0A2",
asset: "ETH", // or "USDG", approved automatically
amount: "0.001",
delivery: offer.package, // the contract verifies the proof again
terms: "10-Q risk summary, JSON, before 18:00 UTC",
deadline: "24h",
});
const key = await order.revealed();
const report = himitsu.decrypt(offer.package, key); // checked against dHash
open verifies the package locally first and throws UnprovenDelivery before anything is sent. Only a salted commitment of terms goes on-chain; keep order.terms and order.salt to prove the terms later.
order.revealed() resolves with the key as soon as the seller claims (the claim publishes it). If the deadline passes first, it submits the refund for you and rejects with Refunded; pass { refund: false } to get Expired instead.
Seller
import { Himitsu } from "@himitsu/sdk";
const himitsu = new Himitsu({ privateKey: process.env.SELLER_PK });
const report = await writeReport(request);
// Poseidon keystream with a one-time key, proven in zero knowledge.
const { package: pkg, keyHash, key } = await himitsu.prove(report);
await sendToBuyer(pkg);
const stop = himitsu.watch({ keyHash }, async (order) => {
await order.claim(key); // reveals the key, pays the seller
stop();
});
One proof covers up to 1 953 bytes. Proving needs the circuit (2 MB) and the proving key (27 MB): by default they are downloaded once from /zk/ on this site and cached; pass artifacts: { wasm, zkey } with paths or URLs to use your own copies. A proof takes a couple of seconds on a laptop.
x402
Buying from any endpoint that speaks himitsu-escrow-zk:
import { payX402 } from "@himitsu/sdk/x402";
const { json, order, openTx, claimTx } = await payX402("https://himitsuprivacy.xyz/api/x402/demo", {
privateKey: process.env.AGENT_PK,
maxPrice: "0.0001", // ETH; refuses to pay more
});
It runs the whole flow: GET, 402 with the offer, verify the proof, lock the price in the escrow, retry with X-PAYMENT, read the key the claim published, decrypt and check against dHash. It only pays into the escrow the client trusts, whatever the endpoint names.
Selling, with any Fetch-style server (Next.js route handlers, Hono, Bun, Deno, Workers):
import { himitsuPaywall } from "@himitsu/sdk/x402";
const paywall = himitsuPaywall({ sellerKey: process.env.SELLER_PK, price: "0.00001" });
export const GET = (req: Request) => paywall(req, () => buildReport());
With Express:
import { expressPaywall } from "@himitsu/sdk/x402";
app.get(
"/v1/report",
expressPaywall({ sellerKey: process.env.SELLER_PK, price: "0.00001" }, (req) => buildReport(req.query.ticker)),
);
This is the same handler as the live endpoint. Without payment it produces the content, encrypts and proves it, and answers 402. With a valid X-PAYMENT it checks the order on-chain (seller, asset, price, key hash, at least two minutes left) and claims it. The key is derived from the seller key and the offer's nonce, so the server keeps no state. Keep a little ETH on the seller key for claim gas.
Reference
| Call | What it does |
|---|---|
new Himitsu({ privateKey | account | wallet, rpc?, escrow?, artifacts?, pollMs? }) |
a client; reads need no key |
verify(pkg) |
true only if the Groth16 proof verifies and the ciphertext is the one it covers |
open({ seller, asset, amount, delivery, terms, salt?, deadline }) |
locks the payment, returns an order handle |
order.revealed({ timeoutMs?, refund? }) |
the key, once the seller claims |
decrypt(pkg, key), decryptBytes(pkg, key) |
the delivery, checked against dHash |
prove(content, { key? }) |
{ package, key, keyHash, cHash, dHash, provedInMs } |
watch({ keyHash?, seller? }, cb) |
new orders to this seller; returns stop() |
claim(id, key), decline(id) |
seller side |
release(id), refund(id) |
buyer side; refund works after the deadline |
getOrder(id) |
the order as stored on-chain |
close() |
lets a Node script exit after proving or verifying |
Errors
| Error | Meaning |
|---|---|
UnprovenDelivery |
the proof does not verify, or the ciphertext is not the one it covers; nothing is sent |
WrongPackage |
not a hmt2. delivery package, or a damaged one |
DeliveryMismatch |
the key does not open the package to the content committed in dHash |
DeliveryTooLarge |
more than 1 953 bytes, the most one proof covers |
InsufficientFunds |
the wallet cannot cover the amount plus gas; nothing is sent |
NoSigner |
a write on a client built without a key |
Refunded |
the order went back to the buyer |
Expired |
the deadline passed with the order still open |
Declined |
the seller declined the order |
Released |
the buyer released the payment without a key |
PriceTooHigh |
the x402 price is above maxPrice; nothing is sent |
X402Error |
the endpoint is not live, names another escrow, or refused the payment |
All of them extend HimitsuError and carry a code.
What stays public
The delivery and the terms are private. The amount, the asset and both addresses are visible on-chain today; hiding them is the next version of the protocol.