Skip to main content

Overview

In this guide, you’ll create your first attestation from scratch using the AttestProtocol SDK. We’ll walk through:
  1. Setting up your environment
  2. Initializing the SDK
  3. Registering as an authority
  4. Creating a schema
  5. Issuing an attestation
  6. Verifying the attestation
This tutorial assumes you’ve already installed the SDK. If not, go back and install it first.

Step 1: Set Up Your Project

Create a new directory and initialize your project:
mkdir my-first-attestation
cd my-first-attestation
npm init -y
npm install @attestprotocol/sdk dotenv
Create your main file:
index.js
import { AttestSDK } from '@attestprotocol/sdk';
import 'dotenv/config';

async function main() {
  console.log('Starting attestation tutorial...');
  
  // We'll add code here step by step
}

main().catch(console.error);

Step 2: Initialize the SDK

Add your configuration to a .env file:
.env
# Choose your blockchain
STELLAR_SECRET_KEY=SXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
STELLAR_PUBLIC_KEY=GXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
STELLAR_RPC_URL=https://soroban-testnet.stellar.org

# Alternative: Solana configuration
# SOLANA_SECRET_KEY=[1,2,3,...]
# SOLANA_RPC_URL=https://api.devnet.solana.com
Get Test Credentials: For Stellar, generate test credentials at laboratory.stellar.org. For Solana, use solana-keygen new.
Initialize the SDK:
import { AttestSDK } from '@attestprotocol/sdk';
import 'dotenv/config';

async function main() {
  console.log('Starting attestation tutorial...');
  
  // Initialize Stellar SDK
  const sdk = await AttestSDK.initializeStellar({
    secretKeyOrCustomSigner: process.env.STELLAR_SECRET_KEY,
    publicKey: process.env.STELLAR_PUBLIC_KEY,
    url: process.env.STELLAR_RPC_URL || 'https://soroban-testnet.stellar.org'
  });

  console.log('Stellar SDK initialized');
}

main().catch(console.error);

Step 3: Register as Authority

Before issuing attestations, you need to register as an authority:
// Add this inside your main() function
try {
  // Check if already registered
  const existingAuthority = await sdk.fetchAuthority();
  
  if (existingAuthority.error) {
    console.log('Registering as authority...');
    const authResult = await sdk.registerAuthority();
    
    if (authResult.error) {
      console.error('Failed to register authority:', authResult.error);
      return;
    }
    
    console.log('Authority registered successfully');
  } else {
    console.log('Already registered as authority');
  }

} catch (error) {
  console.error('Authority registration error:', error);
  return;
}

Step 4: Create a Schema

Schemas define the structure of your attestations:
// Add this after authority registration
try {
  const schemaResult = await sdk.createSchema({
    schemaName: `user-verification-${Date.now()}`,
    schemaContent: 'verified:bool,level:string,score:uint8,timestamp:uint64',
    revocable: true
  });

  if (schemaResult.error) {
    console.error('Schema creation failed:', schemaResult.error);
    return;
  }

  const schemaUID = schemaResult.data.schemaUID;
  console.log('Schema created:', schemaUID);

} catch (error) {
  console.error('Schema creation error:', error);
  return;
}

Step 5: Issue an Attestation

Now let’s create an attestation using our schema:
// Add this after schema creation
try {
  // Example subject address (replace with actual address)
  const subjectAddress = 'GXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
  
  const attestResult = await sdk.attest({
    schemaUID: schemaUID,
    subject: subjectAddress,
    value: 'verified:true,level:enhanced,score:95,timestamp:' + Math.floor(Date.now() / 1000),
    reference: `attestation-${Date.now()}`
  });

  if (attestResult.error) {
    console.error('Attestation failed:', attestResult.error);
    return;
  }

  console.log('Attestation created');
  console.log('Transaction Hash:', attestResult.data);

} catch (error) {
  console.error('Attestation error:', error);
  return;
}

Step 6: Verify the Attestation

The most common operation - checking if a subject has a valid attestation:
// Add this after attestation creation
try {
  // Wait a moment for indexing
  console.log('Waiting for attestation to be indexed...');
  await new Promise(resolve => setTimeout(resolve, 10000));

  const fetchResult = await sdk.fetchAttestation({
    schemaUID: schemaUID,
    subject: subjectAddress
  });

  if (fetchResult.error) {
    console.error('Verification failed:', fetchResult.error);
    return;
  }

  if (fetchResult.data && !fetchResult.data.revoked) {
    console.log('Attestation verified');
    console.log('Attestation data:', fetchResult.data.value);
    console.log('Created at:', new Date(fetchResult.data.timestamp * 1000).toLocaleString());
  } else {
    console.log('No valid attestation found');
  }

} catch (error) {
  console.error('Verification error:', error);
}

