Developer Documentation

Everything you need to integrate AI attestations into your applications

Quick Start

Get up and running with AI attestations in under 5 minutes.

1. Create an Attestation

The simplest way to create an attestation is through our web interface:

https://attest.ink/create/

Or programmatically via our API:

curl -s "https://attest.ink/api/create.html?content_name=My%20Article&model=gpt-4&role=assisted"

2. Embed a Badge

Add this HTML to your page:

<a href="https://attest.ink/verify/?data=eyJ2ZXJzaW9uIj..." target="_blank">
    <img src="https://attest.ink/assets/badges/gpt-4-generated.svg" alt="AI Generated" />
</a>

3. Verify

Click any badge to verify the attestation, or use the API:

// Decode the base64 data parameter
const attestation = JSON.parse(atob(dataParam));

// Verify structure and required fields
if (attestation.version && attestation.id && attestation.content_name) {
    console.log('Valid attestation');
}

Offline Functionality & Embed Badges

attest.ink is designed to work both online and offline, providing flexibility for different use cases.

How Embed Badges Work Offline

Embed badges are self-contained HTML snippets that include the complete attestation data. This design enables:

  • No External Dependencies: The badge contains all necessary data encoded in base64
  • Offline Verification: Anyone can verify the attestation without internet access
  • Permanent Availability: The attestation remains valid even if attest.ink is offline
  • Privacy: No external requests are made when displaying the badge

Embed Badge Structure

<a href="https://attest.ink/verify/?data=eyJ2ZXJzaW9uIj..." 
   target="_blank" 
   style="text-decoration: none; display: inline-flex;">
    <img src="data:image/svg+xml;base64,..." 
         alt="AI GENERATED" 
         style="height: 32px;" />
</a>

The embed badge consists of:

  • Verification Link: Contains the full attestation data as a base64-encoded parameter
  • Badge Image: SVG image embedded as a data URL (no external image loading)
  • Styling: Inline styles ensure consistent appearance

Local Storage

When creating attestations:

  • Attestations are saved to browser localStorage with key attestation-{id}
  • This enables verification of short URLs on the same device/browser
  • localStorage is isolated per browser and domain

Sharing Attestations

For cross-device sharing, use these methods:

Method Offline Support Best For
Embed Badge ✅ Full Websites, documentation, permanent records
Data URL ✅ Full Direct sharing, email, messaging
JSON Export ✅ Full Archival, bulk processing, custom integrations
Short URL ⚠️ Limited Same-device verification (server storage coming soon)

API Reference

All API endpoints are client-side only and run entirely in your browser.

Create Attestation

GET /api/create.html

Parameters

Parameter Type Required Description
content_name string Yes Name or title of the content
content string No The actual content (for hash generation)
model string No AI model ID (default: gpt-4)
role string No generated | assisted | edited | human (default: assisted)
document_type string No Type of content (default: text)
author string No Author name
prompt string No The prompt used with the AI
prompt_private boolean No Hash the prompt instead of storing it
output string No json | curl (default: json)

Example Request

GET /api/create.html?content_name=Blog%20Post&model=claude-3-opus&role=assisted&author=Jane%20Smith

Example Response

{
    "success": true,
    "attestation": {
        "version": "2.0",
        "id": "2025-01-16-abc123",
        "content_name": "Blog Post",
        "model": "claude-3-opus",
        "role": "assisted",
        "author": "Jane Smith",
        "timestamp": "2025-01-16T10:30:00Z",
        "platform": "attest.ink"
    },
    "urls": {
        "short": "https://attest.ink/verify/?id=2025-01-16-abc123",
        "full": "https://attest.ink/verify/?data=eyJ2ZXJzaW9uIj..."
    }
}

Verify Attestation

Verification happens client-side by decoding and validating the attestation data.

URL Parameters

Parameter Description
data Base64-encoded attestation JSON
id Short attestation ID (requires localStorage)
url URL to fetch attestation JSON from

