Fan SDK
Drop in. Fan graph included.
The official TypeScript/JavaScript SDK for revolution.fan. Works in browser, SSR, React Native, and Node.js. One import gives you verified fan identity, $FAN balance, attendance history, and real-time event context.
Installation
npm install @revolution/sdk
# or
pnpm add @revolution/sdk
# or
yarn add @revolution/sdkInitialisation
import { Revolution } from '@revolution/sdk';
const rev = new Revolution({
apiKey: 'rev_live_xxxx', // required — get yours at revolution.fan/developers
baseUrl: 'https://api.revolution.fan/api/v1', // default shown
defaultRegion: 'atx', // optional — pre-fills region on all queries
timeout: 10_000, // optional — ms (default 10 000)
authScheme: 'bearer', // optional — see Auth docs
});Events
Discover, search, and retrieve live events. Available on all key tiers.
List events
const { items, total, hasMore } = await rev.events.list({
region: 'atx', // required — region slug
dateFrom: '2026-05-01', // ISO date
dateTo: '2026-05-31',
genre: 'hip-hop', // optional filter
featured: true, // only featured events
page: 1,
pageSize: 20,
});Get a single event
const event = await rev.events.get('khruangbin-stubbs-2026-05-14');
console.log(event.title); // "Khruangbin at Stubb's"
console.log(event.date); // "2026-05-14T21:00:00-05:00"
console.log(event.venue.name); // "Stubb's Outdoor Amphitheater"
console.log(event.ticketUrl); // "https://..."
console.log(event.imageUrl); // hero imageToday & tomorrow feed
const region = await rev.regions.nearest(lat, lng);
const { today, tomorrow } = await rev.events.todayTomorrow(region.slug);Create an open event
Any authenticated user can create a public event in seconds — no venue account required. Ideal for conference side events, community meetups, birthday parties, and anything in between. Every attendee still earns $FAN and receives an on-chain proof of attendance on check-in.
// POST /api/v1/events/quick — requires a valid user Bearer token
const { event } = await rev.events.create({
title: 'DeFi Happy Hour @ Consensus', // required
startTime: '2026-05-23T18:00:00-05:00', // required (ISO 8601)
endTime: '2026-05-23T21:00:00-05:00', // optional
locationText: 'The Rusty Nail, Austin TX', // free-text — or "Online"
description: 'Side event for Consensus attendees. Drinks on us.',
isFree: true, // default true
ticketPrice: undefined, // number (USD) when isFree=false
imageUrl: 'https://...', // optional hero image
});
console.log(event.slug); // auto-generated from title + date
console.log(event.eventType); // "open_event"
// redirect user to: /events/{event.slug}Venues & Artists
// Venue profile + upcoming shows
const venue = await rev.venues.get('stubbs-austin');
const shows = await rev.venues.upcomingShows('stubbs-austin', { limit: 10 });
// Artist profile + tour dates
const artist = await rev.artists.get('khruangbin');
const tour = await rev.artists.tourDates('khruangbin', { region: 'atx' });Commerce
Purchase tickets and auto-mint proof-of-attendance NFTs. Requires Pro or Enterprise key.
// Purchase tickets + optional NFT proof-of-attendance mint
const order = await rev.commerce.purchase({
eventId: 1042,
quantity: 2,
paymentMethodId: 'pm_stripe_xxx', // Stripe payment method ID
buyerEmail: 'fan@example.com',
walletAddress: '0xabc...', // optional — triggers on-chain mint (SKALE, zero gas)
});
console.log(order.status); // 'confirmed'
console.log(order.nftTokenId); // '12345' — minted if walletAddress provided
console.log(order.tickets[0].qrCode); // scan at door
console.log(order.receiptUrl); // PDF receiptLoyalty & $FAN balance
const loyalty = await rev.commerce.loyalty('0xabc...');
console.log(loyalty.tier); // 'superfan'
console.log(loyalty.fanPoints); // 4200 — $FAN balance (off-chain, Phase 1)
console.log(loyalty.nfts); // [ { tokenId, eventTitle, date, imageUrl } ]Marketplace
Query verified fan profiles for label analytics, tour routing, and ad targeting. Requires a Marketplace key (mkt_xxxx) with authScheme: 'marketplace'.
const rev = new Revolution({ apiKey: 'mkt_xxxx', authScheme: 'marketplace' });
// Browse available attributes
const { catalog } = await rev.marketplace.getCatalog({ sortBy: 'available_users' });
// Preview — free, returns match count + cost estimate
const preview = await rev.marketplace.previewQuery({
filters: [
{ key: 'top_genres', operator: 'contains', value: 'hip-hop' },
{ key: 'concerts_attended_12m', operator: 'gte', value: '3' },
{ key: 'city', operator: 'eq', value: 'Los Angeles' },
],
attributes: ['top_genres', 'events_attended_rfan', 'average_ticket_spend'],
queryType: 'aggregated',
regulatoryMax: 'pii_low',
});
console.log(preview.matchedUsers); // 4 200
console.log(preview.estimatedCostUsd); // 8.40
// Execute — charges your account, distributes $FAN to matching fans
const result = await rev.marketplace.executeQuery({
queryId: preview.queryId,
deliveryFormat: 'json',
});Attendance
Venue check-in and QR scanning. Requires a Scanner key.
const rev = new Revolution({ apiKey: 'scan_xxxx', authScheme: 'scanner' });
// Verify a fan's QR ticket
const result = await rev.attendance.verify({
qrCode: '0xdeadbeef...',
eventId: 1042,
gate: 'MAIN',
});
console.log(result.valid); // true
console.log(result.fanId); // 'fan_0xc3f…'
console.log(result.fanName); // 'Jordan' (if fan opted in to name sharing)
console.log(result.nftMinted); // true — proof-of-attendance written on-chainEmbed Widget
Drop a self-contained event listing into any HTML page — no framework required.
<!-- Add to any website -->
<div id="events"></div>
<script src="https://cdn.revolution.fan/sdk/embed.js"></script>
<script>
RevolutionEmbed.mount('#events', {
apiKey: 'rev_live_xxxx',
region: 'atx',
theme: 'dark',
maxEvents: 6,
onTicketClick: (event) => {
// Handle ticket purchase in your own UI
},
});
</script>Error Handling
import { RevolutionError } from '@revolution/sdk';
try {
const event = await rev.events.get('non-existent-slug');
} catch (err) {
if (err instanceof RevolutionError) {
console.log(err.status); // 404
console.log(err.code); // 'EVENT_NOT_FOUND'
console.log(err.message); // human-readable
}
}Python SDK
The official Python client for revolution.fan. Designed for data science workflows, analytics pipelines, and backend services. Works with Pandas, Jupyter, and any Python 3.8+ environment.
Installation
pip install revolution-fanInitialisation
from revolution_fan import RevolutionFanClient
client = RevolutionFanClient(
api_key="rev_live_xxxx", # or set REVOLUTION_FAN_API_KEY env var
base_url="https://api.revolution.fan/api/v1", # default
timeout=30,
)Events
# List events
result = client.events.list(region="atx", featured=True, page_size=20)
for event in result["items"]:
print(event["title"], event["date"])
# Get a single event
event = client.events.get("khruangbin-stubbs-2026-05-14")
print(event["venue"]["name"])Data Marketplace
from revolution_fan import RevolutionFanClient
client = RevolutionFanClient(
api_key="mkt_xxxx",
auth_scheme="marketplace",
)
# Preview a query
preview = client.marketplace.preview_query(
filters=[
{"key": "top_genres", "operator": "contains", "value": "hip-hop"},
{"key": "concerts_attended_12m", "operator": "gte", "value": "3"},
{"key": "city", "operator": "eq", "value": "Los Angeles"},
],
attributes=["top_genres", "events_attended_rfan", "average_ticket_spend"],
query_type="aggregated",
regulatory_max="pii_low",
)
print(preview["matched_users"]) # 4200
print(preview["estimated_cost_usd"]) # 8.40
# Execute
result = client.marketplace.execute_query(
query_id=preview["query_id"],
delivery_format="json",
)
print(result["record_count"]) # 4200
print(result["download_url"]) # signed S3 URLSandbox Mode
# Use sandbox mode to test without a real API key
from revolution_fan import RevolutionFanClient
client = RevolutionFanClient(sandbox=True) # no api_key required
result = client.marketplace.preview_query(
filters=[{"key": "top_genres", "operator": "contains", "value": "hip-hop"}],
attributes=["top_genres", "spend_band"],
query_type="aggregated",
)
# Returns realistic synthetic data — safe to use in notebooks and CIJupyter Notebooks
Four sample notebooks are included in the repo under notebooks/ covering genre affinity segmentation, concert attendance lookalike modelling, cross-vertical fan profiles, and esports sponsor targeting.
# Clone and run locally
git clone https://github.com/tokenevents/revolution-fan
cd revolution-fan/notebooks
jupyter notebookError Handling (Python)
from revolution_fan.exceptions import RevolutionFanError, AuthenticationError, RateLimitError
try:
result = client.marketplace.execute_query(query_id="q_xxx")
except AuthenticationError:
print("Invalid or expired API key")
except RateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after}s")
except RevolutionFanError as e:
print(f"API error {e.status_code}: {e.message}")