<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Douglas Borthwick</title>
    <description>The latest articles on DEV Community by Douglas Borthwick (@douglasborthwickcrypto).</description>
    <link>https://dev.to/douglasborthwickcrypto</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3790350%2Faa27cd63-7a48-41a3-8d98-459bfecf44fa.png</url>
      <title>DEV Community: Douglas Borthwick</title>
      <link>https://dev.to/douglasborthwickcrypto</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/douglasborthwickcrypto"/>
    <language>en</language>
    <item>
      <title>What a Wallet Can Prove: Every InsumerAPI Condition Type, With Why It Exists</title>
      <dc:creator>Douglas Borthwick</dc:creator>
      <pubDate>Wed, 02 Sep 2026 01:16:22 +0000</pubDate>
      <link>https://dev.to/douglasborthwickcrypto/what-a-wallet-can-prove-every-insumerapi-condition-type-with-why-it-exists-3f1j</link>
      <guid>https://dev.to/douglasborthwickcrypto/what-a-wallet-can-prove-every-insumerapi-condition-type-with-why-it-exists-3f1j</guid>
      <description>&lt;p&gt;&lt;strong&gt;Every condition type InsumerAPI evaluates, what comes back in the signed bytes, what a verifier recomputes, and why each design choice was made. Longer than usual, because the surface has grown.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The primitive has not changed: read wallet state, evaluate conditions, return a signed boolean. What has changed is the range of conditions, the two output formats, the proofs you can attach, and, since the first of September, a second signature beside the first. This is the reference walk-through I would want if I were integrating today. Requests and responses are shown in the shape the API emits; every number here is checked against the running system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The request shape, and the one rule people trip on
&lt;/h2&gt;

&lt;p&gt;One call, &lt;code&gt;POST /v1/attest&lt;/code&gt;, one wallet, one to ten conditions, each with its own chain. The response is a signed attestation: an &lt;code&gt;id&lt;/code&gt;, an aggregate &lt;code&gt;pass&lt;/code&gt;, per-condition &lt;code&gt;results&lt;/code&gt;, and timestamps, with the signature and key identifier beside it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://api.insumermodel.com/v&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;/attest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;X-API-Key:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;insr_live_...&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"wallet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"token_balance"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"chainId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"contractAddress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"threshold"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1000"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rule: quantities are decimal strings. &lt;code&gt;"threshold": "1000"&lt;/code&gt;, never &lt;code&gt;1000&lt;/code&gt;. Every key issued since June signs a canonical, domain-separated payload in which a string quantity is exact to any precision and serializes identically in every runtime; a JSON number is rejected with a 400. The same holds for the ratio fields below. The one deliberate exception is &lt;code&gt;nft_ownership&lt;/code&gt;, whose threshold is the number zero, because it is a presence check and always has been.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is inside the signed bytes
&lt;/h2&gt;

&lt;p&gt;Each result carries the exact predicate that was evaluated, as &lt;code&gt;evaluatedCondition&lt;/code&gt;, and a &lt;code&gt;conditionHash&lt;/code&gt;, the SHA-256 of its canonical form. It also carries the chain anchor: &lt;code&gt;blockNumber&lt;/code&gt; and &lt;code&gt;blockTimestamp&lt;/code&gt; on EVM chains, a ledger index and hash on XRPL and Stellar, a block height and hash on Bitcoin and Tron, a slot on Solana, a checkpoint on Sui. The anchor shape differs by family on purpose, and a verifier that assumes &lt;code&gt;blockNumber&lt;/code&gt; finds no anchor on a Bitcoin result. All of it is inside the signature. The &lt;code&gt;expiresAt&lt;/code&gt; field is beside the signed payload, not inside it, which is why the spec's verification procedure binds it to the signed &lt;code&gt;attestedAt&lt;/code&gt; (an &lt;code&gt;expiresAt&lt;/code&gt; further than the issuance window from &lt;code&gt;attestedAt&lt;/code&gt; can only have been edited after signing).&lt;/p&gt;

&lt;p&gt;That combination, predicate plus hash plus anchor, is the recompute basis. It is what lets anyone re-run the read against any node and compare, which is the property everything else in this guide depends on.&lt;/p&gt;

&lt;h2&gt;
  
  
  The nine condition types
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. token_balance
&lt;/h3&gt;

&lt;p&gt;Does the wallet hold at least the threshold of a token? Thirty-eight chains: thirty-two EVM plus Solana, XRPL, Bitcoin, Tron, Stellar and Sui. Use &lt;code&gt;"contractAddress": "native"&lt;/code&gt; for the chain's own asset. On XRPL the same type covers issued currencies and trust lines, and the result surfaces whether the line is frozen. Why it exists in this shape: the balance itself is never returned, only the boolean, and the threshold travels as a string so the verdict is reproducible to the last decimal.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. nft_ownership
&lt;/h3&gt;

&lt;p&gt;Does the wallet hold at least one of a collection? Thirty-four chains: the EVM set plus Solana and XRPL. Bitcoin, Tron, Stellar and Sui are balance-only. Why: presence is the question, so the threshold is fixed at zero and the verdict is the cleanest possible boolean.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. eas_attestation
&lt;/h3&gt;

&lt;p&gt;Does an attestation exist for this wallet on the Ethereum Attestation Service, on any of six chains, matching a schema? Five templates cover the common cases: &lt;code&gt;coinbase_verified_account&lt;/code&gt;, &lt;code&gt;coinbase_verified_country&lt;/code&gt;, &lt;code&gt;coinbase_one&lt;/code&gt;, &lt;code&gt;gitcoin_passport_score&lt;/code&gt; and &lt;code&gt;gitcoin_passport_active&lt;/code&gt;; any raw &lt;code&gt;schemaId&lt;/code&gt; works too. Why: it lets a condition say "cleared a regulated exchange's checks" or "cleared a humanity score" without the caller ever handling a document. The attestation was issued elsewhere; the verdict says it exists.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. farcaster_id
&lt;/h3&gt;

&lt;p&gt;Does this address own a Farcaster account? Read from the identity registry on Optimism. Why: it is the one social identity that lives on-chain and can therefore be a condition rather than an API call to a platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. evm_view_call
&lt;/h3&gt;

&lt;p&gt;Call any view function on a supported EVM chain that takes a single address and returns a boolean, named by a canonical selector of the form &lt;code&gt;functionName(address)&lt;/code&gt;. The result is met when the function returns true; a revert is a signed false, not an error. Why: every contract that already encodes membership, allowlisting, delegation or voting rights becomes a gate with no new deployment, and the reproduction procedure is stated in the spec so anyone can re-issue the call.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. ratio_to_amount
&lt;/h3&gt;

&lt;p&gt;Met when balance is at least &lt;code&gt;multiple&lt;/code&gt; times &lt;code&gt;amount&lt;/code&gt;, both decimal strings. The derived threshold, computed with a ceiling so the gate errs toward strictness, travels inside &lt;code&gt;evaluatedCondition&lt;/code&gt;. Why: "hold ten times what you are about to spend" is one rule that needs no retuning across chains, prices or transaction sizes. EVM chains with direct RPC access.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. ratio_to_supply
&lt;/h3&gt;

&lt;p&gt;Met when balance divided by &lt;code&gt;totalSupply()&lt;/code&gt; is at least &lt;code&gt;minFraction&lt;/code&gt;, a decimal string in the open-closed interval up to 1. The raw supply read is a sibling of &lt;code&gt;evaluatedCondition&lt;/code&gt;, inside the signed payload but outside the condition hash, so a verifier re-reads balance and supply at the pinned block and re-derives the boolean exactly. Why: share of supply is the honest measure of stake for governance and project tokens; it is meaningless for stablecoins, and we say so.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. erc8004_agent
&lt;/h3&gt;

&lt;p&gt;Is this wallet the owner of, or the signature-bound agent wallet for, agent &lt;code&gt;agentId&lt;/code&gt; in the ERC-8004 identity registry on Base? The result carries &lt;code&gt;agentExists&lt;/code&gt; and &lt;code&gt;matchedVia&lt;/code&gt; (&lt;code&gt;owner&lt;/code&gt;, &lt;code&gt;agent_wallet&lt;/code&gt; or &lt;code&gt;none&lt;/code&gt;). Why the scope note is in the signed bytes: registration is permissionless minting. The verdict states registration and binding, and implies no vetting, no reputation and no endorsement. Merkle proofs are not offered for this type.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. erc7710_delegation
&lt;/h3&gt;

&lt;p&gt;Given a delegation object the caller already holds, is it currently valid for this wallet as delegate? Met when: the EIP-712 signature verifies (an EOA signature or an ERC-1271 smart-contract assertion, and the result names which, because those are different claims), the declared delegator matches &lt;code&gt;expectedDelegator&lt;/code&gt;, the delegation is not revoked as of the anchored block, every caveat uses a recognized enforcer, and any time-window caveat is open. Managers must be a recognized delegation framework deployment on Base; root authority only; up to sixteen caveats; up to three delegation conditions per request.&lt;/p&gt;

&lt;p&gt;Two design points worth understanding. First, &lt;code&gt;declaredLimits&lt;/code&gt;: the decoded caveat terms (timestamps, ERC-20 and native spend ceilings, allowed targets, call counts) are reported, not simulated. They sit inside the signed results but outside &lt;code&gt;conditionHash&lt;/code&gt;, as a sibling of &lt;code&gt;evaluatedCondition&lt;/code&gt;, because the caller submitted those bytes itself and can re-decode them with no external lookup; on-chain redemption enforces them. Second, &lt;code&gt;failReason&lt;/code&gt; distinguishes &lt;code&gt;delegate_mismatch&lt;/code&gt;, &lt;code&gt;principal_mismatch&lt;/code&gt;, &lt;code&gt;invalid_signature&lt;/code&gt;, &lt;code&gt;delegator_not_deployed&lt;/code&gt;, &lt;code&gt;revoked&lt;/code&gt;, &lt;code&gt;unknown_caveat_enforcer&lt;/code&gt; and &lt;code&gt;outside_time_window&lt;/code&gt;, and &lt;code&gt;delegator_not_deployed&lt;/code&gt; is its own reason because no signature was evaluated when the principal has no code on chain yet. Delegation verdicts expire in five minutes, not thirty, because revocation is one transaction away. If the attestation will be forwarded, &lt;code&gt;"declaredLimits": "omit"&lt;/code&gt; keeps the principal's ceiling out of it; &lt;code&gt;met&lt;/code&gt; and the hashes are byte-identical either way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proof mode
&lt;/h2&gt;

&lt;p&gt;Add &lt;code&gt;"proof": "merkle"&lt;/code&gt; and a balance condition carries an EIP-1186 storage proof of the balance slot; a delegation condition carries a proof of the revocation slot, tagged &lt;code&gt;subject: "delegation_revocation"&lt;/code&gt; with the contract address, mapping slot and storage key alongside the standard account and storage proofs. Verify it against the block header's state root from any header source. For revocation: recompute &lt;code&gt;storageKey = keccak256(abi.encode(delegationHash, mappingSlot))&lt;/code&gt; from the &lt;code&gt;delegationHash&lt;/code&gt; in the signed &lt;code&gt;evaluatedCondition&lt;/code&gt; first, because that is what binds the proof to this delegation, then read the proven value, where 1 is revoked and 0 is a positive proof that no revocation exists. Proof mode anchors a few blocks behind the tip on purpose, since the state trie is not reliably retrievable at the tip, and the verdict and the proof always describe the same block. It costs two credits instead of one, and on a balance condition it reveals the raw balance, so it trades privacy for trustlessness by explicit choice. If a proof cannot be produced for a transient reason, the premium is refunded and the call costs one.&lt;/p&gt;

&lt;h2&gt;
  
  
  JWT format
&lt;/h2&gt;

&lt;p&gt;Add &lt;code&gt;"format": "jwt"&lt;/code&gt; and the response also carries a standard ES256 JWT with the same verdict, verifiable by any JWT library against the published JWKS with no SDK. The claims: &lt;code&gt;pass&lt;/code&gt;, the condition hashes, the block anchor, the results, issuer, subject (the wallet), &lt;code&gt;jti&lt;/code&gt; (the attestation id), &lt;code&gt;iat&lt;/code&gt; and &lt;code&gt;exp&lt;/code&gt;. Why both formats: the raw form is the canonical artifact with the exact signed bytes; the JWT is what an API gateway, a WordPress plugin or an edge worker can check with tooling it already has.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fact profiles
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;POST /v1/trust&lt;/code&gt; runs a curated set against one wallet: forty-four base checks across twenty-five chains in five dimensions (stablecoins, governance tokens, NFTs, staking, institutional stablecoins), up to forty-nine checks across twenty-seven chains in nine dimensions with the optional Solana, XRPL, Bitcoin and Tron wallets. The whole profile is signed as one object. No score, no opinion, just cryptographically verifiable evidence organized by dimension. &lt;code&gt;POST /v1/trust/batch&lt;/code&gt; profiles up to ten wallets in one call, fetching block numbers once, with each profile independently signed. Three credits per profile, six with proofs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Paying without a key
&lt;/h2&gt;

&lt;p&gt;Every attest and trust call is also reachable with no API key at all via x402 on Base, paid in USDC per call: five cents for an attestation, ten with a proof, fifteen for a profile, thirty with proofs. The invariant, stated exactly: the payer is charged only for a successful answer, and the payer sees the answer only after the payment settled. Evaluation failure means no payment; settlement failure means no response; settlement success means payment, response and the settlement transaction hash in-band so the payment itself is independently checkable. For keyed access there are three paths: &lt;code&gt;POST /v1/keys/create&lt;/code&gt; for the email free tier (10 free verifications plus 100 reads/day), &lt;code&gt;POST /v1/keys/buy&lt;/code&gt; on-chain, and &lt;code&gt;POST /v1/credits/buy&lt;/code&gt; to top up. Prepaid starts at four cents a call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verification: five independent verdicts
&lt;/h2&gt;

&lt;p&gt;The reference verifier is &lt;code&gt;insumer-verify&lt;/code&gt; on npm, zero required dependencies, Web Crypto only, and it never collapses its answer into one boolean. It reports five verdicts and lets you decide what each means for you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Signature.&lt;/strong&gt; Resolve the key by the &lt;code&gt;kid&lt;/code&gt; on the response from the JWKS; an unresolvable &lt;code&gt;kid&lt;/code&gt; fails closed rather than falling back to the first key. Rebuild the exact preimage the &lt;code&gt;kid&lt;/code&gt; selects and verify ECDSA P-256 over it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Condition hashes.&lt;/strong&gt; Canonicalize each &lt;code&gt;evaluatedCondition&lt;/code&gt;, hash it, compare.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Freshness.&lt;/strong&gt; Compare the signed &lt;code&gt;blockTimestamp&lt;/code&gt; to your own maximum age. The window is yours to set: a checkout wants seconds, an auditor wants none.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiry.&lt;/strong&gt; Bound &lt;code&gt;expiresAt&lt;/code&gt; to the signed &lt;code&gt;attestedAt&lt;/code&gt; plus the issuance window, then compare to now.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Post-quantum companion.&lt;/strong&gt; New, and covered next.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The point of separating them is that "valid" is a policy, and the policy belongs to the relying party. An attestation records that a wallet met a condition at a named block, and that does not decay. The expiry is a freshness policy for access decisions, not a statement about whether the verdict was correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  The post-quantum companion
&lt;/h2&gt;

&lt;p&gt;Since the first of September, every attest and trust response carries a second signature beside the first: &lt;code&gt;pqSig&lt;/code&gt; and &lt;code&gt;pqKid&lt;/code&gt; on the raw form, and a sibling &lt;code&gt;pqJwt&lt;/code&gt; on the JWT form. The algorithm is ML-DSA-65 under FIPS 204. The public key is published in the same JWKS as RFC 9964 &lt;code&gt;AKP&lt;/code&gt; entries under the kids &lt;code&gt;insumer-attest-pq1&lt;/code&gt; and &lt;code&gt;insumer-trust-pq1&lt;/code&gt;, appended after the three EC entries so that any verifier still falling back to the first key keeps a classical one.&lt;/p&gt;

&lt;p&gt;The design is additive, and that word is doing work. &lt;code&gt;sig&lt;/code&gt;, &lt;code&gt;kid&lt;/code&gt;, &lt;code&gt;jwt&lt;/code&gt;, every preimage and every existing key are byte-for-byte unchanged. The companion signs the post-quantum domain tag plus the exact classical preimage the response's &lt;code&gt;kid&lt;/code&gt; selects, so no new canonicalization was introduced and the v1 and v2 eras are covered identically. The &lt;code&gt;pqJwt&lt;/code&gt; is its own compact JWS with the same claims as &lt;code&gt;jwt&lt;/code&gt;, and the verifier binds it to the classical token by &lt;code&gt;jti&lt;/code&gt;, &lt;code&gt;exp&lt;/code&gt; and &lt;code&gt;pass&lt;/code&gt;, so a companion cannot be transplanted from another artifact. Before any of it was published we ran the previous release of the verifier against live responses to confirm it returned identical verdicts with and without the new fields.&lt;/p&gt;

&lt;p&gt;The binding between the classical key and the post-quantum key is a content-addressed statement at &lt;code&gt;/.well-known/pq-key-binding.json&lt;/code&gt;, signed by both keys and anchored on Base in block 50758053. Its block time is the public record of when the companion came into existence, which is what lets a verifier reading an old artifact say, truthfully, that no companion could have existed when it was issued.&lt;/p&gt;

