Happy Employees == Happy ClientsCAREERS AT DEPT®

How to implement KYC/AML protocols for an NFT marketplace

Learn how to implement KYC/AML protocols for an NFT marketplace.

In our previous blog post, we went over what KYC/AML is and why your company may need it: https://engineering.deptagency.com/why-you-need-kyc.

In this article, we will be going over how we approached KYC and AML measures for an NFT collectible marketplace for a major sports organization, a marketplace for digital collectibles on the Algorand blockchain. First, we'll talk about the KYC process, then how we addressed customer support, and finally, what some of the challenges were in building and maintaining this system.

Acronyms

  • NFT = Non-Fungible Token
  • KYC = Know Your Customer
  • AML = Anti-Money Laundering
  • SSN = Social Security Number
  • PII = Personal Identifiable Information
  • PEP = Politically Exposed People

🏅 Background

In the NFT collectible marketplace we built, users can sign up and purchase packs that have an unknown assortment of collectibles, or they can purchase from the secondary marketplace, where individual collectibles are sold for a price determined by the seller. Making the platform accessible to people new to blockchain technologies was a top priority, so accepting credit card payments (in addition to crypto) was important. This, however, increases the risk of fraudulent transactions.

We used Circle for the underlying financial technologies. When purchases are made using credit cards, those funds are converted to USDC-A (USDC on the Algorand blockchain) which are kept in an Algorand wallet that is created per account. Users purchase “credits,” which means loading USDC into the account’s wallet. Circle is a financial institution that has to abide by Anti-Money Laundering (AML) laws, and we entered a KYC reliance agreement with Circle that dictates what KYC and AML processes we need to have in place for compliance.

Our contract with Circle details that we are responsible for enacting fraud detection on their behalf according to the established AML Policy, and therefore, we needed to find a provider to assist with identity verification (KYC) and flagging suspicious or fraudulent behavior. This provider cannot make final decisions; that responsibility is on us, but they can assist in collecting the data needed to make a final decision.

Initially, when trying to find a provider, Trulioo, Jumio, and Onfido were recommended to us, and all seemed to have services for what we needed. See the previous KYC article for advice on what to look for when choosing a provider. For us, the features we needed supported included:

  • Identity verification
  • Documentary verification
  • Biometric verification
  • Ongoing monitoring against AML watchlist

All of the mentioned providers appeared to have products to accomplish what we needed, and Trulioo and Onfido seemed the best match for the technologies we were using. We were impressed with Onfido’s related products, and we opted to use them as our KYC provider.

🪪 The KYC Process

When a user goes through the KYC process, they have to enter personal details, provide documentary evidence (such as a passport), and take a selfie to confirm their identity. Checks are run against AML watchlists - sanctions, politically exposed persons or PEP, and adverse media lists. Onfido is used for data collection and analysis; the workflow logic was contained within Onfido Studio workflows, dictating the flow a user goes through after initiating verification and what data is gathered. There is also logic that lives within our application; we have our own user statuses that we choose for an account after comparing Onfido’s results to the criteria that lives within the application.

Since not everyone is going through the KYC verification process, we built gates throughout the application, both on the frontend and backend, which check the user account status when certain functionality is attempted. When the thresholds are reached, a user will be prompted to go through the KYC verification process to continue transacting on the site. Most commonly users are prompted to go through KYC during the checkout flow, or when attempting to make a payout.

Crypto purchases have some additional restrictions, as certain locales are prohibited from making payments using this method, and we are required to check if any crypto addresses used matched sanctions lists. This feature wasn’t supported by our KYC provider Onfido, but was required for compliance with the AML policy, so we opted to use Chainalysis’ free crypto sanctions product, which allows us to check if an address is sanctioned. At the time we were initially looking into a solution Algorand did not have any sanctioned addresses but it was still a requirement to be monitoring for sanctioned addresses in case that changed.

Making programmatic decisions

Initially we thought that we’d be able to make most decisions automatically based on the results from Onfido’s API, but we quickly realized that there are many situations where we could not be confident in the results. In fact, it would be faster to tell you what we could confidently make programmatic decisions rather than what we couldn’t.

  • Happy path: A user goes through KYC verification without issue, provides a document they are confirmed as the owner of, is not from a restricted locale, and there’s no matching activity on AML watchlists. This user would be placed into a Clear status in our system and would be able to transact freely on the platform, though we would continue to monitor AML lists.
  • Unhappy path: A user is from a prohibited region. We would know if the user is using a restricted locale during the verification workflow when the user provided address data, as well as if they used a form of identification from that region, so we can more confidently restrict based on that data.
  • Unhappy path: Discrepancy between the document and selfie provided. This indicates the person is using someone else’s identification method fraudulently, and would result in them being restricted on the platform.

