<?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: Nikolaos Dimitriadis</title>
    <description>The latest articles on DEV Community by Nikolaos Dimitriadis (@nikoble1926).</description>
    <link>https://dev.to/nikoble1926</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%2F4169058%2F3e5cec25-63ad-471a-8bfb-3290d13e186b.jpg</url>
      <title>DEV Community: Nikolaos Dimitriadis</title>
      <link>https://dev.to/nikoble1926</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nikoble1926"/>
    <language>en</language>
    <item>
      <title>Screening the payee of an x402 payment with Privy: OFAC, UN, EU and UK in one signed call</title>
      <dc:creator>Nikolaos Dimitriadis</dc:creator>
      <pubDate>Thu, 08 Oct 2026 18:20:21 +0000</pubDate>
      <link>https://dev.to/nikoble1926/screening-the-payee-of-an-x402-payment-with-privy-ofac-un-eu-and-uk-in-one-signed-call-54aa</link>
      <guid>https://dev.to/nikoble1926/screening-the-payee-of-an-x402-payment-with-privy-ofac-un-eu-and-uk-in-one-signed-call-54aa</guid>
      <description>&lt;p&gt;Privy has a good recipe for blocking x402 payments to sanctioned addresses: &lt;a href="https://docs.privy.io/recipes/agent-integrations/x402-sanctions-screening" rel="noopener noreferrer"&gt;https://docs.privy.io/recipes/agent-integrations/x402-sanctions-screening&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The enforcement point is Privy's policy engine. You load a denylist into a condition set, and Privy refuses to sign a payment whose recipient is on it. The recipe is clear about what it leaves to you: loading the addresses is "general code, so it is not reproduced here", the example source is the OFAC SDN list, and it suggests pairing the denylist with a screening provider.&lt;/p&gt;

&lt;p&gt;This post shows one way to add that second layer, with a few lines of code and no extra account or API key.&lt;/p&gt;

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

&lt;p&gt;Before the agent pays an x402 endpoint, it asks a screening service to read that endpoint's own 402 and check every payTo it advertises against four lists: OFAC SDN, UN Consolidated, EU and UK. The answer is signed (EIP-191), with each list reported separately and its own version date, so you can keep it as a record of what was checked.&lt;/p&gt;

&lt;p&gt;The check is itself paid over x402: 0.01 USDC on Base or Solana. The same wallet that pays the target pays for the check; in the setup below, that is your Privy wallet.&lt;/p&gt;

&lt;p&gt;Keep the Privy policy as the control that is enforced at signing. Treat this as an extra layer: more lists than OFAC alone, and a signed record per payment for your audit trail.&lt;/p&gt;

&lt;h2&gt;
  
  
  The code (Node 20 or newer)
