Skip to main content

Prerequisites

Before you start, make sure you have:
Merchant account at dashboard.eventop.xyz
At least one subscription plan created
API key from the dashboard
Solana wallet address (we can help you create one)

Step 1: Install SDK (Optional)

If you’re using Node.js, install our SDK for easier integration:
npm install @eventop/sdk
SDKs for other languages are coming soon. For now, use direct HTTP requests to our API (see API Reference).

Step 2: Configure API Client

Node.js/TypeScript

import { Eventop } from '@eventop/sdk';

const eventop = new Eventop({
  apiKey: process.env.EVENTOP_API_KEY,
  environment: 'devnet' // or 'mainnet' for production
});

Direct HTTP (Any Language)

const EVENTOP_API_URL = 'https://api.eventop.xyz';
const API_KEY = process.env.EVENTOP_API_KEY;

async function createCheckout(data) {
  const response = await fetch(`${EVENTOP_API_URL}/checkout/create`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${API_KEY}`
    },
    body: JSON.stringify(data)
  });
  
  return response.json();
}
Never expose your API key in frontend code! Always call our API from your backend.

Step 3: Create Subscription Endpoint

Create an endpoint on your server that generates checkout sessions.
app.post('/api/create-subscription', async (req, res) => {
  try {
    // Get user from session/auth
    const user = req.user;
    const { planId } = req.body;
    
    // Create checkout session
    const session = await eventop.checkout.create({
      merchantWallet: process.env.MERCHANT_WALLET,
      planId: planId,
      customerEmail: user.email,
      customerId: user.id.toString(),
      successUrl: `${process.env.BASE_URL}/subscription/success`,
      cancelUrl: `${process.env.BASE_URL}/pricing`,
      metadata: {
        userId: user.id,
        userName: user.name,
        source: 'web_pricing_page'
      }
    });
    
    // Redirect to checkout
    res.json({ checkoutUrl: session.url });
    
  } catch (error) {
    console.error('Checkout creation failed:', error);
    res.status(500).json({ error: 'Failed to create checkout session' });
  }
});

Step 4: Add Subscribe Button to Frontend

Update your pricing page or subscription form to call your backend endpoint.
import { useState } from 'react';

export function SubscribeButton({ planId, planName }) {
  const [loading, setLoading] = useState(false);
  
  const handleSubscribe = async () => {
    setLoading(true);
    
    try {
      const response = await fetch('/api/create-subscription', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ planId })
      });
      
      const { checkoutUrl } = await response.json();
      
      // Redirect to checkout
      window.location.href = checkoutUrl;
      
    } catch (error) {
      console.error('Subscription failed:', error);
      alert('Failed to start checkout. Please try again.');
    } finally {
      setLoading(false);
    }
  };
  
  return (
    <button 
      onClick={handleSubscribe}
      disabled={loading}
      className="subscribe-button"
    >
      {loading ? 'Loading...' : `Subscribe to ${planName}`}
    </button>
  );
}

Step 5: Setup Webhook Endpoint

Create an endpoint to receive subscription events.
const crypto = require('crypto');

app.post('/webhooks/eventop', express.raw({ type: 'application/json' }), async (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const timestamp = req.headers['x-webhook-timestamp'];
  const webhookId = req.headers['x-webhook-id'];
  
  // Verify signature
  const payload = req.body.toString();
  const expectedSignature = crypto
    .createHmac('sha256', process.env.EVENTOP_WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');
  
  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature))) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  // Prevent replay attacks
  const age = Date.now() - parseInt(timestamp);
  if (age > 300000) { // 5 minutes
    return res.status(401).json({ error: 'Webhook too old' });
  }
  
  // Parse event
  const event = JSON.parse(payload);
  
  // Process event
  try {
    await processWebhookEvent(event);
    res.json({ received: true });
  } catch (error) {
    console.error('Webhook processing failed:', error);
    res.status(500).json({ error: 'Processing failed' });
  }
});
Security Checklist:
  • ✅ Always verify webhook signatures
  • ✅ Check timestamp to prevent replay attacks
  • ✅ Use HTTPS for your webhook endpoint
  • ✅ Return 200 status quickly (< 10 seconds)
  • ✅ Process heavy work asynchronously

Step 6: Add Webhook URL to Dashboard

  1. Go to dashboard.eventop.xyz
  2. Navigate to Settings → Webhooks
  3. Click Add Endpoint
  4. Enter your webhook URL: https://yourdomain.com/webhooks/eventop
  5. Select events to receive (or select “All events”)
  6. Copy the webhook secret (you’ll need this for signature verification)
  7. Save

Step 7: Create Success/Cancel Pages

Create pages where users land after checkout.

Success Page

// /subscription/success
app.get('/subscription/success', async (req, res) => {
  const { session_id } = req.query;
  
  // Optional: Fetch session details
  if (session_id) {
    const session = await eventop.checkout.getSession(session_id);
    
    if (session.status === 'completed') {
      res.render('success', {
        customerEmail: session.customer.email,
        planName: session.plan.planName,
        subscriptionId: session.subscriptionId
      });
      return;
    }
  }
  
  // Fallback if no session_id
  res.render('success-generic');
});
success.html:
<!DOCTYPE html>
<html>
<head>
  <title>Subscription Successful!</title>
</head>
<body>
  <div class="success-container">
    <h1>🎉 Welcome to Premium!</h1>
    <p>Your subscription to {{planName}} is now active.</p>
    <p>We've sent a confirmation email to {{customerEmail}}.</p>
    
    <a href="/dashboard" class="button">Go to Dashboard</a>
  </div>
</body>
</html>

Cancel Page

// /subscription/cancel or back to /pricing
app.get('/subscription/cancel', (req, res) => {
  res.render('pricing', {
    message: 'Subscription was cancelled. Subscribe anytime!'
  });
});

Step 8: Test End-to-End

1

Switch to Devnet Mode

In your code, set environment: 'devnet' and use devnet API keys.
2

Create Test Plan

In the dashboard, create a test subscription plan (e.g., $0.01/month).
3

Test Checkout Flow

  • Click subscribe button on your site
  • Complete checkout in the Eventop app (devnet mode)
  • Verify you’re redirected back to success page
4

Verify Webhook

Check your server logs to confirm webhook was received and processed correctly.
5

Check Dashboard

View the subscription in your merchant dashboard to verify it was created.

Step 9: Go Live

Once testing is complete:
1

Switch to Mainnet

Update environment: 'mainnet' and use mainnet API keys.
2

Update Merchant Wallet

Use your production Solana wallet address (mainnet).
3

Create Production Plans

Set up your real subscription plans with actual pricing.
4

Update Webhook URL

Ensure your production webhook endpoint is configured.
5

Test with Small Amount

Do a final test with a small real payment to verify everything works.
6

Monitor

Watch your dashboard and logs for the first few subscriptions.

Common Issues

Troubleshooting:
  • Verify your webhook URL is publicly accessible
  • Check that you’re returning 200 status code
  • Look for errors in Dashboard → Webhooks → Logs
  • Test with webhook.site first
  • Ensure no firewall is blocking requests from our IPs
Troubleshooting:
  • Double-check you’re using the correct webhook secret
  • Ensure you’re hashing the raw request body (not parsed JSON)
  • Verify you’re using SHA256 HMAC
  • Check for trailing newlines in the secret
Possible causes:
  • User doesn’t have the Eventop app installed
  • User’s subscription wallet has insufficient balance
  • Session expired (30 min TTL)
  • Network issues
Solution: Guide users to download the app and ensure they have sufficient balance.
Troubleshooting:
  • Check if using correct API key for the environment
  • Verify merchant wallet address matches
  • Look for errors in webhook logs
  • Confirm transaction succeeded on Solana explorer

Next Steps