&lt;p&gt;The fifth verdict has four states: &lt;code&gt;verified&lt;/code&gt;, &lt;code&gt;refuted&lt;/code&gt; (present and failing), &lt;code&gt;absent&lt;/code&gt;, and &lt;code&gt;unverifiable&lt;/code&gt; (present but not checkable, because the key could not be resolved or the runtime has no ML-DSA implementation). The rules: refuted always fails the artifact. Absent or unverifiable fail only under your own &lt;code&gt;pqRequiredFrom&lt;/code&gt; cutoff, judged by your clock at verification time and never by any timestamp inside the artifact, because under a classical break every one of those timestamps is forgeable. In &lt;code&gt;mode: "evidence"&lt;/code&gt;, for reading an artifact after the fact, nothing is refused; the verifier reports the state and, given the anchored binding date, whether a companion existed at issuance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;verifyAttestation&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;insumer-verify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// A live access decision: from this date, insist on the companion.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;verifyAttestation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;jwksUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://insumermodel.com/.well-known/jwks.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;pqRequiredFrom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2027-06-01T00:00:00Z&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// "verified" | "refuted" | "absent" | "unverifiable"&lt;/span&gt;

&lt;span class="c1"&gt;// Reading a receipt years later: never refused, always explained.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;verifyAttestation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;jwksUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;evidence&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pqActivatedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bindingBlockTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;existedAtIssuance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// false for anything issued before the binding&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ML-DSA is not in Web Crypto yet, so the verifier loads it from an optional dependency and reports &lt;code&gt;unverifiable&lt;/code&gt; with a reason when it is missing, never a silent pass and never a silent failure. A PHP verifier can do the same through OpenSSL 3.5 or later on PHP 8.4 or later, and SkyeMeta's plugins do exactly that, probing the host with a real vector at activation and saying plainly when the host cannot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test vectors and the multi-issuer envelope
&lt;/h2&gt;

&lt;p&gt;Seventeen published vectors at &lt;code&gt;/.well-known/state-attestation-test-vectors.json&lt;/code&gt;, mirrored from the &lt;code&gt;insumer-examples&lt;/code&gt; repository, which is the authority if the two ever differ. Eleven cover the classical checks, tampered conditions, tampered signatures and an unresolvable &lt;code&gt;kid&lt;/code&gt;. Six cover the companion: both key eras verified, a tampered companion refuted, an unresolvable &lt;code&gt;pqKid&lt;/code&gt; under a cutoff, a pre-companion artifact under a cutoff, and the JWT envelope. Each carries a recompute block with the canonical condition, its hash, and the anchor, and states its expected verdicts as separate booleans rather than one. Anyone can run the whole set against any node without anything from us, which is why a run is the runner's to publish.&lt;/p&gt;

&lt;p&gt;For stacks that carry attestations from several issuers, the same repository holds a multi-attestation envelope spec and a reference verifier: each slot keeps its own issuer's signature and key identifier, the envelope is transport rather than trust, and the aggregate is recomputed from the slot verdicts plus pinned options. Eight envelope fixtures pin the behaviour, including the two cases that matter most, a slot with its signature stripped and an object stapled beside a JWS that bears no signature at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it plugs in
&lt;/h2&gt;

&lt;p&gt;Forty-six operations in the OpenAPI spec. An MCP server with twenty-seven tools, a LangChain toolkit with twenty-six, LlamaIndex tools, ElizaOS actions, a ChatGPT action, and the &lt;code&gt;insumer-verify&lt;/code&gt; package for the checking side. On the product side, SkyeMeta's SkyeGate and SkyeWoo plugins and SkyeMeta's Vercel SDK consume the JWT format and now report the companion too. None of that is new surface; it is the same primitive packaged for wherever your code already lives.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to take from this
&lt;/h2&gt;

&lt;p&gt;If you integrate one thing, integrate the verifier and read its five verdicts instead of one boolean. If you integrate two, add a delegation condition in front of anything an agent can spend. And if you keep attestations as evidence, keep the whole envelope: the block, the condition, the hash and both signatures are what make it worth keeping.&lt;/p&gt;

&lt;p&gt;Conditions in. Signed attestations out. That has not changed. The list of conditions has.&lt;/p&gt;

&lt;p&gt;Douglas&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://insumermodel.com/blog/what-wallet-state-can-prove-developer-guide.html" rel="noopener noreferrer"&gt;insumermodel.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>webdev</category>
      <category>security</category>
      <category>api</category>
    </item>
    <item>
      <title>What Is Wallet Attestation in the UCP Spec?</title>
      <dc:creator>Douglas Borthwick</dc:creator>
      <pubDate>Fri, 28 Aug 2026 17:43:01 +0000</pubDate>
      <link>https://dev.to/douglasborthwickcrypto/what-is-wallet-attestation-in-the-ucp-spec-5dk3</link>
      <guid>https://dev.to/douglasborthwickcrypto/what-is-wallet-attestation-in-the-ucp-spec-5dk3</guid>
      <description>&lt;p&gt;The Universal Commerce Protocol release of 25 August 2026 uses the phrase “wallet attestation” in its normative text. It never defines it. If you went looking for what it means and found nothing, this is that page — what the reserved slot is, how it got into the spec, and what would go in it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the spec actually says
&lt;/h2&gt;

&lt;p&gt;Two places, both in the identity linking capability. The first is the schema, on the &lt;code&gt;provider&lt;/code&gt; definition in &lt;code&gt;identity_linking.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A trusted identity provider for delegated authentication, keyed by the
'type' discriminator. 'oauth2' denotes an OAuth 2.0 / OIDC authorization
server. Future versions MAY define additional types (e.g. wallet
attestation) as non-breaking extensions; platforms MUST treat entries
whose 'type' they do not support as filtered out (see Provider Selection).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second is the Future Extensibility section of the identity linking specification, which describes &lt;code&gt;provider.type&lt;/code&gt; as “a required, open string” where &lt;code&gt;oauth2&lt;/code&gt; is the only type defined in this version, and which “reserves space for future types — wallet attestation, verifiable credentials, or other proof-of-identity protocols.”&lt;/p&gt;

&lt;p&gt;Read that precisely, because the precision is the interesting part. The slot is &lt;strong&gt;reserved, not filled&lt;/strong&gt;. No platform is obliged to support wallet attestation, and verifiable credentials are named in the same sentence. What the spec does commit to is the mechanics of extension: &lt;code&gt;type&lt;/code&gt; is an open string rather than a closed enum, so an unrecognised value validates instead of failing, and a platform that does not understand a provider entry &lt;em&gt;must&lt;/em&gt; filter it out rather than reject the whole profile.&lt;/p&gt;

&lt;h2&gt;
  
  
  What wallet attestation is
&lt;/h2&gt;

&lt;p&gt;It is a way to answer a question about a buyer without learning who they are. A verifier reads public blockchain state at a specific block, evaluates a condition the business defined, and returns a signed boolean. Not a balance, not an address, not a profile — a yes or no, with a signature over the condition that was evaluated.&lt;/p&gt;

&lt;p&gt;The reason it fits beside OAuth rather than against it is that the four operations an identity system has to perform are already native to chain state:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Issuance&lt;/strong&gt; is a chain mutation. Someone minted, was granted, or bought the asset.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consent&lt;/strong&gt; splits in two, and the distinction is worth being exact about. The durable half — I chose to hold this, and still do — is the on-chain act itself. The per-transaction half — I am choosing to show you, now — is the presentation: connecting a wallet, showing a code, tapping a tag. Possession on its own is not consent to disclose, so it is the presentation that carries that, never the holding. OAuth collapses both into one consent screen; here they are separate, and only the second is per-transaction.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Revocation&lt;/strong&gt; is a chain mutation too. Burn it, transfer it, drop below the threshold, and the next evaluation returns false on its own.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Verification&lt;/strong&gt; is a read of current state, signed, checkable offline against a published key set.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OAuth builds consent screens, token expiry, revocation lists and introspection endpoints to approximate those four things for account systems, and it does that well. The point is not that one replaces the other. It is that when the fact you need is already on a public ledger, you can read it directly, and the business never has to hold a session, host a consent page, or store anything about the person.&lt;/p&gt;

&lt;h2&gt;
  
  
  When you would reach for it
&lt;/h2&gt;

&lt;p&gt;The shape is useful whenever a business needs to act on a fact about a buyer that it should not have to store, and that the buyer should not have to prove by logging in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Member pricing an agent can act on.&lt;/strong&gt; A shopping agent is completing a checkout on someone’s behalf. The business offers a better price to holders of a particular pass. Without something like this, the agent has to drive an account login it does not have, or the business has to trust an unverifiable assertion from the agent. With it, the business asks one question and gets a signed answer it can keep as evidence of why it applied the price.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eligibility that currently requires an account.&lt;/strong&gt; Student, alumni, union, employee, early-supporter, season-ticket — these are all facts that exist somewhere, and the usual way to check them is to make the person create yet another account, or to trust a photograph of a card. Where the underlying credential already lives on a chain, checking it is a read rather than an onboarding flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shareholder perks an agent could actually use.&lt;/strong&gt; Issuers have offered benefits to their own shareholders for decades — onboard credit, product discounts, meeting access — and the way you claim one is still to email a brokerage statement to somebody and wait. Tokenised equity does not change what is on offer; it changes what is checkable, because a holding becomes a ledger entry a business can evaluate the same way it evaluates any other wallet condition. The moment that stops being hypothetical is an agent completing a purchase on behalf of someone who holds the issuer’s stock, and wanting the holder’s price. The issuing side of that is being built now, by exchanges and registrars. Reading a holding at a checkout is a different question, and it is the one this mechanism answers — which is what we wrote about &lt;a href="https://insumermodel.com/blog/bullish-tokenized-equity-issuer-rewards-recognition-gap.html" rel="noopener noreferrer"&gt;when an exchange pitched issuers on shareholder rewards&lt;/a&gt; and the register had no way to see the share.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recognition across businesses that share nothing.&lt;/strong&gt; A community issues one pass. Twenty independent shops honour it. None of them holds a customer list, none of them integrates with the others, and the community can add or remove members without telling any of them. Each business evaluates the same public fact independently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Revocation that is actually current.&lt;/strong&gt; A lapsed membership is the awkward case for token-based access, because a token issued last year says nothing about today. Here the check reads present state at a block: if the asset moved, was burned, or fell below the threshold, the next evaluation returns false with no revocation list to publish and no stale-token window to reason about.&lt;/p&gt;

&lt;p&gt;And the boundary, because it matters as much as the cases: if the fact you need is not on a chain, this is the wrong instrument. It answers questions about wallet state. It does not tell you someone’s name, that they are over eighteen, or that they are who they claim to be, and no amount of signing makes it do so. For those, the spec reserved room for other mechanisms in the same sentence, which is the right outcome.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compared with the alternatives
&lt;/h2&gt;

&lt;p&gt;It is not better than the other mechanisms. It is better at one specific question — &lt;em&gt;does this buyer’s wallet satisfy this condition right now&lt;/em&gt; — and worse at most others. The useful comparison is what each one costs you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Against an account login.&lt;/strong&gt; OAuth is the right answer when the fact lives in your database or an identity provider’s, and it is far better than this at anything involving a person’s profile. Agents can use it perfectly well, too — that is exactly what UCP’s identity linking capability is for, and the August release describes agents negotiating identity providers on a buyer’s behalf. What OAuth needs is that a human consented at some point. The consent screen is a human moment by design, and everything afterwards runs on the strength of it, which is a feature rather than a defect. It does mean the first encounter between a buyer and a business contains a person-shaped step. A wallet condition has no prior relationship to establish: the buyer already holds the thing, and the business reads whether they still do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Against verifiable credentials.&lt;/strong&gt; These are stronger wherever an authority has to vouch for something about a person — age, qualification, residency. The cost is an ecosystem: an issuer willing to issue, holder software, a status mechanism for revocation. When the fact is already a public ledger entry, that machinery is doing work the chain has already done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Against calling a partner’s API.&lt;/strong&gt; A lookup is fine when the partner owns the data. It leaves you with a live dependency, a bilateral integration per partner, and a partner who learns every question you ask. Chain state is readable by everyone independently, so twenty businesses can check the same fact without any of them integrating with each other or with the issuer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Against a card, a code, or a screenshot.&lt;/strong&gt; No contest, and this is the honest baseline for most in-person eligibility today. Those are trivially forged and leave no evidence afterwards. A signed result is checkable later by someone who trusts neither party.&lt;/p&gt;

&lt;p&gt;Where it loses is worth being just as plain about. The fact has to be on a chain. It establishes nothing about identity, age or personhood. It requires the buyer to hold and present a wallet, which is a real adoption cost. And it is not privacy for the underlying fact — the ledger is public — it is privacy in what the &lt;em&gt;business&lt;/em&gt; ends up holding, which is a boolean and a signature rather than an address or a balance.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it got into the spec
&lt;/h2&gt;

&lt;p&gt;Through review, which is how vocabulary usually enters a specification.&lt;/p&gt;

&lt;p&gt;On 15 March 2026 we proposed the mechanism and its literal shape in the discussion thread on UCP issue #265 — a provider type of &lt;code&gt;wallet_attestation&lt;/code&gt; carrying a &lt;code&gt;provider_jwks&lt;/code&gt; URL, contributing no scopes and issuing no token. On 18 March a UCP maintainer quoted that block back into the thread. Both comments are public.&lt;/p&gt;

&lt;p&gt;What happened next was not ours. In PR #354, which merged on 6 May 2026, the identity linking foundation established &lt;code&gt;config.providers&lt;/code&gt; with a &lt;code&gt;type&lt;/code&gt; discriminator and reserved room for non-OAuth mechanisms. In PR #423, merged 12 June, the maintainer made that extension structural rather than merely documented: &lt;code&gt;type&lt;/code&gt; became an open string, each mechanism got its own conditional requirements, and unrecognised types were defined as filtered rather than rejected. We had argued for a different structure in that review and were overruled, correctly — the shape that shipped extends more cleanly than the one we proposed.&lt;/p&gt;

&lt;p&gt;The release of 25 August carried that reservation into published normative text. Our own proposal for the concrete mechanism, &lt;a href="https://github.com/Universal-Commerce-Protocol/ucp/pull/415" rel="noopener noreferrer"&gt;PR #415&lt;/a&gt;, is open and unmerged. It is a proposal, not a standard, and this page is not claiming otherwise.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a provider entry looks like
&lt;/h2&gt;

&lt;p&gt;Inside the identity linking capability config, providers are keyed by reverse-domain name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"providers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"com.example.walletauth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wallet_attestation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"provider_jwks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://api.example.com/.well-known/jwks.json"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because &lt;code&gt;type&lt;/code&gt; is an open string and the provider object permits additional properties, an entry like this &lt;strong&gt;validates against the released schema as published&lt;/strong&gt;. A platform that supports the mechanism resolves the key set and verifies attestations against it. A platform that does not filters the entry out and carries on with whatever else is advertised. Neither one breaks, which is what the forward-compatibility rule is for.&lt;/p&gt;

&lt;p&gt;The verification itself is ordinary: fetch the key set, verify the ES256 signature, and check the hash of the condition that was evaluated so you know which question was answered. No callback to the issuer, no shared secret, nothing that expires in a drawer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this is not
&lt;/h2&gt;

&lt;p&gt;It is worth being blunt about the limits, because they are checkable and you would find them anyway.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;UCP has &lt;strong&gt;not adopted&lt;/strong&gt; wallet attestation. It reserved a slot and named it as one candidate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Verifiable credentials are named alongside it&lt;/strong&gt; in the same sentence. Nothing privileges one over the other.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;oauth2&lt;/code&gt; remains the only provider type defined in the current version.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Our proposal for the concrete mechanism is &lt;strong&gt;open, not merged&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What is durable is smaller and more useful than an adoption claim: the extension point exists in released normative text, it names the mechanism, the mechanics of adding a type are specified, and a conforming entry can be written today. If you are building on UCP identity linking and want the wallet-state question answered without taking custody of an identity, that is the shape it takes.&lt;/p&gt;

&lt;p&gt;Whether this becomes how agentic commerce checks eligibility, or one option among several, is not something this page can tell you — the slot is reserved and nothing is settled. For the wider argument about why checks that work without a human present are being asked for at all, that is a separate and more opinionated piece: &lt;a href="https://insumermodel.com/blog/passwords-to-proofs.html" rel="noopener noreferrer"&gt;From Passwords to Proofs&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>api</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Verifying an AI Agent's Authority Before It Spends: Signed Booleans Across Six Chains</title>
      <dc:creator>Douglas Borthwick</dc:creator>
      <pubDate>Thu, 30 Jul 2026 19:32:09 +0000</pubDate>
      <link>https://dev.to/douglasborthwickcrypto/verifying-an-ai-agents-authority-before-it-spends-signed-booleans-across-six-chains-1332</link>
      <guid>https://dev.to/douglasborthwickcrypto/verifying-an-ai-agents-authority-before-it-spends-signed-booleans-across-six-chains-1332</guid>
      <description>&lt;p&gt;At 4:52 on a Friday afternoon, an instruction lands at a corporate treasury service: pay this invoice. $48,000 in USDC to a vendor wallet, on behalf of a client called Meridian Labs. The sender is not Meridian's CFO. It is Meridian's procurement agent, a piece of software carrying a signed permission slip.&lt;/p&gt;

&lt;p&gt;There is no human to call. The payment is irreversible the second it settles. And the one thing everyone has learned about AI agents this year is that some of them are compromised, confused, or running on authority that was revoked twenty minutes ago.&lt;/p&gt;

&lt;p&gt;This post walks through how I answer that question with two API calls: what goes in, what comes back, why every answer is a signed boolean instead of a score, and how to verify the signatures yourself without trusting the API that produced them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two-party problem
&lt;/h2&gt;

&lt;p&gt;The thing that makes agent payments different from checkout is that the actor and the owner are different parties. The agent spends; the money is Meridian's; whoever executes the payment sits in the middle carrying the liability if those two facts ever disagree.&lt;/p&gt;

&lt;p&gt;So there are questions about two different wallets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The agent's wallet:&lt;/strong&gt; is this a registered, identifiable agent, and does it hold currently-valid authority from its principal?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The principal's wallet:&lt;/strong&gt; is there a KYC-attested entity behind this, and can the treasury actually stand the payment?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An attestation evaluates one wallet, so this is two calls to &lt;code&gt;POST /v1/attest&lt;/code&gt;. One receipt for the actor, one for the owner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Call 1: may this agent act?
&lt;/h2&gt;

