Skip to content

Widget API Reference

The main widget component for integrating Proof of Spend into your React application.

interface ProofOfSpendWidgetProps {
apiUrl: string;
onVerified: (data: VerificationData) => void;
onError?: (error: Error) => void;
theme?: 'light' | 'dark';
providers?: Provider[];
className?: string;
}
PropTypeRequiredDefaultDescription
apiUrlstringYes-OAuth backend base URL
onVerified(data: VerificationData) => voidYes-Called when task is verified
onError(error: Error) => voidNoundefinedError handler callback
theme'light' | 'dark'No'light'Widget color theme
providersProvider[]NoAll providersAvailable OAuth providers
classNamestringNo''Custom CSS class
import { ProofOfSpendWidget } from '@proof-of-spend/widget';
function App() {
const handleVerified = (data: VerificationData) => {
console.log('Task completed:', data);
// Store verification proof
};
const handleError = (error: Error) => {
console.error('Widget error:', error);
// Show error to user
};
return (
<ProofOfSpendWidget
apiUrl="https://oauth.example.com"
onVerified={handleVerified}
onError={handleError}
theme="dark"
providers={['openai', 'anthropic']}
/>
);
}

Custom React hook for building your own UI around the Proof of Spend logic.

const {
state,
task,
response,
verificationData,
error,
setResponse,
selectProvider,
fetchNewTask,
submitResponse,
reset,
} = useProofOfSpend(config);
interface UseProofOfSpendConfig {
apiUrl: string;
providers?: Provider[];
}
interface UseProofOfSpendReturn {
// State
state: WidgetState;
task: AnnotationTask | null;
response: string;
verificationData: VerificationData | null;
error: Error | null;
// Actions
setResponse: (response: string) => void;
selectProvider: (provider: Provider) => Promise<void>;
fetchNewTask: () => Promise<void>;
submitResponse: () => Promise<void>;
reset: () => void;
}

The hook uses a state machine with the following states:

type WidgetState =
| 'loading' // Initial state, fetching config
| 'provider-selection' // User selects OAuth provider
| 'task-ready' // Task loaded and ready
| 'submitting' // Submitting response
| 'verifying' // Verifying API call
| 'verified' // Task verified successfully
| 'error'; // Error occurred
import { useProofOfSpend } from '@proof-of-spend/widget';
function CustomWidget() {
const {
state,
task,
response,
setResponse,
selectProvider,
submitResponse,
error,
} = useProofOfSpend({
apiUrl: 'https://oauth.example.com',
});
if (state === 'loading') {
return <div>Loading...</div>;
}
if (state === 'provider-selection') {
return (
<div>
<h2>Select Provider</h2>
<button onClick={() => selectProvider('openai')}>
OpenAI
</button>
<button onClick={() => selectProvider('anthropic')}>
Anthropic
</button>
</div>
);
}
if (state === 'task-ready' && task) {
return (
<div>
<h2>{task.category}</h2>
<p>{task.prompt}</p>
<textarea
value={response}
onChange={(e) => setResponse(e.target.value)}
placeholder="Paste API response here"
/>
<button onClick={submitResponse}>
Submit
</button>
</div>
);
}
if (state === 'error') {
return <div>Error: {error?.message}</div>;
}
return null;
}
type Provider = 'openai' | 'anthropic' | 'google';
interface AnnotationTask {
id: string;
category: string;
prompt: string;
examples?: string[];
metadata?: Record<string, unknown>;
}
interface VerificationData {
taskId: string;
response: string;
provider: Provider;
cost: number;
timestamp: string;
proof: {
accessToken: string;
apiCallHash: string;
signature: string;
};
}
interface WidgetError extends Error {
code: string;
details?: unknown;
}

Error Codes:

  • PROVIDER_AUTH_FAILED: OAuth authorization failed
  • TASK_FETCH_FAILED: Failed to fetch annotation task
  • SUBMISSION_FAILED: Failed to submit response
  • VERIFICATION_FAILED: Failed to verify API call
  • NETWORK_ERROR: Network request failed

Low-level API client for direct integration.

const api = new ProofOfSpendAPI(baseUrl: string);

Fetch an annotation task.

async fetchTask(accessToken: string): Promise<AnnotationTask>

Example:

const task = await api.fetchTask('ACCESS_TOKEN');
console.log(task.prompt);

Submit an annotation response.

async submitAnnotation(
taskId: string,
response: string,
accessToken: string
): Promise<VerificationData>

Example:

const verification = await api.submitAnnotation(
'task_123',
'API response text',
'ACCESS_TOKEN'
);
console.log(verification.proof);

Get available annotation categories.

async getCategories(): Promise<string[]>

Example:

const categories = await api.getCategories();
console.log(categories); // ['sentiment', 'classification', ...]

The widget uses CSS modules and can be customized via CSS variables:

.proof-of-spend-widget {
--widget-bg: #ffffff;
--widget-text: #000000;
--widget-primary: #0066cc;
--widget-border: #e0e0e0;
--widget-radius: 8px;
}
.proof-of-spend-widget[data-theme="dark"] {
--widget-bg: #1a1a1a;
--widget-text: #ffffff;
--widget-primary: #3399ff;
--widget-border: #333333;
}

The widget emits custom events that can be listened to:

// Listen for state changes
widget.addEventListener('statechange', (event) => {
console.log('New state:', event.detail.state);
});
// Listen for task loaded
widget.addEventListener('taskloaded', (event) => {
console.log('Task:', event.detail.task);
});
// Listen for verification complete
widget.addEventListener('verified', (event) => {
console.log('Verification:', event.detail.data);
});