Badge Generation

Generate badges dynamically using our JavaScript API.

// Include the badge renderer
<script src="https://attest.ink/static/badge-renderer.js"></script>

// Create a badge programmatically
const svg = AttestInk.createBadgeSVG('gpt-4', 'generated');
document.getElementById('badge').innerHTML = svg;

JavaScript SDK

The attest.ink JavaScript SDK provides utilities for creating and verifying attestations.

Installation

<script src="https://attest.ink/static/attestation-tool.js"></script>
<script src="https://attest.ink/static/badge-renderer.js"></script>

Core Functions

AttestInk.createBadgeSVG(modelId, role)

Creates an SVG badge for the specified model and role.

const badge = AttestInk.createBadgeSVG('gpt-4-turbo', 'assisted');
// Returns: <svg...>...</svg>

AttestInk.getBadgeUrl(modelId)

Returns the URL for a pre-rendered badge SVG.

const url = AttestInk.getBadgeUrl('claude-3-opus');
// Returns: https://attest.ink/assets/badges/claude-3-opus.svg

AttestInk.renderBadges()

Automatically renders all badges on the page with class ai-attest-badge.

<div class="ai-attest-badge" 
     data-model="gpt-4" 
     data-role="generated"
     data-attestation-url="/attestation.json">
</div>

<script>
    AttestInk.renderBadges();
</script>

AttestInk.verifyAttestation(attestation)

Validates an attestation object structure.

const isValid = AttestInk.verifyAttestation(attestationObject);
// Returns: { valid: boolean, errors: string[] }

AttestInk.calculateHash(content)

Calculates SHA-256 hash of content.

const hash = await AttestInk.calculateHash('Hello, world!');
// Returns: sha256:315f5bdb76d078c43b8ac0064e4a0164...

Integration Guides

HTML/CSS Integration

The simplest way to add attestation badges to any HTML page.

Static Badge

<!-- Simple image badge -->
<a href="https://attest.ink/verify/?data=..." target="_blank">
    <img src="https://attest.ink/assets/badges/ai-generated.svg" 
         alt="AI Generated" 
         width="140" 
         height="30" />
</a>

Dynamic Badge

<!-- Dynamic badge with attestation data -->
<div class="ai-attest-badge" 
     data-attestation-url="https://example.com/attestation.json">
</div>

<script src="https://attest.ink/static/badge-renderer.js"></script>
<script>
    document.addEventListener('DOMContentLoaded', function() {
        AttestInk.renderBadges();
    });
</script>

Custom Styling

/* Position badge in bottom right */
.ai-badge-container {
    position: relative;
}

.ai-badge-container .ai-attest-badge {
    position: absolute;
    bottom: 10px;
    right: 10px;
}

README/Markdown Integration

Add AI attestation badges to your README files and documentation. Two styles available:

Shields.io Style (Recommended for GitHub)

These badges match the standard GitHub badge style and work great alongside build status, license, and other project badges.

