ScamVerify™
Use Cases

Online Marketplace Trust & Safety

Screen sellers, scan listings, and protect buyers on peer-to-peer marketplaces.

Peer-to-peer marketplaces like Poshmark, Mercari, OfferUp, and Facebook Marketplace face a constant battle against fraudulent sellers. Fake accounts, counterfeit listings, off-platform payment scams, and phishing links in listings cost these platforms millions in chargebacks, user trust erosion, and moderation overhead. The ScamVerify™ API provides automated seller screening, listing content scanning, and buyer protection signals.

The Problem

Marketplace fraud operates at scale. A single bad actor can create dozens of accounts using disposable VoIP numbers, list items they do not own, collect payments, and disappear. By the time buyer complaints arrive, the seller has moved on to new accounts. Traditional moderation catches these accounts reactively. ScamVerify™ helps you catch them proactively.

Common Fraud Patterns

  • Multi-accounting: One person creates 10+ seller accounts using cheap VoIP numbers, rotating through them as accounts get banned
  • Off-platform payment scams: Sellers post phone numbers or payment links in listing descriptions to move transactions off-platform where buyers have no protection
  • Phishing listings: Product pages that link to external sites mimicking the marketplace's checkout, harvesting payment credentials
  • Counterfeit storefronts: Sellers create listings with URLs to fake "brand authorized" sites as proof of authenticity

How ScamVerify™ Helps

  • Phone lookup at seller registration catches disposable VoIP numbers before accounts are created
  • URL scanning in listing content detects phishing links, malware domains, and suspicious external sites
  • Text analysis on listing descriptions flags social engineering patterns and off-platform payment solicitations
  • Buyer-side phone checks verify seller contact numbers shared through messaging

Code Example: Seller Registration Verification

class MarketplaceTrustEngine {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = 'https://scamverify.ai/api/v1';
  }

  async callApi(endpoint, body) {
    const response = await fetch(`${this.baseUrl}${endpoint}`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(body),
    });
    if (!response.ok) throw new Error(`API error: ${response.status}`);
    return response.json();
  }

  async screenSellerRegistration(phoneNumber) {
    const result = await this.callApi('/phone/lookup', {
      phone_number: phoneNumber,
    });

    const signals = {
      riskScore: result.risk_score,
      lineType: result.signals.line_type,
      carrier: result.signals.carrier,
      ftcComplaints: result.signals.ftc_complaints,
      robocall: result.signals.robocall_detected,
    };

    // Tiered seller verification
    if (result.risk_score >= 60 || result.signals.robocall_detected) {
      return {
        decision: 'REJECT',
        reason: 'Phone number does not meet seller verification requirements.',
        signals,
        internalReason: result.explanation,
      };
    }

    if (
      result.signals.line_type === 'voip' &&
      result.risk_score >= 25
    ) {
      return {
        decision: 'ENHANCED_VERIFICATION',
        reason: 'Additional identity verification required to sell.',
        nextSteps: ['government_id', 'selfie_match', 'bank_verification'],
        signals,
      };
    }

    if (result.risk_score >= 30 || result.signals.ftc_complaints > 0) {
      return {
        decision: 'PROBATION',
        reason: 'Account approved with selling limits.',
        restrictions: {
          maxListings: 5,
          maxTransactionValue: 100,
          payoutHoldDays: 7,
        },
        signals,
      };
    }

    return {
      decision: 'APPROVED',
      signals,
      restrictions: null,
    };
  }

  async scanListing(listing) {
    const issues = [];

    // Extract and check URLs in listing description
    const urlRegex = /https?:\/\/[^\s)>]+/gi;
    const urls = listing.description.match(urlRegex) || [];

    for (const url of urls) {
      const check = await this.callApi('/url/lookup', { url });

      if (check.risk_score >= 25) {
        issues.push({
          type: 'risky_url',
          value: url,
          riskScore: check.risk_score,
          verdict: check.verdict,
          explanation: check.explanation,
        });
      }
    }

    // Extract and check phone numbers in listing description
    const phoneRegex = /\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}/g;
    const phones = listing.description.match(phoneRegex) || [];

    // Phone numbers in listings are suspicious on their own
    // (sellers should use in-app messaging)
    if (phones.length > 0) {
      for (const phone of phones) {
        const check = await this.callApi('/phone/lookup', {
          phone_number: phone,
        });

        issues.push({
          type: 'phone_in_listing',
          value: phone,
          riskScore: check.risk_score,
          lineType: check.signals.line_type,
          // Any phone in a listing is concerning, high-risk ones doubly so
          severity: check.risk_score >= 30 ? 'high' : 'medium',
        });
      }
    }

    // Check for off-platform payment solicitation patterns
    const offPlatformPatterns = /\b(venmo|zelle|cashapp|cash app|paypal\.me|wire transfer|western union|send money)\b/i;
    if (offPlatformPatterns.test(listing.description)) {
      issues.push({
        type: 'off_platform_payment',
        severity: 'high',
        detail: 'Listing mentions off-platform payment methods.',
      });
    }

    const hasHighSeverity = issues.some(
      i => i.severity === 'high' || i.riskScore >= 50
    );
    const hasMediumSeverity = issues.some(
      i => i.severity === 'medium' || (i.riskScore >= 25 && i.riskScore < 50)
    );

    return {
      listingId: listing.id,
      approved: issues.length === 0,
      action: hasHighSeverity
        ? 'REMOVE_LISTING'
        : hasMediumSeverity
          ? 'HOLD_FOR_REVIEW'
          : 'APPROVE',
      issues,
    };
  }
}