&lt;p&gt;Two conditions against the agent's wallet, both answered from chain state on Base:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://insumermodel.com/v&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;/attest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;X-API-Key:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"wallet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xA9b3...the agent's wallet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"erc8004_agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"chainId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8453&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"agentId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"412"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Registered ERC-8004 agent"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"erc7710_delegation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"chainId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8453&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"delegationManager"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xdb9B1e94B5b69Df7e401DDbedE43491141047dB3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"expectedDelegator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x51fA...Meridian's treasury"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"delegation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"...the signed ERC-7710 delegation object..."&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Currently authorized by Meridian's treasury"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Response, abridged (illustrative values, exact real shape):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pass"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"results"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Registered ERC-8004 agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"met"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"matchedVia"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"owner"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Currently authorized by Meridian's treasury"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"met"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"declaredLimits"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"erc20_transfer_amount"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x8335...USDC on Base"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"maxAmount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"75000000000"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"attestedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-07-31T20:52:14.000Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"expiresAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-07-31T20:57:14.000Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sig"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MEUCIQDrT..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"kid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"insumer-attest-v2"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few fields worth unpacking:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;erc8004_agent&lt;/code&gt; is honest about what it proves.&lt;/strong&gt; ERC-8004 registration is permissionless NFT minting, so &lt;code&gt;met: true&lt;/code&gt; means exactly "registered in the Identity Registry at this agentId, and this wallet owns the agent NFT or is the registry's signature-verified agent wallet binding." &lt;code&gt;matchedVia&lt;/code&gt; tells you which. No vetting, no reputation, no endorsement implied. An attestation that overclaims is worse than none.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;erc7710_delegation&lt;/code&gt; checks the whole chain of facts.&lt;/strong&gt; &lt;code&gt;met: true&lt;/code&gt; only when the attested wallet is the delegate, the declared principal matches &lt;code&gt;expectedDelegator&lt;/code&gt;, the EIP-712 signature verifies (EOA recovery, or ERC-1271 for smart-contract principals, and the result names which), the delegation is unrevoked as of the anchored block, every caveat uses a recognized enforcer, and any time window is currently open.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;declaredLimits&lt;/code&gt; is a decode, not a verdict.&lt;/strong&gt; The spending caveats the principal signed come back decoded, with amounts in base units. &lt;code&gt;75000000000&lt;/code&gt; on a 6-decimal token is a $75,000 USDC cap, sitting above this $48,000 invoice. It is reported as what the principal signed rather than something the API simulated, and each entry carries the raw caveat &lt;code&gt;terms&lt;/code&gt; hex it was decoded from, so you can re-derive the decode yourself from the enforcer's documented byte layout. If you plan to forward the attestation and would rather the cap not travel with it, send &lt;code&gt;declaredLimits: "omit"&lt;/code&gt; in the request; &lt;code&gt;met&lt;/code&gt; and the hashes stay byte-identical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The expiry is 5 minutes, not the standard 30.&lt;/strong&gt; Revocation is one transaction away, so a verdict about delegation is only fresh while it is fresh. The short window is the honest window.&lt;/p&gt;

&lt;h2&gt;
  
  
  Call 2: the owner, wherever the money lives
&lt;/h2&gt;

&lt;p&gt;Corporate crypto treasuries are never on one chain. BTC in cold reserve, USDT on Tron because that is where payment liquidity is, RLUSD on the XRP Ledger, operating USDC on Base and Ethereum. The second call attests Meridian's treasury wallet, and each condition carries its own &lt;code&gt;chainId&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"wallet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x51fA...Meridian's treasury"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"xrplWallet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rN7n..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bitcoinWallet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bc1q..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tronWallet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TWdc..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eas_attestation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"template"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"coinbase_verified_account"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"KYC-attested entity"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ratio_to_amount"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"chainId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8453&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"contractAddress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x8335...USDC on Base"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"multiple"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"48000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Operating account covers 1.5x this payment"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"token_balance"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"chainId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"contractAddress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xA0b8...USDC on Ethereum"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"threshold"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"250000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Mainnet float above policy floor"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"token_balance"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"chainId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xrpl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"contractAddress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rMxC...RLUSD issuer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RLUSD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"threshold"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"100000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RLUSD reserve above floor"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"token_balance"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"chainId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bitcoin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"contractAddress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"native"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"threshold"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BTC cold reserve intact"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"token_balance"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"chainId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tron"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"contractAddress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TR7N...USDT on Tron"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"threshold"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"150000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USDT payment float above floor"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Six booleans come back across five chains, each block-anchored (&lt;code&gt;blockNumber&lt;/code&gt; on EVM chains, &lt;code&gt;ledgerIndex&lt;/code&gt; on XRPL, block height on Bitcoin), all under one signature. One call, one credit.&lt;/p&gt;

