@proofchain/partner-sdk
v1.4.1
Published
ProofChain Partner SDK for integrating with campaign data
Maintainers
Readme
ProofChain Partner SDK
SDK for partners to integrate with ProofChain campaigns. Provides methods for:
- OTT authentication — redeem one-time tokens to verify user identity from redirects
- Fetching campaign configuration with dynamic feedback schemas
- Checking user consent status
- Querying user data views
- Submitting feedback events with schema validation
Installation
npm install @proofchain/partner-sdkQuick Start
OTT Authentication (Redeem a One-Time Token)
If your app receives users via redirect from a ProofChain tenant, use OTT to verify their identity:
import { ProofChainPartner } from '@proofchain/partner-sdk';
const partner = new ProofChainPartner({
partnerKey: 'pk_live_xxx', // from Portal > Integrators > Partner Keys
});
// In your redirect callback handler
const session = await partner.redeemOTT(req.query.ott);
session.user_id; // stable ProofChain user identifier
session.session_data; // non-PII fields (e.g. display_name, avatar)
session.session_timeout; // seconds until session expires
session.jwt; // signed HS256 JWT (if redemption mode = "jwt")Campaign Data Queries
If your app also queries campaign data, provide both keys:
const partner = new ProofChainPartner({
partnerKey: 'pk_live_xxx', // for OTT redemption
apiKey: 'ik_live_xxx', // for campaign data queries
campaignId: 'your-campaign-uuid', // for campaign data queries
});
// Get campaign configuration (includes feedback schemas)
const config = await partner.getConfig();
console.log('Available views:', config.data_views);
console.log('Feedback types:', config.feedback.types);
// Check if user has consented
const consent = await partner.checkConsent('user_123');
if (!consent.has_consent) {
// Redirect to consent page
const consentUrl = partner.getConsentUrl('user_123', {
redirectUrl: 'https://your-site.com/callback'
});
window.location.href = consentUrl;
}
// Query user data
const profile = await partner.getUserProfile('user_123');
console.log('User profile:', profile.data);
// Submit feedback event
const result = await partner.submitFeedback('user_123', 'purchase', {
amount: 99.99,
currency: 'USD',
product_id: 'ticket-123'
});
console.log('Feedback submitted:', result.feedback_id);Dynamic Feedback Schemas
Each campaign can define custom feedback types with their own schemas. The SDK provides methods to discover and validate against these schemas:
// Get all available feedback types
const feedbackTypes = await partner.getFeedbackTypes();
// Returns: [
// {
// type: 'purchase',
// name: 'Purchase',
// description: 'Track when a user makes a purchase',
// schema: {
// type: 'object',
// properties: {
// amount: { type: 'number', minimum: 0 },
// currency: { type: 'string', enum: ['USD', 'EUR', 'GBP', 'ZAR'] },
// product_id: { type: 'string' }
// },
// required: ['amount', 'currency']
// }
// },
// ...
// ]
// Get schema for a specific feedback type
const purchaseSchema = await partner.getFeedbackSchema('purchase');
// Validate data before submitting
const validation = await partner.validateFeedback('purchase', {
amount: 99.99,
currency: 'INVALID'
});
if (!validation.valid) {
console.error('Validation errors:', validation.errors);
}React Integration
The SDK includes React components and hooks:
import {
PartnerProvider,
usePartner,
ConsentWidget,
FeedbackForm
} from '@proofchain/partner-sdk/react';
function App() {
return (
<PartnerProvider config={{
apiKey: 'ik_live_xxx',
campaignId: 'your-campaign-uuid',
}}>
<MyComponent />
</PartnerProvider>
);
}
function MyComponent() {
const { partner, config, loading } = usePartner();
if (loading) return <div>Loading...</div>;
return (
<div>
<h1>{config?.campaign_name}</h1>
{/* Consent widget */}
<ConsentWidget
partner={partner}
userId="user_123"
onSuccess={(consent) => console.log('Consented!', consent)}
onCancel={() => console.log('Cancelled')}
/>
{/* Dynamic feedback form */}
<FeedbackForm
partner={partner}
userId="user_123"
feedbackType="purchase"
onSuccess={(result) => console.log('Submitted!', result)}
/>
</div>
);
}OTT Integration Examples
Express.js
import express from 'express';
import { ProofChainPartner } from '@proofchain/partner-sdk';
const app = express();
const partner = new ProofChainPartner({
partnerKey: process.env.PROOFCHAIN_PARTNER_KEY!,
});
// Handle the redirect from the tenant app
app.get('/auth/callback', async (req, res) => {
const { ott } = req.query;
if (!ott) return res.redirect('/login?error=missing_token');
try {
const session = await partner.redeemOTT(ott as string);
// Create your own session from the verified identity
req.session.userId = session.user_id;
req.session.displayName = session.session_data.display_name;
res.redirect('/dashboard');
} catch (err) {
// OTT is single-use — if already redeemed, returns 404
console.error('OTT redemption failed:', err);
res.redirect('/login?error=invalid_token');
}
});Next.js (App Router)
// app/api/auth/ott/route.ts
import { ProofChainPartner } from '@proofchain/partner-sdk';
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';
const partner = new ProofChainPartner({
partnerKey: process.env.PROOFCHAIN_PARTNER_KEY!,
});
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const ott = searchParams.get('ott');
if (!ott) return redirect('/login?error=missing_token');
try {
const session = await partner.redeemOTT(ott);
if (session.jwt) {
const cookieStore = await cookies();
cookieStore.set('session', session.jwt, {
httpOnly: true,
secure: true,
maxAge: session.session_timeout,
});
}
return redirect('/dashboard');
} catch {
return redirect('/login?error=invalid_token');
}
}Full Flow: OTT + Campaign Data
const partner = new ProofChainPartner({
partnerKey: 'pk_live_xxx',
apiKey: 'ik_live_xxx',
campaignId: 'campaign-uuid',
});
// 1. Redeem the OTT to identify the user
const session = await partner.redeemOTT(ott);
// 2. Query their campaign data
const profile = await partner.queryView(session.user_id, 'fan_profile');
const activity = await partner.getActivitySummary(session.user_id);
// 3. Submit feedback based on their actions
await partner.submitFeedback(session.user_id, 'page_visit', {
page: '/dashboard',
referrer: 'ott_redirect',
});API Reference
ProofChainPartner
Constructor
new ProofChainPartner({
partnerKey?: string, // Partner key (pk_live_xxx) — required for OTT
apiKey?: string, // Integrator key (ik_live_xxx) — required for campaign operations
campaignId?: string, // Campaign UUID — required for campaign operations
baseUrl?: string, // API base URL (default: https://api.proofchain.io)
timeout?: number, // Request timeout in ms (default: 30000)
debug?: boolean, // Enable debug logging
})At least one of partnerKey or apiKey must be provided.
Methods
OTT Authentication
| Method | Description |
|--------|-------------|
| redeemOTT(ott) | Redeem a one-time token. Returns { user_id, session_data, session_timeout, jwt? }. Requires partnerKey. |
Campaign Operations (require apiKey + campaignId)
| Method | Description |
|--------|-------------|
| getConfig() | Get campaign configuration including feedback schemas |
| getAvailableViews() | Get list of available data views |
| getFeedbackTypes() | Get available feedback types with schemas |
| getFeedbackSchema(type) | Get schema for a specific feedback type |
| checkConsent(userId) | Check if user has consented |
| getConsentUrl(userId, options?) | Get URL for consent widget |
| queryView(userId, viewName) | Query a data view |
| getUserProfile(userId) | Get user's fan profile |
| getActivitySummary(userId) | Get user's activity summary |
| getEvents(userId) | Get user's recent events |
| submitFeedback(userId, type, data) | Submit a feedback event |
| validateFeedback(type, data) | Validate feedback data against schema |
Error Handling
All methods throw PartnerError on failure:
interface PartnerError {
status: number; // HTTP status code
code: string; // Error code
message: string; // Human-readable message
details?: object; // Additional details
}Common error codes:
TIMEOUT- Request timed out (client-side, configurable viatimeoutoption)INVALID_FEEDBACK_TYPE- Feedback type not allowed for this campaignMISSING_REQUIRED_FIELDS- Required fields missing from feedback dataCONSENT_REQUIRED- User has not consented to data sharingRATE_LIMITED- Too many requests
OTT-specific errors:
- HTTP 404 — Token not found (expired or already redeemed)
- HTTP 403 — Partner key does not match the key that created the token
- HTTP 422 — Missing or invalid
ottparameter
License
MIT
