Base Verify Onchain

Integration

You build two things — a contract that declares your policy and checks verifications, and an app that fetches verifications — and point both at Base Verify.

What you'll need

InputValue (Base Sepolia)
SignerRegistry0x4f15593fbF7e3491d15080e1610E7AF8deBA1a02
API base URLhttps://verify.base.dev/v1
ChainBase Sepolia (84532)
Consumer baseBaseVerifyConsumer.sol (from Base Verify)

Deployed example contracts (Base Sepolia)

Two working consumers you can inspect on Basescan, both extending BaseVerifyConsumer and calling the registry above:

1. Write your contract

Extend the Base Verify consumer base so your policy is readable onchain, check verifications through the registry, and dedupe on identityHash.

import {BaseVerifyConsumer, Condition} from "@baseverify/BaseVerifyConsumer.sol"; contract MyAirdrop is BaseVerifyConsumer { mapping(bytes32 => bool) public claimed; error AlreadyClaimed(); // Base Verify registry address for your chain. constructor(address registry_) BaseVerifyConsumer(registry_) {} // Your eligibility policy — must be constant. function provider() external pure override returns (string memory) { return "coinbase"; } function conditions() external pure override returns (Condition[] memory) { Condition[] memory c = new Condition[](1); c[0] = Condition("coinbase_one_active", "eq", "true"); return c; } function claim(bytes32 identityHash, uint40 expiration, bytes calldata signature) external { if (claimed[identityHash]) revert AlreadyClaimed(); _verify(identityHash, expiration, signature); // binds msg.sender; reverts on a bad or expired verification claimed[identityHash] = true; // ... your reward logic ... } }

provider() and conditions() must be immutable constants — a changing policy invalidates outstanding verifications and breaks dedupe.

Optionally override cutoffBlock() to require a credential no older than a given block; unlike provider/conditions it isn't part of policyHash, so you can change it without invalidating outstanding verifications. See Core concepts.

2. Fetch a verification in your app

Have the user sign a SIWE message that names your contract, then POST it to the Base Verify API. Pass the response to your contract's claim function.

import { createSiweMessage, generateSiweNonce } from "viem/siwe"; // The statement and Resources line below are required by the API. const message = createSiweMessage({ domain: window.location.host, address: userAddress, statement: "Claim eligibility for a Base Verify onchain benefit.", uri: window.location.origin, version: "1", chainId: 84532, nonce: generateSiweNonce(), resources: [`eip155:84532:${MY_CONTRACT_ADDRESS}`], }); const signature = await signMessageAsync({ message }); const res = await fetch("https://verify.base.dev/v1/onchain_verifications", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message, signature }), }); const { identityHash, expiration, signature } = await res.json(); await writeContract({ address: MY_CONTRACT_ADDRESS, abi, functionName: "claim", args: [identityHash, expiration, signature], });

See the API reference for the full request, response, and errors.