// Integration with your seller registration
const trust = new MarketplaceTrustEngine(process.env.SCAMVERIFY_API_KEY);

app.post('/api/sellers/register', async (req, res) => {
  const { phone, email, name } = req.body;

  const screening = await trust.screenSellerRegistration(phone);

  switch (screening.decision) {
    case 'REJECT':
      return res.status(400).json({
        error: screening.reason,
        code: 'SELLER_VERIFICATION_FAILED',
      });

    case 'ENHANCED_VERIFICATION':
      const pendingAccount = await createSellerAccount({
        phone, email, name,
        status: 'pending_verification',
        requiredSteps: screening.nextSteps,
      });
      return res.json({
        accountId: pendingAccount.id,
        status: 'pending_verification',
        nextSteps: screening.nextSteps,
      });

    case 'PROBATION':
      const restricted = await createSellerAccount({
        phone, email, name,
        status: 'active_restricted',
        restrictions: screening.restrictions,
      });
      return res.json({
        accountId: restricted.id,
        status: 'active',
        restrictions: screening.restrictions,
      });

    case 'APPROVED':
      const account = await createSellerAccount({
        phone, email, name,
        status: 'active',
      });
      return res.json({
        accountId: account.id,
        status: 'active',
      });
  }
});

// Integration with listing creation
app.post('/api/listings/create', async (req, res) => {
  const listing = req.body;

  const scan = await trust.scanListing(listing);

  if (scan.action === 'REMOVE_LISTING') {
    await flagSeller(listing.sellerId, scan.issues);
    return res.status(400).json({
      error: 'This listing could not be published. Please review our seller guidelines.',
    });
  }

  if (scan.action === 'HOLD_FOR_REVIEW') {
    await createListing({ ...listing, status: 'pending_review' });
    return res.json({ status: 'pending_review' });
  }

  await createListing({ ...listing, status: 'active' });
  return res.json({ status: 'active' });
});
import re
import requests
import os

class MarketplaceTrustEngine:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = "https://scamverify.ai/api/v1"

    def _call_api(self, endpoint: str, body: dict) -> dict:
        response = requests.post(
            f"{self.base_url}{endpoint}",
            headers={
                "Authorization": f"Bearer {self.api_key}",
                "Content-Type": "application/json",
            },
            json=body,
        )
        response.raise_for_status()
        return response.json()

    def screen_seller(self, phone_number: str) -> dict:
        result = self._call_api("/phone/lookup", {"phone_number": phone_number})

        if result["risk_score"] >= 60 or result["signals"]["robocall_detected"]:
            return {"decision": "REJECT", "risk_score": result["risk_score"]}

        if (
            result["signals"]["line_type"] == "voip"
            and result["risk_score"] >= 25
        ):
            return {
                "decision": "ENHANCED_VERIFICATION",
                "risk_score": result["risk_score"],
                "next_steps": ["government_id", "selfie_match"],
            }

        if result["risk_score"] >= 30 or result["signals"]["ftc_complaints"] > 0:
            return {
                "decision": "PROBATION",
                "risk_score": result["risk_score"],
                "restrictions": {
                    "max_listings": 5,
                    "max_transaction_value": 100,
                    "payout_hold_days": 7,
                },
            }

        return {"decision": "APPROVED", "risk_score": result["risk_score"]}

    def scan_listing(self, description: str, listing_id: str) -> dict:
        issues = []

        urls = re.findall(r"https?://[^\s)>]+", description, re.IGNORECASE)
        for url in urls:
            check = self._call_api("/url/lookup", {"url": url})
            if check["risk_score"] >= 25:
                issues.append({
                    "type": "risky_url",
                    "url": url,
                    "risk_score": check["risk_score"],
                })

        phones = re.findall(r"\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}", description)
        for phone in phones:
            issues.append({"type": "phone_in_listing", "phone": phone})

        off_platform = re.search(
            r"\b(venmo|zelle|cashapp|paypal\.me|wire transfer)\b",
            description,
            re.IGNORECASE,
        )
        if off_platform:
            issues.append({"type": "off_platform_payment", "severity": "high"})

        action = "APPROVE"
        if any(i.get("severity") == "high" or i.get("risk_score", 0) >= 50 for i in issues):
            action = "REMOVE"
        elif issues:
            action = "REVIEW"

        return {"listing_id": listing_id, "action": action, "issues": issues}

