# 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>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.tagbase.io/extension/integration-guide.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