Complete Example

Here’s the complete working example for Stellar:
import { AttestSDK } from '@attestprotocol/sdk';
import 'dotenv/config';

async function main() {
  console.log('Starting attestation tutorial...');
  
  try {
    // Initialize SDK
    const sdk = await AttestSDK.initializeStellar({
      secretKeyOrCustomSigner: process.env.STELLAR_SECRET_KEY,
      publicKey: process.env.STELLAR_PUBLIC_KEY,
      url: 'https://soroban-testnet.stellar.org'
    });
    console.log('Stellar SDK initialized');

    // Register as authority
    const existingAuthority = await sdk.fetchAuthority();
    if (existingAuthority.error) {
      const authResult = await sdk.registerAuthority();
      if (authResult.error) throw new Error(authResult.error);
      console.log('Authority registered');
    } else {
      console.log('Already registered as authority');
    }

    // Create schema
    const schemaResult = await sdk.createSchema({
      schemaName: `user-verification-${Date.now()}`,
      schemaContent: 'verified:bool,level:string,score:uint8,timestamp:uint64',
      revocable: true
    });
    if (schemaResult.error) throw new Error(schemaResult.error);
    
    const schemaUID = schemaResult.data.schemaUID;
    console.log('Schema created:', schemaUID);

    // Create attestation
    const subjectAddress = 'GXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
    const attestResult = await sdk.attest({
      schemaUID: schemaUID,
      subject: subjectAddress,
      value: `verified:true,level:enhanced,score:95,timestamp:${Math.floor(Date.now() / 1000)}`,
      reference: `demo-${Date.now()}`
    });
    if (attestResult.error) throw new Error(attestResult.error);
    
    console.log('Attestation created:', attestResult.data);

    // Verify attestation
    console.log('Waiting for indexing...');
    await new Promise(resolve => setTimeout(resolve, 10000));
    
    const fetchResult = await sdk.fetchAttestation({
      schemaUID: schemaUID,
      subject: subjectAddress
    });
    
    if (fetchResult.data && !fetchResult.data.revoked) {
      console.log('Attestation verified');
      console.log('Data:', fetchResult.data.value);
    }

    console.log('Tutorial completed successfully');

  } catch (error) {
    console.error('Error:', error.message);
  }
}

main().catch(console.error);

Run Your Example

Save your code and run it:
node index.js
You should see output like this:
Starting attestation tutorial...

Stellar SDK initialized
Already registered as authority
Schema created: a1b2c3d4e5f6789012345678901234567890123456789012345678901234567890
Attestation created: 5KJp3F2B1Y8Z...
Waiting for indexing...
Attestation verified
Data: verified:true,level:enhanced,score:95,timestamp:1704067200

Tutorial completed successfully

Understanding the Results

Let’s break down what happened:
  • Created a blockchain-specific SDK instance with your credentials
  • Connected to the testnet for safe experimentation
  • Established connection to the AttestProtocol smart contracts
  • Registered your wallet as an authority capable of issuing attestations
  • This is a one-time setup per wallet address
  • Authorities can create schemas and issue attestations
  • Created a reusable template defining the structure of verification data
  • Each schema has a unique UID and defines field types and validation rules
  • Schemas are stored on-chain and can be reused for multiple attestations
  • Created a signed, verifiable claim about a subject’s verification status
  • The attestation is stored on-chain with immutable cryptographic proof
  • Data follows the schema structure with typed fields
  • Retrieved and validated the attestation from the blockchain
  • Checked for active status and parsed the structured data
  • Confirmed the cryptographic integrity of the claim

Next Steps

Now that you’ve created your first attestation, explore these topics:

Common Issues

If you see “insufficient balance” errors:
  • Ensure your wallet has test tokens for transaction fees
  • For Stellar: Use the friendbot to fund your account
  • For Solana: Use solana airdrop 2 to get test SOL
  • Double-check your secret key format and ensure it’s valid
  • For Stellar: Secret keys start with ‘S’ and are 56 characters
  • For Solana: Secret keys are 64-number arrays
  • Never expose secret keys in production code
If you see “schema already exists”:
  • Use a different schema name with a timestamp
  • Or reference the existing schema instead of creating a new one
  • Schema names must be unique per authority
  • Verify your RPC endpoint is accessible
  • Check your internet connection
  • Try switching to a different RPC provider if available
Pro Tip: Save the schema UID from your first run and reuse it in future attestations. You only need to create each schema once per authority!