Seller Trust Tiers

TierEntry CriteriaSelling LimitsPayout Schedule
Rejectedrisk_score >= 60 or robocall detectedCannot sellN/A
Enhanced VerificationVoIP + risk_score >= 25Cannot sell until ID verifiedN/A
Probationrisk_score: 30-59 or FTC complaints5 listings, $100 max per item7-day hold
Standardrisk_score < 30, clean signalsUnlimited listingsStandard payout
Trusted90+ days clean history, 50+ completed salesPremium featuresExpedited payout

Listing Content Scanning Signals

SignalWhat It MeansAction
URL with risk_score >= 50Link to a known phishing or malware domainRemove listing, flag seller account
URL with risk_score: 25-49Link to a suspicious or newly registered domainHold for manual review
Phone number in listing textSeller attempting to move communication off-platformHold for review, warn seller
Off-platform payment mentionDirect violation of marketplace policies on most platformsRemove listing, issue seller warning
Multiple flagged URLsPattern of malicious linking, likely a scam operationSuspend seller account

Buyer Protection: Messaging Scans

When buyers and sellers communicate through in-app messaging, scan messages that contain URLs or phone numbers.

app.post('/api/messages/send', async (req, res) => {
  const { senderId, recipientId, text } = req.body;

  // Check for URLs in messages
  const urls = text.match(/https?:\/\/[^\s)>]+/gi) || [];

  for (const url of urls) {
    const check = await trust.callApi('/url/lookup', { url });

    if (check.risk_score >= 40) {
      await blockMessage(senderId, recipientId, {
        reason: 'Message contains a potentially unsafe link.',
        url,
        riskScore: check.risk_score,
      });

      return res.status(400).json({
        error: 'This message contains a link that did not pass our safety check.',
      });
    }
  }

  await deliverMessage(senderId, recipientId, text);
  return res.json({ status: 'sent' });
});

Seller feedback loop. When a seller is flagged by ScamVerify™ and later confirmed as fraudulent through buyer reports, log that correlation. Over time, this data helps you fine-tune your risk thresholds for your specific marketplace category.

Scaling Moderation

For marketplaces with thousands of new listings per day, automated scanning replaces the first layer of human moderation.

  1. Auto-approve listings with no flagged content (typically 85-90% of listings)
  2. Auto-reject listings with confirmed malicious URLs or critical signals (typically 1-3%)
  3. Queue for human review listings with medium-risk signals (typically 7-12%)

This reduces human moderation workload by 85-90% while catching more fraud than manual review alone.

Best Practices

  • Screen at registration, not just at listing. Catching bad accounts before they list anything is cheaper than removing listings and handling buyer complaints.
  • Use graduated responses. Not every VoIP number is fraud. Probationary periods with selling limits let legitimate sellers prove themselves while containing the damage from fraudulent ones.
  • Scan listing content on creation and on edit. Fraudsters sometimes create clean listings to pass initial review, then edit in malicious content later.
  • Protect your messaging channel. Off-platform payment scams start in marketplace messaging. Scanning messages for URLs and phone numbers blocks the most common attack vector.

Getting Started

  1. Create an API key and set up your account
  2. Follow the Quickstart guide to make your first lookup
  3. Review the Phone Lookup API and URL Verification API reference docs
  4. Integrate seller registration screening first, then expand to listing and messaging scans

On this page