&lt;/h2&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; @privy-io/node@0.35.0 @x402/fetch@2.17.0
&lt;span class="c"&gt;# @privy-io/node/x402 also imports these at load time, so install them too:&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; @solana/kit@^5.1.0 @x402/svm@2.17.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;createX402Client&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;@privy-io/node/x402&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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;wrapFetchWithPayment&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;@x402/fetch&lt;/span&gt;&lt;span class="dl"&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;SCREEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://sanctions.nsgoods.org/screen-url?url=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Pay the target only if every payTo it advertises is clear on all four lists.&lt;/span&gt;
&lt;span class="c1"&gt;// Anything else (deny, review, an error, a timeout) means do not pay.&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;screenThenFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fetchWithPayment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;targetUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&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;fetchWithPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SCREEN&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetUrl&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;body&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&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;screening unavailable: do not pay&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;verdict&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;clean&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="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="s2"&gt;`payee not clear (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;res&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="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;verdict&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no verdict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;): do not pay`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fetchWithPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Privy wallet, as in Privy's x402 docs&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x402client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createX402Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;privy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;walletId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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;wallet&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchWithPayment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;wrapFetchWithPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x402client&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;response&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;screenThenFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fetchWithPayment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example.com/premium&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The verdict is &lt;code&gt;clean&lt;/code&gt; only when every payee is clear on all four lists. &lt;code&gt;deny&lt;/code&gt; means an OFAC match. &lt;code&gt;review&lt;/code&gt; means a UN, EU or UK match, or a list that could not be checked. A bad, unreachable or non x402 URL returns 400, 422 or 502 and you are not charged.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The check reads the 402 at the moment you call it. The response includes &lt;code&gt;quote_sha256&lt;/code&gt; and &lt;code&gt;quote_read_at&lt;/code&gt;, so you can log exactly what was checked, but the Privy policy is still what enforces at signing.&lt;/li&gt;
&lt;li&gt;Passing means the payee is not on these four lists at their stated version dates. It says nothing about indirect exposure or where the funds go next. Not legal advice.&lt;/li&gt;
&lt;li&gt;We tested &lt;code&gt;screenThenFetch&lt;/code&gt; on Base with &lt;code&gt;@x402/fetch&lt;/code&gt; 2.17.0 and a plain EVM wallet: a clean payee was screened and then paid, and a non x402 URL was refused with no payment. We checked that &lt;code&gt;@privy-io/node&lt;/code&gt; 0.35.0 exports &lt;code&gt;createX402Client&lt;/code&gt;, but we have not run a payment with a Privy account.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Free signed sample of the response: &lt;a href="https://sanctions.nsgoods.org/screen-url/preview" rel="noopener noreferrer"&gt;https://sanctions.nsgoods.org/screen-url/preview&lt;/a&gt;&lt;br&gt;
Node and Python examples, with offline signature verification for /screen-multi: &lt;a href="https://github.com/Nikoble1926/sanctions-check-before-pay" rel="noopener noreferrer"&gt;https://github.com/Nikoble1926/sanctions-check-before-pay&lt;/a&gt;&lt;br&gt;
OpenAPI: &lt;a href="https://sanctions.nsgoods.org/openapi.json" rel="noopener noreferrer"&gt;https://sanctions.nsgoods.org/openapi.json&lt;/a&gt;&lt;/p&gt;

</description>
      <category>x402</category>
      <category>ai</category>
      <category>web3</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Check the payee before your AI agent pays it (x402, Node and Python)</title>
      <dc:creator>Nikolaos Dimitriadis</dc:creator>
      <pubDate>Wed, 07 Oct 2026 14:37:09 +0000</pubDate>
      <link>https://dev.to/nikoble1926/check-the-payee-before-your-ai-agent-pays-it-x402-node-and-python-671</link>
      <guid>https://dev.to/nikoble1926/check-the-payee-before-your-ai-agent-pays-it-x402-node-and-python-671</guid>
      <description>&lt;p&gt;An AI agent that pays over x402 reads a &lt;code&gt;payTo&lt;/code&gt; address from a 402 response and sends USDC to it. Some agent wallets already let the owner set a daily budget, a per transaction limit and approved domains. A check on the address itself is a separate question: is the wallet you are about to pay on a sanctions list?&lt;/p&gt;

&lt;p&gt;This post shows a small pattern for that, with working Node and Python examples. The full code is here: &lt;a href="https://github.com/Nikoble1926/sanctions-check-before-pay" rel="noopener noreferrer"&gt;https://github.com/Nikoble1926/sanctions-check-before-pay&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What the check does
&lt;/h2&gt;

&lt;p&gt;One paid call screens a wallet address against four lists: OFAC SDN, UN Consolidated, EU and UK. The response is signed and reports each list separately, matched or clear, with that list's version date. It costs 0.01 USDC per call, paid over x402 itself, on Base or Solana. No account, no API key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET https://sanctions.nsgoods.org/screen-multi?address=&amp;lt;payTo&amp;gt;&amp;amp;chain=&amp;lt;optional hint&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a free signed sample of the exact response shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET https://sanctions.nsgoods.org/screen-multi/preview
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The one rule that matters: fail closed
&lt;/h2&gt;

