Developer Documentation
Everything you need to integrate AI attestations into your applications
Table of Contents
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
[](YOUR_VERIFY_URL)
[](YOUR_VERIFY_URL)
[](YOUR_VERIFY_URL)
# With model name
[](YOUR_VERIFY_URL)
[](YOUR_VERIFY_URL)
# With emoji
[](YOUR_VERIFY_URL)
Advanced Customization
# Different styles
[](YOUR_VERIFY_URL)
[](YOUR_VERIFY_URL)
[](YOUR_VERIFY_URL)
# With logos
[](YOUR_VERIFY_URL)
[](YOUR_VERIFY_URL)
# Custom colors (use hex without #)
[](YOUR_VERIFY_URL)
[](YOUR_VERIFY_URL)
Complete README Example
# My Awesome Project
[](https://attest.ink/verify/?data=...)
[](https://opensource.org/licenses/MIT)
[](https://github.com/user/repo/actions)
[](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:
[](YOUR_VERIFY_URL)
[](YOUR_VERIFY_URL)
Creating Your Badge
- Create your attestation at attest.ink/create
- Copy the verification URL from the result page
- Choose a badge style from above
- Replace
YOUR_VERIFY_URL
with your actual verification URL - 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 | |
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
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!
- GitHub Issues: Report bugs or request features
- Email: info@attest.ink
- Documentation: Protocol Specification
- Examples: Live Examples
Contributing: We welcome contributions! Check our GitHub repository for contribution guidelines.