<!-- Markdown copy of https://insumermodel.com/developers/compliance/ for agents. -->

> Check Coinbase Verifications, Gitcoin Passport score and Farcaster identity for a wallet in one call, returned as one signed attestation. No PII handled.
>
> Page: https://insumermodel.com/developers/compliance/ · API: https://api.insumermodel.com · OpenAPI: https://insumermodel.com/openapi.json · Index for agents: https://insumermodel.com/llms.txt

[Developers](https://insumermodel.com/developers/) [API Map](https://insumermodel.com/workbench/) › Compliance Gating

# Compliance Gating

Verify KYC attestations on-chain using EAS attestation conditions. Pre-configured compliance templates abstract away schema IDs, attester addresses, and decoder contracts.

Uses [`POST /v1/attest`](https://insumermodel.com/developers/verification/) with pre-configured compliance templates.

Auth: `X-API-Key`, or `Authorization: Wallet` for EVM agents who bought their key via `/v1/keys/buy`. [See Authentication →](https://insumermodel.com/developers/api-reference/#auth)

**Building this in Claude Code?** Install the wallet auth skill and Claude will write correct, signature-verifying integration code on the first try.

```bash
git clone https://github.com/insumerapi/insumer-skill.git ~/.claude/skills/insumer
```

[View on Smithery](https://smithery.ai/skills/douglasborthwick/insumer-skill) · [GitHub repo](https://github.com/insumerapi/insumer-skill)

## What this does

Use `eas_attestation` conditions with compliance templates to verify Coinbase Verifications, Gitcoin Passport status, and other on-chain identity attestations. One API call checks the attestation without handling PII.

## Compliance template attest call

POST /v1/attest

```javascript
const res = await fetch("https://api.insumermodel.com/v1/attest", {
  method: "POST",
  headers: { "Content-Type": "application/json", "x-api-key": "YOUR_API_KEY" },
  body: JSON.stringify({
    wallet: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    conditions: [{
      type: "eas_attestation",
      template: "coinbase_verified_account",
      label: "KYC verified"
    }]
  })
});

const { data } = await res.json();
console.log(data.attestation.pass); // true if wallet has Coinbase KYC
```

```python
import requests

res = requests.post(
    "https://api.insumermodel.com/v1/attest",
    headers={"x-api-key": "YOUR_API_KEY"},
    json={
        "wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
        "conditions": [{
            "type": "eas_attestation",
            "template": "coinbase_verified_account",
            "label": "KYC verified"
        }]
    }
)

data = res.json()["data"]
print(data["attestation"]["pass"])  # True if wallet has Coinbase KYC
```

```bash
curl -X POST https://api.insumermodel.com/v1/attest \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "conditions": [{
      "type": "eas_attestation",
      "template": "coinbase_verified_account",
      "label": "KYC verified"
    }]
  }'

# Response: { "ok": true, "data": { "attestation": { "pass": true }, "sig": "...", "kid": "..." }, "meta": { "version": "1.0", ... } }
```

## Compliance Templates

Each template maps to a specific EAS schema, attester address, and chain. Pass the `template` field instead of configuring those values manually.

coinbase_verified_account Base (8453)

Coinbase

Verify wallet has completed Coinbase KYC. Most widely issued on-chain identity attestation.

coinbase_verified_country Base (8453)

Coinbase

Verify the wallet holds a valid Coinbase Verified Country attestation. The condition checks that the attestation exists and is not revoked or expired; it does not match a specific country.

coinbase_one Base (8453)

Coinbase

Verify Coinbase One membership status. Gate premium features for Coinbase One subscribers.

gitcoin_passport_score Optimism (10)

Gitcoin

Verify Gitcoin Passport humanity score is 20 or above. Uses GitcoinPassportDecoder contract. On-chain Sybil resistance.

gitcoin_passport_active Optimism (10)

Gitcoin

Check wallet has active Gitcoin Passport with any positive score. Lighter check for basic humanity verification.

## Custom EAS Issuers

Templates cover Coinbase Verifications and Gitcoin Passport. To verify attestations from your own EAS schema, pass `schemaId`, `attester`, and `indexer` directly. The indexer is the load-bearing piece: it is how the API resolves the attestation UID, so a raw condition without one is refused with a 400.

### How resolution works

For a raw `eas_attestation` condition, the API:

1. Calls `getAttestationUid(address recipient, bytes32 schema) returns (bytes32)` on your `indexer` contract (selector `0xab2717dd`) to get the UID for (wallet, schema).
2. Calls `getAttestation(bytes32 uid)` on the EAS contract for the target chain to fetch the attestation struct.
3. Verifies `recipient == wallet` (auto-bound), `revocationTime == 0`, `expirationTime == 0 || expirationTime >` the anchored block’s timestamp, `schema == schemaId` (checked on the attestation itself, not taken from the indexer), and (if specified) `attester == condition.attester`.

**Recipient is not a request-side field.** It auto-binds to the wallet being verified. An attestation issued with a different recipient (including `0x0`) will fail the condition regardless of schema or attester match.

### Deploying an indexer

Coinbase's EAS Verifications indexer is open source and the standard reference. Fork it, deploy on your target chain, and wire your issuance flow to write each new attestation's `(recipient, schema) → uid` mapping. The indexer must implement the `getAttestationUid` selector exactly; that is the single ABI requirement.

Once deployed, pass the indexer address as the `indexer` field. EAS contracts on supported chains: Base/Optimism (`0x4200000000000000000000000000000000000021`), Ethereum (`0xA1207F3BBa224E2c9c3c6D5aF63D0eb1582Ce587`), Arbitrum, Polygon.

### Example condition

Custom EAS condition:

```json
{
  "type": "eas_attestation",
  "chainId": 8453,
  "schemaId": "0x78bfda217fd8dceeed9138bf9b867edf716aabec55b6f01eff1576eb02e9c863",
  "attester": "0x3Af7fb877e581CF013cb5b5A4C38D813D07D748c",
  "indexer": "<your indexer contract address>",
  "label": "Custom attestation"
}
```

## Farcaster Identity

`farcaster_id` is a standalone condition type, not a template. It uses the IdRegistry contract on Optimism. The contract's `idOf(address)` method returns the wallet's Farcaster ID (FID), or 0 if unregistered. No `contractAddress` or `chainId` is needed in the condition.

```javascript
const res = await fetch("https://api.insumermodel.com/v1/attest", {
  method: "POST",
  headers: { "Content-Type": "application/json", "x-api-key": "YOUR_API_KEY" },
  body: JSON.stringify({
    wallet: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    conditions: [{
      type: "farcaster_id",
      label: "Farcaster user"
    }]
  })
});

const { data } = await res.json();
console.log(data.attestation.pass); // true if wallet has a Farcaster ID
```

```python
import requests

res = requests.post(
    "https://api.insumermodel.com/v1/attest",
    headers={"x-api-key": "YOUR_API_KEY"},
    json={
        "wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
        "conditions": [{
            "type": "farcaster_id",
            "label": "Farcaster user"
        }]
    }
)

data = res.json()["data"]
print(data["attestation"]["pass"])  # True if wallet has a Farcaster ID
```

```bash
curl -X POST https://api.insumermodel.com/v1/attest \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "conditions": [{
      "type": "farcaster_id",
      "label": "Farcaster user"
    }]
  }'

# Response: { "ok": true, "data": { "attestation": { "pass": true }, "sig": "...", "kid": "..." }, "meta": { "version": "1.0", ... } }
```

## Gating Patterns

Combine compliance templates with other condition types in the same `conditions` array. The attestation passes only when ALL conditions are met. This lets you gate on KYC status and token holdings together for regulated use cases.

```javascript
const res = await fetch("https://api.insumermodel.com/v1/attest", {
  method: "POST",
  headers: { "Content-Type": "application/json", "x-api-key": "YOUR_API_KEY" },
  body: JSON.stringify({
    wallet: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    conditions: [
      {
        type: "eas_attestation",
        template: "coinbase_verified_account",
        label: "KYC verified"
      },
      {
        type: "token_balance",
        contractAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
        chainId: 1,
        threshold: "1000", // decimal string (v2 keys reject a JSON number with 400)
        label: "Holds 1000+ USDC"
      }
    ]
  })
});

const { data } = await res.json();
// pass is true only when BOTH conditions are met
console.log(data.attestation.pass);
```

```python
import requests

res = requests.post(
    "https://api.insumermodel.com/v1/attest",
    headers={"x-api-key": "YOUR_API_KEY"},
    json={
        "wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
        "conditions": [
            {
                "type": "eas_attestation",
                "template": "coinbase_verified_account",
                "label": "KYC verified"
            },
            {
                "type": "token_balance",
                "contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
                "chainId": 1,
                "threshold": "1000", # decimal string (v2 keys reject a JSON number with 400)
                "label": "Holds 1000+ USDC"
            }
        ]
    }
)

data = res.json()["data"]
# pass is True only when BOTH conditions are met
print(data["attestation"]["pass"])
```

```bash
curl -X POST https://api.insumermodel.com/v1/attest \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "conditions": [
      {
        "type": "eas_attestation",
        "template": "coinbase_verified_account",
        "label": "KYC verified"
      },
      {
        "type": "token_balance",
        "contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
        "chainId": 1,
        "threshold": "1000",
        "label": "Holds 1000+ USDC"
      }
    ]
  }'

# pass is true only when BOTH conditions are met
```

## Related articles

[Compliance Gating with Coinbase Verifications](https://insumermodel.com/blog/compliance-gating-coinbase-verifications.html) [Privacy by Design in the Insumer API](https://insumermodel.com/blog/privacy-by-design-insumer-api.html)

See how this endpoint fits the full API → [API Topology](https://insumermodel.com/workbench/)

[← Trust](https://insumermodel.com/developers/trust/) [Next: Commerce →](https://insumermodel.com/developers/commerce/)