&lt;p&gt;The response has a headline &lt;code&gt;verdict&lt;/code&gt; (&lt;code&gt;clean&lt;/code&gt;, &lt;code&gt;deny&lt;/code&gt; or &lt;code&gt;indeterminate_ofac_unavailable&lt;/code&gt;) and an &lt;code&gt;any_list_match&lt;/code&gt; flag that covers all four lists. The headline verdict on its own only speaks for OFAC. So the decision uses both, and it treats everything that is not an explicit clean answer as a no:&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decide&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;verdict&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clean&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;any_list_match&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;deny&lt;/code&gt;, &lt;code&gt;indeterminate_ofac_unavailable&lt;/code&gt;, a 400, a 5xx, a timeout or a body that is not JSON all mean: do not pay. We had this wrong in our first draft. The script said "pay" when the OFAC feed was unavailable, which is the worst possible failure for a check like this. A check that cannot run must never turn into a yes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it
&lt;/h2&gt;

&lt;p&gt;Node 20 or newer:&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;&lt;span class="nv"&gt;EVM_PRIVATE_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x... node check-before-pay.mjs &amp;lt;payTo address&amp;gt; &lt;span class="o"&gt;[&lt;/span&gt;chain]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python:&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; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;span class="nv"&gt;EVM_PRIVATE_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x... python check_before_pay.py &amp;lt;payTo address&amp;gt; &lt;span class="o"&gt;[&lt;/span&gt;chain]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exit code 0 means clean, go ahead. Any other exit code means do not pay, so you can drop it in front of the payment step of an agent or a script. Without &lt;code&gt;EVM_PRIVATE_KEY&lt;/code&gt; both scripts stop at the 402 and print the price, so you can try them without a wallet. Use a low balance hot wallet for the key, never your main one.&lt;/p&gt;

&lt;p&gt;Two things we only found by testing on a clean machine, in case they save you time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;With &lt;code&gt;@x402/axios&lt;/code&gt;, the payment happens when the first 402 comes back as an error. If you set &lt;code&gt;validateStatus: () =&amp;gt; true&lt;/code&gt; on the paying client, the 402 counts as a success and the client never pays. The example uses &lt;code&gt;validateStatus: s =&amp;gt; s !== 402&lt;/code&gt;, so 400 and 5xx still do not throw.&lt;/li&gt;
&lt;li&gt;The Python x402 EVM signer needs &lt;code&gt;web3&lt;/code&gt; installed (the &lt;code&gt;x402[evm]&lt;/code&gt; extra). Without it, the import fails before anything runs. The &lt;code&gt;requirements.txt&lt;/code&gt; in the repo pins it.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;The response is signed, so you do not have to trust the transport:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node verify-signature.mjs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It fetches the free preview and recovers the signer offline. The service signs the body without &lt;code&gt;signed_by&lt;/code&gt; and &lt;code&gt;signature&lt;/code&gt;, as compact JSON with sorted keys and non ASCII characters escaped, with an Ethereum personal_sign. Expected signer: &lt;code&gt;0x57fF0F084Cba33e6761503f90eEF0Da9F159350c&lt;/code&gt;. The one trap here: the escaping. JavaScript's &lt;code&gt;JSON.stringify&lt;/code&gt; leaves non ASCII characters as they are, so the verifier escapes them by hand to match.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits
&lt;/h2&gt;

&lt;p&gt;Not legal advice. Passing the rule means the address is not on these four lists at their stated version dates, nothing more. It says nothing about who controls the wallet or where its funds came from.&lt;/p&gt;

&lt;p&gt;Code, MIT licensed: &lt;a href="https://github.com/Nikoble1926/sanctions-check-before-pay" rel="noopener noreferrer"&gt;https://github.com/Nikoble1926/sanctions-check-before-pay&lt;/a&gt;&lt;br&gt;
More about the service: &lt;a href="https://x402.nsgoods.org" rel="noopener noreferrer"&gt;https://x402.nsgoods.org&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>web3</category>
      <category>javascript</category>
      <category>python</category>
    </item>
  </channel>
</rss>