Basic Examples
# Standard badge styles
[![AI Assisted](https://img.shields.io/badge/AI-Assisted-blue)](YOUR_VERIFY_URL)
[![AI Generated](https://img.shields.io/badge/AI-Generated-green)](YOUR_VERIFY_URL)
[![AI Edited](https://img.shields.io/badge/AI-Edited-yellow)](YOUR_VERIFY_URL)

# With model name
[![GPT-4 Assisted](https://img.shields.io/badge/AI-GPT--4_Assisted-blue)](YOUR_VERIFY_URL)
[![Claude 3 Opus](https://img.shields.io/badge/AI-Claude_3_Opus-purple)](YOUR_VERIFY_URL)

# With emoji
[![🤖 AI Assisted](https://img.shields.io/badge/🤖_AI-Assisted-blue)](YOUR_VERIFY_URL)
Advanced Customization
# Different styles
[![AI Assisted](https://img.shields.io/badge/AI-Assisted-blue?style=flat-square)](YOUR_VERIFY_URL)
[![AI Assisted](https://img.shields.io/badge/AI-Assisted-blue?style=for-the-badge)](YOUR_VERIFY_URL)
[![AI Assisted](https://img.shields.io/badge/AI-Assisted-blue?style=plastic)](YOUR_VERIFY_URL)

# With logos
[![AI Assisted](https://img.shields.io/badge/AI-Assisted-blue?logo=openai&logoColor=white)](YOUR_VERIFY_URL)
[![AI Assisted](https://img.shields.io/badge/AI-Assisted-blue?logo=anthropic&logoColor=white)](YOUR_VERIFY_URL)

# Custom colors (use hex without #)
[![AI Magic](https://img.shields.io/badge/AI-Magic-ff69b4)](YOUR_VERIFY_URL)
[![AI Powered](https://img.shields.io/badge/AI-Powered-blueviolet)](YOUR_VERIFY_URL)
Complete README Example
# My Awesome Project

[![AI Assisted](https://img.shields.io/badge/AI-Assisted-blue)](https://attest.ink/verify/?data=...)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Build Status](https://github.com/user/repo/actions/workflows/ci.yml/badge.svg)](https://github.com/user/repo/actions)
[![GitHub stars](https://img.shields.io/github/stars/user/repo.svg?style=social)](https://github.com/user/repo)

This project was built with AI assistance...

attest.ink Native Badges

Use our pixel-art style badges for a unique, retro look:

[![AI Generated](https://attest.ink/assets/badges/gpt-4-generated.svg)](YOUR_VERIFY_URL)
[![AI Assisted](https://attest.ink/assets/badges/claude-3-opus-assisted.svg)](YOUR_VERIFY_URL)

Creating Your Badge

  1. Create your attestation at attest.ink/create
  2. Copy the verification URL from the result page
  3. Choose a badge style from above
  4. Replace YOUR_VERIFY_URL with your actual verification URL
  5. Add to your README.md file

React Integration

Create a reusable React component for attestation badges.

import React, { useEffect, useRef } from 'react';

const AIAttestationBadge = ({ attestationUrl, model = 'gpt-4', role = 'assisted' }) => {
    const badgeRef = useRef(null);

    useEffect(() => {
        // Load the badge renderer script
        const script = document.createElement('script');
        script.src = 'https://attest.ink/static/badge-renderer.js';
        script.onload = () => {
            if (window.AttestInk && badgeRef.current) {
                badgeRef.current.innerHTML = window.AttestInk.createBadgeSVG(model, role);
            }
        };
        document.body.appendChild(script);

        return () => {
            document.body.removeChild(script);
        };
    }, [model, role]);

    return (
        <a href={`https://attest.ink/verify/?url=${encodeURIComponent(attestationUrl)}`} 
           target="_blank" 
           rel="noopener noreferrer">
            <div ref={badgeRef} />
        </a>
    );
};

export default AIAttestationBadge;

Usage

<AIAttestationBadge 
    attestationUrl="/attestations/blog-post.json"
    model="claude-3-opus"
    role="assisted"
/>

Vue.js Integration

Vue component for attestation badges.

<template>
    <a :href="verifyUrl" target="_blank" class="ai-attestation-badge">
        <div ref="badge"></div>
    </a>
</template>

<script>
export default {
    name: 'AIAttestationBadge',
    props: {
        attestationUrl: String,
        model: {
            type: String,
            default: 'gpt-4'
        },
        role: {
            type: String,
            default: 'assisted'
        }
    },
    computed: {
        verifyUrl() {
            return `https://attest.ink/verify/?url=${encodeURIComponent(this.attestationUrl)}`;
        }
    },
    mounted() {
        this.loadBadgeRenderer();
    },
    methods: {
        async loadBadgeRenderer() {
            // Load script if not already loaded
            if (!window.AttestInk) {
                await this.loadScript('https://attest.ink/static/badge-renderer.js');
            }
            
            // Create badge
            if (window.AttestInk) {
                this.$refs.badge.innerHTML = window.AttestInk.createBadgeSVG(this.model, this.role);
            }
        },
        loadScript(src) {
            return new Promise((resolve, reject) => {
                const script = document.createElement('script');
                script.src = src;
                script.onload = resolve;
                script.onerror = reject;
                document.body.appendChild(script);
            });
        }
    }
}
</script>

WordPress Integration

Add AI attestation badges to your WordPress site.

Shortcode Implementation

// Add to your theme's functions.php or a custom plugin

function ai_attestation_badge_shortcode($atts) {
    $atts = shortcode_atts(array(
        'model' => 'gpt-4',
        'role' => 'assisted',
        'url' => '',
        'data' => ''
    ), $atts);
    
    $verify_url = 'https://attest.ink/verify/';
    if ($atts['data']) {
        $verify_url .= '?data=' . $atts['data'];
    } elseif ($atts['url']) {
        $verify_url .= '?url=' . urlencode($atts['url']);
    }
    
    $badge_url = "https://attest.ink/assets/badges/{$atts['model']}-{$atts['role']}.svg";
    
    return sprintf(
        '<a href="%s" target="_blank" class="ai-attestation-badge">
            <img src="%s" alt="AI %s with %s" width="140" height="30" />
        </a>',
        esc_url($verify_url),
        esc_url($badge_url),
        ucfirst($atts['role']),
        strtoupper($atts['model'])
    );
}
add_shortcode('ai_badge', 'ai_attestation_badge_shortcode');

Usage in Posts

[ai_badge model="claude-3-opus" role="assisted" url="https://example.com/attestation.json"]

Gutenberg Block

// Register block in your plugin
registerBlockType('attest-ink/badge', {
    title: 'AI Attestation Badge',
    icon: 'shield',
    category: 'common',
    attributes: {
        model: { type: 'string', default: 'gpt-4' },
        role: { type: 'string', default: 'assisted' },
        attestationUrl: { type: 'string' }
    },
    edit: (props) => {
        // Block editor UI
    },
    save: (props) => {
        // Frontend render
    }
});

Schema Reference

Complete reference for the attestation schema version 2.0.

Schema Structure

{
    "version": "2.0",                    // Required: Schema version
    "id": "2025-01-16-abc123",          // Required: Unique identifier
    "content_name": "Blog Post Title",   // Required: Human-readable name
    "content_hash": "sha256:...",        // Optional: SHA-256 hash of content
    "document_type": "markdown",         // Required: Type of document
    "model": "gpt-4-turbo",             // Required: AI model identifier or "human"
    "role": "assisted",                  // Required: generated|assisted|edited|human
    "author": "Jane Smith",              // Optional: Human author
    "timestamp": "2025-01-16T10:30:00Z", // Required: ISO 8601 timestamp
    "platform": "attest.ink",            // Required: Platform identifier
    "prompt": "Write about...",          // Optional: AI prompt used
    "prompt_hash": "sha256:...",         // Optional: Hashed prompt
    "signature": {                       // Optional: Digital signature
        "type": "ethereum|local|hmac-sha256", // Signature type
        "value": "0x...",                // Signature value
        "signer": "0x...",               // Signer address (ethereum)
        "algorithm": "HMAC-SHA256",      // Algorithm (hmac-sha256)
        "data_to_sign": "{...}"          // Data structure signed (hmac-sha256)
        "message": "{...}"               // Signed message
    },
    "signer": {                          // Optional: Signer info (hmac-sha256)
        "name": "Austin Harshberger",    // Signer name
        "id": "97115104"                 // Optional: Signer ID
    },
    "generation_type": "human|ai"        // Optional: Generation type
}

Document Types

Type Description File Extensions
text Plain text .txt
markdown Markdown formatted text .md
html HTML documents .html, .htm
code Source code .js, .py, .java, etc.
image Image files .jpg, .png, .gif, etc.
audio Audio files .mp3, .wav, etc.
video Video files .mp4, .mov, etc.
pdf PDF documents .pdf
latex LaTeX documents .tex

Signature Types

Attestations can be signed using different methods:

Type Description Required Fields
ethereum Ethereum wallet signature (MetaMask, etc.) signature.value, signature.signer
local Password-based signature (client-side) signature.value, signature.salt
hmac-sha256 HMAC-SHA256 signature (server-side) signature.value, signer.name
none No signature (unsigned attestation) N/A

HMAC-SHA256 Signature Details

For server-side HMAC signing, the data structure to sign is:

const dataToSign = JSON.stringify({
    content_name: attestation.content_name,
    content_hash: attestation.content_hash,
    timestamp: attestation.timestamp,
    model: attestation.model
});

// Server-side signing
const signature = crypto
    .createHmac('sha256', signingKey)
    .update(dataToSign)
    .digest('hex');

AI Model Registry

Access the complete list of supported AI models:

// Get all supported models
const models = window.AI_MODELS;

// Example structure
{
    "openai": {
        "name": "OpenAI",
        "models": [
            {
                "id": "gpt-4-turbo-2024-04-09",
                "name": "GPT-4 Turbo (Apr 2024)",
                "color": "#74aa9c"
            },
            // ... more models
        ]
    },
    // ... more providers
}

Security Considerations

Important: Always validate attestations on the client side. Never trust attestation data without verification.

Content Hash Verification

Always verify content hashes when possible:

async function verifyContentHash(content, expectedHash) {
    const encoder = new TextEncoder();
    const data = encoder.encode(content);
    const hashBuffer = await crypto.subtle.digest('SHA-256', data);
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    const calculatedHash = 'sha256:' + hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
    
    return calculatedHash === expectedHash;
}

Signature Verification

For Ethereum wallet signatures:

async function verifyWalletSignature(attestation) {
    if (!attestation.signature || attestation.signature.type !== 'wallet') {
        return false;
    }
    
    const message = attestation.signature.message;
    const signature = attestation.signature.value;
    const expectedSigner = attestation.signature.signer;
    
    // Using ethers.js
    const recoveredAddress = ethers.utils.verifyMessage(message, signature);
    return recoveredAddress.toLowerCase() === expectedSigner.toLowerCase();
}

Best Practices

  • Always use HTTPS when fetching attestations
  • Validate all required fields before trusting an attestation
  • Implement rate limiting for API requests
  • Store sensitive prompts as hashes, not plain text
  • Use Content Security Policy (CSP) headers
  • Sanitize any user-provided content before display

Code Examples

Complete HTML Example

<!DOCTYPE html>
<html>
<head>
    <title>Blog Post with AI Attestation</title>
    <style>
        .article-footer {
            margin-top: 40px;
            padding-top: 20px;
            border-top: 1px solid #ddd;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
    </style>
</head>
<body>
    <article>
        <h1>Understanding Quantum Computing</h1>
        <p>Content here...</p>
        
        <div class="article-footer">
            <span>Published: January 16, 2025</span>
            <a href="https://attest.ink/verify/?data=eyJ2ZXJzaW9uIj..." target="_blank">
                <img src="https://attest.ink/assets/badges/gpt-4-assisted.svg" 
                     alt="AI Assisted with GPT-4" 
                     width="140" 
                     height="30" />
            </a>
        </div>
    </article>
</body>
</html>

Node.js Script Example

const fs = require('fs');
const crypto = require('crypto');
const fetch = require('node-fetch');

async function createAttestation(contentPath, options = {}) {
    // Read content
    const content = fs.readFileSync(contentPath, 'utf8');
    
    // Calculate hash
    const hash = crypto.createHash('sha256');
    hash.update(content);
    const contentHash = 'sha256:' + hash.digest('hex');
    
    // Create attestation
    const params = new URLSearchParams({
        content_name: options.title || 'Untitled',
        content: content,
        model: options.model || 'gpt-4',
        role: options.role || 'assisted',
        author: options.author || 'Anonymous'
    });
    
    const response = await fetch(`https://attest.ink/api/create.html?${params}`);
    const result = await response.json();
    
    // Save attestation
    fs.writeFileSync(
        contentPath.replace(/\.[^.]+$/, '.attestation.json'),
        JSON.stringify(result.attestation, null, 2)
    );
    
    console.log('Attestation created:', result.urls.full);
    return result;
}

// Usage
createAttestation('./blog-post.md', {
    title: 'My Blog Post',
    model: 'claude-3-opus',
    role: 'assisted',
    author: 'Jane Smith'
});

Python Example

import hashlib
import json
import requests
from datetime import datetime
import base64

def create_attestation(content_name, content=None, **kwargs):
    """Create an AI attestation for content"""
    
    # Calculate content hash if content provided
    content_hash = None
    if content:
        hash_obj = hashlib.sha256(content.encode('utf-8'))
        content_hash = f"sha256:{hash_obj.hexdigest()}"
    
    # Build attestation
    attestation = {
        "version": "2.0",
        "id": f"{datetime.now().strftime('%Y-%m-%d')}-{hashlib.md5(content_name.encode()).hexdigest()[:6]}",
        "content_name": content_name,
        "content_hash": content_hash,
        "model": kwargs.get("model", "gpt-4"),
        "role": kwargs.get("role", "assisted"),
        "timestamp": datetime.utcnow().isoformat() + "Z",
        "platform": "attest.ink"
    }
    
    # Add optional fields
    for field in ["author", "document_type", "prompt"]:
        if field in kwargs:
            attestation[field] = kwargs[field]
    
    # Create verification URL
    attestation_json = json.dumps(attestation)
    encoded = base64.b64encode(attestation_json.encode()).decode()
    verify_url = f"https://attest.ink/verify/?data={encoded}"
    
    return {
        "attestation": attestation,
        "verify_url": verify_url
    }

# Usage
result = create_attestation(
    "My Research Paper",
    content="Full paper content here...",
    model="claude-3-opus",
    role="assisted",
    author="Dr. Smith"
)

print(f"Verify at: {result['verify_url']}")

Troubleshooting

Common Issues

Badge not displaying

Problem: Badge doesn't appear on the page

Solutions:

  • Ensure the badge renderer script is loaded: <script src="https://attest.ink/static/badge-renderer.js">
  • Check browser console for errors
  • Verify the badge container has the correct class: ai-attest-badge
  • Call AttestInk.renderBadges() after DOM is loaded

404 Error on Short URLs

Problem: Short attestation URLs return 404

Solutions:

  • Short URLs only work in the same browser where the attestation was created
  • Use the full data URL for sharing: ?data=...
  • Save and host the attestation JSON file

CORS Errors

Problem: Cannot fetch attestation from external URL

Solutions:

  • Ensure the server hosting the attestation allows CORS
  • Add appropriate CORS headers: Access-Control-Allow-Origin: *
  • Use the data URL method instead of fetching

Debugging Tips

// Enable debug logging
window.ATTEST_INK_DEBUG = true;

// Check if attestation is valid
console.log('Attestation valid?', AttestInk.verifyAttestation(attestation));

// Manually create and log badge
const badge = AttestInk.createBadgeSVG('gpt-4', 'generated');
console.log('Badge SVG:', badge);

// Check available models
console.log('Available models:', Object.keys(window.AI_MODELS));

Getting Help

Need assistance? We're here to help!

Contributing: We welcome contributions! Check our GitHub repository for contribution guidelines.