BRANDITSCAN V2 IS HERE FASTER SCANS SMARTER TAKEDOWNS NOW INCLUDES URLINKS PRO ALL-NEW PLATFORM BRANDITSCAN V2 IS HERE FASTER SCANS SMARTER TAKEDOWNS NOW INCLUDES URLINKS PRO ALL-NEW PLATFORM BRANDITSCAN V2 IS HERE FASTER SCANS SMARTER TAKEDOWNS NOW INCLUDES URLINKS PRO ALL-NEW PLATFORM

API Reference

Search data with built-in piracy labeling, structured piracy intelligence, and integrations that put creator protection inside your product — from a copy-paste widget to a full platform partnership.

Building with an AI agent? The widgets and the whole funnel live in one machine-readable file — hand your agent the MD and it builds the preferred setup end to end, or any lighter shape down to a single embedded iframe.
guide.md →

How access works

Everything except the Leak Check widget is scoped per partner — no open keys

The Leak Check widget is live and free for everyone — copy the snippet and go. Everything else — the APIs and the Self Submissions Widget — is available on request: we scope access to your use case instead of handing out open keys. Getting set up is fast:

1
Email your use case What you're building, which APIs you need, and the volume you expect.
2
We scope it with you Endpoints, limits, and pricing where relevant — shaped around your integration.
3
Credentials issued API key, signing secret, and base URL — typically within 1 working day.
help@branditscan.com Or book a 30-min intro call
Brands we work with — building with BranditScan

Creators love our products. Boost your brand.

Platforms like YourVids, LoyalFans, Aylo, and CosmoPayment put BranditScan protection in front of their creators. Give yours the tools they already ask for:

Free unlimited self submissions for your users Full scan results & brand insights Traffic optimizations

And you get paid: earn commission on every subscription your integration produces.

Data APIs

Google Search API

Live SERP data — web, images & videos, piracy-labeled

On request
What you'll need
  • A scoped API key + base URL, issued after approval — email your use case: what you're building and the monthly volume you expect. Credentials typically within 1 working day.

Live Google SERP data from the same engine that powers our scanners — web, image, and video sections with position data. Every result is checked against the BranditScan Entry database of 5,000,000+ pirate sites, so piracy labeling comes built in.

GET/v1/search/googleWeb results — the "All" section
GET/v1/search/google/imagesImage results, with thumbnail + source page
GET/v1/search/google/videosVideo results, with duration + platform
ParameterDescription
qRequired. The search query.
numResults per page, 10–100. Default 20.
pageResult page. Default 1.
hlInterface language, e.g. en.
glCountry to search from, e.g. us.

Sample request

cURL
curl "$BASE_URL/v1/search/google?q=jane+doe+leaks&num=50&hl=en&gl=us" \
  -H "Authorization: Bearer $API_KEY"
200 — response (truncated)
{
  "query": "jane doe leaks",
  "engine": "google",
  "section": "web",
  "total_results": 1840000,
  "results": [
    {
      "position": 1,
      "title": "Jane Doe Leaked Videos — Watch Free",
      "link": "https://superpirate.xyz/jane-doe",
      "domain": "superpirate.xyz",
      "snippet": "Watch Jane Doe leaked videos free in HD...",
      "piracy": {
        "is_pirate": true,
        "category": "video cloud",
        "tracked_leaks": 128411
      }
    },
    {
      "position": 2,
      "title": "Jane Doe (@janedoe) — Official",
      "link": "https://onlyfans.com/janedoe",
      "domain": "onlyfans.com",
      "snippet": "Official page of Jane Doe.",
      "piracy": { "is_pirate": false }
    }
  ]
}
Request Google Search API access

Bing Search API

Identical contract — swap the engine segment

On request
What you'll need
  • A scoped API key + base URLemail your use case and expected volume; one request can cover several engines. Credentials typically within 1 working day.

The same contract as the Google Search API, running against Bing — web, image, and video sections with identical parameters (q, num, page, hl, gl) and the same per-result piracy labeling. Swap the engine segment and keep your integration code.

GET/v1/search/bingWeb results — the "All" section
GET/v1/search/bing/imagesImage results
GET/v1/search/bing/videosVideo results
cURL
curl "$BASE_URL/v1/search/bing?q=jane+doe+leaks&num=50" \
  -H "Authorization: Bearer $API_KEY"
Request Bing Search API access

Yandex Search API

Identical contract — Eastern Europe & CIS coverage

On request
What you'll need
  • A scoped API key + base URLemail your use case and expected volume; one request can cover several engines. Credentials typically within 1 working day.

Yandex coverage matters when your audience — or the piracy targeting it — lives in Eastern Europe and CIS markets. Same request contract and response shape as Google and Bing: web, image, and video sections, position data, and per-result piracy labeling against our Entry database.

GET/v1/search/yandexWeb results — the "All" section
GET/v1/search/yandex/imagesImage results
GET/v1/search/yandex/videosVideo results
cURL
curl "$BASE_URL/v1/search/yandex?q=jane+doe+leaks&num=50" \
  -H "Authorization: Bearer $API_KEY"
Request Yandex Search API access

Piracy Data API

The dataset behind the Brandit Atlas — 5,000,000+ pirate sites

On request
What you'll need
  • A scoped API key + base URLemail your use case; bulk exports and webhook feeds are available for approved partners. Credentials typically within 1 working day.

Structured piracy intelligence from the largest takedown operation in the creator space — the dataset behind the Brandit Atlas. Domain reputation, threat ratings, tracked-leak volumes, category data, and takedown capability per site. Classify any domain or URL in one call.

GET/v1/piracy/domains/{domain}Full intelligence profile for a domain
GET/v1/piracy/check?url={url}Classify a full URL — is this a pirate page?

Sample request

cURL
curl "$BASE_URL/v1/piracy/domains/fapello.com" \
  -H "Authorization: Bearer $API_KEY"
200 — response
{
  "domain": "fapello.com",
  "is_pirate": true,
  "category": "image host",
  "threat": { "level": 4, "label": "Critical" },
  "tracked_leaks": 1284110,
  "reported_infringements": 96731,
  "capabilities": {
    "source_removal": true,
    "google_delisting": true
  },
  "description": "High-volume aggregator redistributing paywalled creator content..."
}
Request Piracy Data API access
Integrations

Leak Check Widget — iframe embed

No key, no signup, no approval — copy the snippet and ship it

Live — free

The only thing on this page you don't need to email us for. A live piracy scanner your visitors use right on your page: they type a stage name, we run a real-time Google scan and check every result against our database of 5,000,000+ pirate sites. Free to embed anywhere HTML works.

