Skip to content
Watermark
Menu
For airdrops, mints and rewards

Stop bots from farming your airdrop.

Watermark lets only wallets backed by a real bank card claim. Add it with one line. No KYC. Your users pay no fees.

Airdrop claimsExample

Only stamped wallets can claim.

  1. 0x9c1e…41abRefused · no stamp
  2. 0x4d07…e2f0Refused · no stamp
  3. 0x71aa…09c3Refused · no stamp
  4. 0xb3f2…7d15Claimed #042 · stamped wallet
Genesis Drop stamp #042 of 100: a Mumbai postage stamp of the Bandra–Worli Sea Link

How it works

Three steps. Zero bots.

  1. Step 1

    You add one check

    In your contract, your backend or your AI agent.

  2. Step 2

    Users tap their card once

    On our phone app. A private proof checks the card is real. No card number is stored.

  3. Step 3

    Only stamped wallets claim

    Bots get refused before they touch your tokens.

Add it

Add it in one line.

Check a stamp from Solidity, TypeScript or your AI agent. No API key.

Any contract can check a stamp in one call. A wallet with no live stamp gets refused.

Your contract: the one line

function claim()external onlyStamped { … }

Paste once, from docs/INTEGRATE.md

Solidity · onlyStamped
interface IWatermarkRegistry {
    function isStamped(address wallet, uint256 appId) external view returns (bool ok, uint64 expiresAt);
}

modifier onlyStamped() {
    (bool ok, uint64 expiresAt) = watermark.isStamped(msg.sender, watermarkAppId);
    require(ok && expiresAt > block.timestamp, "Watermark: no live stamp");
    _;
}
Chain IDWhitechain Sepolia
1874
RegistryWatermarkRegistry
0x998934Efa31a6bE75945fDfAa126d3D6401F8Fd6VerifiedExplorer (opens in a new tab)
Live appIdRuPay bank debit (India, no prepaid)
393344891601835728760966937624776276735512086066329273346256164761263100630
Deploy blockEvent history starts here
12335610

For AI agents

Let your AI agent add it.

Copy this prompt into Claude Code, Cursor or any coding agent. It reads our docs and adds the bot check to your app.

Prompt
Add Watermark anti-bot gating to this project. A Watermark stamp means a wallet was linked to one real bank card. Only stamped wallets may claim our airdrops, mints and rewards.

1. Read https://usewatermark.xyz/watermark.txt first. Use only the addresses, functions and tool names it gives. Don't invent any.

2. Find every place this repo pays out: airdrop claims, mints, rewards, allowlists. Check whether they live in Solidity contracts, a TypeScript/JavaScript backend, or both.

3. App id: <YOUR_APP_ID> below is a placeholder; keep it in one config constant. For real RuPay bank cards, set it to the live app id: 393344891601835728760966937624776276735512086066329273346256164761263100630. Register our own app only if we want our own card list: draft it with watermark_draft_policy, then watermark_prepare_register_app (unsigned; I send it, and we must run our own session signer). Tell me which you chose and why.

4. Solidity: contracts on Whitechain Sepolia (chain 1874) can gate directly. Add the IWatermarkRegistry interface and the onlyStamped modifier from the docs, with the registry 0x998934Efa31a6bE75945fDfAa126d3D6401F8Fd6 and <YOUR_APP_ID>, and put onlyStamped on each claim function. A contract on another chain can't read the registry: check in the backend instead.

5. Backend: before paying out, call check() from @watermark/sdk, or the plain viem isStamped read in the docs (the SDK isn't on npm yet). Refuse when stamped is false. Never trust a stamp flag sent by the browser.

6. For users who aren't stamped, show a "Get verified with Watermark" link to https://usewatermark.xyz/verify?app=<YOUR_APP_ID> (what watermark_create_verify_link returns). Tell them to verify the same wallet they claim with.

7. Never ask for, store or log card numbers or any card data. We only need the wallet address.

8. Keep every existing test passing. Add a test showing an unstamped wallet is refused (mock the registry or the check). Add no keys or secrets; reading a stamp needs none.

Finish with a short summary: files changed, where each check sits, the app id and why, how to run the new test, and anything left for me to do.

Read the full docs: watermark.txt (opens in a new tab)

Try to break it

Try to farm it.

Press the button. We make 5 bot wallets and send them at our own drop. Every one gets refused. These are real requests.

Illustration

Is this wallet stamped?

We ask the chain. Your app would get the same answer.

App

Live app: RuPay bank debit cards from India.

Read-only. Nothing is signed or sent.

You stay in control

You decide who counts.

Use our live card list, or register your own app with your own. Every list is public, and fixed for its app.

  • Which cards count

    4,208 RuPay bank debit ranges from India. No prepaid cards, because anyone can buy many.

    • Classic
    • Platinum
    • PMJDY (Jan Dhan)
    • RuPay Select
    • Standard
  • Sponsor your users' fees

    They pay $0, up to 20 payments a day each.

    Fees your users pay
    $0
    Free payments per wallet, per day
    20
  • Stamps last up to 3 months

    One card, one wallet per app.

  • Nothing sensitive to store

    No KYC files, no card numbers.

Public records · Test networks

See it yourself.

Every step leaves a public record. Tap any one to check it.

The fine print

Privacy and limits.

What we see, store and put on-chain

Briefly, in memory
Your card data, to make the proof, then wiped.
Stored
Nothing from your card.
On-chain
A proof, a one-way card ID, your wallet and an expiry month.

You have to trust us on the wipe. Proving on the phone is the real fix. It's on our roadmap.

Read our privacy notes (opens in a new tab)

Good to know

  • Only RuPay bank debit cards from India work today.
  • Everything runs on test networks: Whitechain Sepolia and an Ethereum test network.
  • One card gets one stamp per app. A stamp is not KYC: three cards, three stamps.
  • A tap has no PIN, so a stamp shows a wallet is backed by a real bank card, not who holds it.