For all other unhappy paths, we place the user into Manual Review. This status requires further exploration by someone on the compliance team. There are regular situations that could lead to an unclear result, such as submitting a blurry photo for the document or providing an unclear selfie. If there is a problem with the data provided, the customer service team can request the user try verification again by placing into the appropriate status for them to retry, and communicating the issue.

The most common reason, however, that someone falsely ends up being flagged during the process is due to AML watchlists. We check AML watchlists to identify if any active users match sanctions, PEP, or adverse media watchlists, all of which would be prohibited. The AML watchlists very often have false matches, with an emphasis on the adverse media and politically exposed persons (PEP) watchlists. Due to the many false positives, this requires human intervention to analyze the record and determine if the user is the one identified by the watchlist. This analysis takes time, as you have to review the data that was flagged by Onfido as well as the user’s provided data initially and make a decision on if that is the same person. Sometimes it’s obvious, but other times it can be difficult to determine. It is also wise to analyze other user interaction data to make sure there’s no suspicious behavior flagged for any users that are looked into as well.

Since further exploration is often needed when users are placed into Manual Review, this had implications for customer support. We knew customer support is a necessary part of the KYC process, but it was underestimated how much of a lift this would be.

💁 Customer Support

Users would often write in with basic questions, some of which the customer service team can be prepared to answer, but the vast majority of the time questions were handed off to those familiar with the AML policies. It was pivotal to have decision maker(s) who could guide the customer service team and help them with what information to share and what not to share, and who can do further analysis to determine what action should be taken and communicate to the development team if any behavior needs to be verified.

In order to support the compliance team, which was doing the more in-depth analysis, we built various tools for analyzing user behavior. We started out using a headless CMS to build out administrative functionality, but we transitioned to using a product called Retool since it made creating these tools much easier.

We found the following tools very useful in our KYC exploration.

💻 Administrative tools

Many tools were built to support the application, but I’d consider the following tools most critical when analyzing fraudulent or suspicious activity. It was also necessary to educate the compliance team on how to use the tools, and to support them by creating new tools as needed to assist in customer support.

1) User Diagnostics

The most widely used application we created in Retool was for user diagnostics. This enabled searching for users using various criteria, and if a user is selected, this would populate information on associated payments, payment cards, transactions, payouts, marketplace listings, login history, notes, and more.

The only action that could be taken in this application is changing the user status and optionally adding notes. This was a requirement when analyzing users in manual review, since a final status needs to be chosen that either enables or restricts their account.

2) Fraud Detection

Circle would periodically send us a CSV with information about refunds and chargebacks so we built a tool that directly ingested this CSV and processed it. This allowed us to respond quickly when users were flagged.

We also built out functionality that would allow us to use IP addresses and user agent information to help identify accounts that are likely owned by the same user. It is not reliable to use IP addresses to indicate the same person logged into an account. IP addresses are shared by more than one household in certain locales, and VPNs add a whole other layer of complication. It can, however, be helpful to analyze in addition to other user behavior.

3) Marketplace statistics

One thing the compliance team needed to look for was items being sold for suspiciously high prices. We built functionality around analyzing marketplace statistics to determine reasonable prices for marketplace items. Minimums, maximums, averages, and medians were collected per collectible in a materialized view in the database and displayed within Retool.

4) Track bot activity

Users would alert us to bots being used on the site, but there were legitimate uses and we were not able to simply ban all bots. Therefore, we built functionality using Google Recaptcha that tracks scores for each purchase event. The score indicates the likelihood of it having been a bot. We also built a tool in Retool for listing purchase events with this score, along with data on the buyer and seller. This allowed us to keep tabs on where bots were being used, so we could analyze each situation more effectively.

5) Process refunds

In certain cases users had started transacting on the site and then were banned. This could happen, for instance, if a user is from a restricted country but that information was not provided on sign up. We needed to build support for refunding users that had loaded funds but were in a restricted state and not able to cash out.

🔔 Notification System

A notification system has been critical for alerting the compliance team and/or customer service team to certain suspicious activity within the application. Often suspicious activity is not clear-cut enough to act on programmatically, so often what we decided to do was to identify the behavior, and then alert the team, as opposed to taking automatic action. Alerts go out when there are:

1) Overly-priced marketplace items

As mentioned, we built a materialized view within our database that compiled data on sales statistics. This was then used to determine reasonable prices for sales on the marketplace and allows us to alert the compliance team whenever a suspiciously high-priced item is sold on the marketplace.

2) Maximum amount of payment cards is exceeded