&lt;p&gt;Two details I want to highlight for developers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;ratio_to_amount&lt;/code&gt; is the payment check that never goes stale.&lt;/strong&gt; A flat threshold tuned for $48,000 invoices is wrong for $480,000 invoices. With a ratio you pass the transaction amount and your risk multiple per request, and the signed boolean is always scaled to the payment in front of you: &lt;code&gt;balance &amp;gt;= multiple * amount&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The caller never learns a balance.&lt;/strong&gt; The service knows the operating account holds at least 1.5x this payment. It does not know if that is $72,001 or $40 million. That asymmetry is why a counterparty is willing to answer at all. (One documented trade-off: Merkle proof mode on a &lt;code&gt;token_balance&lt;/code&gt; condition does reveal the raw balance to the caller, since the proof is of the balance storage slot itself. Standard mode never does.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify the signature yourself
&lt;/h2&gt;

&lt;p&gt;The response is ECDSA P-256 signed. &lt;code&gt;kid&lt;/code&gt; tells you which scheme: &lt;code&gt;insumer-attest-v2&lt;/code&gt; signs a domain-separated canonical preimage of &lt;code&gt;{v, id, pass, results, attestedAt}&lt;/code&gt; with keys sorted recursively. The public key is in a standard JWKS at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;https://insumermodel.com/.well-known/jwks.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So verification is any JOSE library plus the documented preimage, or &lt;code&gt;npm install insumer-verify&lt;/code&gt; if you want it done for you. Add &lt;code&gt;"format": "jwt"&lt;/code&gt; to the request and you also get the whole attestation as an ES256 JWT that any standard JWT library can verify against the same JWKS, which makes the verdict portable: hand it to another service and they can check it without calling anyone.&lt;/p&gt;

&lt;p&gt;And for the one clause that could change a block later, you do not have to take the API's word at all. Request the delegation check with &lt;code&gt;proof: "merkle"&lt;/code&gt; and the response carries an EIP-1186 storage proof of the DelegationManager's revocation slot, verifiable against the block header from any source you trust. "Unrevoked as of block N" stops being an assertion and becomes arithmetic.&lt;/p&gt;

&lt;h2&gt;
  
  
  No API key? The agent can pay per call
&lt;/h2&gt;

&lt;p&gt;The part I find most fitting: the machine this was built for does not need an account. Send the request with no credential headers and the API responds with an HTTP 402 quote. Sign an EIP-3009 USDC authorization on Base, retry with the &lt;code&gt;X-PAYMENT&lt;/code&gt; header, and the attestation comes back. Five cents, gasless for the payer, settled on-chain. An agent can go from never having heard of the API to holding a signed delegation verdict in two HTTP requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  The menu is bigger than this scenario
&lt;/h2&gt;

&lt;p&gt;Everything above is one composition. The same endpoint takes up to ten conditions per call, mixed across 38 chains, from nine condition types: token balances (including native BTC, TRX, XLM, SUI), NFT ownership (34 of the 38 chains), EAS attestations by template or raw schema, Farcaster identity, arbitrary boolean view calls against your own contracts (&lt;code&gt;hasAccess(address)&lt;/code&gt; style), ratio rules against an amount or against total supply, and the two agent-standing types shown here.&lt;/p&gt;

&lt;p&gt;The shape of the answer never changes: wallet state, checked against conditions you wrote, at a block, signed. Not a score. Nobody's model weighed anything. The policy (the 1.5x multiple, the reserve floors, which attestation counts as KYC) stays in your request where an auditor can read it, and the facts come back signed where an auditor can verify them. Fourteen months later, when someone asks why your service let a bot move $48,000, you are not defending an opinion. You are handing over arithmetic.&lt;/p&gt;

&lt;p&gt;Docs, if you want to try it: &lt;a href="https://insumermodel.com/developers/verification/" rel="noopener noreferrer"&gt;verification API reference&lt;/a&gt;, &lt;a href="https://insumermodel.com/state-attestation-spec/" rel="noopener noreferrer"&gt;state attestation spec&lt;/a&gt;. Free tier is an email and 100 reads a day, or skip the key entirely and pay per call over x402.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>webdev</category>
      <category>blockchain</category>
      <category>ai</category>
      <category>api</category>
    </item>
    <item>
      <title>Your Agent Doesn't Need an API Key</title>
      <dc:creator>Douglas Borthwick</dc:creator>
      <pubDate>Wed, 20 May 2026 14:31:50 +0000</pubDate>
      <link>https://dev.to/douglasborthwickcrypto/your-agent-doesnt-need-an-api-key-5ee4</link>
      <guid>https://dev.to/douglasborthwickcrypto/your-agent-doesnt-need-an-api-key-5ee4</guid>
      <description>&lt;p&gt;&lt;strong&gt;Every AI agent today carries secret strings.&lt;/strong&gt; Open its &lt;code&gt;.env&lt;/code&gt; file and you will see them. &lt;code&gt;OPENAI_API_KEY&lt;/code&gt;. &lt;code&gt;ANTHROPIC_API_KEY&lt;/code&gt;. &lt;code&gt;STRIPE_SECRET_KEY&lt;/code&gt;. Whoever holds those strings gets the access. That is the entire authentication model. After running our own agent for a few months, we got tired of it, so we shipped something else. It is on-chain. You can verify it on Basescan in two minutes.&lt;/p&gt;

&lt;p&gt;API keys authenticate &lt;em&gt;possession of a secret&lt;/em&gt;. Wallet signatures authenticate &lt;em&gt;control of a wallet&lt;/em&gt;. That distinction is the whole article.&lt;/p&gt;

&lt;p&gt;A secret is a thing that exists somewhere. It can be copied. It can be exfiltrated. It can be checked into a public repository by accident at 11pm on a Friday and sit there indexed by every crawler on the internet by Monday morning. The string itself is the authentication; whoever holds it is the legitimate user, as far as the API can tell.&lt;/p&gt;

&lt;p&gt;A signature is not a reusable secret. It is a proof, generated on the spot, that whoever wrote this specific message also holds the private key for this specific wallet. The signature can be safely transmitted in cleartext. There is nothing in it that lets the recipient impersonate the signer. The signing key never moves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agents are already good at signing
&lt;/h2&gt;

&lt;p&gt;Humans hate wallets. Humans forget passwords, lose hardware devices, paste seed phrases into the wrong channel, and get phished by emails that look exactly like the real ones. That aversion is the load-bearing reason wallet auth never replaced passwords for consumer login. Wallets are hard for humans, and it is a real reason.&lt;/p&gt;

&lt;p&gt;Agents are not humans. For an agent, signing a message is a function call. The signing library is already in the runtime because the agent already uses a wallet for payments. The marginal cost of using the same wallet to sign API requests is zero. The thing that made wallet auth a non-starter for humans is the thing that makes it natural for agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we built
&lt;/h2&gt;

&lt;p&gt;We dogfooded it on our own API first, so we could speak from the experience of running it rather than describing what it might look like.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The agent's wallet sends 5 USDC to our platform wallet on Base. That buys 125 attestation credits, the unit one &lt;code&gt;/v1/attest&lt;/code&gt; call consumes.&lt;/li&gt;
&lt;li&gt;The agent POSTs the transaction hash to a single endpoint at &lt;code&gt;api.insumermodel.com&lt;/code&gt;. In one response, the API returns an API key string &lt;strong&gt;and&lt;/strong&gt; mints a non-transferable access pass to the same wallet on-chain.&lt;/li&gt;
&lt;li&gt;For every subsequent &lt;code&gt;/v1/attest&lt;/code&gt; call, the agent has two options. Present the API key in an &lt;code&gt;X-API-Key&lt;/code&gt; header, the way every API has worked since the early 2000s. Or sign a fresh message with its wallet's private key and put the signature in an &lt;code&gt;Authorization: Wallet&lt;/code&gt; header. No reusable secret crosses the wire. Other endpoints currently require &lt;code&gt;X-API-Key&lt;/code&gt;; we'll expand wallet auth to them in later stages as their billing and write paths are reviewed for wallet-identity callers.&lt;/li&gt;
&lt;li&gt;Our backend verifies the signature, confirms the wallet holds the access pass, debits one credit, and returns an ECDSA-signed attestation that anyone with the published key can verify offline.&lt;/li&gt;
&lt;li&gt;No bearer secret ever transmitted. The signing key stays in the agent's runtime. The wallet sits where it is. The pass does not move.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Authentication becomes signing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the whole pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  The token is not the payment
&lt;/h2&gt;

&lt;p&gt;The token is the proof the wallet belongs to a legitimate customer.&lt;/p&gt;

&lt;p&gt;This is where the design gets interesting, and where it would be easy to confuse two things that need to stay separate.&lt;/p&gt;

&lt;p&gt;The pass is a &lt;strong&gt;membership&lt;/strong&gt;. It proves that the wallet has paid for an InsumerAPI account at some point. It lives in the wallet permanently. It does not expire when credits run out. It does not have to be re-issued. If the agent stops using the account, the pass sits there. If it comes back a year later and tops up, the same pass is still there.&lt;/p&gt;

&lt;p&gt;Credits are &lt;strong&gt;consumption&lt;/strong&gt;. The agent buys a batch, uses them up on attestation calls, buys more. When they run out, the API returns a 402 with a clear path to top up. The wallet itself does not change. The pass is unaffected.&lt;/p&gt;

&lt;p&gt;That separation matters because it lets the token act as a portable trust signal without coupling the holder to anybody's billing system. A third party building an API can check whether a wallet holds the pass and treat that as a soft signal that this wallet is a real customer of a real verification service, without needing to talk to us about anything, without OAuth federation, without shared databases, without a live API coordination round-trip.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The token is not the payment. The token is the proof the wallet belongs to a legitimate customer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can see the collection on Basescan: &lt;a href="https://basescan.org/address/0x3E2a408cc6eceba04FF9d04A5B8B05aBa8DD50ce" rel="noopener noreferrer"&gt;&lt;code&gt;0x3E2a408cc6eceba04FF9d04A5B8B05aBa8DD50ce&lt;/code&gt;&lt;/a&gt;. The settler wallet that mints to customers is owned by us. Customers only ever receive passes.&lt;/p&gt;

&lt;p&gt;Issuers can deploy an access collection from any NFT factory, or write their own. We used &lt;a href="https://rnwy.com" rel="noopener noreferrer"&gt;RNWY&lt;/a&gt;'s on Base for ours: &lt;a href="https://basescan.org/address/0x7ee64394904968629F93039585c3Fc8562691F31" rel="noopener noreferrer"&gt;&lt;code&gt;0x7ee64394...&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The proof you can check yourself
&lt;/h2&gt;

&lt;p&gt;Last night, our test agent's wallet, starting with $6 of USDC and a few cents of Base ETH for gas, ran the loop end to end. The four transactions sitting on Base mainnet are the public record. Anyone with the right amount of USDC can repeat the exercise.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;USDC payment&lt;/strong&gt;, test wallet to platform wallet: &lt;a href="https://basescan.org/tx/0xf873f5e6b5d9d00efb9ef163317f59f0f66fd8b8826e1230c78c87fe88d1d6f2" rel="noopener noreferrer"&gt;&lt;code&gt;0xf873f5e6...&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pass mint&lt;/strong&gt; to the same wallet: &lt;a href="https://basescan.org/tx/0x6cb43ea1374d16e9b76bc4f6ff82989b7b43e7870f7adb06a5a3bc991813368d" rel="noopener noreferrer"&gt;&lt;code&gt;0x6cb43ea1...&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Holder address&lt;/strong&gt;: &lt;a href="https://basescan.org/address/0x259e32F4b53130003c8c364f49cE2EA9Cda5B671" rel="noopener noreferrer"&gt;&lt;code&gt;0x259e32F4...&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collection&lt;/strong&gt;: &lt;a href="https://basescan.org/address/0x3E2a408cc6eceba04FF9d04A5B8B05aBa8DD50ce" rel="noopener noreferrer"&gt;&lt;code&gt;0x3E2a408c...&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We then revoked the pass from the test wallet and tried to authenticate again. The API rejected the request with the exact message it should: &lt;em&gt;wallet does not hold an Insumer Access pass.&lt;/em&gt; The negative path works too. The whole cycle is repeatable.&lt;/p&gt;

&lt;p&gt;And the signed attestations themselves are not just checkable today. Every response is signed against a public key published at our JWKS endpoint. Anyone holding the response, today, tomorrow, or years from now, can verify the signature offline against that key, without calling our service at verification time. The bytes are tamper-evident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this fits in the wallet's evolution
&lt;/h2&gt;

&lt;p&gt;Wallets started as places to hold crypto. Then they became login systems. &lt;a href="https://login.xyz/" rel="noopener noreferrer"&gt;Sign-in-with-Ethereum&lt;/a&gt; has been a standard since 2021. Now they are becoming machine authenticators.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The wallet is the natural credential.&lt;br&gt;
The signature is the natural authentication primitive.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent is the natural user. There is no human in the loop to lose a hardware device or forget a passphrase. The runtime signs in milliseconds, every time, without complaint. That progression has been visible in the standards conversations for a while. Mastercard is &lt;a href="https://insumermodel.com/blog/mastercard-ai-agent-payment-standard-on-chain-verification.html" rel="noopener noreferrer"&gt;drafting an agent-payment standard&lt;/a&gt;. NIST is running &lt;a href="https://insumermodel.com/blog/nist-nccoe-ai-agent-identity-submission.html" rel="noopener noreferrer"&gt;workshops on agent identity&lt;/a&gt;. Coinbase is &lt;a href="https://insumermodel.com/blog/coinbase-agentic-market-agents-need-wallet-auth.html" rel="noopener noreferrer"&gt;opening agentic markets&lt;/a&gt; that assume agents will arrive with wallets attached. The shape is settling. We are one of several teams arguing that wallet-signed authentication will end up doing for agents what OAuth did for delegated human login.&lt;/p&gt;

&lt;h2&gt;
  
  
  We are not replacing API keys
&lt;/h2&gt;

&lt;p&gt;Humans will keep using API keys for a long time. For the typical developer, with a handful of services and a personal laptop, the API key model works. It is familiar. It is supported by every client library. The marginal benefit of switching is small.&lt;/p&gt;

&lt;p&gt;What we shipped is purely additive. The &lt;code&gt;X-API-Key&lt;/code&gt; header still works on every endpoint. Every existing customer sees zero behavioral change. We are not pushing anyone to switch. We are not killing the old path. We are not requiring wallets.&lt;/p&gt;

&lt;p&gt;But agents are different. Agents already:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sign,&lt;/li&gt;
&lt;li&gt;transact,&lt;/li&gt;
&lt;li&gt;hold wallets,&lt;/li&gt;
&lt;li&gt;persist identity across sessions,&lt;/li&gt;
&lt;li&gt;and operate continuously, without human supervision.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For software with those properties, wallet-based authentication is often the more natural primitive. The asymmetry between human pain and machine ease, the one that kept wallet auth out of consumer login, runs in the opposite direction when the user is autonomous code.&lt;/p&gt;

&lt;h2&gt;
  
  
  The category, in our terms
&lt;/h2&gt;

&lt;p&gt;The primitive is &lt;strong&gt;wallet auth&lt;/strong&gt;: read wallet state, evaluate conditions, return a &lt;em&gt;signed boolean&lt;/em&gt;. The category is &lt;strong&gt;condition-based access&lt;/strong&gt;. A single signed call can stack up to 10 conditions across 37 chains, mixing ERC-20 balances, NFT ownership, EAS attestations, and Farcaster identity in any combination. Agent API auth is one stack among many. An SDK adopter who wants to gate on the access pass &lt;em&gt;and&lt;/em&gt; an EAS attestation &lt;em&gt;and&lt;/em&gt; a Pudgy Penguin can ask for that exact compound in one call.&lt;/p&gt;

&lt;h2&gt;
  
  
  You can do this for your own API
&lt;/h2&gt;

&lt;p&gt;We built this for ourselves first because we wanted to feel the operational friction of running it before recommending it to anybody else. It went into production yesterday. The next step is letting other APIs do the same thing without having to write the middleware from scratch.&lt;/p&gt;

&lt;p&gt;Our sister company, &lt;a href="https://skyemeta.com" rel="noopener noreferrer"&gt;Skye Meta&lt;/a&gt;, ships a free, MIT-licensed npm package for exactly this, called &lt;a href="https://www.npmjs.com/package/@skyemeta/access" rel="noopener noreferrer"&gt;&lt;code&gt;@skyemeta/access&lt;/code&gt;&lt;/a&gt;. One line to install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @skyemeta/access
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is either-or middleware. API-key requests pass through unchanged. Wallet-signed requests are verified through InsumerAPI's &lt;code&gt;/v1/attest&lt;/code&gt; endpoint under the hood. Your existing customers see zero change. Your agent customers get a path that does not require them to manage a secret string. Bring your own InsumerAPI key, pick the access collection of your choice, and wrap your existing route handlers with the supplied middleware.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://insumermodel.com/developers/quickstart/" rel="noopener noreferrer"&gt;developer quickstart&lt;/a&gt; walks through grabbing a free InsumerAPI key (10 attestation credits, 100 requests per day, no credit card) and the first &lt;code&gt;/v1/attest&lt;/code&gt; call. The package source is on GitHub at &lt;a href="https://github.com/douglasborthwick-crypto/skyemeta-access" rel="noopener noreferrer"&gt;douglasborthwick-crypto/skyemeta-access&lt;/a&gt;. If you would rather skip the middleware and call the underlying InsumerAPI primitive directly, the &lt;a href="https://insumermodel.com/developers/api-reference/" rel="noopener noreferrer"&gt;API reference&lt;/a&gt; documents every endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ending
&lt;/h2&gt;

&lt;p&gt;The first generation of APIs authenticated software with shared secrets. The next generation may authenticate software with signatures instead.&lt;/p&gt;

&lt;p&gt;Last night, our own agent's wallet paid for access, received a pass, signed a request, and successfully authenticated, without ever transmitting a reusable secret. The transactions are public. The pattern works.&lt;/p&gt;

&lt;p&gt;We are not arguing that every API should switch tomorrow. We are arguing that, for the subset of API consumers that are autonomous software with wallets, the more natural primitive is now available and on-chain, and the cost of trying it is the price of one cup of coffee.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://insumermodel.com/blog/your-agent-doesnt-need-an-api-key.html" rel="noopener noreferrer"&gt;insumermodel.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>blockchain</category>
      <category>webdev</category>
      <category>security</category>
    </item>
    <item>
      <title>Wallet Auth Now Reads Tron, Stellar, Sui, and XDC</title>
      <dc:creator>Douglas Borthwick</dc:creator>
      <pubDate>Thu, 14 May 2026 18:56:51 +0000</pubDate>
      <link>https://dev.to/douglasborthwickcrypto/wallet-auth-now-reads-tron-stellar-sui-and-xdc-24in</link>
      <guid>https://dev.to/douglasborthwickcrypto/wallet-auth-now-reads-tron-stellar-sui-and-xdc-24in</guid>
      <description>&lt;p&gt;&lt;strong&gt;Stablecoin settlement runs through Tron. Tokenized money market funds issue on Stellar. Object-native value lives on Sui. Trade finance is collateralizing on XDC. Four chains. Four different storage models. Four different reasons to be there. Wallet auth reads all of them now.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The chain count moved from 33 to 37 this week. That is not the headline. The headline is what the new four represent: four economic environments that look nothing like each other underneath, all answering to the same signed boolean on the way out.&lt;/p&gt;

&lt;p&gt;InsumerAPI's primitive is wallet auth. Read on-chain state, evaluate against caller-supplied conditions, return an ECDSA-signed attestation. Conditions in. Signed attestations out. The contract surface for a relying agent or service is one POST to &lt;code&gt;/v1/attest&lt;/code&gt; and one signature to check against the public JWKS. What changes when a new chain ships is not that surface. It is the set of things the surface can answer about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tron: where USDT actually moves
&lt;/h2&gt;

&lt;p&gt;USDT on Tron is the largest stablecoin venue on chain by transfer volume. The supply of USDT-TRC20 has, at various points across 2025 and into 2026, exceeded the supply of USDT on every other chain combined. Remittance corridors in Southeast Asia, Latin America, and parts of Africa default to it. Centralized exchanges treat it as the canonical deposit rail.&lt;/p&gt;

&lt;p&gt;If an agent's job is to evaluate whether a counterparty wallet can settle in dollars, ignoring Tron means ignoring the largest dollar venue on chain. The new &lt;code&gt;tronWallet&lt;/code&gt; parameter on &lt;code&gt;POST /v1/attest&lt;/code&gt; and &lt;code&gt;POST /v1/trust&lt;/code&gt; closes that gap. Pass a T-prefixed base58 address, set &lt;code&gt;chainId&lt;/code&gt; to &lt;code&gt;"tron"&lt;/code&gt;, and the attestation returns the same shape as every other chain. Native TRX uses &lt;code&gt;contractAddress: "native"&lt;/code&gt;. TRC-20 tokens use a T-prefixed contract address. USDT-TRC20 lives at &lt;code&gt;TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t&lt;/code&gt;, six decimals.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stellar: where tokenized US Treasuries issue
&lt;/h2&gt;

&lt;p&gt;Stellar hosts BENJI, Franklin Templeton's tokenized US Government Money Market Fund (the on-chain wrapper of FOBXX). BENJI is one of the largest tokenized money market funds in circulation. Holders receive the underlying fund's yield. Redemption is in-fund. The token tracks the share price. BENJI on Stellar is a classic trustline asset, not a smart-contract balance.&lt;/p&gt;

&lt;p&gt;Stellar also hosts Circle's classic-trustline USDC, distinct from any Soroban contract version. Wallet auth reads the classic trustline state, because that is the issuer-anchored deposit ledger that BENJI and USDC actually live on. Pass a G-prefixed StrKey wallet, set &lt;code&gt;chainId&lt;/code&gt; to &lt;code&gt;"stellar"&lt;/code&gt;, and add an &lt;code&gt;assetCode&lt;/code&gt; field for trustline tokens (&lt;code&gt;"USDC"&lt;/code&gt;, &lt;code&gt;"BENJI"&lt;/code&gt;). The signed attestation comes back with &lt;code&gt;ledgerIndex&lt;/code&gt; and &lt;code&gt;ledgerHash&lt;/code&gt; alongside the boolean. Soroban contract balances are out of scope for this release.&lt;/p&gt;

&lt;p&gt;The USDC issuer on Stellar is &lt;code&gt;GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN&lt;/code&gt;. The BENJI issuer is &lt;code&gt;GBJW74JRHIIIYC3X3J5VKLR2CR4UJHKO76V5J5SAYTUFAUE7PJBKCT5R&lt;/code&gt;. Pass either as the &lt;code&gt;contractAddress&lt;/code&gt;, pair with the matching &lt;code&gt;assetCode&lt;/code&gt;, and the trustline state is the read.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sui: object-native USDC
&lt;/h2&gt;

&lt;p&gt;Sui runs on the Move language, and Move does not think about balances the way EVM does. There is no contract holding a mapping from address to amount. There are objects, owned by addresses, with types. USDC on Sui is a &lt;code&gt;Coin&amp;lt;USDC&amp;gt;&lt;/code&gt; object type. Reading how much USDC a wallet holds means summing the wallet's owned objects of that type.&lt;/p&gt;

&lt;p&gt;Circle deployed native USDC on Sui in 2024, and the deployment has expanded supply through 2025 and into 2026, with growing integration on Cetus, Navi, and Sui's institutional rails. The &lt;code&gt;contractAddress&lt;/code&gt; for a Sui token is the fully-qualified Move type string. For USDC on Sui, that is &lt;code&gt;0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC&lt;/code&gt;. Pass a 64-hex-character &lt;code&gt;suiWallet&lt;/code&gt;, set &lt;code&gt;chainId&lt;/code&gt; to &lt;code&gt;"sui"&lt;/code&gt;, and the attestation comes back with &lt;code&gt;checkpointSequence&lt;/code&gt; and &lt;code&gt;checkpointDigest&lt;/code&gt; binding the read to a specific Sui consensus checkpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  XDC: enterprise EVM where trade finance settles
&lt;/h2&gt;

&lt;p&gt;XDC (&lt;code&gt;chainId: 50&lt;/code&gt;) is the EVM chain banks actually point at. It is the only EVM ledger with native ISO 20022 message-format compatibility, which is the standard banks already use for cross-border wire and clearing instructions. That alignment is why the TradeFinex consortium runs there and why a growing pile of tokenized trade-finance assets, factoring receivables, and institutional RWAs issue on XDC rather than on consumer-DeFi EVM venues. The economic identity is different from a Base or an Arbitrum: it is the venue where regulated cash-flow instruments tokenize.&lt;/p&gt;

&lt;p&gt;Because XDC accepts standard EVM tooling, every condition type works without any chain-specific wrapper. Add &lt;code&gt;chainId: 50&lt;/code&gt; to a condition that already worked on another EVM chain and it evaluates the same way. No new wallet parameter. No new address shape. The same &lt;code&gt;wallet&lt;/code&gt; field handles it. Merkle proofs (EIP-1186 storage proofs) are available for &lt;code&gt;token_balance&lt;/code&gt; conditions on XDC, the same as on the other EVM chains whose RPC supports &lt;code&gt;eth_getProof&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trust profile got a new dimension
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;POST /v1/trust&lt;/code&gt; returns a multi-dimensional fact profile. The previous shape had four base dimensions: stablecoins (USDC and USDT across 21 EVM chains), governance, NFTs, and staking. Optional &lt;code&gt;solanaWallet&lt;/code&gt;, &lt;code&gt;xrplWallet&lt;/code&gt;, and &lt;code&gt;bitcoinWallet&lt;/code&gt; would tack on Solana, XRPL, and Bitcoin dimensions when those wallets were supplied.&lt;/p&gt;

&lt;p&gt;This release adds a fifth base dimension that runs on every call: &lt;code&gt;institutional_stablecoins&lt;/code&gt;. Eight checks spanning EVM, Solana, XRPL, Stellar, and Sui. The inventory covers Société Générale-FORGE's EURCV on Ethereum, Solana, and XRPL; FORGE's USDCV on Ethereum and Solana; Circle's classic-trustline USDC on Stellar; Franklin Templeton's BENJI on Stellar; and Circle's native USDC on Sui. The five EVM/Solana/XRPL checks resolve from the standard wallet fields. The three Stellar and Sui checks activate when &lt;code&gt;stellarWallet&lt;/code&gt; and &lt;code&gt;suiWallet&lt;/code&gt; are passed.&lt;/p&gt;

&lt;p&gt;Optional &lt;code&gt;tronWallet&lt;/code&gt; adds a separate &lt;code&gt;tron&lt;/code&gt; dimension covering USDT-TRC20. Up to 49 checks across 27 chains in a single signed profile. No score. No opinion. Just verifiable evidence organized by dimension.&lt;/p&gt;

&lt;h2&gt;
  
  
  What did not change
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;/v1/attest&lt;/code&gt; envelope is byte-identical for existing callers. The signature scheme is unchanged: ECDSA P-256, resolved by &lt;code&gt;kid&lt;/code&gt; from the JWKS at &lt;code&gt;/v1/jwks&lt;/code&gt; (&lt;code&gt;insumer-attest-v1&lt;/code&gt; on keys from this release's era; keys minted today sign under &lt;code&gt;insumer-attest-v2&lt;/code&gt;). The JWT format (set &lt;code&gt;format: "jwt"&lt;/code&gt; on the request body) returns an ES256 token verifiable by any standard JWT library. Existing integrations on EVM, Solana, XRPL, and Bitcoin keep working with zero code changes. The four new wallet fields and the new &lt;code&gt;chainId&lt;/code&gt; enum values are additive optionals.&lt;/p&gt;

&lt;p&gt;That non-event is the point. Wallet auth as a primitive is meant to abstract chain differences. If adding four chains had broken the envelope, the primitive would have failed its job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Available today
&lt;/h2&gt;

&lt;p&gt;All four chains are live in production at &lt;a href="https://api.insumermodel.com" rel="noopener noreferrer"&gt;api.insumermodel.com&lt;/a&gt;. The SDK family shipped the same day: &lt;a href="https://www.npmjs.com/package/insumer-verify" rel="noopener noreferrer"&gt;&lt;code&gt;insumer-verify@1.4.4&lt;/code&gt;&lt;/a&gt; (npm), &lt;a href="https://www.npmjs.com/package/mcp-server-insumer" rel="noopener noreferrer"&gt;&lt;code&gt;mcp-server-insumer@1.10.0&lt;/code&gt;&lt;/a&gt; (npm), &lt;a href="https://www.npmjs.com/package/@insumermodel/plugin-eliza" rel="noopener noreferrer"&gt;&lt;code&gt;@insumermodel/plugin-eliza@2.1.0&lt;/code&gt;&lt;/a&gt; (npm), &lt;a href="https://pypi.org/project/langchain-insumer/" rel="noopener noreferrer"&gt;&lt;code&gt;langchain-insumer@0.11.0&lt;/code&gt;&lt;/a&gt; (PyPI), and &lt;a href="https://pypi.org/project/llama-index-tools-insumer/" rel="noopener noreferrer"&gt;&lt;code&gt;llama-index-tools-insumer@0.3.0&lt;/code&gt;&lt;/a&gt; (PyPI). The OpenAPI spec, ChatGPT Custom GPT action schema, and &lt;code&gt;llms.txt&lt;/code&gt; agent-discovery files all reflect the 37-chain surface.&lt;/p&gt;

&lt;p&gt;The free tier at &lt;a href="https://insumermodel.com/developers/" rel="noopener noreferrer"&gt;insumermodel.com/developers&lt;/a&gt; grants 10 verification credits, which is enough to run a multi-chain trust profile call against a wallet that touches Tron, Stellar, Sui, and EVM, then inspect the &lt;code&gt;institutional_stablecoins&lt;/code&gt; dimension end to end. Add &lt;code&gt;tronWallet&lt;/code&gt;, &lt;code&gt;stellarWallet&lt;/code&gt;, and &lt;code&gt;suiWallet&lt;/code&gt; to the same request body and the response composes everything in one signed envelope.&lt;/p&gt;

&lt;p&gt;The full chain list and per-chain condition shapes live in the &lt;a href="https://insumermodel.com/developers/api-reference/" rel="noopener noreferrer"&gt;API reference&lt;/a&gt; and the &lt;a href="https://insumermodel.com/developers/trust/" rel="noopener noreferrer"&gt;trust profile docs&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>ai</category>
      <category>payments</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Condition-Based Access for Machine Payments Protocol: A Signed Yes-or-No Before the Charge</title>
      <dc:creator>Douglas Borthwick</dc:creator>
      <pubDate>Thu, 07 May 2026 13:35:59 +0000</pubDate>
      <link>https://dev.to/douglasborthwickcrypto/condition-based-access-for-machine-payments-protocol-a-signed-yes-or-no-before-the-charge-3cpm</link>
      <guid>https://dev.to/douglasborthwickcrypto/condition-based-access-for-machine-payments-protocol-a-signed-yes-or-no-before-the-charge-3cpm</guid>
      <description>&lt;p&gt;&lt;strong&gt;This is pre-transaction gating: a signed yes-or-no before any machine payment executes. MPP routes charge money. &lt;code&gt;@insumermodel/mppx-condition-gate&lt;/code&gt; puts that yes-or-no in front of any charge: wallets that meet your conditions get a free-access receipt referencing a per-call signed attestation, everyone else falls through to the normal paid path. First listed entry on Tempo's &lt;code&gt;/extensions&lt;/code&gt; page (PR #445, merged March 23). The primitive underneath is the same wallet auth that backs every other InsumerAPI surface: read → evaluate → sign.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/tempoxyz/mpp" rel="noopener noreferrer"&gt;Machine Payments Protocol&lt;/a&gt; (MPP) gives every payment method a typed shape. A &lt;code&gt;Method.Server&lt;/code&gt; returns a Promise that resolves to a payment receipt. &lt;a href="https://www.npmjs.com/package/@insumermodel/mppx-condition-gate" rel="noopener noreferrer"&gt;&lt;code&gt;@insumermodel/mppx-condition-gate&lt;/code&gt;&lt;/a&gt; sits in front of any &lt;code&gt;Method.Server&lt;/code&gt; and inserts one decision before the charge runs.&lt;/p&gt;

&lt;p&gt;If the requesting wallet meets the configured conditions, the gate returns a free-access receipt that references a per-call signed attestation. If it does not, control falls through to the original &lt;code&gt;Method.Server&lt;/code&gt;, and the charge proceeds normally.&lt;/p&gt;

&lt;p&gt;Tempo's MPP documentation lists &lt;code&gt;@insumermodel/mppx-condition-gate&lt;/code&gt; as the first entry on its &lt;a href="https://github.com/tempoxyz/mpp/pull/445" rel="noopener noreferrer"&gt;&lt;code&gt;/extensions&lt;/code&gt; page&lt;/a&gt;, merged March 23, 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap MPP leaves open
&lt;/h2&gt;

&lt;p&gt;MPP already carries the payer's wallet on every request. Each payment credential includes a &lt;code&gt;credential.source&lt;/code&gt; field shaped like &lt;code&gt;did:pkh:eip155:8453:0xABC...&lt;/code&gt;. The chain ID and address are part of the request envelope.&lt;/p&gt;

&lt;p&gt;What MPP does not provide is the layer that decides whether a particular wallet should be charged at all. There is no native pattern for "this wallet meets a configured condition, give it a free receipt." Without an adapter, every &lt;code&gt;Method.Server&lt;/code&gt; that wants this behavior has to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parse the DID format&lt;/li&gt;
&lt;li&gt;Maintain RPC endpoints across however many chains it cares about&lt;/li&gt;
&lt;li&gt;Run its own ownership and attestation checks&lt;/li&gt;
&lt;li&gt;Cache the result&lt;/li&gt;
&lt;li&gt;Decide what to return when the check fails&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most projects skip the work. The ones that do build it end up reimplementing the same plumbing the next project will reimplement next month.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four condition types
&lt;/h2&gt;

&lt;p&gt;The package exposes one function. Hand it any &lt;code&gt;Method.Server&lt;/code&gt; and a list of conditions. v2.0 supports four condition types. Mix any of them in a single call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Mppx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tempo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mppx/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;conditionGate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@insumermodel/mppx-condition-gate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tempoCharge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tempo&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0xYourAddress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gatedCharge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;conditionGate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tempoCharge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;INSUMER_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;matchMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;any&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;conditions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// Token holders pass&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;token_balance&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0xYourToken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8453&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;100&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// NFT holders pass&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nft_ownership&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="na"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0xYourNFT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="na"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8453&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// Coinbase-verified wallets pass&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eas_attestation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;coinbase_verified_account&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8453&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// Wallets with a Farcaster account pass&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;farcaster_id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mppx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Mppx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;gatedCharge&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a request lands, &lt;code&gt;conditionGate&lt;/code&gt; extracts the wallet from &lt;code&gt;credential.source&lt;/code&gt;, calls &lt;a href="https://insumermodel.com/developers/verification/" rel="noopener noreferrer"&gt;&lt;code&gt;POST /v1/attest&lt;/code&gt;&lt;/a&gt; with that wallet and the conditions, and looks at the result.&lt;/p&gt;

&lt;p&gt;If any of the conditions are met (or all of them, when &lt;code&gt;matchMode: 'all'&lt;/code&gt;), the gate returns a receipt where the &lt;code&gt;reference&lt;/code&gt; field is &lt;code&gt;condition-gate:free:{attestationId}&lt;/code&gt;. The signed attestation is retrievable by ID, the receipt itself just points to it.&lt;/p&gt;

&lt;p&gt;If no conditions are met, or the API is unreachable, the gate calls the original &lt;code&gt;Method.Server&lt;/code&gt;'s &lt;code&gt;verify&lt;/code&gt; and lets the payment proceed normally.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the adapter does not do
&lt;/h2&gt;

&lt;p&gt;The adapter does not re-sign the attestation. The signature on the result is the one InsumerAPI produced, the adapter passes it through unchanged.&lt;/p&gt;

&lt;p&gt;The adapter does not wrap the attestation in a second envelope. The receipt's &lt;code&gt;reference&lt;/code&gt; field carries the attestation ID as a plain string, the attestation itself is retrievable byte-identical to what a direct &lt;code&gt;curl&lt;/code&gt; to &lt;code&gt;/v1/attest&lt;/code&gt; would produce.&lt;/p&gt;

&lt;p&gt;The adapter does not introduce a second signing key. There is no MPP-side or adapter-side root key that signs anything. The only signature in the chain is the one from InsumerAPI's per-call signing.&lt;/p&gt;

&lt;p&gt;The adapter does not call back to InsumerAPI for verification. Any downstream service can check the signature offline against the public &lt;a href="https://insumermodel.com/.well-known/jwks.json" rel="noopener noreferrer"&gt;JWKS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The signed primitive stays untouched. The adapter is plumbing. It translates between MPP's request shape and the wallet auth call. It is not an actor that produces its own claims.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this shape composes
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Method.Server&lt;/code&gt; is the right composition point. Every MPP payment method ships one. So the same &lt;code&gt;conditionGate&lt;/code&gt; adapter applies to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tempo charges&lt;/li&gt;
&lt;li&gt;Stripe charges&lt;/li&gt;
&lt;li&gt;Any other &lt;code&gt;Method.Server&lt;/code&gt; built on the MPP interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is also framework-agnostic. The adapter never touches request routing. It takes a &lt;code&gt;Method.Server&lt;/code&gt; in and returns a &lt;code&gt;Method.Server&lt;/code&gt; out. So the same package works under:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hono&lt;/li&gt;
&lt;li&gt;Express&lt;/li&gt;
&lt;li&gt;Elysia&lt;/li&gt;
&lt;li&gt;Next.js&lt;/li&gt;
&lt;li&gt;Any other framework that consumes an MPP server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And it is non-destructive. The adapter sits before the original &lt;code&gt;verify&lt;/code&gt;, on miss it falls through to the original &lt;code&gt;Method.Server&lt;/code&gt;. Adding it to a paid route does not break the paid path, it only adds a free path for wallets that meet the configured conditions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verifying offline
&lt;/h2&gt;

&lt;p&gt;Every result that comes out of the attest call carries an ECDSA P-256 signature and a key ID (&lt;code&gt;kid&lt;/code&gt;). The signing key is published at &lt;a href="https://insumermodel.com/.well-known/jwks.json" rel="noopener noreferrer"&gt;insumermodel.com/.well-known/jwks.json&lt;/a&gt;. Any party that has the attestation can verify the signature against that JWKS using any standard JOSE library. No callback to InsumerAPI required.&lt;/p&gt;

&lt;p&gt;If you ask for &lt;code&gt;jwt: true&lt;/code&gt; in the options, the same result also comes back as a standard ES256 JWT with the signed attestation as JWT claims. That turns the output into a drop-in bearer token. Any service that already verifies JWTs can verify the gate result without learning anything new.&lt;/p&gt;

&lt;p&gt;Each result is a boolean per condition. Met or unmet. &lt;strong&gt;Boolean, not balance.&lt;/strong&gt; The gate tells you whether the wallet meets the configured condition, never how much it holds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chains and pricing
&lt;/h2&gt;

&lt;p&gt;InsumerAPI covers &lt;strong&gt;33 chains&lt;/strong&gt; today: 30 EVM (Ethereum, Base, Polygon, Arbitrum, Optimism, BNB, Avalanche, and 23 more), plus Solana, XRPL, and Bitcoin. Token and NFT conditions evaluate on any of these. EAS conditions evaluate on EVM chains. Farcaster ID conditions always evaluate on Optimism.&lt;/p&gt;

&lt;p&gt;The wallet holder pays nothing at the gated route. The operator running the gate pays per attestation call out of the API key's credit balance.&lt;/p&gt;

&lt;p&gt;Two ways to provision a key. &lt;code&gt;POST /v1/keys/create&lt;/code&gt; takes an email and ships 10 free attestation credits, no credit card. &lt;code&gt;POST /v1/keys/buy&lt;/code&gt; takes a USDC, USDT, or BTC transfer and provisions a key in one call. The transaction sender wallet is the identity, the payment is the auth. No email, no human in the loop. The first path is the natural fit for human-managed deployments, the second for an autonomous agent inside the gate.&lt;/p&gt;

&lt;p&gt;Top up an existing key on-chain via &lt;code&gt;POST /v1/credits/buy&lt;/code&gt;: USDC or USDT on any major EVM chain, USDC on Solana, or BTC on Bitcoin. Same rails the &lt;code&gt;Method.Server&lt;/code&gt; underneath sits on, same self-serve loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this fits
&lt;/h2&gt;

&lt;p&gt;The wallet auth primitive does not change shape when it lands inside MPP. It still reads on-chain state, evaluates conditions, and returns a signed boolean. &lt;code&gt;@insumermodel/mppx-condition-gate&lt;/code&gt; is the thin adapter that lets MPP routes ask for that boolean across token, NFT, EAS, and Farcaster conditions before deciding whether to charge. Tempo's extensions page is the first listed surface. The shape extends to any payment-route platform that exposes a &lt;code&gt;Method.Server&lt;/code&gt;-style interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before a machine pays, it should qualify.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>blockchain</category>
      <category>payments</category>
      <category>ai</category>
    </item>
    <item>
      <title>How InsumerAPI Powers SkyeGate Lite</title>
      <dc:creator>Douglas Borthwick</dc:creator>
      <pubDate>Tue, 05 May 2026 13:21:56 +0000</pubDate>
      <link>https://dev.to/douglasborthwickcrypto/how-insumerapi-powers-skyegate-lite-3327</link>
      <guid>https://dev.to/douglasborthwickcrypto/how-insumerapi-powers-skyegate-lite-3327</guid>
      <description>&lt;p&gt;&lt;a href="https://skyemeta.com/blog/skyegate-lite-now-on-wordpress/" rel="noopener noreferrer"&gt;SkyeGate Lite is now live on WordPress.org&lt;/a&gt;. It runs on InsumerAPI. The primitive is wallet auth: read, evaluate, sign. &lt;strong&gt;Boolean, not balance.&lt;/strong&gt; Verified yes or no. This is what InsumerAPI provides, and what a product like SkyeGate stands on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wallet auth, defined
&lt;/h2&gt;

&lt;p&gt;Wallet auth is to a wallet what OAuth is to an account. It is a primitive for proving access. The difference is what it proves. OAuth proves who the user is. Wallet auth proves what the wallet holds.&lt;/p&gt;

&lt;p&gt;A caller sends conditions. A token balance threshold. An NFT held. An EAS attestation present. A chain of these, combined into one boolean. InsumerAPI reads chain state, evaluates the conditions, and signs the verdict. The response is one boolean per condition.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Verified yes or no. Boolean, not balance.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What the signed verdict carries
&lt;/h2&gt;

&lt;p&gt;Every verdict from InsumerAPI is an ES256 JWT. ECDSA over P-256, the same cryptographic shape used in modern web standards. The payload is short. Pass or fail per condition. A condition hash for tamper detection. An expiration. The issuer (&lt;code&gt;https://api.insumermodel.com&lt;/code&gt;). A signing key identifier (&lt;code&gt;insumer-attest-v1&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The signing key is published at &lt;a href="https://api.insumermodel.com/.well-known/jwks.json" rel="noopener noreferrer"&gt;https://api.insumermodel.com/.well-known/jwks.json&lt;/a&gt;. Anyone can fetch it. Anyone can re-verify any verdict, end to end, without asking InsumerAPI again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three properties products inherit
&lt;/h2&gt;

&lt;p&gt;A product running on InsumerAPI inherits three things by virtue of using the primitive.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic.&lt;/strong&gt; Same wallet, same conditions, same chain state. Same verdict. No model drift. No scoring opinion. No judgment call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;End-to-end verifiable.&lt;/strong&gt; The signature is from InsumerAPI, not from the product. A product cannot forge a pass even if it wanted to, because anyone can re-verify the JWT against the public JWKS endpoint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No consumer secrets in the loop.&lt;/strong&gt; The primitive does not accept and cannot use consumer credentials. There is nothing to phish, rotate, store, or leak.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A product like SkyeGate gets all three properties by design, not by discipline.&lt;/p&gt;

&lt;h2&gt;
  
  
  No secrets, no identity-first, no static credentials
&lt;/h2&gt;

&lt;p&gt;This is the narrative core. A visitor connects a wallet and supplies a public address. That is the entire input on the consumer side. There is no password. No email. No API key on the consumer side. No shared secret between the merchant and the customer. There is no identity claim at all. Only what the wallet holds.&lt;/p&gt;

&lt;p&gt;The merchant inherits this property automatically. A merchant running on InsumerAPI cannot accidentally introduce consumer-secret leakage, because the primitive does not accept consumer secrets to begin with. The failure mode wallet auth removes from the surface is the failure mode every credential-based gate suffers from. Storing consumer secrets that someone, somewhere, eventually leaks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Provable and private
&lt;/h2&gt;

&lt;p&gt;Both properties have to coexist or the primitive does not work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provable.&lt;/strong&gt; A merchant or end user can take any verdict and re-verify it against the public JWKS using only public information. The verdict cannot be forged. The condition cannot be silently changed, because the condition hash catches it. InsumerAPI itself cannot rewrite history, because the signature pins the verdict to the moment it was issued.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Private.&lt;/strong&gt; The verdict is a boolean. It does not say how much is in the wallet, what else is held, who the user is, what other addresses they control, or what they have done. A merchant gating ETH at a 0.1 threshold learns yes or no. Not the balance. Not the wallet history. Not the identity. &lt;em&gt;Boolean, not balance.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provable and private.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Condition-based access, one primitive, many surfaces
&lt;/h2&gt;

&lt;p&gt;SkyeGate is one product on top of the primitive. It runs on WordPress.&lt;/p&gt;

&lt;p&gt;The same primitive also slices. SkyeGate Lite, the free WordPress plugin, exposes one condition per gate. SkyeGate, the paid version, exposes up to ten conditions chained into one boolean. Both run on the same &lt;code&gt;/v1/attest&lt;/code&gt; call. The primitive does not change. The product chooses the slice.&lt;/p&gt;

&lt;p&gt;The same primitive runs other surfaces too. SkyeWoo gates WooCommerce. AgentTalk handles agent-to-agent calls. Same boolean, same JWKS, different transport. Any HTTP-speaking client can call &lt;code&gt;/v1/attest&lt;/code&gt;, get back a signed verdict, and gate whatever it gates.&lt;/p&gt;

&lt;p&gt;The primitive scales sideways. New surfaces do not require a new primitive. They require a new consumer of the same primitive. A signed boolean is portable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;SkyeGate Lite is free on WordPress.org. The &lt;a href="https://skyemeta.com/blog/skyegate-lite-now-on-wordpress/" rel="noopener noreferrer"&gt;SkyeMeta announcement&lt;/a&gt; walks through install and the first shortcode.&lt;/p&gt;

&lt;p&gt;Or build your own consumer. POST conditions to &lt;code&gt;/v1/attest&lt;/code&gt;, verify the returned JWT against the JWKS endpoint, and gate whatever your stack gates. The full reference is at &lt;a href="https://insumermodel.com/developers/api-reference/" rel="noopener noreferrer"&gt;/developers/api-reference/&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>webdev</category>
      <category>security</category>
      <category>api</category>
    </item>
    <item>
      <title>Add Wallet Auth from Claude Code in One Command</title>
      <dc:creator>Douglas Borthwick</dc:creator>
      <pubDate>Tue, 28 Apr 2026 15:42:58 +0000</pubDate>
      <link>https://dev.to/douglasborthwickcrypto/add-wallet-auth-from-claude-code-in-one-command-4b93</link>
      <guid>https://dev.to/douglasborthwickcrypto/add-wallet-auth-from-claude-code-in-one-command-4b93</guid>
      <description>&lt;p&gt;You are building something in Claude Code. A discount flow that requires holding a specific token. An AI agent that will not move money for unverified wallets. An NFT-gated dashboard. The wallet auth piece is fiddly. Chain RPCs, contract calls, signature verification, edge cases. One Smithery skill turns it into one command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install once, ask Claude
&lt;/h2&gt;

&lt;p&gt;The skill lives at &lt;a href="https://smithery.ai/skills/douglasborthwick/insumer-skill" rel="noopener noreferrer"&gt;smithery.ai/skills/douglasborthwick/insumer-skill&lt;/a&gt;. Add it to Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;smithery skill add douglasborthwick/insumer-skill &lt;span class="nt"&gt;--agent&lt;/span&gt; claude-code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That registers the skill at the project level. &lt;code&gt;--global&lt;/code&gt; registers it across every project on the machine. The skill works the same way across the rest of the agent ecosystem: &lt;code&gt;--agent cursor&lt;/code&gt;, &lt;code&gt;--agent codex&lt;/code&gt;, &lt;code&gt;--agent windsurf&lt;/code&gt;, &lt;code&gt;--agent cline&lt;/code&gt;, and others.&lt;/p&gt;

&lt;p&gt;Once installed, ask Claude what you want. Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Add a check that gates this endpoint on holders of at least 100 USDC on Base.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Verify this wallet owns the Pudgy Penguins NFT before letting them claim.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Before this agent moves money, pull a trust profile and require it to score above the warning threshold.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Add a delegated-authority check using delegate.xyz.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Verify an EAS attestation on the wallet before approving the transaction.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Claude reads the skill, picks the right endpoint, writes the call, parses the signed response, and adds JWKS verification so the result holds up offline. You review the diff and ship.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Claude knows after installing
&lt;/h2&gt;

&lt;p&gt;The skill is procedural knowledge, readable in full on Smithery before you install. It teaches Claude six things that are easy to get wrong otherwise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pick the right endpoint.&lt;/strong&gt; &lt;code&gt;POST /v1/attest&lt;/code&gt; when the developer specifies the exact condition (token balance, NFT ownership, delegated authority, EAS attestation, USDC threshold). &lt;code&gt;POST /v1/trust&lt;/code&gt; when the developer wants a curated multi-dimension fact profile across 25 chains, up to 27 with optional Solana, XRPL, Bitcoin, and Tron wallets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify the signature.&lt;/strong&gt; Every response carries an ECDSA P-256 signature under one of three key IDs: &lt;code&gt;insumer-attest-v1&lt;/code&gt;, &lt;code&gt;insumer-attest-v2&lt;/code&gt; or &lt;code&gt;insumer-trust-v2&lt;/code&gt;. The skill makes Claude verify against the published JWKS at &lt;code&gt;https://insumermodel.com/.well-known/jwks.json&lt;/code&gt;, never trust the raw JSON body. &lt;em&gt;(Update, September 2026: every response also carries a post-quantum companion signature, &lt;code&gt;pqSig&lt;/code&gt; and &lt;code&gt;pqKid&lt;/code&gt; under &lt;code&gt;insumer-attest-pq1&lt;/code&gt; or &lt;code&gt;insumer-trust-pq1&lt;/code&gt;, resolved from the same JWKS; the ECDSA signature and the three EC key IDs are unchanged.)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boolean, not balance.&lt;/strong&gt; The skill stops Claude from leaking raw balances to the client. Standard mode returns a signed yes or no plus the condition hash. The actual chain read happens server-side.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resolve the key by kid.&lt;/strong&gt; The skill reads the &lt;code&gt;kid&lt;/code&gt; on each response (&lt;code&gt;insumer-attest-v2&lt;/code&gt; on keys minted today, &lt;code&gt;insumer-attest-v1&lt;/code&gt; on pre-cutover keys) and selects the matching key from the JWKS set, so verification survives key rotation instead of breaking on a pinned literal. &lt;em&gt;(Update, September 2026: the set now also holds two &lt;code&gt;AKP&lt;/code&gt; entries for the post-quantum companion key, so matching by &lt;code&gt;kid&lt;/code&gt;, and by &lt;code&gt;pqKid&lt;/code&gt; for the companion, is the only safe way to pick an entry.)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never inline the API key.&lt;/strong&gt; The skill enforces &lt;code&gt;process.env.INSUMER_API_KEY&lt;/code&gt; server-side only. No browser fetches. No keys in source.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use the right primitives for the right layer.&lt;/strong&gt; Wallet auth is condition-based access. The skill stops Claude from confusing it with WalletConnect (UX layer), wagmi or viem (RPC layer), or SIWE / EIP-4361 (proof of ownership). Different primitives, different jobs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What you get back from a call
&lt;/h2&gt;

&lt;p&gt;Every &lt;code&gt;/v1/attest&lt;/code&gt; response is a signed envelope. The shape Claude will write against:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"attestation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ATST-9F2C4E6A1B3D5F70"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"pass"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"results"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"100+ USDC on Base"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"token_balance"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"chainId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8453&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"met"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"evaluatedCondition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"token_balance"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"chainId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8453&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"contractAddress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"operator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gte"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"threshold"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"100"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"conditionHash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x3a7f..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"blockNumber"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x21e8a40"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"blockTimestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-03-06T10:00:01.000Z"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"passCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"failCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"attestedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-03-06T10:00:01.000Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"expiresAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-03-06T10:30:01.000Z"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sig"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MEQCIB...base64..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"kid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"insumer-attest-v2"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"meta"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-03-06T10:00:01.000Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"creditsCharged"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"creditsRemaining"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The verification is portable. Any service downstream of the agent can re-verify the signature against the public JWKS without calling the API back. The condition hash lets the caller confirm the verdict is for the exact condition they asked about, not a substituted one. The block number and timestamp pin the read to a specific point in chain history.&lt;/p&gt;

&lt;h2&gt;
  
  
  What 38 chains buys you
&lt;/h2&gt;

&lt;p&gt;Coverage is the boring part of wallet auth that bites you in production. The skill knows the live surface:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;32 EVM chains&lt;/strong&gt;, with optional Merkle storage proofs where the chain's RPC serves them (Ethereum, Base, Arbitrum, Optimism, Polygon, BNB Chain, Avalanche, and others).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solana&lt;/strong&gt; for SPL token holdings and SOL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;XRPL&lt;/strong&gt; for trust lines and stablecoin holdings (RLUSD, USD-issued lines).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bitcoin&lt;/strong&gt; for native BTC holdings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tron, Stellar, and Sui&lt;/strong&gt; for token balances.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a developer asks Claude to verify a condition on a chain the API does not cover, the skill instructs Claude to surface that explicitly rather than fabricate an integration. The list of supported chains lives in the skill's reference data, not in Claude's training-time memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Free key, no signup
&lt;/h2&gt;

&lt;p&gt;The first thing the skill tells Claude to do is mint a free key. The flow is one curl, no email confirmation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://api.insumermodel.com/v1/keys/create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"email":"you@example.com","appName":"my-project","tier":"free"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response includes a &lt;code&gt;key&lt;/code&gt; starting with &lt;code&gt;insr_live_&lt;/code&gt;. Drop it in &lt;code&gt;.env&lt;/code&gt; as &lt;code&gt;INSUMER_API_KEY&lt;/code&gt;. The free tier comes with 10 free verifications plus 100 reads per day, enough to wire up an integration end-to-end and ship the first version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this fits with the rest of the agent stack
&lt;/h2&gt;

&lt;p&gt;The Smithery skill is one of several integration paths into InsumerAPI. Pick whichever matches the stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smithery skill&lt;/strong&gt;: the post you are reading. Best when the developer is in Claude Code, Cursor, Codex, Windsurf, or another Smithery-compatible agent and wants Claude to write the integration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP server&lt;/strong&gt;: when the agent needs typed tools at runtime, not procedural guidance at code-write time. &lt;code&gt;npx -y mcp-server-insumer&lt;/code&gt;, 27 tools across 38 chains.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LlamaIndex toolkit&lt;/strong&gt;: for Python agents on LlamaIndex or LangGraph.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAPI Actions&lt;/strong&gt;: load openapi.yaml directly into a custom GPT.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All four hit the same endpoints, return the same signed envelopes, and verify against the same JWKS.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The transport changes; the primitive does not.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is a good fit for Claude Code in particular
&lt;/h2&gt;

&lt;p&gt;Claude Code already writes most of the boilerplate. The hard part of wallet auth is not the boilerplate. It is the parts most LLMs get subtly wrong: confusing wallet auth with wallet connection, validating a JWT but not the underlying signature, picking the wrong endpoint, asking for a balance when a boolean is the right contract. The skill closes that gap. Claude reads the rules, writes correct integration code the first time, and the diff is small enough to review in a minute.&lt;/p&gt;

&lt;p&gt;If you are sitting in Claude Code right now, the install is one command. The next thing Claude writes will be the integration you actually wanted.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>blockchain</category>
      <category>agents</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Coinbase Agentic.Market Opens: Agents Need Wallet Auth, Not Just Tools</title>
      <dc:creator>Douglas Borthwick</dc:creator>
      <pubDate>Mon, 27 Apr 2026 00:04:44 +0000</pubDate>
      <link>https://dev.to/douglasborthwickcrypto/coinbase-agenticmarket-opens-agents-need-wallet-auth-not-just-tools-5831</link>
      <guid>https://dev.to/douglasborthwickcrypto/coinbase-agenticmarket-opens-agents-need-wallet-auth-not-just-tools-5831</guid>
      <description>&lt;p&gt;Coinbase just launched &lt;a href="https://www.coinbase.com/developer-platform/discover/launches/agentic-market" rel="noopener noreferrer"&gt;Agentic.Market&lt;/a&gt;, a marketplace where AI agents discover tools, transact autonomously, and settle payments using the x402 protocol. Agents can browse services, negotiate terms, and execute payments without human intervention. The infrastructure is live. Agentic.Market proves agents can pay. It doesn't prove they should be trusted. Payment rails solve settlement. They don't solve counterparty risk. That's the gap wallet auth fills, and it's what POST /v1/trust was built for.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Agentic.Market Actually Launched
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.coinbase.com/developer-platform/discover/launches/agentic-market" rel="noopener noreferrer"&gt;Agentic.Market&lt;/a&gt; is Coinbase's new marketplace for autonomous agent commerce. Agents discover services, evaluate pricing, and complete transactions server-to-server using x402, the open standard for agent payments. The protocol standardizes how agents pay for API calls, data feeds, and compute services using USDC or other stablecoins.&lt;/p&gt;

&lt;p&gt;The market is aimed at agent builders who need their agents to autonomously procure resources: language model inference, data retrieval, blockchain indexing, oracle feeds, compute cycles. Instead of developers pre-funding API accounts with credit cards, agents operate their own wallets and pay per request.&lt;/p&gt;

&lt;p&gt;This is a big unlock. Agents can now discover and purchase capabilities at runtime, not just use what their creator hard-coded. The vision is agent-to-agent commerce at scale. One agent sells compute. Another buys it. Settlement happens on-chain. No human approval loop.&lt;/p&gt;

&lt;p&gt;But autonomy creates a trust problem. When an agent shows up at your API endpoint with a wallet and a payment, how do you know it's safe to serve the request? You need more than proof of payment. You need context about what kind of wallet this is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Payment Rails Are Not Enough for Agent Commerce
&lt;/h2&gt;

&lt;p&gt;x402 solves the payment side: the agent proves it can pay, the service delivers, settlement happens atomically. That's the easy part. The hard part is deciding &lt;em&gt;whether&lt;/em&gt; to accept the transaction in the first place.&lt;/p&gt;

&lt;p&gt;Traditional commerce has credit scoring, fraud detection, KYC, transaction history, chargebacks, dispute resolution. Agent commerce has none of that. An agent wallet shows up. It has USDC. Should you serve the request? Charge premium pricing? Require escrow? Reject it outright?&lt;/p&gt;

&lt;p&gt;You can't ask for identity. Agents don't have passports or corporate registrations. You can't rely on reputation systems that don't exist yet. You can't call the agent's creator, because the whole point is autonomous operation.&lt;/p&gt;

&lt;p&gt;What you &lt;em&gt;can&lt;/em&gt; do is read the wallet's on-chain state and evaluate it against conditions. Does it hold governance tokens? Stablecoins across multiple chains? NFTs from known projects? Has it staked assets? This is wallet auth: condition-based access against on-chain state. It's verifiable in real time, and it doesn't require the agent to disclose balances.&lt;/p&gt;

&lt;p&gt;That's what &lt;a href="https://insumermodel.com/how-it-works/" rel="noopener noreferrer"&gt;POST /v1/trust&lt;/a&gt; returns: a signed wallet auth profile with up to 40 checks across up to 7 dimensions. The base profile covers stablecoins (26 checks: 16 USDC + 10 USDT), governance tokens, NFT ownership, and staking positions. Optional Solana, XRPL, and Bitcoin holdings extend the profile when those wallets are supplied. The API reads on-chain state, evaluates the conditions, and returns a cryptographically signed result. No balances exposed. No transaction history. Just a boolean summary.&lt;/p&gt;

&lt;p&gt;For attestations like Coinbase KYC, Coinbase Verified Country, or Gitcoin Passport, the right surface is &lt;a href="https://insumermodel.com/how-it-works/" rel="noopener noreferrer"&gt;POST /v1/attest&lt;/a&gt; with custom conditions. These EAS attestations (Ethereum Attestation Service, the on-chain registry where issuers publish signed claims) sit alongside token balance thresholds in the same signed result.&lt;/p&gt;

&lt;p&gt;This is the same pattern Web2 went through. Stripe solved payments; every merchant still needed fraud detection. Plaid solved bank-account linking; every fintech still needed KYC. Settlement and trust live at different layers, and trust is where the differentiation sits. Agent commerce is the same dynamic, just on-chain. Wallet auth is to agent commerce what fraud detection was to e-commerce.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Integrators Use Wallet Auth in x402 Agent Commerce
&lt;/h2&gt;

&lt;p&gt;Revettr is a counterparty risk scoring service for x402 payments. Their integration pattern uses POST /v1/trust as the wallet auth signal that feeds their scoring model. Revettr doesn't write its own multi-chain logic. It consumes Insumer's signed wallet auth profile and maps it to its own counterparty tiers.&lt;/p&gt;

&lt;p&gt;This is the pattern with x402 infrastructure: payments are commoditized, wallet auth is not. Stablecoin settlement is a solved problem. Knowing whether to accept the transaction is the hard part. As we covered in &lt;a href="https://insumermodel.com/blog/ai-agents-wallet-trust-profiles-verification.html" rel="noopener noreferrer"&gt;AI Agents Need Wallet Trust Profiles Before They Handle Money&lt;/a&gt;, agents need verifiable context about their counterparties before settlement, not just proof of funds.&lt;/p&gt;

&lt;p&gt;AsterPay's KYA Hook (ERC-8183 agentic commerce) is built on POST /v1/attest with custom conditions. Token balance thresholds combined with EAS attestations like Coinbase KYC and Coinbase Verified Country feed AsterPay's trust tiering, which determines the commercial terms an agent receives at checkout.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Merchants on Agentic.Market Actually Need
&lt;/h2&gt;

&lt;p&gt;If you're a service provider listing on Agentic.Market, here's what you need to make agent commerce work:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Payment verification.&lt;/strong&gt; x402 gives you this. The agent proves it can pay, you deliver the service, settlement happens atomically. This is the base layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wallet auth.&lt;/strong&gt; Before you accept the transaction, you need to evaluate the counterparty wallet against your conditions: Is this a wallet I should serve? Should I charge standard pricing or require premium? Should I ask for escrow or deliver immediately? POST /v1/trust gives you this. Up to 40 checks across up to 7 dimensions. Signed result. 3 credits per call. Single-call latency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audit trail.&lt;/strong&gt; When an agent transaction goes wrong, you need a signed record of what the wallet looked like at the time of transaction. Insumer responses are ECDSA P-256 signed with public keys published at /.well-known/jwks.json. You can verify the signature client-side using insumer-verify (npm, zero dependencies) or server-side using any JWKS library. The signature proves the data came from Insumer and hasn't been tampered with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-chain coverage.&lt;/strong&gt; Agents operate across chains. Your wallet auth layer needs to cover all of them. Insumer supports 33 chains: 30 EVM chains (Ethereum, Base, Polygon, Arbitrum, Optimism, BNB Chain, Avalanche, and 23 others), plus Solana, XRPL, and Bitcoin. One API call, one signed profile, all chains.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Privacy by default.&lt;/strong&gt; You don't need to see raw balances. You need boolean results: does this wallet meet the threshold or not? Insumer never returns balance amounts, transaction history, or portfolio data. Just evaluated conditions and a signed yes/no.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Integrate Wallet Auth into Your Agent Commerce Flow
&lt;/h2&gt;

&lt;p&gt;If you're building a service for Agentic.Market or any x402-enabled agent platform, here's the integration pattern:&lt;/p&gt;

&lt;p&gt;Agent initiates transaction. It sends a payment proof via x402. Before you accept, you call POST /v1/trust with the agent's wallet address. Insumer returns a signed wallet auth profile. You evaluate the profile against your own merchant tiers: standard pricing, premium access, escrow-required, or reject.&lt;/p&gt;

&lt;p&gt;You serve the request or reject it. If you serve, you log the signed wallet auth profile as your audit trail. If something goes wrong later, you have cryptographic proof of what the wallet looked like at transaction time.&lt;/p&gt;

&lt;p&gt;This is not a human-in-the-loop decision. It's a server-side API call that happens before settlement. The entire flow is autonomous: agent discovers service, requests access, proves payment ability, gets evaluated against your conditions, completes transaction. No email. No KYC form. No manual approval.&lt;/p&gt;

&lt;p&gt;For AI agent platforms, the MCP server integration makes this even simpler. mcp-server-insumer (npm, also published in the &lt;a href="https://registry.modelcontextprotocol.io/" rel="noopener noreferrer"&gt;MCP Official Registry&lt;/a&gt;) ships 27 tools spanning attestation, wallet auth profiles, compliance templates, merchant onboarding, and credit management. The agent can call wallet_trust directly and get back a parsed signed result without the developer writing integration code. Same for LangChain agents: langchain-insumer (PyPI) ships 26 tools covering the same surface.&lt;/p&gt;

&lt;p&gt;The agent doesn't need to understand blockchain RPCs, signature verification, or multi-chain state. It just asks: does this wallet meet the conditions? The API answers with a signed boolean. The agent uses that result to make autonomous decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Means for Agent Commerce Infrastructure
&lt;/h2&gt;

&lt;p&gt;Agentic.Market is the first major marketplace for autonomous agent commerce, but it won't be the last. &lt;a href="https://decrypt.co/365153/google-spend-185-billion-this-year-power-agentic-era-ai-ceo" rel="noopener noreferrer"&gt;Google announced up to $185 billion in AI infrastructure spend for 2026&lt;/a&gt;, with CEO Sundar Pichai framing this as the "agentic era." Agents are moving from demos to production, and production agents need to transact autonomously.&lt;/p&gt;

&lt;p&gt;Payment rails are necessary but not sufficient. Every agent commerce platform will need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Settlement infrastructure (x402, USDC, stablecoin rails)&lt;/li&gt;
&lt;li&gt;Wallet auth infrastructure (condition-based access, signed boolean verdicts, multi-chain state evaluation)&lt;/li&gt;
&lt;li&gt;Audit infrastructure (signed records, cryptographic proof, dispute resolution)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Insumer is infrastructure for number 2. We're not an x402 tool. We're the wallet auth layer x402 tools build on. Revettr's pattern consumes signed wallet auth profiles from POST /v1/trust as the input to its counterparty scoring. AsterPay's KYA Hook (ERC-8183) is built on POST /v1/attest with custom conditions for agent trust tiering. SettlementWitness's pattern published POST /v1/attest as the pre-transaction wallet auth layer in its Settlement Attestation Record (SAR) flow. Wallet auth qualifies the counterparty before payment, and SAR verifies the deliverable after.&lt;/p&gt;

&lt;p&gt;Payment infrastructure commoditizes. Wallet auth differentiates. Stablecoin settlement is a solved problem; wallet auth is the hard part. And unlike Web2 fraud detection, on-chain wallet state is verifiable, composable, and privacy-preserving. You don't need to see transaction history. You just need a signed boolean: does this wallet meet the conditions or not?&lt;/p&gt;

&lt;p&gt;That's what Insumer returns. Boolean, not balance. Verified yes or no. Provable and private. Read, evaluate, sign. No secrets. No identity-first. No static credentials. Just condition-based access for autonomous agents operating at scale.&lt;/p&gt;

&lt;p&gt;Payment rails let agents transact. Wallet auth determines whether they should. In agent commerce, that distinction becomes infrastructure.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>blockchain</category>
      <category>payments</category>
      <category>agents</category>
    </item>
    <item>
      <title>AI Agents Need Wallet Trust Profiles Before They Handle Money</title>
      <dc:creator>Douglas Borthwick</dc:creator>
      <pubDate>Sun, 19 Apr 2026 17:21:56 +0000</pubDate>
      <link>https://dev.to/douglasborthwickcrypto/ai-agents-need-wallet-trust-profiles-before-they-handle-money-amj</link>
      <guid>https://dev.to/douglasborthwickcrypto/ai-agents-need-wallet-trust-profiles-before-they-handle-money-amj</guid>
      <description>&lt;p&gt;AI agents can now write code, deploy contracts, and execute payments. They still can't answer one question: &lt;strong&gt;should this wallet be trusted with money?&lt;/strong&gt; Raw capability doesn't solve that. Neither does identity. What's missing is a verification layer that runs before settlement, one that reads wallet state, evaluates conditions, and returns a signed boolean, without private keys or human approval. &lt;a href="https://aws.amazon.com/about-aws/whats-new/2026/04/claude-opus-4.7-amazon-bedrock/" rel="noopener noreferrer"&gt;Claude Opus 4.7&lt;/a&gt; just hit 87.6% on SWE-bench Verified. Impressive, but meaningless if the agent can't prove trustworthiness before touching real money.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Missing Layer in Agent Commerce
&lt;/h2&gt;

&lt;p&gt;The AI agent payment narrative focuses on rails: x402 protocol, Chainlink CRE workflows, USDC settlement. Every demo shows an agent paying for an API call, executing a transaction, or buying compute. Great. But who verifies the agent's wallet before it gets access?&lt;/p&gt;

&lt;p&gt;This is the flaw that drains treasuries and exposes wallets. Without a verification layer in front of settlement, the question isn't whether an agent system gets exploited, it's when. If an agent requests access to a service, a payment gateway, or a privileged API endpoint, the receiving system needs to answer a binary question: &lt;strong&gt;is this wallet trusted enough for this action?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's not an identity problem. It's not an auth problem. It's a &lt;em&gt;condition-based access&lt;/em&gt; problem. You don't need to know &lt;em&gt;who&lt;/em&gt; the agent is. You need to know &lt;em&gt;what kind of wallet it's operating with&lt;/em&gt;. Does it hold stablecoins across multiple chains? Does it participate in governance? Does it stake assets? Has it held NFTs long-term? Those signals indicate wallet maturity, not identity.&lt;/p&gt;

&lt;p&gt;The pattern is simple and keeps appearing: &lt;strong&gt;verification before settlement&lt;/strong&gt;. Read wallet state, evaluate conditions, return a signed boolean. Read-only. No signatures. No approvals. No private keys. No human in the loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  What POST /v1/trust Actually Returns (and Why It's Not a Balance Check)
&lt;/h2&gt;

&lt;p&gt;POST /v1/trust is the wallet trust profile endpoint. It runs a fixed, curated set of checks across stablecoins (USDC and USDT), governance tokens, NFTs, and staking, 36 base checks across 20 chains, extensible to Solana, XRPL, and Bitcoin when those wallet types are provided. (Update, September 2026: 44 base checks across 25 chains, up to 49 across 27 chains with the optional Solana, XRPL, Bitcoin, and Tron wallets.) Each check returns &lt;code&gt;met: true&lt;/code&gt; or &lt;code&gt;met: false&lt;/code&gt;. No raw amounts. No balance sheet. No exposure.&lt;/p&gt;

&lt;p&gt;The response is signed using ECDSA P-256. Public keys are available at &lt;code&gt;/.well-known/jwks.json&lt;/code&gt;. Any system receiving the profile can verify the signature client-side using the insumer-verify npm package, four independent checks: signature validity, condition hash integrity, block freshness, and expiry timestamp. Zero dependencies. (Update, September 2026: insumer-verify 1.8.0 and later reports a fifth verdict, the post-quantum companion signature, ML-DSA-65, that every response now carries as pqSig and pqKid beside the ECDSA one.)&lt;/p&gt;

&lt;p&gt;This is fundamentally different from POST /v1/attest, which evaluates 1-10 &lt;em&gt;custom&lt;/em&gt; conditions you define in the request. /v1/trust answers one question: &lt;strong&gt;what kind of wallet is this?&lt;/strong&gt; It refuses to sign partial data. If any check fails to complete, the entire request fails. That prevents cherry-picking signals or gaming the profile.&lt;/p&gt;

&lt;p&gt;Payment rails solved &lt;em&gt;how&lt;/em&gt; agents move money. Verification layers will determine &lt;em&gt;which&lt;/em&gt; agents are allowed to. Every agent commerce stack will need to answer that question before settlement. Most don't today.&lt;/p&gt;

&lt;h2&gt;
  
  
  How AI Agents Use MCP and LangChain to Verify Wallets Autonomously
&lt;/h2&gt;

&lt;p&gt;Agents reach the verification layer two ways: the MCP server (npm: mcp-server-insumer, 26 tools, listed in Anthropic's official registry) or the LangChain toolkit (PyPI: langchain-insumer, 26 tools, exposes &lt;code&gt;WalletTrustTool&lt;/code&gt; and &lt;code&gt;AttestConditionsTool&lt;/code&gt;). An agent negotiating a transaction calls WalletTrustTool to evaluate counterparty trustworthiness before proceeding, no human in the loop.&lt;/p&gt;

&lt;p&gt;The demand signal is already here. &lt;a href="https://www.businessupturn.com/brand-post/cryptact-launches-mcp-server-for-ai-assistants/" rel="noopener noreferrer"&gt;Cryptact&lt;/a&gt; (200,000+ users) just shipped its own MCP server for read-only portfolio queries. &lt;a href="https://blog.modelcontextprotocol.io/" rel="noopener noreferrer"&gt;MCP crossed 97 million monthly downloads&lt;/a&gt; in March 2026. &lt;a href="https://news.bitcoin.com/tron-network-deepens-role-in-agentic-ai-infrastructure-as-b-ai-launches/" rel="noopener noreferrer"&gt;TRON's B.AI launch&lt;/a&gt; integrates ERC-8004 for agent identity and x402 for agent payments, the same stack AsterPay and Coinbase are building on. Agent commerce is consolidating around read-only, signed, cross-chain primitives. Wallet verification is one of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The x402 Ecosystem Pattern: Verification Before Settlement
&lt;/h2&gt;

&lt;p&gt;The x402 payment protocol (Coinbase's standard for agent-initiated transactions) creates a new verification layer. Agents request payment authorization. Gateways need to evaluate trust before approving settlement. This is where condition-based access infrastructure fits.&lt;/p&gt;

&lt;p&gt;AsterPay's KYA implementation is the live proof. They use ERC-8183 (the agentic commerce standard) to structure requests. Before approving EUR settlement for an AI agent transaction, AsterPay's KYA Hook fires a single POST /v1/attest call with 4 conditions: Base USDC balance, &lt;code&gt;coinbase_verified_account&lt;/code&gt;, &lt;code&gt;coinbase_verified_country&lt;/code&gt;, and &lt;code&gt;gitcoin_passport_score&lt;/code&gt;. Those 4 conditions feed 4 of 7 trust score components, contributing up to 44 out of 100 points. Higher score = lower friction. Lower score = additional verification or rejection.&lt;/p&gt;

&lt;p&gt;The AsterPay KYA Hook is the first IACPHook with third-party attestation integration. The verification happens server-side. The agent never sees the API call. It just receives approval or denial based on the trust score.&lt;/p&gt;

&lt;p&gt;Revettr does the same for counterparty risk. Their API serves wallet analysis to other platforms evaluating transaction risk. When a Revettr customer queries a wallet's risk score, Revettr calls POST /v1/trust in the background. The signed profile feeds their scoring model.&lt;/p&gt;

&lt;p&gt;SettlementWitness takes it to pre/post transaction verification (the SAR pattern: Suspicious Activity Report workflows). They call POST /v1/attest as the pre-transaction verification layer before settlement clears. If conditions aren't met, the transaction doesn't proceed.&lt;/p&gt;

&lt;p&gt;This is the x402 pattern: &lt;strong&gt;verification before settlement&lt;/strong&gt;. Not auth. Not identity. Condition-based access. Does this wallet satisfy trust thresholds? Return a signed boolean. Let the gateway decide what to do with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Wallet Verification Needs to Be Read-Only (No Approvals, No Keys)
&lt;/h2&gt;

&lt;p&gt;The hidden flaw in most agent payment systems: they require wallet approvals, signature requests, or private key exposure to verify holdings. That's a security disaster. An agent operating autonomously can't stop mid-workflow to ask a human for approval. And giving an agent access to private keys means one compromised model = drained wallet.&lt;/p&gt;

&lt;p&gt;Read-only verification solves this. InsumerAPI never requests wallet signatures. Never asks for approvals. Never touches private keys. It reads public blockchain state (token balances, NFT ownership, staking positions, trust lines), evaluates conditions, and returns a cryptographically signed result.&lt;/p&gt;

&lt;p&gt;The signed result is the proof. The ECDSA P-256 signature binds the attestation to the API's public key. Any system can verify the signature using the JWKS public key at &lt;code&gt;/.well-known/jwks.json&lt;/code&gt;. The insumer-verify npm package does this client-side with zero dependencies.&lt;/p&gt;

&lt;p&gt;The privacy model matters for agents. InsumerAPI returns booleans, not balances. An agent checking whether a wallet holds stablecoins gets back &lt;code&gt;met: true&lt;/code&gt; or &lt;code&gt;met: false&lt;/code&gt; for each chain. It doesn't see &lt;em&gt;how much&lt;/em&gt; USDC the wallet holds. It doesn't see transaction history. It doesn't see wallet connections or interaction graphs. Just threshold results.&lt;/p&gt;

&lt;p&gt;Agents operating in the x402 ecosystem need the same guarantees. Trustless verification. No balance exposure. No pivot risk. Signed results that any counterparty can independently verify.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Missing Piece in Agent Commerce
&lt;/h2&gt;

&lt;p&gt;AI agents don't fail because they lack capability. They fail because no one verifies them before they act.&lt;/p&gt;

&lt;p&gt;Payment rails solved movement. This layer solves permission. &lt;strong&gt;This is the missing primitive in agent commerce.&lt;/strong&gt; Verification before settlement isn't an optimization, it's the difference between autonomous systems that scale and ones that can't be trusted with money.&lt;/p&gt;

&lt;p&gt;The primitive works today. 33 chains. 24 endpoints. 100,000+ tokens verifiable. Live in production with AsterPay, Revettr, and SettlementWitness. Free tier, no credit card: &lt;a href="https://insumermodel.com/for-businesses/" rel="noopener noreferrer"&gt;start at the developer docs&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>blockchain</category>
      <category>webdev</category>
      <category>security</category>
    </item>
    <item>
      <title>Wallet Auth for LlamaIndex: Condition-Based Access for AI Agents</title>
      <dc:creator>Douglas Borthwick</dc:creator>
      <pubDate>Thu, 16 Apr 2026 22:19:20 +0000</pubDate>
      <link>https://dev.to/douglasborthwickcrypto/wallet-auth-for-llamaindex-condition-based-access-for-ai-agents-4lhl</link>
      <guid>https://dev.to/douglasborthwickcrypto/wallet-auth-for-llamaindex-condition-based-access-for-ai-agents-4lhl</guid>
      <description>&lt;p&gt;&lt;strong&gt;LlamaIndex ships 68 community tool integrations out of the box. Today there is a 69th: &lt;code&gt;llama-index-tools-insumer&lt;/code&gt;. Four methods, 33 chains, ECDSA-signed boolean verdicts your agent can verify offline against a public JWKS. Boolean, not balance.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why an agent needs wallet auth
&lt;/h2&gt;

&lt;p&gt;Autonomous agents increasingly hold wallets, decide what to buy, decide who to trust, and decide when to act. The question &lt;em&gt;"does this wallet meet this specific on-chain condition right now?"&lt;/em&gt; is one that agents ask constantly, before discounting, before routing a payment, before admitting a counterparty to a session. Today, most agents answer it by scraping a block explorer, parsing a JSON response, and guessing. That is neither portable nor verifiable.&lt;/p&gt;

&lt;p&gt;Wallet auth collapses that question into a single tool call. The agent receives back a cryptographic artifact: a signed yes or no, bound to the exact condition that was evaluated, with a block height and a condition hash. The agent can reason over the result, pass it to a downstream service, or log it for audit, all without ever seeing the raw wallet balance.&lt;/p&gt;

&lt;h2&gt;
  
  
  What shipped today
&lt;/h2&gt;

&lt;p&gt;One pip install, one ToolSpec, four methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;llama-index-tools-insumer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The package exposes a single &lt;code&gt;InsumerToolSpec&lt;/code&gt; class. Following LlamaIndex convention, each of the four &lt;code&gt;spec_functions&lt;/code&gt; becomes a tool the agent can invoke by name:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;attest_wallet&lt;/code&gt;&lt;/strong&gt;: run a wallet attestation against one to ten conditions (token balance, NFT ownership, EAS attestation, Farcaster ID). Returns a signed verdict per condition. Maps to &lt;code&gt;POST /v1/attest&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;get_trust_profile&lt;/code&gt;&lt;/strong&gt;: fetch a multi-dimensional wallet trust profile (stablecoins, governance, NFTs, staking, plus optional Solana, XRPL, and Bitcoin dimensions). Returns a signed summary. Maps to &lt;code&gt;POST /v1/trust&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;list_compliance_templates&lt;/code&gt;&lt;/strong&gt;: discover pre-configured EAS compliance templates (Coinbase Verified Account, Gitcoin Passport, and so on). No API key required.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;get_jwks&lt;/code&gt;&lt;/strong&gt;: fetch the public JSON Web Key Set so your agent can verify any signed result offline against the key named by the response's &lt;code&gt;kid&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Drop it into an agent loop
&lt;/h2&gt;

&lt;p&gt;Any LlamaIndex agent that accepts a tool list will accept this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;llama_index.tools.insumer&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;InsumerToolSpec&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;llama_index.agent.openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAIAgent&lt;/span&gt;

&lt;span class="n"&gt;insumer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;InsumerToolSpec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;insr_live_...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OpenAIAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_tools&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;insumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_tool_list&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Does wallet 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hold at least 100 USDC on Base?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood the agent picks &lt;code&gt;attest_wallet&lt;/code&gt;, fills in the right arguments, receives back a signed boolean, and reasons over it the same way it reasons over anything else a tool returns. The agent never sees, and never needs to know, how the balance was read, from which chain, or whether the answer came from a cache or a live read. It just sees a yes or a no, with a signature attached.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the API actually returns
&lt;/h2&gt;

&lt;p&gt;A single live &lt;code&gt;attest_wallet&lt;/code&gt; call against vitalik.eth checking USDC on Base ≥ 1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"attestation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ATST-33DCD2AC57859853"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"pass"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"results"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="nl"&gt;"met"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"conditionHash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"blockNumber"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x..."&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"passCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"failCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"attestedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-04-16T21:xx:xx.000Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"expiresAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-04-16T22:xx:xx.000Z"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sig"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;                         &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ECDSA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;P&lt;/span&gt;&lt;span class="mi"&gt;-256&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;base&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"kid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"insumer-attest-v2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;JWKS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ID&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pqSig"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ML-DSA&lt;/span&gt;&lt;span class="mi"&gt;-65&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;companion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;since&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Sept&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pqKid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"insumer-attest-pq1"&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;JWKS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;AKP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ID&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"meta"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"creditsRemaining"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;999&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"creditsCharged"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;pass&lt;/code&gt; field tells you the verdict. The &lt;code&gt;sig&lt;/code&gt; + &lt;code&gt;kid&lt;/code&gt; let any relying party verify the result offline. The &lt;code&gt;conditionHash&lt;/code&gt; binds the signature to the exact condition that was evaluated, tamper with the condition and the signature no longer checks. The raw balance is never in the response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Boolean, not balance
&lt;/h2&gt;

&lt;p&gt;This is the core differentiator worth spelling out for anyone coming from a block-explorer mindset. Standard on-chain APIs return balances, transaction lists, NFT inventories, the underlying state. The consumer is expected to evaluate the predicate themselves and act on the raw numbers.&lt;/p&gt;

&lt;p&gt;Wallet auth inverts that. The caller sends the predicate in, the API evaluates it against the live chain state, and the response is a cryptographically signed yes or no. The balance never crosses the wire. That matters for three reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy by default.&lt;/strong&gt; An agent that needs to know whether a wallet is a "USDC holder" does not also need to see the exact holdings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit without exposure.&lt;/strong&gt; The signed verdict is verifiable by any party, forever, without re-reading the chain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portability.&lt;/strong&gt; The attestation is the receipt. It survives outside the agent, outside the session, outside the request context it was issued in.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why LlamaIndex specifically
&lt;/h2&gt;

&lt;p&gt;LlamaIndex is the second-most-adopted agent framework in Python after LangChain, with 48K GitHub stars and a library of nearly 70 official tool integrations. The plug-in shape, one &lt;code&gt;ToolSpec&lt;/code&gt; class, multiple &lt;code&gt;spec_functions&lt;/code&gt;, published as a standalone pip package, is exactly the pattern a new integration should follow. Anything else looks out of place.&lt;/p&gt;

&lt;p&gt;There is also a &lt;code&gt;langchain-insumer&lt;/code&gt; package for LangChain developers, an MCP server for any MCP-aware client (Claude Desktop, Cursor, Cline), and an ElizaOS plugin. The LlamaIndex tool completes the four major agent-framework surfaces. Developers can pick the framework they already use and get the same primitive everywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes this different from scraping
&lt;/h2&gt;

&lt;p&gt;A naive answer to "does wallet X hold Y?" is to hit a public RPC, call &lt;code&gt;balanceOf&lt;/code&gt;, compare to a threshold, return a boolean. That works once, inside one program, for one caller. The answer is not portable, another service has to trust your service blindly, or repeat the RPC call itself. And if you log the answer, the log is worthless to anyone else.&lt;/p&gt;

&lt;p&gt;A signed attestation is different. Any service that holds the verdict can verify it independently, offline, forever, against the published JWKS. The condition hash binds the signature to the exact predicate. The block number records when it was read. An audit log of signed attestations is an audit log &lt;em&gt;anyone&lt;/em&gt; can verify, including regulators, counterparties, and future instances of the agent itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Free to start
&lt;/h2&gt;

&lt;p&gt;Every new API key ships with enough credits to run end-to-end before you spend anything. Attestations cost 1 credit, trust profiles cost 3 credits. Template discovery and JWKS lookups are free.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://api.insumermodel.com/v1/keys/create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"email": "you@example.com", "appName": "my-agent", "tier": "free"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a real agent deployment needs more, credits top up via on-chain payment, USDC or USDT on any major EVM chain, USDC on Solana, BTC on Bitcoin, through &lt;code&gt;POST /v1/credits/buy&lt;/code&gt;. No Stripe, no signup flow, no fiat rails. Same rails the agents themselves run on.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three-step primitive
&lt;/h2&gt;

&lt;p&gt;If you take one thing away from this post: wallet auth is &lt;strong&gt;read → evaluate → sign&lt;/strong&gt;. The API reads wallet state from the chain, evaluates it against the caller-specified condition, and signs the verdict. No secrets. No identity-first. No static credentials. The condition is public, the signature binds it to the verdict, and the verdict is the truth, right up until &lt;code&gt;expiresAt&lt;/code&gt;, when the agent is free to re-read.&lt;/p&gt;

&lt;p&gt;LlamaIndex now gives agents that primitive as a first-class tool. &lt;code&gt;pip install&lt;/code&gt; is the whole ceremony.&lt;/p&gt;




&lt;p&gt;Canonical URL: &lt;a href="https://insumermodel.com/blog/llamaindex-tool-wallet-auth-condition-based-access.html" rel="noopener noreferrer"&gt;https://insumermodel.com/blog/llamaindex-tool-wallet-auth-condition-based-access.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Package: &lt;a href="https://pypi.org/project/llama-index-tools-insumer/" rel="noopener noreferrer"&gt;https://pypi.org/project/llama-index-tools-insumer/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://github.com/douglasborthwick-crypto/llama-index-tools-insumer" rel="noopener noreferrer"&gt;https://github.com/douglasborthwick-crypto/llama-index-tools-insumer&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>llm</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Wallet Auth for Tether's WDK: Pre-Transaction Checks in 20 Lines</title>
      <dc:creator>Douglas Borthwick</dc:creator>
      <pubDate>Tue, 14 Apr 2026 20:43:08 +0000</pubDate>
      <link>https://dev.to/douglasborthwickcrypto/wallet-auth-for-tethers-wdk-pre-transaction-checks-in-20-lines-2a4m</link>
      <guid>https://dev.to/douglasborthwickcrypto/wallet-auth-for-tethers-wdk-pre-transaction-checks-in-20-lines-2a4m</guid>
      <description>&lt;p&gt;&lt;strong&gt;Tether's Wallet Development Kit ships Swap, Bridge, Lending, and Fiat protocols. It does not ship a pre-transaction policy layer. Here is one, as a first-class WDK protocol module, installable from npm.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.wdk.tether.io/" rel="noopener noreferrer"&gt;Tether's Wallet Development Kit&lt;/a&gt; (WDK) is the open-source toolkit that powers &lt;a href="https://tether.wallet" rel="noopener noreferrer"&gt;tether.wallet&lt;/a&gt;, Rumble Wallet, and any other multi-chain self-custodial wallet built on its modular plug-in framework. It is explicitly designed for "humans, machines, and AI agents."&lt;/p&gt;

&lt;p&gt;Out of the box, WDK exposes four protocol categories alongside its wallet modules: &lt;strong&gt;Swap&lt;/strong&gt; (Velora), &lt;strong&gt;Bridge&lt;/strong&gt; (USDT0/LayerZero), &lt;strong&gt;Lending&lt;/strong&gt; (Aave), and &lt;strong&gt;Fiat&lt;/strong&gt; (MoonPay). Each is a typed interface that wallet apps compose into their UX.&lt;/p&gt;

&lt;p&gt;What is missing is the layer that runs &lt;em&gt;before&lt;/em&gt; any of those: a pre-transaction check. Given a wallet and a set of on-chain conditions, return a cryptographically signed yes or no. Before signing a transfer, before approving a contract call, before letting an autonomous agent broadcast anything at all. That primitive is what &lt;a href="https://insumermodel.com/blog/wallet-auth-gate-api-on-wallet-state.html" rel="noopener noreferrer"&gt;wallet auth&lt;/a&gt; already provides for backends — we just hadn't yet packaged it as a native WDK module.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fifth protocol
&lt;/h2&gt;

&lt;p&gt;We shipped &lt;a href="https://www.npmjs.com/package/@insumermodel/wdk-protocol-wallet-auth" rel="noopener noreferrer"&gt;&lt;code&gt;@insumermodel/wdk-protocol-wallet-auth&lt;/code&gt;&lt;/a&gt; — a WDK protocol module that exposes the wallet auth primitive (read → evaluate → sign) inside the WDK shape. Same protocol pattern as Swap, Bridge, Lending, and Fiat. Two methods, two jobs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;attest({ address, conditions })&lt;/code&gt;&lt;/strong&gt; — evaluate 1–10 on-chain conditions against a wallet, get back a signed pass/fail attestation. Maps to &lt;code&gt;POST /v1/attest&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;trust({ address })&lt;/code&gt;&lt;/strong&gt; — get a multi-dimensional trust profile: 36+ signed checks across stablecoins, governance, NFTs, and staking. Maps to &lt;code&gt;POST /v1/trust&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install it like any other WDK protocol module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @insumermodel/wdk-protocol-wallet-auth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And use it before any state-changing call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;WalletAuth&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@insumermodel/wdk-protocol-wallet-auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;walletAuth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WalletAuth&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;INSUMER_API_KEY&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Before broadcasting a transfer, verify the counterparty:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;kid&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;walletAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attest&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;counterparty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;conditions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;token_balance&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;USDC &amp;gt;= 1000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;counterparty failed wallet auth check&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// sig + kid are the audit trail: verifiable offline against the JWKS.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the complete surface. Twenty lines is generous — the real surface is three: construct, call, check the boolean. Everything else the module does — bound account resolution, multi-chain address routing, error envelope unwrapping, optional JWT output, optional EIP-1186 Merkle proofs — is plumbing.&lt;/p&gt;

&lt;p&gt;The napkin version, collapsed into one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;walletAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attest&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;conditions&lt;/span&gt; &lt;span class="p"&gt;})).&lt;/span&gt;&lt;span class="nx"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;block&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same operation. &lt;em&gt;Block&lt;/em&gt; is whatever your app does when a check fails — throw, redirect, refund, tell the user to top up. The protocol itself doesn't prescribe the reject path. It just tells you, with a signature, what the right answer is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters for WDK wallets
&lt;/h2&gt;

&lt;p&gt;There are three distinct buyers for a pre-transaction check inside a self-custodial wallet, and WDK touches all three:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Agent wallets.&lt;/strong&gt; WDK's own framing puts "machines and AI agents" alongside humans. When an autonomous agent holds keys, the operator wants programmable constraints the agent cannot argue its way around — and a cryptographic audit trail the operator can verify after the fact. "Only send to counterparties that pass trust check X" is a real constraint. The signed attestation is the receipt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Consumer apps on WDK rails.&lt;/strong&gt; A creator-payment tool like Rumble Wallet, a remittance app, a treasury product — any WDK-based app that serves end users and wants compliance cover needs something between "user clicks send" and "transaction broadcasts." Travel Rule. Sanctions. Counterparty risk. A drop-in module that returns a cryptographically verifiable attestation is cheaper than building it in-house and, crucially, &lt;em&gt;portable&lt;/em&gt; — the attestation survives outside the wallet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Receive-side trust display.&lt;/strong&gt; The most interesting call is not on your own send, it is on someone else's incoming payment. A creator wants to know the wallet sending them money is not freshly funded from a mixer. A merchant wants to know the incoming USDT is not about to be frozen. That is &lt;code&gt;trust()&lt;/code&gt; on the inbound address, surfaced in the UI before the user accepts the payment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it fits WDK's shape
&lt;/h2&gt;

&lt;p&gt;WDK's protocol modules are not hooks or middleware. They are typed interfaces that wallet apps compose into their own flow. &lt;code&gt;Swap&lt;/code&gt; has &lt;code&gt;quoteSwap()&lt;/code&gt; and &lt;code&gt;swap()&lt;/code&gt;. &lt;code&gt;Lending&lt;/code&gt; has &lt;code&gt;supply()&lt;/code&gt;, &lt;code&gt;borrow()&lt;/code&gt;, &lt;code&gt;repay()&lt;/code&gt;. Each is a verb the app calls when it needs that capability.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;WalletAuthProtocol&lt;/code&gt; follows the same pattern. The app calls &lt;code&gt;attest()&lt;/code&gt; or &lt;code&gt;trust()&lt;/code&gt; before the action it wants to gate. The protocol itself never touches private keys, never signs transactions, never broadcasts. It runs &lt;em&gt;before&lt;/em&gt; the signing flow, not inside it. This matters: it means the module is additive and composable with every other WDK protocol, not a replacement or a wrapper.&lt;/p&gt;

&lt;p&gt;The abstract base class (&lt;code&gt;WalletAuthProtocol&lt;/code&gt;) is shape-compatible with WDK's existing &lt;code&gt;SwapProtocol&lt;/code&gt;, &lt;code&gt;BridgeProtocol&lt;/code&gt;, &lt;code&gt;LendingProtocol&lt;/code&gt;, and &lt;code&gt;FiatProtocol&lt;/code&gt; base classes in &lt;code&gt;@tetherto/wdk-wallet/protocols&lt;/code&gt;. It is intentionally structured so that it can be proposed upstream as a blessed fifth protocol module. The reference implementation (&lt;code&gt;InsumerWalletAuthProtocol&lt;/code&gt;) is a clean subclass that any WDK app can install from npm today.&lt;/p&gt;

&lt;h2&gt;
  
  
  What gets signed
&lt;/h2&gt;

&lt;p&gt;Every &lt;code&gt;attest()&lt;/code&gt; result carries an ECDSA P-256 signature and a key ID. Every &lt;code&gt;trust()&lt;/code&gt; result does the same. Verification is offline — any JOSE or JWT library can check the signature against the public JWKS at &lt;a href="https://insumermodel.com/.well-known/jwks.json" rel="noopener noreferrer"&gt;insumermodel.com/.well-known/jwks.json&lt;/a&gt;. There is no server call, no account, no API key required to &lt;em&gt;verify&lt;/em&gt;. Only to &lt;em&gt;create&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If you ask for &lt;code&gt;jwt: true&lt;/code&gt;, the attestation also comes back as a standard ES256 JWT with the signed result as JWT claims. That turns the output into a drop-in bearer token: Kong, Nginx, Cloudflare Access, or AWS API Gateway can verify it the same way they verify any other JWT, without knowing anything about wallet auth at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Supported chains
&lt;/h2&gt;

&lt;p&gt;InsumerAPI covers &lt;strong&gt;33 chains&lt;/strong&gt; today: 30 EVM networks (Ethereum, Polygon, Arbitrum, Optimism, Base, Avalanche, BNB, and the rest of the major EVM set), plus Solana, XRPL, and Bitcoin. WDK's own chain coverage overlaps heavily with this — every EVM chain you hit via &lt;code&gt;wdk-wallet-evm&lt;/code&gt; is already attestable today, same with &lt;code&gt;wdk-wallet-solana&lt;/code&gt; and &lt;code&gt;wdk-wallet-btc&lt;/code&gt;, and the module also covers XRPL natively even though WDK doesn't yet ship an XRPL wallet module.&lt;/p&gt;

&lt;p&gt;Three WDK surfaces do not yet have InsumerAPI coverage: &lt;strong&gt;TRON, TON, and Lightning/Spark&lt;/strong&gt;. Apps on those runtimes can still use &lt;code&gt;attest()&lt;/code&gt; and &lt;code&gt;trust()&lt;/code&gt; against EVM, Solana, XRPL, or Bitcoin addresses the user holds — they just can't yet condition on, say, a TRC-20 balance. Those three chains are on our roadmap and the request shape will stay identical when they land.&lt;/p&gt;

&lt;p&gt;The request shape is already identical across everything that is covered. EVM, Solana, Bitcoin, and XRPL addresses ride in their own fields (&lt;code&gt;wallet&lt;/code&gt;, &lt;code&gt;solanaWallet&lt;/code&gt;, &lt;code&gt;bitcoinWallet&lt;/code&gt;, &lt;code&gt;xrplWallet&lt;/code&gt;) and the module routes them automatically based on each condition's &lt;code&gt;chainId&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Paying for it
&lt;/h2&gt;

&lt;p&gt;The free tier ships 10 attestation credits to every new key so you can kick the tyres end-to-end before spending anything. When a wallet app needs more, credits are purchased on-chain — no Stripe, no fiat rails, no signup flow. The &lt;code&gt;POST /v1/credits/buy&lt;/code&gt; endpoint accepts transfers of &lt;strong&gt;USDC or USDT on any major EVM chain&lt;/strong&gt; (auto-detected from the transaction), &lt;strong&gt;USDC on Solana&lt;/strong&gt;, or &lt;strong&gt;BTC on Bitcoin&lt;/strong&gt;, and credits post as soon as the transaction confirms on-chain. Same rails the wallets themselves run on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where next
&lt;/h2&gt;

&lt;p&gt;The package is public on npm and GitHub, and the README has the full API reference. Three things on the roadmap:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Upstream proposal.&lt;/strong&gt; The &lt;code&gt;WalletAuthProtocol&lt;/code&gt; base class is intentionally a clean extension of the &lt;code&gt;@tetherto/wdk-wallet/protocols&lt;/code&gt; pattern. The next step is proposing it upstream as a blessed fifth protocol module on the WDK repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React Native and Bare runtimes.&lt;/strong&gt; The module uses &lt;code&gt;globalThis.fetch&lt;/code&gt; by default and accepts a &lt;code&gt;fetch&lt;/code&gt; override, so it already works in WDK's React Native and Bare Kit environments. A first-party example in &lt;a href="https://github.com/tetherto/wdk-starter-react-native" rel="noopener noreferrer"&gt;wdk-starter-react-native&lt;/a&gt; is the natural next doc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Receive-side widget.&lt;/strong&gt; The most visually obvious use case — a small trust badge surfaced in the wallet UI when a payment comes in — is a UI component, not a protocol. That will ship separately, layered on top of the protocol module.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you are building a wallet on WDK and any of the three buyer profiles above apply, the module is one install away. And if you are on Tether's side of the fence and want to see Wallet Auth land in the official protocol base classes, open an issue on &lt;a href="https://github.com/douglasborthwick-crypto/wdk-protocol-wallet-auth" rel="noopener noreferrer"&gt;the repo&lt;/a&gt; and let us know.&lt;/p&gt;

&lt;p&gt;OAuth proves who you are. Wallet auth proves what you hold. WDK now has both sides of the flow.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>web3</category>
    </item>
  </channel>
</rss>
