<?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: Ishan Shrestha</title>
    <description>The latest articles on DEV Community by Ishan Shrestha (@ishan_shrestha).</description>
    <link>https://dev.to/ishan_shrestha</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%2F4103034%2Fa58ed59a-0eea-4921-833d-4845927b94f9.png</url>
      <title>DEV Community: Ishan Shrestha</title>
      <link>https://dev.to/ishan_shrestha</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ishan_shrestha"/>
    <language>en</language>
    <item>
      <title>I built a small C++ game engine so an AI IDE could touch the whole thing</title>
      <dc:creator>Ishan Shrestha</dc:creator>
      <pubDate>Thu, 03 Sep 2026 20:08:11 +0000</pubDate>
      <link>https://dev.to/ishan_shrestha/i-built-a-small-c-game-engine-so-an-ai-ide-could-touch-the-whole-thing-3fki</link>
      <guid>https://dev.to/ishan_shrestha/i-built-a-small-c-game-engine-so-an-ai-ide-could-touch-the-whole-thing-3fki</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://medium.com/@ishanshrestha/i-built-a-small-c-game-engine-so-an-ai-ide-could-touch-the-whole-thing-fee629c8fd78" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I wanted to make a game. I also wanted the AI IDE on my desk to edit the whole running process, not just the scripts.&lt;/p&gt;

&lt;p&gt;Godot still makes you do linking and scene wiring in the UI. Unreal would not run on this laptop. Writing a raw Vulkan renderer from scratch meant months before I could drop a cube on screen. So I took the middle: Diligent Engine for the GPU, and I built everything else.&lt;/p&gt;

&lt;p&gt;The machine is an Intel HD 620. No discrete GPU. That forced the rest of the design. Keep draw calls low. Cull hard. Do not pull in heavy middleware.&lt;/p&gt;

&lt;p&gt;Demo: &lt;a href="https://youtu.be/nsptiy-I4Ps" rel="noopener noreferrer"&gt;https://youtu.be/nsptiy-I4Ps&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/Ishan5hrestha/SapanaEngine" rel="noopener noreferrer"&gt;https://github.com/Ishan5hrestha/SapanaEngine&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Diligent, not Godot or raw Vulkan
&lt;/h2&gt;

&lt;p&gt;Full engines hide the part I wanted to learn, and they are too fat for this hardware. Raw Vulkan is a career by itself. Diligent sits in between. Pipeline state, resource binding, HLSL once, targets Vulkan / D3D12 / Metal / D3D11 / GL. It is a dependency. It is not the codebase.&lt;/p&gt;

&lt;p&gt;I write ECS, scenes, assets, physics, cameras, input, and a flight sim. Diligent draws.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is in the engine
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;ECS and scenes.&lt;/strong&gt; EnTT. Scenes are JSON. Entities get transforms, mesh refs, physics blocks, LOD groups. A loader fills the registry at startup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assets.&lt;/strong&gt; GLB/glTF through Diligent's loader, wrapped in my own cache. Builtin cube and plane for quick tests. String IDs like &lt;code&gt;builtin:cube&lt;/code&gt; or &lt;code&gt;meshes/drone.glb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rendering.&lt;/strong&gt; Two modes in config: Basic (forward, color, optional PCF shadows) and PBR (Diligent's GLTF PBR path, behind pimpl). Procedural sky, no skybox texture. Cascaded shadows. Frustum cull, distance LOD, far cull with hysteresis.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Physics.&lt;/strong&gt; Jolt 5.3.0, FetchContent, pinned. Opt-in. No physics block in the JSON means mesh-only. Static and dynamic bodies, box and plane shapes for now. Public headers never see Jolt. Pimpl.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flight.&lt;/strong&gt; The sandbox has a quad. Two profiles on the same craft.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DJI: level, altitude hold, heading-frame move.&lt;/li&gt;
&lt;li&gt;FPV: acro, rate pitch/roll/yaw, idle throttle is freefall.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Four virtual motor forces at the arm corners. Tunables in &lt;code&gt;config/flight.json&lt;/code&gt;. Cameras: freelook, chase, FPV nose. L flips the flight profile. K cycles cameras.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Input.&lt;/strong&gt; Bindings live in JSON. Cursor capture for mouse look.&lt;/p&gt;

&lt;p&gt;Most of the C++ came out of the AI IDE. The real work was keeping it light enough that this laptop still runs, and fixing the parts the model got wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sandbox
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr75131c23cidlgfndcnl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr75131c23cidlgfndcnl.png" alt="Sapana Sandbox — drone, trees, physics cubes on Vulkan" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That shot is Sapana Sandbox on Vulkan. Same frame you see in the title bar: mid-60s fps on integrated graphics. Green ground with static physics. Dynamic cubes. Visual-only glTF cube. One flyable drone. About forty static trees with box colliders.&lt;/p&gt;

&lt;p&gt;Edit a config or the scene JSON, rebuild, relaunch. No recompile hunt for every tweak. Builds on Linux (Mint 22.3 here) and Windows (&lt;code&gt;win&lt;/code&gt; branch).&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug
&lt;/h2&gt;