A user can only have a small number of cards in their account to prevent fraudulent behavior where someone creates an account and then tries to use various stolen cards for purchase. The compliance team is alerted whenever a card is added to a user account, after a certain threshold.

3) Workflow completed with a Rejected or Manual Review result

The user is alerted anytime the verification workflow is completed for their account. If the account is moved to manual review or restricted, then the compliance team is notified. The user diagnostics tool can be used for further analysis, either searching for all users in review, or searching for a particular user.

4) AML watchlist report completed

An ongoing monitoring subscription is made in Onfido for every verified user on the platform. The monitor continuously checks AML watchlists for any matches for that user. If added to an AML watchlist, the user's account will be restricted or moved into manual review, and the compliance team is notified so they can assess the situation.

⛰️ Biggest challenges

There are high stakes in the KYC world. You think you’ve thought of everything, and the fraudsters find a new way! The KYC process and gating of features should be thoroughly tested, and new issues reported by customers should be looked into within a short time frame. We found other users were a big help in finding suspicious behavior, and users will write in with questions which can uncover flaws which need to be addressed. You’ll thank yourself that you’re responsive and looking into each report when there’s a serious issue that needs attention as quickly as possible. Thankfully we were able to resolve each situation quickly, and always made modifications to deter future situations.

Challenge 1: Preventing duplicate accounts

In our situation, we chose to not require KYC verification for every user. There would be reduced complexity if all users went through verification, but that would also deter some users. We opted to only require KYC when certain limitations were reached according to our AML Policy. This makes it easier to sign up, but also adds complexity, as we have to enable/disable functionality for more situations.

Since we are not requiring KYC for every user, we do not know it’s the same user. Users are prohibited from having multiple accounts, but that of course did not deter many from doing just that. We needed to find a way to identify duplicate accounts. We did not have a way of being sure without requiring verification for all, but we did come up with ways to help us determine.

One situation that presented itself was that users being flagged in chargebacks were being found to use the same card with multiple accounts. We built out the functionality to restrict users if they used a card already being used by another account. If users wrote in to dispute, we would explain the requirement and after they agreed to respect that, we would enable their account again, assuming there wasn’t anything else to be suspicious about.

In addition, we started tracking IP addresses and user agents. This is not reliable, as IP addresses aren’t unique per household in every locale, and it’s also acceptable for two people to live together and have an account. It is also easy to get around IP checks by using a VPN, and on the flip side, multiple people could be using the same VPN IP address. It is, however, a helpful piece of information to analyze while analyzing other information. If a user has a matching IP address and user agent associated with multiple accounts, it’s likely they are the same person.

These methods helped us narrow down, but they weren't the silver bullet we were looking for. We assessed fingerprinting services but opted out because we were skeptical about how useful they would be to us. Our team found through testing that it too frequently could not identify duplicates, and the cost was too significant to warrant without being able to use it with more confidence.

The more we searched, the more we felt confident that the only reliable way to find duplicate accounts was through KYC verification. Instead of requiring verification on sign-up, we decided to implement additional gates that would require verification to use additional features. In addition, we planned to require documentary verification for every user instead of having certain locales have the option to provide an SSN in place of a government document. This would allow us to run biometric verification for every user, and Onfido even has a product called Known Faces that would alert us to the same person associated with different accounts. We had not yet implemented this change, so I cannot speak to how effective it is. Still, we hoped to reduce the number of duplicate accounts by requiring KYC verification more frequently and then watching for matching faces between different accounts.

Challenge 2: Reducing fraudulent transactions on the marketplace

The secondary marketplace is where we found the majority of suspicious behavior. Users can sell items they purchased on the marketplace for a predetermined amount. One fraudulent scheme we identified is when a user sells items on the marketplace, and then signs into other accounts to purchase the items using stolen credit cards. Ultimately, fraudulent users are deterred because to withdraw, you have to complete KYC verification. It’s possible someone hacks into an account that has KYC verification completed, which would be the jackpot for a fraudster, but that had not been the case with any situations we came across. We did have one user complete verification in order to gather funds after hacking into a user’s account; we could report that user so they would be flagged for other platforms, but they clearly found the reward to be more attractive than that.

After analyzing the user behavior, we decided to implement a couple features that would help deter similar fraudulent activity on the platform. I’ll go into each below.

a) Restrict the amount of cards a user could have in one account

By restricting the amount of cards a user can have saved in their account, we can cut down on the number of fraudsters that load stolen cards into their account. Most users have one card saved in their account, maybe two. It would be unusual to have a large assortment, which is common with fraudulent situations.