HTML — paste anywhere
<!-- BranditScan Leak Check widget -->
<iframe src="https://branditscan.com/embed/leak-check" title="Free Leak Check by BranditScan" style="display:block;width:100%;max-width:960px;margin:0 auto;height:620px;border:0;border-radius:24px;background:url(https://branditscan.com/front/lp/assets/images/leak-widget-spinner.svg) no-repeat center 140px;" scrolling="no" loading="lazy"></iframe>
<script>
window.addEventListener("message", function (e) {
  if (e.origin !== "https://branditscan.com" || !e.data || e.data.type !== "bs-leak-check:height") return;
  document.querySelectorAll("iframe[src^='https://branditscan.com/embed/leak-check']").forEach(function (f) {
    if (f.contentWindow === e.source) f.style.height = Math.ceil(e.data.height) + "px";
  });
});
</script>
ParameterWhat it does
affYour BranditScan affiliate slug. Signups from the widget are credited to you — see the earnings note below.
stagenamePrefills the search and runs it immediately on load, e.g. ?stagename=janedoe. Results are cached, so repeat loads are instant.
railPins the side visual: odometer (money counter), sweep (before/after), cases (sliding case studies) or loss (average piracy loss). Omit for random rotation per load.
borderborder=0 turns the animated rainbow shell border off (on by default).
blurblur=0 renders result images unblurred by default (they're NSFW-blurred with click-to-reveal out of the box).
tOptional — only if you want SSO (partner platforms): pass your signed Self Submissions Widget token and the CTAs flip to a one-click "Open my BranditScan" sign-in for members with a BranditScan account you created (new tab, no password, zero extra code). Absent or invalid — nothing changes.

postMessage API

The widget talks to your page over postMessage, so you can auto-size the iframe and drive scans from your own UI:

JavaScript
// OUT — sent by the widget on every layout change (auto-height):
//   { "type": "bs-leak-check:height", "height": 1240 }

// IN — prefill + run a scan from your own page:
var frame = document.querySelector("iframe[src*='/embed/leak-check']");
frame.contentWindow.postMessage(
  { type: "bs-leak-check:scan", stagename: "jane doe" },
  "https://branditscan.com"
);
Get paid for it — 10% for life. Use the widget as-is for free, or create a free BranditScan account, grab your affiliate link from the Earnings Hub and add ?aff=your-slug to the iframe URL. Every creator who signs up through your widget earns you 10% of everything they ever pay — the exact embed code with your slug baked in is waiting in your Earnings Hub. Full commission terms are on the Affiliate Program page.

Live demo — embedded on your site

Changes apply to the demo below — and the embed snippet above adjusts to your settings.

yoursite.com

This is the real widget, live on this page — type a stage name, or hit Run sample scan to see it work end-to-end (uses the widget's postMessage API).

Conversion Funnel — connect the widgets to your UI

Two components, one hidden data feed — a Takedowns menu item, a banner, and a page that converts

On request
What you'll need
  • Nothing for the Leak Check side — the scanner, the hidden module, the nav badge and the banner work immediately, no key.
  • A Self Submissions signing secret for the free-takedowns card — email us when you start building (same-day, free) and include your production domain plus your local dev hosts (localhost, *.test) so the widget renders in your dev environment too.
  • Your affiliate slug (optional) for signup attribution — free BranditScan account, it's in your Earnings Hub.

You get two embeddable components — use both or just one.

Leak Check Widget

Scans a name live — leaks, traffic-loss %, the stolen images. Run it visible, or hidden as a data feed.

Free — no key, works today
Self Submissions Widget

Real DMCA takedowns, filed from your page — we file, track and sign them.

Free — signing secret required

Use both together (recommended — that's the funnel below) or either one on its own.


The preferred implementation

Give the widgets their own section. Create a dedicated page in your app where both widgets live, point a menu item at it, and — optionally — feed it traffic with a dashboard banner. Live on partner platforms today:

1Install the module

Runs silently: an invisible iframe pulls the creator's piracy data and caches it in their browser for 24h — all frontend, no backend, no database. Every surface below renders from it.

<script src="bs-funnel.js"> invisible iframecached 24hfrontend-only
2A dedicated page for the widgets

A new page in your app — file a takedown free or go automated, side by side, with the full leak report loading underneath so creators immediately see their leaks.

SUBMIT FREE GO AUTOMATED
SELF SUBMISSIONS WIDGET
LEAK CHECK REPORT
3A menu item that earns the click

Powered by the module: it fills the badge with the creator's own live number — "▲ 18%" traffic loss — right in your nav, and points at your new page. Name it Takedowns, Leaks or Remove Leaks.

Takedowns▲ 18%
4A banner to draw further attention — optional

Also powered by the module: it personalizes the banner with their own leaked images, blurred, on the dashboard or settings page — clicking straight into the page.

+18%
hidden Leak Check iframe postMessage result cached in the browser, 24h badge · banner · page

No database, nothing to poll — one hidden load per creator per day. The module below does all of it.


Build it — step by step

Four pastes, in this order. Or your own order — after step 1 the data is yours (see the payload reference below the steps).

1Install the modulein your main layout — not per-page

Two script tags, in your main layout: every page that shows the nav item or the banner needs the module available, so include it globally. What it does: when there's no fresh data for the creator, it loads the Leak Check widget in an invisible iframe, silently reads the scan result the widget posts, caches it in the creator's browser for 24 hours, and removes the iframe. Nothing is saved to your backend or database — the data lives on the frontend, and any surface can render from it: the nav badge, the banner, or anything else you want to build with it. Every step after this is just placing HTML hooks.

config + include
<!-- Once, on every logged-in dashboard page: the config + the module -->
<script>
  window.BS_FUNNEL = {
    stagename: "SARAH",          // <- the logged-in creator's stagename (template it server-side)
    aff: "your-affiliate-slug"   // <- optional: your BranditScan affiliate slug
  };
</script>
<script src="/js/bs-funnel.js" defer></script>  <!-- the module: copy it from the block below -->
bs-funnel.js — v1, dependency-free, the whole integration
/* bs-funnel.js — BranditScan protection funnel, v1.
   Config: window.BS_FUNNEL = { stagename, aff } (set before this runs). */
(function () {
  'use strict';

  var cfg = window.BS_FUNNEL || {};
  var STAGENAME = (cfg.stagename || '').trim();
  if (!STAGENAME) return;                       // viewers, no-stagename users: do nothing

  var ORIGIN = 'https://branditscan.com';
  var CACHE_KEY = 'bs-leak-check:' + STAGENAME.toLowerCase();
  var DAY = 24 * 60 * 60 * 1000;

  /* ---------- pub/sub ---------- */

  function publish(result) {
    window.bsLeakData = result;                 // for late-joining code
    document.dispatchEvent(new CustomEvent('bs-leak-data', { detail: result }));
  }

  /* ---------- normalization ---------- */

  function toResult(d) {
    // Google-Images pirated thumbs first, then per-site samples as fill —
    // deduped, capped. Covers creators whose Google-Images page is clean
    // but whose proof images live on the pirate sites themselves.
    var thumbs = (d.thumbs || []).concat(d.samples || [])
      .filter(function (src, i, all) { return all.indexOf(src) === i; })
      .slice(0, 12);
    return {
      standing: d.standing,
      traffic: d.traffic || null,               // { pct, surface: 'web'|'images' }
      pirates: d.pirates || 0,
      domains: (d.domains || []).slice(0, 6),
      thumbs: thumbs,
      estimatedLoss: d.estimatedLoss || null,
      at: Date.now()
    };
  }

  /* ---------- verified accept (probe + visible embed share this) ---------- */

  function isOwnResult(event, frame) {
    if (event.origin !== ORIGIN) return false;
    if (!frame || !frame.contentWindow || event.source !== frame.contentWindow) return false;
    var d = event.data || {};
    if (d.type !== 'bs-leak-check:result') return false;
    // Poisoning guard: only the logged-in creator's own name may be cached.
    return (d.stagename || '').toLowerCase() === STAGENAME.toLowerCase();
  }

  function accept(data) {
    var result = toResult(data);
    try { localStorage.setItem(CACHE_KEY, JSON.stringify(result)); } catch (e) { /* storage blocked — in-memory only */ }
    publish(result);                            // latest verified message wins
  }

  /* ---------- the hidden probe ---------- */

  function embedUrl() {
    return ORIGIN + '/embed/leak-check?branding=0&border=0'
      + (cfg.aff ? '&aff=' + encodeURIComponent(cfg.aff) : '')
      + '&stagename=' + encodeURIComponent(STAGENAME);
  }

  function startProbe() {
    var frame = document.createElement('iframe');
    frame.src = embedUrl();
    frame.referrerPolicy = 'no-referrer';       // scans 403 silently without this
    frame.style.cssText = 'position:absolute;width:2px;height:2px;left:-9999px;top:0;border:0;';
    frame.setAttribute('aria-hidden', 'true');
    frame.setAttribute('tabindex', '-1');

    var gotFirst = false;
    function teardown() {
      window.removeEventListener('message', onMsg);
      if (frame.parentNode) frame.parentNode.removeChild(frame);
    }
    function onMsg(event) {
      if (!isOwnResult(event, frame)) return;
      accept(event.data);
      if (!gotFirst) {
        gotFirst = true;
        setTimeout(teardown, 15000);            // linger: catch the enriched samples re-post
      }
    }
    window.addEventListener('message', onMsg);
    setTimeout(function () { if (!gotFirst) teardown(); }, 180000);  // fail silent
    document.body.appendChild(frame);
  }

  /* ---------- consumers ---------- */

  document.addEventListener('bs-leak-data', function (e) { renderAll(e.detail); });

  function renderAll(r) {
    if (!r || !r.standing) return;
    renderNavBadge(r);
    renderBanner(r);
    renderTakedownsPage(r);
  }

  /* Nav badge: red % pill when at risk, green check for members, nothing
     when clean. Compact by design — long badges truncate nav labels. */
  function renderNavBadge(r) {
    document.querySelectorAll('[data-bs-nav-badge]').forEach(function (slot) {
      if (slot.dataset.done) return;
      if (r.standing === 'at_risk') {
        slot.textContent = (r.traffic && r.traffic.pct > 0)
          ? '\u25B2 ' + Math.round(r.traffic.pct) + '%'
          : r.pirates + ' leaks';
        slot.className = 'bs-badge bs-badge--alert';
        slot.hidden = false;
      } else if (r.standing === 'account') {
        slot.textContent = '\u2713';
        slot.className = 'bs-badge bs-badge--ok';
        slot.hidden = false;
      }
      slot.dataset.done = '1';                  // decide once per pageview
    });
  }

  /* Banner: server-rendered generic copy is the default state; this only
     upgrades it when there is something personal to say. */
  function renderBanner(r) {
    var el = document.querySelector('[data-bs-banner]');
    if (!el || el.dataset.done) return;
    el.dataset.done = '1';

    function setText(sel, text) {
      var n = el.querySelector(sel);
      if (n) { n.textContent = text; n.hidden = false; }
    }

    if (r.standing === 'account') {
      el.classList.add('bs-banner--protected');
      setText('[data-bs-banner-headline]', 'Your content is protected');
      setText('[data-bs-banner-sub]',
        'BranditScan is watching your name 24/7 \u2014 new leaks get found and taken down for you.');
      return;
    }
    if (r.standing !== 'at_risk' || r.pirates < 1) return;   // keep the generic pitch

    var name = (el.getAttribute('data-user-name') || '').trim();
    setText('[data-bs-banner-headline]',
      (name ? name + ', we' : 'We') + ' found your content on pirate sites.');
    setText('[data-bs-banner-sub]',
      'Take it down free \u2014 takedowns are covered for every creator.');

    if (r.domains.length) {
      setText('[data-bs-banner-domains]',
        'Found on: ' + r.domains.slice(0, 2).join(' \u00B7 ')
        + (r.domains.length > 2 ? ' \u00B7 +' + (r.domains.length - 2) + ' more' : ''));
    }

    var statNum = el.querySelector('[data-bs-banner-stat]');
    var statLabel = el.querySelector('[data-bs-banner-stat-label]');
    if (statNum && statLabel) {
      if (r.traffic && r.traffic.pct > 0) {
        statNum.textContent = '+' + Math.round(r.traffic.pct) + '%';
        statLabel.textContent = 'revenue to reclaim';
      } else {
        statNum.textContent = String(r.pirates);
        statLabel.textContent = 'leaks to remove';
      }
      statNum.hidden = statLabel.hidden = false;
    }

    var strip = el.querySelector('[data-bs-banner-thumbs]');
    if (strip && r.thumbs.length) renderThumbStrip(strip, r.thumbs);
  }

  /* Leaked-image strip: preload off-DOM, render only survivors (hotlinked
     images die unpredictably), favicon-badge each tile, blur via YOUR css.
     Tiles land in a .bs-leak-track; with 4+ survivors the set is duplicated
     and the track tagged --loop, so the CSS marquee slides it seamlessly.
     Too few tiles = no duplication, no animation — a static row. */
  function renderThumbStrip(strip, urls) {
    var loaded = [];
    var pending = urls.length;
    var rendered = false;

    function makeTile(src, isClone) {
      var tile = document.createElement('span');
      tile.className = 'bs-leak-tile';
      if (isClone) tile.setAttribute('aria-hidden', 'true');
      var img = document.createElement('img');
      img.src = src;
      img.referrerPolicy = 'no-referrer';
      img.alt = '';
      tile.appendChild(img);
      try {
        var host = new URL(src).hostname.replace(/^www\./, '');
        var fav = document.createElement('img');
        fav.className = 'bs-leak-tile__favicon';
        fav.src = 'https://t1.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&size=32&url=https://' + host;
        fav.onerror = function () { fav.remove(); };
        tile.appendChild(fav);
        tile.title = host;
      } catch (e) {}
      return tile;
    }

    function render() {
      if (rendered || !loaded.length) return;
      rendered = true;
      var set = loaded.slice(0, 8);
      var track = document.createElement('div');
      track.className = 'bs-leak-track' + (set.length >= 4 ? ' bs-leak-track--loop' : '');
      set.forEach(function (src) { track.appendChild(makeTile(src, false)); });
      if (set.length >= 4) {
        set.forEach(function (src) { track.appendChild(makeTile(src, true)); });
      }
      strip.appendChild(track);
      strip.hidden = false;
    }

    urls.forEach(function (src) {
      var probe = new Image();
      probe.referrerPolicy = 'no-referrer';
      probe.onload = function () { loaded.push(src); if (--pending === 0) render(); };
      probe.onerror = function () { if (--pending === 0) render(); };
      probe.src = src;
    });
    setTimeout(render, 8000);                   // straggler cutoff: show what loaded
  }

  /* Takedowns page: fill the automation card's %, decide the leak embed
     once (a late probe result must never yank a loaded widget). */
  function renderTakedownsPage(r) {
    var pct = document.querySelector('[data-bs-pct]');
    if (pct && r.standing === 'at_risk' && r.traffic && r.traffic.pct > 0) {
      pct.textContent = '+' + Math.round(r.traffic.pct) + '%';
    }
    var frame = document.getElementById('bs-leakcheck');
    if (!frame || frame.dataset.decided || frame.getAttribute('src')) return;
    frame.dataset.decided = '1';
    var section = document.querySelector('[data-bs-leak-section]');
    if (r.standing === 'good' || r.standing === 'account') {
      if (section) section.hidden = true;       // nothing to look at; saves scan quota
    } else if (frame.dataset.srcPrefilled) {
      frame.src = frame.dataset.srcPrefilled;   // at_risk: auto-run the full report
    }
  }

  /* ---------- iframe heights + visible-embed harvesting ---------- */

  window.addEventListener('message', function (e) {
    if (e.origin !== ORIGIN) return;
    var d = e.data || {};
    var lk = document.getElementById('bs-leakcheck');
    var tw = document.getElementById('bs-takedowns');
    if (d.type === 'bs-leak-check:height' && lk && e.source === lk.contentWindow) {
      lk.style.height = Math.ceil(d.height) + 'px';
    }
    if (d.type === 'bs-takedowns:height' && tw && e.source === tw.contentWindow) {
      tw.style.height = Math.ceil(d.height) + 'px';
    }
    // The visible embed keeps refreshing the cache for the whole visit —
    // including manual re-scans of the creator's OWN name (others rejected).
    if (lk && isOwnResult(e, lk)) accept(d);
  });

  /* ---------- boot ---------- */

  var cached = null;
  try { cached = JSON.parse(localStorage.getItem(CACHE_KEY) || 'null'); } catch (e) {}

  var visibleEmbed = document.getElementById('bs-leakcheck');
  if (cached && (Date.now() - cached.at) < DAY) {
    publish(cached);                            // instant, zero network
  } else if (visibleEmbed && visibleEmbed.dataset.srcPrefilled) {
    visibleEmbed.dataset.decided = '1';         // no data: the VISIBLE embed is the probe
    visibleEmbed.src = visibleEmbed.dataset.srcPrefilled;
  } else {
    startProbe();                               // any other page: hidden probe
  }
})();

Two rules already baked in (skipping them costs every integrator a day): referrerpolicy="no-referrer" on every frame — scans 403 silently without it — and the probe parks off-screen, never display:none, never loading="lazy".

2Create your Takedowns pagethe destination

A new page in your app — the menu item and banner will point here. Best practice is showing both ways to act, side by side: Submit free — the Self Submissions widget, unlimited; smaller and mid-size creators happily stay on it forever. Go automated — links out to BranditScan with your aff code; typically what bigger creators pick once the free path has shown them what's out there. The full Leak Check report runs underneath.

YourVids' live Protection page — the two cards side by side above the embedded widget
Live on YourVids — the two cards above the widget; the sidebar badge "Protection ▲ 16%" is step 3 doing its job
The Self Submissions widget on the same page — paste box and filed takedowns with live states
The same page, scrolled — the widget at work: filed notices with live states ("Delisted from search")

How the pieces fit — your design, your copy; the screenshots above are inspiration, not a template:

  • The "go automated" card is a plain link out to BranditScan with your aff code — nothing to wire.
  • The "submit free" card toggles the Self Submissions iframe right below it — hidden until that click, so it never loads for visitors who don't ask for it.
  • The Leak Check report loads underneath automatically — creators land on the page and immediately see their leaks (the module auto-runs it for at-risk creators and hides it for clean or already-protected ones).
HTML — the /takedowns page skeleton
<!-- /takedowns — two simple cards, style them your way (see the screenshots) -->
<div class="cards">

  <div class="card">                            <!-- FREE — self submission -->
    <h4>Submit takedowns — free</h4>
    <p>Paste a stolen link — a formal DMCA notice gets filed for you. Unlimited.</p>
    <a href="#takedown-widget" data-bs-open-takedowns>Submit a link</a>
  </div>

  <div class="card">                            <!-- AUTOMATED — your aff link -->
    <h4>Want it fully automated?</h4>
    <p>24/7 scanning and takedowns handled for you — reclaim up to
       <b data-bs-pct>+22%</b> of your traffic.</p>
    <a href="https://branditscan.com/register?aff=your-affiliate-slug"
       target="_blank" rel="noopener">Get protected</a>
  </div>

</div>

<!-- Self Submissions widget — hidden until the free card is clicked; the
     iframe never loads for visitors who don't ask for it. Signing secret:
     email help@branditscan.com when you START building (guide section 5.2). -->
<section id="takedown-widget" hidden>
  <iframe id="bs-takedowns" data-src="https://branditscan.com/embed/takedowns?t=TOKEN&funnel=off"
          referrerpolicy="no-referrer" scrolling="no" style="width:100%;border:0;height:520px;"></iframe>
</section>
<script>
  /* the free card's CTA reveals the widget and loads its iframe */
  document.addEventListener('click', function (e) {
    var t = e.target.closest('[data-bs-open-takedowns]');
    if (!t) return;
    e.preventDefault();
    var s = document.getElementById('takedown-widget');
    var f = document.getElementById('bs-takedowns');
    s.hidden = false;
    if (f && !f.getAttribute('src') && f.dataset.src) f.src = f.dataset.src;
    s.scrollIntoView();
  });
</script>

<!-- Leak Check report — loads by itself; the module decides once per pageview:
     at risk           -> auto-runs, creators see their leaks the moment they land
     clean / protected -> this WHOLE SECTION stays hidden (and those creators
                          get no nav badge either — silence is the reward)
     no data yet       -> loads prefilled and doubles as that day's probe -->
<section data-bs-leak-section>
  <iframe id="bs-leakcheck"
          data-src-prefilled="https://branditscan.com/embed/leak-check?aff=your-affiliate-slug&border=0&stagename=SARAH"
          referrerpolicy="no-referrer" scrolling="no" style="width:100%;border:0;height:600px;"></iframe>
</section>

Signing secret (see "What you'll need" up top) not arrived yet? Ship the automated card alone — never show "Submit free" before the page can deliver it.

3Add the menu itemthe traffic source

One nav link plus one empty span — the module fills it from the hidden scan. Name it Takedowns, Leaks or Remove Leaks.

Live partner implementation — the nav item with the badge
Live on YourVids — "Protection ▲ 16%" between the platform's own nav items, filled by the module
HTML — nav item + badge slot
<a href="/takedowns">
  Takedowns <span data-bs-nav-badge hidden></span>
</a>
<!-- the module fills it: at risk -> red "▲ 18%" · member -> green ✓ · clean -> nothing -->
4Add the banneroptional — the strongest push

Server-render your generic pitch; the module upgrades it in place when the creator is at risk — name headline, domains, green stat, their own leaked images (blurred) — and recolors it to "protected" for members. Works on the dashboard, settings, or an empty state.

Live partner implementation — the dashboard banner
Live on YourVids — the at-risk banner: headline, real domains, "+16% revenue to reclaim", a case study — clicks into the page

A live sample — and exactly what the snippet below renders once the module fills it. Hover pauses the strip. Sample images; on a real dashboard these are the creator's own leaked images, blurred.

HTML + CSS — the banner above, ready to paste
<!-- Server-render your generic pitch; the module upgrades it in place when
     the cache has something personal to say — the sample above is exactly
     what this renders for an at-risk creator. One [data-bs-banner] per
     page: dashboard, settings, an empty state... -->
<div class="bs-banner" data-bs-banner data-user-name="Sarah"
     onclick="if (!event.target.closest('a')) location.href='/takedowns'">
  <span class="bs-banner__stat">
    <b data-bs-banner-stat hidden></b>          <!-- "+18%" (green — opportunity framing) -->
    <i data-bs-banner-stat-label hidden></i>    <!-- "revenue to reclaim" -->
  </span>
  <h3 data-bs-banner-headline>Protect your content</h3>
  <p data-bs-banner-sub>Pirate sites repost creator content within days of upload.
     Run a free scan and see what's out there with your name on it.</p>
  <p data-bs-banner-domains hidden></p>         <!-- "Found on: site1 · site2 · +2 more" -->
  <div data-bs-banner-thumbs hidden></div>      <!-- their leaked images: blurred sliding tiles -->
  <a href="/takedowns">Check my name &rarr;</a>
  <small>Powered by BranditScan</small>
</div>

<style>
/* The banner above, verbatim — restyle freely, every class name is yours. */
.bs-banner { position: relative; overflow: hidden; cursor: pointer; border-radius: 14px;
             border: 1px solid rgba(233, 162, 0, .42); background: #fffdf2;
             padding: 18px 128px 14px 20px; }
.bs-banner h3 { margin: 0 0 3px; font-size: 15.5px; }
.bs-banner p  { margin: 0; font-size: 12.5px; line-height: 1.55; color: #606662; }
.bs-banner [data-bs-banner-domains] { margin-top: 6px; font-size: 11.5px; color: #8c928e; }
.bs-banner__stat { position: absolute; top: 18px; right: 20px; text-align: right;
                   color: #1f9d5b; font-size: 22px; line-height: 1.1; font-weight: 600; }
.bs-banner__stat i { display: block; font-style: normal; font-weight: 400;
                     font-size: 10.5px; color: #7a807c; margin-top: 2px; }
.bs-banner > a { display: inline-block; margin-top: 10px; font-size: 12.5px;
                 font-weight: 600; color: #7f42fd; text-decoration: none; }
.bs-banner > small { display: block; margin-top: 10px; font-size: 10.5px; color: #969c98; }
.bs-banner--protected { border-color: rgba(31, 157, 91, .4); background: #f3fbf6; }

/* The proof strip — the module fills [data-bs-banner-thumbs] with a
   .bs-leak-track and duplicates the tiles, so -50% loops seamlessly. */
[data-bs-banner-thumbs] { margin-top: 12px; overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent); }
.bs-leak-track { display: flex; width: max-content; }
.bs-leak-track--loop { animation: bsLeakSlide 32s linear infinite; }
[data-bs-banner-thumbs]:hover .bs-leak-track { animation-play-state: paused; }
.bs-leak-tile { position: relative; flex-shrink: 0; width: 64px; height: 64px; margin-right: 8px;
                border: 2px solid #e5484d; border-radius: 10px; overflow: hidden; }
.bs-leak-tile img:first-child { width: 100%; height: 100%; object-fit: cover;
                                filter: blur(7px); transform: scale(1.15); }  /* the blur is non-negotiable */
.bs-leak-tile__favicon { position: absolute; right: 3px; bottom: 3px; width: 15px; height: 15px;
                         border-radius: 4px; background: #fff; padding: 1px; }
@keyframes bsLeakSlide { to { transform: translateX(-50%); } }
@media (max-width: 560px) {
  .bs-banner { padding-right: 20px; }
  .bs-banner__stat { position: static; display: block; margin-bottom: 6px; }
}
@media (prefers-reduced-motion: reduce) { .bs-leak-track--loop { animation: none; } }
</style>
Do it your way. The three surfaces are the proven pattern, not a rulebook — after step 1 the result is yours via the bs-leak-data event: put the % on the earnings page, in the onboarding checklist, on a settings row. The full payload reference is right below.

The data — bs-leak-check:result

When a scan completes, the widget posts everything your UI needs. The module verifies, normalizes and caches it (24h), then fires one bs-leak-data event every surface listens to:

FieldWhat it powers
standingThe state machine: at_risk (pirates found) · good (clean) · account (already a BranditScan member — no scan data is sent, render "Protected", never upsell)
traffic.pctThe headline number — % of the creator's search traffic going to pirate sites. The nav badge ("▲ 18%") and the banner stat ("+18% revenue to reclaim")
piratesFallback headline when there's no traffic %: "6 leaks to remove"
domains ≤6The proof line — "Found on: site1 · site2 · +3 more"
thumbs + samples ≤50 eachThe creator's actual leaked images (Google Images + pulled straight off the pirate sites). Render blurred, always. samples arrives in a second, enriched re-post of the same result a few seconds later — the module handles it
estimatedLoss"≈ $12.4K/yr at risk" — formatted string; render only when it starts with $
stagenameEchoed on every result — the verification key. The module only caches results matching the logged-in creator's name, so a manual scan of someone else can never poison the cache

Live demo — a mock creator dashboard

It fires on its own: a sample result runs through the module's exact pipeline — the badge lands on the nav item, the banner personalizes with the creator's leaked images. Everything is fed by the module from its 24h browser cache — all front-end, no backend — and both the badge and the banner exist to push traffic to your Takedowns page.

yourplatform.com/dashboard
Protect your content

Pirate sites repost creator content within days. Run a free scan and see what's out there.

sample payload — the real bs-leak-check:result has this exact shape

                                            

Going deeper — higher self-submission volume & custom skins on the widget, server-side scan data (no iframes), one-click SSO — is the credentialed partner tier: book a call or email us.

Agency Leak Check Widget — roster scans

The Leak Check widget, rebuilt for agencies — multiple models, one embed

Live — free

Your users manage rosters, not single names? This is the same live scanner as the Leak Check Widget, adjusted for agencies: they add every model's stage name, the widget scans each one against our database of 5,000,000+ pirate sites and rolls it up into an agency report — models at risk, revenue at risk across the roster, the sites hitting the most models, and a per-model drill-down. Free to embed anywhere HTML works, no key needed.

HTML — paste anywhere
<!-- BranditScan Agency Leak Check widget -->
<iframe src="https://branditscan.com/embed/agency-leak-check" title="Agency Leak Check by BranditScan" style="display:block;width:100%;max-width:960px;margin:0 auto;height:620px;border:0;border-radius:24px;background:url(https://branditscan.com/front/lp/assets/images/leak-widget-spinner.svg) no-repeat center 140px;" scrolling="no" loading="lazy"></iframe>
<script>
window.addEventListener("message", function (e) {
  if (e.origin !== "https://branditscan.com" || !e.data || e.data.type !== "bs-agency-leak-check:height") return;
  document.querySelectorAll("iframe[src^='https://branditscan.com/embed/agency-leak-check']").forEach(function (f) {
    if (f.contentWindow === e.source) f.style.height = Math.ceil(e.data.height) + "px";
  });
});
</script>
ParameterWhat it does
stagenamesComma-separated roster prefill that runs immediately on load, e.g. ?stagenames=jane,ava,mia — up to 10 models per scan. Results are cached per name, so repeat loads are instant.
affYour BranditScan affiliate slug. Signups from the widget are credited to you — same 10%-for-life program as the Leak Check Widget above.
railPins the side visual: odometer (money counter — the default here), sweep, cases or loss.
borderborder=0 turns the animated rainbow shell border off (on by default).
blurblur=0 renders result images unblurred by default (NSFW-blurred with click-to-reveal out of the box).
brandingbranding=0 hides the BranditScan endnote for white-label embeds.
wMax-width cap in px (400–1400) for standalone previews — real embeds size via the iframe.

postMessage API

Same contract as the single-name widget, in its own namespace — auto-size the iframe, push a roster in from your own UI, and read the aggregate result back:

JavaScript
// OUT — sent by the widget on every layout change (auto-height):
//   { "type": "bs-agency-leak-check:height", "height": 1240 }

// OUT — sent when the roster scan completes:
//   { "type": "bs-agency-leak-check:result",
//     "models": [{ "name", "standing", "piratePct", "pirates" }],
//     "atRisk": 3, "clean": 1, "protected": 0, "failed": 0, "total": 4,
//     "avgPct": 24.6, "estimatedYearlyLoss": 54000, "domains": ["fapello.com"] }

// IN — push a roster in and run it from your own page:
var frame = document.querySelector("iframe[src*='/embed/agency-leak-check']");
frame.contentWindow.postMessage(
  { type: "bs-agency-leak-check:scan", stagenames: ["jane doe", "ava belle"] },
  "https://branditscan.com"
);
Custom skins — we match your UI 1:1. The widget ships in the BranditScan look, and per-partner skins are a ?skin= param away: hand us your design tokens and we build a skin that disappears into your product, exactly like our platform-branded takedown widgets. Ask for a skin — or go white-label today with ?branding=0.

Live demo — embedded on your site

Changes apply to the demo below — and the embed snippet above adjusts to your settings.

youragencyapp.com

This is the real widget, live on this page — add a few stage names, or hit Run sample roster to watch it scan a whole roster end-to-end (uses the widget's postMessage API).

Self Submissions Widget

Unlimited takedowns — embedded in your product

On request
What you'll need
  • Per-platform enablement — your embed, tenancy and limits are set up with you, typically within a few days: request it with your production domain and your local dev hosts (localhost, *.test) so it renders in your dev environment too.
  • Any depth you want — from the drop-in widget to a fully custom build in your design (like Takedown Labs below).

Own a platform? Give your entire user base unlimited self-submitted takedowns — free, globally, as your feature. Your users paste leak links right inside your product, we take them down, and every link's state updates as it moves through removal. The single most requested tool in the creator industry, shipped plug-and-play.

Ship it as simple or as advanced as you want: drop the ready-made widget in with one snippet (like the Leak Check widget above), or go fully custom — the surface is white-label-friendly and we match your UI/UX and design language so it feels native to your product. Either way there's no per-submission cost to you or your users, and under the hood every submission runs through the same pipeline our own creators use: validation, per-site grouping, DMCA notices, escalations, and Google delisting.

How it works

1
Your user pastes leak links Right inside your product — we validate, dedupe, expand shorteners, and group them per site.
2
We take them down Source removal + Google delisting, with escalations — filed and tracked by our pipeline 24/7.
3
States update automatically Every link moves Submitted → In Progress → Removed / Delisted — your users watch it happen without leaving your platform.

What the widget handles — and what stays in BranditScan

The widget files takedowns for standard web-page links — the pirate tubes, forums, blogs and file pages that make up the bulk of leaks. The in-app Self Submission's special-case machinery is deliberately not embedded; when a creator pastes one of these, the widget explains why and points them to the full BranditScan app (your embed doubles as a conversion surface):

SOCIALinstagram.com · x.com / twitter.com · facebook.comImpersonation (catfish) reports & social takedowns — need identity verification and the catfish review pipeline
GOOGLEshare.google · google.com/search · /url · /imgresGoogle links aren't hosting pages — the app expands them to the real page automatically
SHORTbit.ly · goo.gl · t.co · tinyurl.com · fb.me · ig.me · m.meShorteners get expanded before filing — an app-side step
REVIEWescalations & re-reviewsDuplicate escalation, support flags and manual review flows live in the app

Creators see the alert both while pasting and in the submission result ("Only available in BranditScan"), with a signup link — the same pattern the in-app flow uses for platform notices like TikTok.

Live integration — Takedown Labs on YourVids

A real partner build on this surface, fully customized to YourVids' own design — creators submit stolen-content links, takedowns run, and every request tracks its removals live:

The Self Submissions widget live on YourVids — protection stats, paste-a-link submit box, and the filed takedowns list
The widget live — stats, the paste-a-link submit box, and every filed notice with its state
A notice expanded on YourVids — takedown opened, submitted to Google, delisted from Google, with the delisting proof screenshot
A notice expanded — the full takedown timeline, down to the Google delisting proof

Embed — two steps

Your backend signs a short-lived token per page view with your existing HMAC signing secret (issued with your credentials), binding the widget session to one of your users — no other site can load it, and nobody but that user can see their data. Optional stagename / originals claims prefill their one-time setup:

Backend — sign the embed token (same code, your stack)
const crypto = require("crypto");

const payload = Buffer.from(JSON.stringify({
  v: 1,
  pid: YOUR_PLATFORM_ID,           // issued with your credentials
  uid: user.id,                    // YOUR user's id — any stable string
  name: user.displayName,          // optional
  stagename: user.stageName,       // optional prefill
  originals: [user.profileUrl],    // optional prefill (their official pages)
  iat: Math.floor(Date.now() / 1000),
  exp: Math.floor(Date.now() / 1000) + 86400   // 24h — up to 7 days
})).toString("base64url");

const token = payload + "." + crypto
  .createHmac("sha256", process.env.BS_SIGNING_SECRET)
  .update(payload)
  .digest("hex");
HTML — drop the iframe in (auto-resizes)
<iframe src="https://branditscan.com/embed/takedowns?t=${token}"
        title="Takedowns — powered by BranditScan"
        style="display:block;width:100%;max-width:960px;margin:0 auto;height:520px;border:0;border-radius:24px;background:#fff url(https://branditscan.com/front/lp/assets/images/leak-widget-spinner.svg) no-repeat center 140px;"
        scrolling="no" loading="lazy"></iframe>
<script>
  window.addEventListener("message", (e) => {
    if (e.data && e.data.type === "bs-takedowns:height")
      document.querySelector("iframe[src*='/embed/takedowns']").style.height = Math.ceil(e.data.height) + "px";
  });
</script>

Only domains you register with us can frame the widget (browser-enforced), tokens expire on their own, and suspending a platform cuts every embed instantly. Pairs naturally with the Platform API (accounts, scans, results in your UI) and SSO — but it also works standalone: the widget alone is enough to put takedowns in your product.

Make it yours — theming & white-label

The widget is built to disappear into your product. Every platform gets its own theme, the BranditScan branding is optional, and if theme variables aren't enough we design it with you:

THEMEaccent · background · radius · font · your logo & labelConfigured per platform — the widget renders in your colors, type and shape out of the box
CUSTOMyour UI/UX & design, 1:1We can make it match your UI/UX & design exactly — or build a fully custom version, like Takedown Labs above
ParameterWhat it does
brandingbranding=0 removes the BranditScan logo and text entirely — the widget runs white-label inside your product (branding shown by default).
borderborder=1 adds the animated rainbow shell border — the Leak Check treatment (off by default).
logoURL of your logo, e.g. logo=https://yoursite.com/logo.png — shown in the widget header (transparent PNG works best; https only, wins over the per-platform theme logo).
celebratecelebrate=1 adds the celebration reel — a slow vertical rotation of the creator's real removal screenshots (source removals first, then delistings, each with the site's icon) behind a big green count of everything removed & delisted (off by default; appears once the creator has removals).
blurblur=0 unblurs the NSFW image thumbnails (the funnel's stolen-image tiles and the nested leak-check results) — blurred by default.
funnelHow the built-in leak-check funnel presents itself: simple (default — the clean card), pulse (primary CTA with a live-dot and a periodic sheen), or one of the personalized variants that pre-run the scan in the background and rewrite the card from the result: teaser ("31% of your search traffic goes to leak sites" + the pirate sites' icons), revenue (the upside framing — "Boost your revenue by +31%", green with a gold coin), loss (the money framing — "creators lose on average $18,000 a year to piracy", gold figure), evidence (4 of the creator's actual stolen images, blurred with red rings, straight from Google Images), or wall (the full grid — up to 50 confirmed pirated images, each title-matched to the creator on a confirmed pirate site). Pre-run scans are cached per stage name — one scan per creator. funnel=off removes the leak-check card entirely.
Want SSO too? Already wired — nothing extra to integrate. If you also create BranditScan accounts for your members (Platform API POST /users, same external id as the token's uid), the widget automatically shows an "Open my BranditScan" button — one click signs the member into their own account in a new tab, reusing the very token that authenticated the iframe. Not doing SSO? Skip this — nothing changes.

Live demo — sandbox

Changes apply to the sandbox below — and the embed snippet above adjusts to your settings.

yourvids.com

This is the real widget in sandbox mode — fixture data, nothing is filed. Paste any links and submit to see the full flow, exactly as your users would.

Request the Self Submissions Widget

SSO API

Sign your users into BranditScan in one tap

On request
What you'll need

Use case: your users tap "Open BranditScan" inside your app, site, or Telegram bot — and land in their BranditScan dashboard already signed in. No passwords, no onboarding friction, no support tickets.

SSO is part of the Platform API: you mint a one-time, short-lived token for a user your platform created, then send the user to the returned URL. The consume page is crawler-proof — link previews and bots that prefetch URLs can't burn the token.

POST/api/platform/sso/tokenMint a one-time SSO token for one of your users
GET/sso/platform/{token}Browser URL — signs the user in (dashboard, or the onboarding wizard until it's completed)

How to wire it — four steps

  1. Once per user — create their BranditScan account. SSO only works for users your platform created via POST /api/platform/users. Use your own user id as external_id — that's the reference you'll mint tokens with forever after. The call is idempotent, so it's safe to run it right before every mint.
  2. On every "Open BranditScan" click — mint a token from your backend. POST /api/platform/sso/token with {"reference": "<your external_id>"}, signed like every Platform API call (the token endpoint is server-to-server — your signing secret never touches the browser). Mint fresh per click; never pre-mint, never cache, never put the URL in emails or chat messages.
  3. Send the user's browser to redirect_url — as a top-level navigation: window.location = url or a new tab (window.open / target="_blank"). Never inside an iframe — third-party cookie rules break the session there. The user sees a split-second interstitial, then they're signed in on branditscan.com. (The interstitial is what makes links crawler-proof: a bot's GET can't consume the token; only the browser's auto-submit does.)
  4. Where they land: platforms on wizard onboarding → straight onto the onboarding wizard's stage-name step, prefilled from the name you sent (then the live first scan and the plan offer; returners resume at whichever step they left). Already-onboarded users → their dashboard.
Embedding the widgets? SSO is already wired. The Self Submissions Widget shows an "Open my BranditScan" button automatically whenever its embed token maps to an account you created (same uid / external_id), and the Leak Check Widget does the same when you pass that token as &t=. Both reuse the widget token as proof — you don't call the mint endpoint at all for in-widget sign-ins.

Step 2 in practice — mint the token

cURL
curl -X POST https://branditscan.com/api/platform/sso/token \
  -H "Authorization: Bearer bsp_12_XXXXXXXXXXXXXXXXXXXX" \
  -H "X-Platform-Timestamp: 1767225600" \
  -H "X-Platform-Signature: 3f2a9c1e8b..." \
  -H "Content-Type: application/json" \
  -d '{"reference": "tg_482913"}'
201 — response
{
  "redirect_url": "https://branditscan.com/sso/platform/hnJdQ3...64-char-token...kQ",
  "expires_at": "2026-07-14T18:08:21+00:00",
  "expires_in": 300
}

The whole button, end to end

Node.js — your backend + your button
// BACKEND — one route your button calls:
app.post('/integrations/branditscan/open', async (req, res) => {
  const reference = String(req.user.id);

  // idempotent: 201 first time, 200 after; 409 = email already on BranditScan
  const created = await bsApi('POST', '/users', {
    email: req.user.email,
    name: req.user.displayName,
    stagenames: [req.user.stagename],
    external_id: reference,
  });
  if (created.status === 409) return res.status(409).json({ error: 'existing_account' });

  const sso = await bsApi('POST', '/sso/token', { reference });
  return res.json({ redirect_url: sso.json.redirect_url });
});

// FRONTEND — the "Open BranditScan" button:
const { redirect_url } = await fetch('/integrations/branditscan/open', { method: 'POST' })
  .then(r => r.json());
window.open(redirect_url, '_blank');   // or: window.location = redirect_url

Error semantics

404unknown referenceThe user was never created by your platform — run step 1 first
403refusedSSO not enabled for your platform, or the target is a privileged account
expiredused / >5 min oldThe user sees a friendly "link expired" login page — just mint a fresh one on the next click
  • One-time use, 5-minute TTL — mint a fresh token for every tap; never cache or reuse URLs.
  • Tenancy-scoped — a platform can only mint SSO for users it created. Admin and staff accounts can never be signed in via SSO.
  • Signed requests — same authentication scheme as the rest of the Platform API.
Request SSO integration

Network Manager API

Roster-wide protection reports for agencies & studios

On request
What you'll need
  • A network manager (agency / studio) account on BranditScan plus an API token — ask and we'll switch it on for your account.

Use case: you run an agency or studio with a roster of creators on BranditScan — and you want their protection numbers inside your own dashboards, reporting, and client decks instead of logging in per account.

Roster-wide reporting over every creator your network manager account oversees: links found, takedowns filed, removals, and per-domain breakdowns — filterable by membership tier, domain, and date range.

POST/api/v2/manager/users/reportProtection report for every managed creator
POST/api/v2/manager/users/cachePre-warm report caches for your roster
POST/api/manager/takedownFile takedowns on behalf of a managed creator
ParameterDescription
membershipFilter the roster: premium, basic, or unverified. Default premium.
domainScope the report to one pirate domain, e.g. fapello.com.
from_date / to_dateReport window, Y-m-d. Both required when either is set.

Sample request

cURL
curl -X POST https://branditscan.com/api/v2/manager/users/report \
  -H "Authorization: Bearer $MANAGER_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"membership": "premium", "from_date": "2026-06-01", "to_date": "2026-06-30"}'
Request Manager API access

Platform API — scans & results

Launch scans for your users, serve their piracy results in your product

On request
What you'll need

Own a platform? Put real leak scans and live piracy results inside your product — your platform creates BranditScan accounts for its users, launches scans on demand, and renders the findings natively in your own UI. Your users see their leaks where they already are: on your platform. And you earn a commission on every subscription it produces.

The Platform API is a multi-tenant partner surface: create BranditScan accounts for your users, launch scans, poll completion, pull infringements and per-site rollups into your own UI, and sign users straight into their dashboard via SSO. Everything is tenancy-scoped — your platform only ever sees the users it created. Looking for unlimited self-submitted takedowns instead? That's the Self Submissions Widget.

Endpoints

POST/api/platform/usersCreate a BranditScan user (1–3 stagenames)
POST/api/platform/users/syncBulk membership status for up to 200 of your users
POST/api/platform/users/lookupMass existence check by email or stagename
POST/api/platform/scansLaunch a scan for one of your users
GET/api/platform/scans/{id}Poll scan progress + summary
GET/api/platform/users/{ref}/infringementsPaginated infringing links
GET/api/platform/users/{ref}/branditsPer-domain rollup with piracy intel
POST/api/platform/traffic-checkRun a leak check for any stagename
POST/api/platform/sso/tokenMint an SSO login URL — see SSO API

Authentication

Every request carries three headers: your bearer key, a unix timestamp (±300s of server time), and an HMAC-SHA256 signature of "{timestamp}.{rawBody}" keyed by your signing secret. An IP allowlist and per-platform rate limits apply on top.

Node.js — sign a request
const crypto = require("crypto");

const timestamp = Math.floor(Date.now() / 1000).toString();
const body = JSON.stringify(payload); // exact raw body you will send

const signature = crypto
  .createHmac("sha256", process.env.BS_SIGNING_SECRET)
  .update(timestamp + "." + body)
  .digest("hex");

// Headers:
//   Authorization:        Bearer bsp_12_XXXXXXXXXXXXXXXXXXXX
//   X-Platform-Timestamp: timestamp
//   X-Platform-Signature: signature

1 — Create a user

Two onboarding modes, set per platform. Provisioned — the account is created ready to scan with the given stagenames (headless integrations, bots). Wizard onboarding — a bare OAuth-style registration: email pre-verified, the display name from your platform, and the stage-name step prefilled; when the creator SSOs in they walk through the standard BranditScan onboarding (scan → plan) themselves. Signups are attributed to your affiliate account either way.

cURL
curl -X POST https://branditscan.com/api/platform/users \
  -H "Authorization: Bearer bsp_12_XXXXXXXXXXXXXXXXXXXX" \
  -H "X-Platform-Timestamp: 1767225600" \
  -H "X-Platform-Signature: 3f2a9c1e8b..." \
  -H "Content-Type: application/json" \
  -d '{"email": "creator@example.com", "name": "Jane Doe", "stagenames": ["jane doe"], "external_id": "tg_482913"}'
201 — response
{
  "user": {
    "bs_user_id": 38412,
    "external_id": "tg_482913",
    "email": "creator@example.com",
    "is_premium": false,
    "membership": 0
  }
}
  • Existing emails are rejected (409) — a platform can never claim an account it didn't create.
  • Idempotent — re-sending the same external_id returns the existing user instead of erroring.

2 — Launch a scan, poll until complete

cURL
curl -X POST https://branditscan.com/api/platform/scans \
  -H "Authorization: Bearer bsp_12_XXXXXXXXXXXXXXXXXXXX" \
  -H "X-Platform-Timestamp: 1767225600" \
  -H "X-Platform-Signature: 9d41be07ac..." \
  -H "Content-Type: application/json" \
  -d '{"reference": "tg_482913"}'
GET /api/platform/scans/512 — once completed
{
  "scan": {
    "id": 512,
    "reference": "tg_482913",
    "bs_user_id": 38412,
    "queue": "first-search",
    "progress": 100,
    "completed": true,
    "created_at": "2026-07-14T18:03:21+00:00",
    "completed_at": "2026-07-14T19:41:05+00:00",
    "summary": {
      "total_links": 1204,
      "total_views": 8125940,
      "total_loss": 24377,
      "total_domains": 87,
      "top_websites": [
        { "domain": "fapello.com", "links_count": 214 },
        { "domain": "leakedzone.com", "links_count": 168 }
      ]
    }
  }
}

3 — Pull the findings into your UI

GET /api/platform/users/tg_482913/infringements?page=1&per_page=25
{
  "data": [
    {
      "id": 981220431,
      "url": "https://fapello.com/jane-doe/",
      "title": "Jane Doe Nude Leaks",
      "website": "fapello.com",
      "views": 48210,
      "states": ["Active"],
      "in_dmca": true,
      "found_at": "2026-07-14T19:22:41+00:00"
    }
  ],
  "pagination": { "page": 1, "per_page": 25, "total": 1204, "last_page": 49 }
}

Finish the loop with SSO: one tap in your product and the creator is inside their BranditScan dashboard, where takedowns run 24/7.

Pitch us your platform Affiliate Program

Book an intro call

30 minutes — scope your integration live with the founding team

Faster than email ping-pong: grab a slot, tell us what you're building, and we'll map the right APIs, quotas, and commercials with you on the call — credentials usually follow within a working day.

Fair use: the Leak Check widget may be embedded on any site as long as it isn't modified, wrapped in misleading UI, or used to misrepresent BranditScan. Widget scans are rate-limited per visitor and shared across all embeds. API credentials are issued per use case and may not be shared or resold; data from the widget or APIs may not be resold or republished as a dataset. We may revoke access for abuse. That's it — build something good.