&lt;p&gt;Far-distance cull, with LOD enabled, can strobe. Builtin cubes pop. Sky shows through. Freelook and drone share one view path, so both get it. Far hide vs camera far plane, shadow casters dropping while receivers still draw, PCF on basic meshes. Hysteresis helped. It is not fixed. Workaround: turn LOD off in &lt;code&gt;config/lod.json&lt;/code&gt; and restart.&lt;/p&gt;

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

&lt;p&gt;It is not Unreal. It is not a product. It is a small engine for a specific game, on limited VRAM, where the whole loop is files an IDE can touch.&lt;/p&gt;

&lt;p&gt;If you want the boring details, the README in the repo has the layer list, controls, and build steps.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>gamedev</category>
      <category>graphics</category>
      <category>cpp</category>
    </item>
    <item>
      <title>How I Stop Fake Signups From Farming Free Credits (JS/Python)</title>
      <dc:creator>Ishan Shrestha</dc:creator>
      <pubDate>Mon, 31 Aug 2026 16:28:05 +0000</pubDate>
      <link>https://dev.to/ishan_shrestha/how-i-stop-fake-signups-from-farming-free-credits-jspython-10hd</link>
      <guid>https://dev.to/ishan_shrestha/how-i-stop-fake-signups-from-farming-free-credits-jspython-10hd</guid>
      <description>&lt;p&gt;A few client apps had the same leak.&lt;/p&gt;

&lt;p&gt;They offered free credits so people could try the product. Normal and fair. Then throwaway emails showed up, grabbed the free stuff, and disappeared. Support time went up. Costs went up. Real users got a worse experience.&lt;/p&gt;

&lt;p&gt;We tried free tools. One helped for a while. One broke at the worst time. After patching this more than once, I wanted one simple rule for signup:&lt;/p&gt;

&lt;p&gt;If the email looks abusive or undeliverable, block quietly and move on.&lt;/p&gt;

&lt;p&gt;That is what I built into: &lt;a href="https://emailscore.neuralevo.com/" rel="noopener noreferrer"&gt;https://emailscore.neuralevo.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post is the practical version: what to check, and copy-paste code in JavaScript and Python.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule that matters
&lt;/h2&gt;

&lt;p&gt;Call the validate API and gate on &lt;code&gt;verdict&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;allow&lt;/code&gt;: continue signup / trial&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;block&lt;/code&gt;: stop with a neutral message&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can inspect other fields later. For signup abuse, start with &lt;code&gt;verdict&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;POST https://api.emailscore.neuralevo.com/api/v1/validate/email&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Header:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Authorization: Bearer YOUR_API_KEY&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  JavaScript (Node fetch)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;shouldAllowSignup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;apiKey&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;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;fetch&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://api.emailscore.neuralevo.com/api/v1/validate/email&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="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;apiKey&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&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="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;email&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&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;`Validate failed: &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="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="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&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;response&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="c1"&gt;// Primary signup gate&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&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;allow&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="c1"&gt;// Example&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ok&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;shouldAllowSignup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ada@company.com&lt;/span&gt;&lt;span class="dl"&gt;"&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;EMAIL_SCORE_API_KEY&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;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Show a neutral error. Do not explain the abuse logic.&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please use a different email.&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Python (requests)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;should_allow_signup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.emailscore.neuralevo.com/api/v1/validate/email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verdict&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;allow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;should_allow_signup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ada@company.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;EMAIL_SCORE_API_KEY&lt;/span&gt;&lt;span class="sh"&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="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Please use a different email.&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;h2&gt;
  
  
  What a response looks like
&lt;/h2&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;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ada@company.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"normalized"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ada@company.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"verdict"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"policyReason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"clean"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"checks"&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;"syntax"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pass"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"disposable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"miss"&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;"deliverability"&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;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deliverable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mx_found"&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;Useful extras when you need them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;checks.disposable&lt;/code&gt;: throwaway / block list hit&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;deliverability.status&lt;/code&gt;: can the domain receive mail&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;policyReason&lt;/code&gt;: why policy decided what it did&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most signup flows, still gate on &lt;code&gt;verdict&lt;/code&gt; first.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Free trials and free credits&lt;/li&gt;
&lt;li&gt;Waitlists&lt;/li&gt;
&lt;li&gt;Invites&lt;/li&gt;
&lt;li&gt;Any form where fake emails quietly cost money&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;If you want to poke at it without wiring code first, there is a free checker on the homepage:&lt;br&gt;
&lt;a href="https://emailscore.neuralevo.com" rel="noopener noreferrer"&gt;https://emailscore.neuralevo.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is also free API access for devs.&lt;/p&gt;

&lt;p&gt;If you try the snippets, tell me what broke or felt unclear. I am still improveing this from more client pain, so blunt feedback helps more than polite compliments.&lt;/p&gt;




&lt;p&gt;Originally published on &lt;a href="https://medium.com/@ishanshrestha/how-i-stop-fake-signups-from-farming-free-credits-js-python-80f30d85334f" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>python</category>
      <category>webdev</category>
      <category>api</category>
    </item>
  </channel>
</rss>