The feature we implemented would check for the number of cards associated with a user when a purchase was made. If over the threshold and KYC verification has not yet been completed, the user will be required to complete verification. If over the threshold and the user has completed KYC verification, the compliance team will be notified for each additional card added. When we released this feature, all user accounts with cards above the threshold were moved to a status that would require KYC verification to continue using the platform.

b) Prevent multiple accounts from having the same card associated

Duplicate accounts are prohibited on the platform, so if there is a card matching numerous accounts, it is suspicious and could mean that someone is trying to load stolen cards into multiple accounts. Our payment provider, Circle, has a fingerprint value for each payment card used. We use this fingerprint value to determine if multiple accounts are using the same payment card and restrict those users.

If the user reaches out to the compliance team, their account may be unblocked if there is a reasonable explanation. One reasonable situation we identified was that some users were using a service that protects the card number, where temporary numbers are generated that will result in the card being charged but hide the actual card number from the payment service. If a user used a service of this type, they would quickly be flagged as having too many cards.

c) Track overly-priced items

To review what was discussed in the Administrative Tools section, a materialized view was created in the database that tracked averages, min, max, and medians for collectibles on the marketplace. These values were then used programmatically to determine if there was a suspiciously-high-priced item on the marketplace that was just sold. Users may accidentally list an item for too high of a price, but if that item is sold, we can assume that was a fraudulent transaction. No user would opt to purchase the much more expensive version of the same item.

d) Track too high of a success rate

A success rate that is too high can indicate fraudulent activity. If a user sold every item they tried to sell, that would be highly suspicious. We planned to build support for tracking this information and adding it to the notification system to alert the compliance team.

Users flagged for too high of a success rate may first be flagged for selling high-priced items, but it's also possible someone games the system selling lower-priced items, so tracking success rate is another important indicator.

Challenge 3: Communicating KYC process to users

Many updates were made to increase clarity for users around the KYC process. These decisions were usually made by the development and administrative teams. It could have been helpful to have more design expertise involved in those decisions, as it is difficult to properly communicate the process to a user. In an ideal world, a KYC process would be user-tested to see where confusion lies.

A confusing KYC process is frustrating to users. Your users must trust your platform to make purchases, and confusion can lead to distrust. There are also really high stakes with KYC since fraudulent users could lead to legal repercussions as well. It’s to everyone’s benefit that the process be smooth and seamless, and adequate attention should be paid to making this process as seamless as any checkout flow.

It does seem the industry is moving towards in-house KYC done by payment providers. This comes with its benefits and drawbacks. Our setup had a lot of flexibility, which may not be the case when KYC is done in-house, since that provider is assuming all that risk. It would greatly simplify several aspects and may reduce the complexity in communicating to users. I’d need to use a service that had KYC in-house before making an effective comparison.

Final Thoughts

Some final thoughts from our experience implementing KYC/AML protocols for an NFT marketplace…

There's no one-size-fits-all solution.

Your specific KYC verification and AML protocols will depend entirely on your business plan and the amount of risk you’re taking. There may be unique requirements provided by service providers as well.

While KYC for every user would have been much simpler, it would have provided barriers to purchase.

And anyone who does funnel optimization will tell you that you should remove barriers to purchase, not add them…

But playing devil’s advocate, if KYC is required for basic functionality that any user would need to use, such as payouts, there may be an argument for providing that barrier earlier on.

It's expensive to build and maintain

This can be a difficult pill to swallow if there isn't steady revenue coming in or if the majority of sales are for low-price tag items. You'll find that services that provide KYC in-house often have a much higher minimum price requirement.

Fiat transactions made KYC verification necessary

Supporting payments and payouts using fiat currencies was a primary goal of this project, but if supporting fiat was not a requirement, KYC verification could have been avoided altogether. Blockchain address verification against sanctions lists might still be necessary, but it is a much lighter lift. This would have greatly simplified the project, but not supporting fiat transactions would have scared away any customers new to the crypto space.

If the service you are building is successful, it only becomes more challenging.

Consider it a compliment if the fraudsters find you! The more popular the service is, the quicker someone is going to find a critical issue or a way to exploit the system. Be responsive in reviewing issues, and regularly and thoroughly test the verification and security protocols so you can find any issues as quickly as possible.


I hope our takeaways from implementing a verification system can be useful to you in your project. There is a lot to understand in the KYC/AML world, so if you’re new to the topic, try not to get overwhelmed too quickly. For us, there have been a lot of iterations and a lot of learning over time. It’s also a rapidly evolving industry. If you are implementing for your own project, the best takeaway may be that it’s complicated. Consider the verification process and related security protocols an integral part of your system that requires as much attention as any critical path, even if it is not utilized by every user.

And if you want to implement a verification system for your project and want to work with someone towards that goal, hit us up! We’d love to take that on with you.