# Integration Guide

#### Overview

This guide covers:

1. Fetching claims for a URL
2. Displaying verification badges
3. Implementing ownership verification flow
4. Handling verification states

***

#### Prerequisites

* Basic knowledge of JavaScript/TypeScript
* A web application to integrate with
* No API keys required — the API is public

***

#### Step 1: Fetch Claims for a URL

Query the TAGBASE API to check if a URL has any associated claims.

**JavaScript Example:**

```javascript
async function fetchClaims(resourceUrl) {
  const response = await fetch(
    `https://api.extension.tagbase.io/claims?resource_url=${encodeURIComponent(resourceUrl)}`
  );
  
  if (!response.ok) {
    throw new Error('Failed to fetch claims');
  }
  
  const data = await response.json();
  return data.claims;
}

// Usage
const claims = await fetchClaims('https://example.com/product/123');
console.log(`Found ${claims.length} claims`);
```

***

#### Step 2: Display Verification Status

Render verification badges based on claim data.

**React Example:**

```tsx
function VerificationBadge({ claim }) {
  const hasOwnership = claim.ownership?.status === 'verified';
  
  return (
    <div className="verification-badge">
      <img 
        src={claim.product?.image_url} 
        alt={claim.product?.name} 
      />
      <div>
        <h3>{claim.product?.name}</h3>
        <p>Verification ID: {claim.verification_id}</p>
        
        {hasOwnership ? (
          <span className="badge verified">
            ✓ Ownership Verified
          </span>
        ) : (
          <span className="badge pending">
            Ownership Not Verified
          </span>
        )}
        
        {claim.token && (
          <span className="badge blockchain">
            {claim.token.blockchain_type} Token
          </span>
        )}
      </div>
    </div>
  );
}
```

***

#### Step 3: Implement Ownership Verification

Allow users to prove they own the blockchain token associated with a product.

**3.1 Request a Challenge**

```javascript
async function requestChallenge(verificationId) {
  const response = await fetch(
    `https://api.extension.tagbase.io/verifications/${verificationId}/challenge`,
    { method: 'POST' }
  );
  
  if (!response.ok) {
    throw new Error('Failed to request challenge');
  }
  
  return await response.json();
}

// Response includes:
// - session_id: unique session identifier
// - message: message to sign
// - expires_at: challenge expiry time (5 minutes)
// - blockchain_type: 'cardano' or 'ethereum'
// - expected_holders: array of holder addresses (Cardano only)
// - uuid: verification UUID for proof submission
```

**3.2 Sign with Cardano Wallet (CIP-30)**

```javascript
async function signWithCardano(walletApi, message) {
  // Get the wallet's used addresses
  const addresses = await walletApi.getUsedAddresses();
  const address = addresses[0];
  
  // Convert message to hex
  const messageHex = Array.from(new TextEncoder().encode(message))
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');
  
  // Sign using CIP-30 signData
  const signedData = await walletApi.signData(address, messageHex);
  
  return {
    address,
    signature: signedData.signature,
    key: signedData.key
  };
}

// Connect to wallet first
const walletApi = await window.cardano.eternl.enable();
const { address, signature, key } = await signWithCardano(walletApi, challenge.message);
```

**3.3 Sign with Ethereum Wallet**

```javascript
async function signWithEthereum(message) {
  const accounts = await window.ethereum.request({ 
    method: 'eth_requestAccounts' 
  });
  const address = accounts[0];
  
  const signature = await window.ethereum.request({
    method: 'personal_sign',
    params: [message, address]
  });
  
  return { address, signature };
}

const { address, signature } = await signWithEthereum(challenge.message);
```

**3.4 Submit Proof**

```javascript
async function submitProof(uuid, proofData) {
  const response = await fetch(
    `https://api.extension.tagbase.io/verifications/${uuid}/proof`,
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(proofData)
    }
  );
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error || 'Proof submission failed');
  }
  
  return await response.json();
}

// Cardano proof
await submitProof(challenge.uuid, {
  session_id: challenge.session_id,
  address: signedData.address,
  signature: signedData.signature,
  key: signedData.key,
  blockchain_type: 'cardano'
});

// Ethereum proof
await submitProof(challenge.uuid, {
  session_id: challenge.session_id,
  address: signedData.address,
  signature: signedData.signature,
  blockchain_type: 'ethereum'
});
```

***

#### Step 4: Complete Flow Example

```javascript
async function verifyOwnership(verificationId, walletType = 'cardano') {
  try {
    // 1. Request challenge
    const challenge = await requestChallenge(verificationId);
    console.log('Challenge received, expires:', challenge.expires_at);
    
    // 2. Sign with wallet
    let proofData;
    
    if (walletType === 'cardano') {
      const walletApi = await window.cardano.eternl.enable();
      const signed = await signWithCardano(walletApi, challenge.message);
      proofData = {
        session_id: challenge.session_id,
        address: signed.address,
        signature: signed.signature,
        key: signed.key,
        blockchain_type: 'cardano'
      };
    } else {
      const signed = await signWithEthereum(challenge.message);
      proofData = {
        session_id: challenge.session_id,
        address: signed.address,
        signature: signed.signature,
        blockchain_type: 'ethereum'
      };
    }
    
    // 3. Submit proof
    const result = await submitProof(challenge.uuid, proofData);
    
    if (result.success) {
      console.log('Ownership verified!', result.ownership);
      return result.ownership;
    }
  } catch (error) {
    console.error('Verification failed:', error.message);
    throw error;
  }
}
```

***

#### Handling Verification States

| State              | Description                            | UI Recommendation                             |
| ------------------ | -------------------------------------- | --------------------------------------------- |
| No claims          | URL has no TAGBASE claims              | Show nothing or "Not registered"              |
| Claim exists       | Product registered, no ownership proof | Show product info + "Verify Ownership" button |
| Ownership verified | Valid signature on file                | Show verified badge with wallet address       |
| Challenge expired  | 5-minute window passed                 | Prompt user to try again                      |
| Token not held     | Wallet doesn't hold the token          | Show error: "Token not in wallet"             |

***

#### Error Handling

```javascript
async function safeVerification(verificationId) {
  try {
    const result = await verifyOwnership(verificationId);
    return { success: true, data: result };
  } catch (error) {
    const message = error.message;
    
    if (message.includes('expired')) {
      return { success: false, error: 'Challenge expired. Please try again.' };
    }
    if (message.includes('not hold')) {
      return { success: false, error: 'Your wallet does not hold the required token.' };
    }
    if (message.includes('Signature')) {
      return { success: false, error: 'Signature verification failed. Please try again.' };
    }
    
    return { success: false, error: 'Verification failed. Please try again.' };
  }
}
```

***

#### Best Practices

1. **Cache claims** — Don't fetch on every page load; cache for 5-10 minutes
2. **Handle wallet errors** — Users may reject signing or have locked wallets
3. **Show loading states** — Blockchain operations can take a few seconds
4. **Validate before submission** — Check challenge hasn't expired before signing
5. **Graceful degradation** — If API is unavailable, don't break your UI

<br>
