<?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: Adewebs</title>
    <description>The latest articles on DEV Community by Adewebs (@adewebs).</description>
    <link>https://dev.to/adewebs</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%2F1314879%2F8c8abbb8-687c-4bdf-9e8c-8603f03d7a7f.jpeg</url>
      <title>DEV Community: Adewebs</title>
      <link>https://dev.to/adewebs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adewebs"/>
    <language>en</language>
    <item>
      <title>Add KYC to your product without building a KYC screen: verification links, an iframe and webhooks</title>
      <dc:creator>Adewebs</dc:creator>
      <pubDate>Sun, 18 Oct 2026 22:39:40 +0000</pubDate>
      <link>https://dev.to/adewebs/add-kyc-to-your-product-without-building-a-kyc-screen-verification-links-an-iframe-and-webhooks-4eh7</link>
      <guid>https://dev.to/adewebs/add-kyc-to-your-product-without-building-a-kyc-screen-verification-links-an-iframe-and-webhooks-4eh7</guid>
      <description>&lt;p&gt;Most teams that need to check who a customer is end up building the same thing: a page that asks for an ID number, a camera screen for a selfie, a progress bar, a consent notice, retries when a photo is blurry, and a back office to review the results. It is weeks of work, and it is not your product.&lt;/p&gt;

&lt;p&gt;There is a shorter way: let a hosted flow do the screens, and keep control of the decision. Here is how that looks with the Verification Suite from &lt;a href="https://identifyorg.com/products/verification-suite" rel="noopener noreferrer"&gt;IdentifyOrg&lt;/a&gt; (disclosure: I work on it). The ideas apply to any provider that offers hosted verification.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three ways in
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;No code.&lt;/strong&gt; A business sets up a flow in a dashboard (which checks, in what order), then sends each applicant a personal link on WhatsApp.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An iframe or a script&lt;/strong&gt; on your own site.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your server&lt;/strong&gt; creates a session through the API for each applicant and reads the result afterwards.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All three end in the same place: a session with a status and a result per step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a session from your server
&lt;/h2&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.identifyorg.com/v1/verification-sessions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-IdentifyOrg-Key: io_live_..."&lt;/span&gt; &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;'{
    "flow_id": "vf_YOUR_FLOW_ID",
    "reference": "order-1042",
    "applicant": { "name": "Ada Obi", "phone": "08031234567" }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get back a &lt;code&gt;url&lt;/code&gt;. Send it to the applicant, or give it to your page. Two details worth copying into your own designs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;reference&lt;/code&gt; is &lt;em&gt;your&lt;/em&gt; id (an order or customer number). Sending the same reference again while that session is open returns the same session, so a retry never creates a second one.&lt;/li&gt;
&lt;li&gt;Use a &lt;strong&gt;secret&lt;/strong&gt; key on your server only. The flow id that goes in a public page is not a secret and cannot read anything.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Embed it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"identifyorg-verify"&lt;/span&gt; &lt;span class="na"&gt;data-flow=&lt;/span&gt;&lt;span class="s"&gt;"vf_YOUR_FLOW_ID"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://identifyorg.com/embed/verify.js"&lt;/span&gt; &lt;span class="na"&gt;async&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or a plain iframe. The one thing people forget is the permissions attribute, without which the browser will not let the frame use the camera:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;iframe&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://identifyorg.com/v/vf_YOUR_FLOW_ID?embed=1"&lt;/span&gt;
  &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Identity verification"&lt;/span&gt;
  &lt;span class="na"&gt;allow=&lt;/span&gt;&lt;span class="s"&gt;"camera; geolocation"&lt;/span&gt;
  &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width:100%;max-width:480px;height:760px;border:0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The form only renders inside websites you have allowed in the flow settings. Any other site sees a blank frame.&lt;/p&gt;

&lt;h2&gt;
  
  
  Listen to the frame
&lt;/h2&gt;

&lt;p&gt;The embedded page talks to yours with &lt;code&gt;postMessage&lt;/code&gt;. Always check the origin:&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&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;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://identifyorg.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&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;d&lt;/span&gt; &lt;span class="o"&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;data&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;d&lt;/span&gt; &lt;span class="o"&gt;||&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;source&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;identifyorg-verify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&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;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resize&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;iframe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&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;height&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;px&lt;/span&gt;&lt;span class="dl"&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;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;showThanks&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// they finished, not "they passed"&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Events you will see: &lt;code&gt;ready&lt;/code&gt;, &lt;code&gt;started&lt;/code&gt;, &lt;code&gt;step&lt;/code&gt;, &lt;code&gt;received&lt;/code&gt;, &lt;code&gt;resize&lt;/code&gt;, &lt;code&gt;completed&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not treat &lt;code&gt;completed&lt;/code&gt; as proof of anything.&lt;/strong&gt; It only means the person reached the end. The result belongs to your server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the result with a webhook
&lt;/h2&gt;

&lt;p&gt;Register an endpoint and you get &lt;code&gt;verification_session.started&lt;/code&gt;, &lt;code&gt;.completed&lt;/code&gt;, &lt;code&gt;.failed&lt;/code&gt; and &lt;code&gt;.awaiting_funds&lt;/code&gt;. Verify the signature before you trust a payload. The header looks like &lt;code&gt;t=1760437440,v1=9f2c...&lt;/code&gt; and the signature is an HMAC-SHA256 of &lt;code&gt;"{t}.{raw_body}"&lt;/code&gt; with your webhook secret:&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;import&lt;/span&gt; &lt;span class="n"&gt;hmac&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&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;secret&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;tolerance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&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;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;t&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tolerance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;                      &lt;span class="c1"&gt;# too old: could be a replay
&lt;/span&gt;    &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hmac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;raw_body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&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;hmac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compare_digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The payload includes the status, each step's outcome, and the ID number &lt;strong&gt;masked&lt;/strong&gt; (last four digits). Pictures are never in the webhook; the business reviews those in the dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test it first
&lt;/h2&gt;

&lt;p&gt;A flow in &lt;strong&gt;test mode&lt;/strong&gt; returns sample results, charges nothing and makes no real checks. Build the whole integration against it, then switch the flow to live. A test key does the same for the API.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to decide yourself
&lt;/h2&gt;

&lt;p&gt;A verification result is evidence, not a verdict. Decide what you require (an ID number check only, or also a selfie and a liveness test), what a "review" outcome means for your business, and who looks at it. The tool gives you the signals; the policy is yours.&lt;/p&gt;

&lt;p&gt;Docs: &lt;a href="https://identifyorg.com/docs/verification-suite" rel="noopener noreferrer"&gt;Verification Suite and embed guide&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
      <category>security</category>
      <category>javascript</category>
    </item>
    <item>
      <title>NIN vs BVN: what Nigerian identity numbers are, and which one to verify in your app</title>
      <dc:creator>Adewebs</dc:creator>
      <pubDate>Sun, 18 Oct 2026 22:38:24 +0000</pubDate>
      <link>https://dev.to/adewebs/nin-vs-bvn-what-nigerian-identity-numbers-are-and-which-one-to-verify-in-your-app-2loh</link>
      <guid>https://dev.to/adewebs/nin-vs-bvn-what-nigerian-identity-numbers-are-and-which-one-to-verify-in-your-app-2loh</guid>
      <description>&lt;p&gt;If you are building a product for Nigerian users, KYC conversations start with two eleven-digit numbers: the &lt;strong&gt;BVN&lt;/strong&gt; and the &lt;strong&gt;NIN&lt;/strong&gt;. They are not interchangeable, and picking the wrong one can exclude users or leave a gap in your checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  BVN: Bank Verification Number
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Issued through the banking system. You get one when you register biometrics with a bank.&lt;/li&gt;
&lt;li&gt;It identifies a person across all their bank accounts.&lt;/li&gt;
&lt;li&gt;Anyone with a bank account normally has one. Someone with no bank account normally does not.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use it when&lt;/strong&gt; you are dealing with money: lending, wallets, payouts, account opening. It ties the person to the banking system.&lt;/p&gt;

&lt;h2&gt;
  
  
  NIN: National Identification Number
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Issued by the national identity authority (NIMC) to citizens and legal residents.&lt;/li&gt;
&lt;li&gt;Not tied to a bank account. People without a bank account can have one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use it when&lt;/strong&gt; you need to identify a person who may not be banked: staffing and HR, telecom and utility sign-ups, community programmes, resellers and agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which should you ask for?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your situation&lt;/th&gt;
&lt;th&gt;Ask for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lending or wallets for banked users&lt;/td&gt;
&lt;td&gt;BVN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Onboarding sellers, riders, resellers or staff&lt;/td&gt;
&lt;td&gt;NIN (or let the person choose)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High-risk accounts&lt;/td&gt;
&lt;td&gt;Both, plus a selfie and liveness test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unbanked users&lt;/td&gt;
&lt;td&gt;NIN&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Many products let the applicant pick either number, which avoids turning away someone who has only one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a number check does and does not prove
&lt;/h2&gt;

&lt;p&gt;A lookup tells you the number exists and that the name (and other details you send) match the record. It does &lt;strong&gt;not&lt;/strong&gt; prove that the person typing the number is the owner. Anyone who knows or has found a number can type it. To tie the number to a person you need more signals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;selfie matched to the ID card photo&lt;/strong&gt; the applicant uploads,&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;liveness test&lt;/strong&gt; so the selfie is a live person,&lt;/li&gt;
&lt;li&gt;details that the genuine owner would know (date of birth and phone number are commonly required for a BVN check).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also be clear about photos: some lookups return no photo, so there may be no official photo to compare a selfie with. If that is your provider's behaviour, tell your users and your compliance team, and compare with the card photo the applicant uploads instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handle the data like a regulated identifier
&lt;/h2&gt;

&lt;p&gt;These numbers are personal data under Nigerian data protection law. Practical habits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Encrypt the number at rest and show only the last four digits by default.&lt;/li&gt;
&lt;li&gt;Log every time someone reveals it.&lt;/li&gt;
&lt;li&gt;Record consent with a timestamp and the version of the wording.&lt;/li&gt;
&lt;li&gt;Delete data after the retention period you promised, and on request.&lt;/li&gt;
&lt;li&gt;Tell users what you check and why.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Calling a verification API
&lt;/h2&gt;

&lt;p&gt;With IdentifyOrg (where I work), a NIN check is one call, billed only when the check completes:&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.identifyorg.com/v1/verify/nin &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-IdentifyOrg-Key: io_test_..."&lt;/span&gt; &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;'{ "nin": "12345678901", "first_name": "Adaeze", "last_name": "Okafor" }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use a test key first: it returns realistic responses without charging or contacting any third party. If you do not want to build the screens yourself, the same checks (plus selfie match, liveness and address) are available as a &lt;a href="https://identifyorg.com/products/verification-suite" rel="noopener noreferrer"&gt;no-code verification link&lt;/a&gt; you send on WhatsApp or embed on your site. More detail: &lt;a href="https://identifyorg.com/products/nin-verification" rel="noopener noreferrer"&gt;NIN verification&lt;/a&gt; and &lt;a href="https://identifyorg.com/products/bvn-verification" rel="noopener noreferrer"&gt;BVN verification&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Identity numbers and the checks available depend on the country. Outside Nigeria, phone, ID card reading, selfie match, liveness and address checks work; identity-number checks for other countries are being added.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>fintech</category>
      <category>africa</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
