QuickStart

BetSync Quickstart Guide

BetSync enables your users to securely connect their sportsbook accounts for automatic bet tracking, sharing, and analytics. This guide will walk you through setting up a complete BetSync integration.

Prerequisites

Before you begin, you'll need:

  • A SharpSports API account (Sign up here)
  • Your public API key (found in Dashboard → Settings → API Keys)
  • A webhook endpoint URL for receiving events
  • Basic understanding of REST APIs

Step 1: Set Up Your Development Environment

1.1 Start with Sandbox Mode

All new accounts start in sandbox mode, perfect for testing:

# Sandbox API endpoint
BASE_URL=https://api.sharpsports.io/v1/

# Your sandbox public API key
API_KEY=public_sandbox_XXXXXXXXX

1.2 Test Your API Connection

curl -X GET \
  -H "Authorization: Token YOUR_PUBLIC_API_KEY" \
  https://api.sharpsports.io/v1/books

Step 2: Implement Account Linking (SDK Required)

2.1 Generate a Context ID with Internal ID (Required)

The internalId is a required field that links the SharpSports bettor to your internal user system. This ID:

  • Must be unique for each user in your system
  • Will be included in all webhook events for this user
  • Allows you to associate bet data with your user records
  • Cannot be changed once set for a bettor

Create a context for the linking session:

curl -X POST \
  -H "Authorization: Token YOUR_PUBLIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "internalId": "user_123",  # REQUIRED: Your unique user identifier
    "webhookUrl": "https://yourapp.com/webhooks/sharpsports"
  }' \
  https://api.sharpsports.io/v1/context

Response:

{
  "cid": "CTX_abc123xyz",
  "internalId": "user_123",  // Your user ID linked to this session
  "webhookUrl": "https://yourapp.com/webhooks/sharpsports"
}

2.2 SDK Integration (Choose Your Platform)

Important: You must use one of the SharpSports SDKs to enable account linking. Choose the SDK that matches your platform:

Option A: Web Browser SDK

// Install the SDK
npm install @sharpsports/web-sdk

// Import and initialize
import { SharpSports } from '@sharpsports/web-sdk';

const ss = new SharpSports({
  apiKey: 'YOUR_PUBLIC_API_KEY'
});

// Link account with required internalId
const result = await ss.linkAccount({
  internalId: 'user_123',  // REQUIRED: Your unique user ID
  contextId: 'CTX_abc123xyz'
});

// Direct to linking UI
const linkUrl = `https://ui.sharpsports.io/link/${result.contextId}`;
window.open(linkUrl, 'LinkAccount', 'width=600,height=800');

Option B: React Native SDK

// Install the SDK
npm install @sharpsports/react-native-sdk

// Import and use
import { linkAccount } from '@sharpsports/react-native-sdk';

const result = await linkAccount({
  token: 'YOUR_PUBLIC_API_KEY',
  internalId: 'user_123'  // REQUIRED: Your unique user ID
});

Option C: iOS SDK (Swift)

// Install via CocoaPods
pod 'SharpSportsSDK'

// Link account
SharpSports.linkAccount(
    token: "YOUR_PUBLIC_API_KEY",
    internalId: "user_123"  // REQUIRED: Your unique user ID
) { result in
    // Handle result
}

Option D: Android SDK (Kotlin)

// Add to build.gradle
implementation 'io.sharpsports:android-sdk:latest'

// Link account
SharpSports.linkAccount(
    token = "YOUR_PUBLIC_API_KEY",
    internalId = "user_123"  // REQUIRED: Your unique user ID
) { result ->
    // Handle result
}

Step 3: Handle Webhook Events

3.1 Set Up Your Webhook Endpoint

Create an endpoint to receive SharpSports webhooks:

// Express.js example
app.post('/webhooks/sharpsports', (req, res) => {
  const { type, data } = req.body;

  switch(type) {
    case 'bettor.created':
      handleBettorCreated(data);
      break;
    case 'bettorAccount.verified':
      handleAccountVerified(data);
      break;
    case 'refreshResponse.created':
      handleRefreshComplete(data);
      break;
    case 'bettorAccount.unverified':
      handleAccountUnverified(data);
      break;
  }

  // Always respond quickly with 200
  res.status(200).send('OK');

  // Process heavy operations asynchronously
  processWebhookAsync(type, data);
});

3.2 Critical Webhook Events

EventWhen It FiresAction Required
bettor.createdFirst account linked for userStore bettorId with internalId
bettorAccount.verifiedAccount successfully linked/verifiedUpdate UI to show connected status
refreshResponse.createdBet data refresh completedProcess and store bet slips
bettorAccount.unverifiedAccount needs re-authenticationPrompt user to re-link account

Step 4: Refresh Bet Data

4.1 Manual Refresh (User-Initiated)

Important: All refreshes must be initiated manually via API calls. There is no automatic refresh cadence.

// Refresh all accounts for a bettor
async function refreshAllAccounts(bettorId) {
  const response = await fetch(
    `https://api.sharpsports.io/v1/bettors/${bettorId}/refresh`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Token ${API_KEY}`
      }
    }
  );
  return response.json();
}

// Refresh specific account
async function refreshAccount(bettorAccountId) {
  const response = await fetch(
    `https://api.sharpsports.io/v1/bettorAccounts/${bettorAccountId}/refresh`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Token ${API_KEY}`
      }
    }
  );
  return response.json();
}

Best Practices for Refresh Timing:

  • Trigger a refresh when user logs into your app
  • Add a manual refresh button for users
  • Limit refreshes to 1-2 times per day per account
  • Handle refresh responses via webhooks (don't poll)

Step 5: Display Bet Data

5.1 Fetch Bet Slips

// Get all bet slips for a bettor
async function getBetSlips(bettorId) {
  const response = await fetch(
    `https://api.sharpsports.io/v1/betSlips?bettorId=${bettorId}`,
    {
      headers: {
        'Authorization': `Token ${API_KEY}`
      }
    }
  );
  return response.json();
}

5.2 Understanding Bet Structure

// Example bet slip structure
{
  "id": "SLIP_xyz123",
  "bettorAccountId": "BACT_abc456",
  "status": "won",  // pending, won, lost, push, canceled
  "atRisk": 100.00,
  "toWin": 191.00,
  "payout": 291.00,
  "placedAt": "2024-01-15T10:30:00Z",
  "gradedAt": "2024-01-15T23:45:00Z",
  "bets": [
    {
      "id": "BET_def789",
      "type": "spread",
      "odds": -110,
      "bookDescription": "Lakers -5.5",
      "incomplete": false,
      "event": {
        "id": "EVT_ghi012",
        "sport": "basketball",
        "league": "nba",
        "startTime": "2024-01-15T19:00:00Z"
      },
      "marketSelection": {
        "team": {
          "id": "TEAM_lakers",
          "name": "Los Angeles Lakers"
        },
        "position": "favorite",
        "spread": -5.5
      }
    }
  ]
}

5.3 Handle Incomplete Bets

When incomplete: true, only display accounting fields and bookDescription:

function displayBet(bet) {
  if (bet.incomplete) {
    // Show only what we have
    return {
      description: bet.bookDescription,
      odds: bet.odds,
      status: bet.status
    };
  }

  // Full bet details available
  return {
    team: bet.marketSelection.team.name,
    type: bet.type,
    line: bet.marketSelection.spread,
    odds: bet.odds,
    status: bet.status,
    event: bet.event
  };
}

Step 6: Account Management Widget

6.1 Implement the Pre-Built Management Widget

SharpSports provides a pre-built account management widget that handles all account operations (refresh, pause, remove, reverify) with a consistent UI:

<!-- Add the account management widget to your page -->
<div id="SSAccountManager"></div>

<script src="https://d388bvybj12fcd.cloudfront.net/account-manager.js"
  token="YOUR_PUBLIC_API_KEY"
  internalId="user_123"
  theme="light"
  showRefreshButton="true"
  showPauseButton="true"
  showRemoveButton="true">
</script>

6.2 Widget Configuration Options

ParameterTypeDescription
tokenstringYour public API key (required)
internalIdstringYour user's unique ID (required)
themestringWidget theme: 'light' or 'dark'
showRefreshButtonbooleanShow manual refresh option
showPauseButtonbooleanAllow pausing accounts
showRemoveButtonbooleanAllow removing accounts
onAccountStatusChangefunctionCallback for status changes

6.3 Handle Widget Events

// Listen for account status changes from the widget
window.addEventListener('SSAccountStatusChange', (event) => {
  const { accountId, status, action } = event.detail;

  console.log(`Account ${accountId} status: ${status}`);

  switch(action) {
    case 'refresh_started':
      showLoadingIndicator();
      break;
    case 'account_paused':
      updateAccountUI(accountId, 'paused');
      break;
    case 'account_removed':
      removeAccountFromUI(accountId);
      break;
    case 'reverification_needed':
      promptUserToRelink(accountId);
      break;
  }
});

6.4 Account States in the Widget

The widget automatically handles these account states:

StateWidget DisplayUser Actions Available
Verified✅ ConnectedRefresh, Pause, Remove
Unverified⚠️ Needs AttentionReverify, Remove
Unverifiable❌ Reconnect RequiredRe-link, Remove
Paused⏸️ PausedResume, Remove
Refreshing🔄 Updating...None (wait)

Step 7: Testing with Sandbox

7.1 Available Test Users

UsernamePasswordBehavior
gooduserTest1Successful verification, immediate response
realuserTest2Successful verification with realistic delays
2FAuserTest6Requires 2FA (use code: 123456)
changepassworduserTest5Simulates password change error
errorloginuserTest3Fails verification

7.2 Test Flow Example

// 1. Create context with test internal ID
const context = await createContext('test_user_001');

// 2. Direct test user to link UI
const linkUrl = `https://ui.sharpsports.io/link/${context.cid}`;
console.log('Use test credentials:', {
  username: 'gooduser',
  password: 'Test1'
});

// 3. Your webhook will receive:
// - bettor.created
// - bettorAccount.verified
// - refreshResponse.created (with test bets)

// 4. Test refresh
const refreshResult = await refreshAllAccounts(bettorId);

// 5. Fetch and display test bets
const betSlips = await getBetSlips(bettorId);

Step 8: Go Live

8.1 Switch to Production

  1. Sign up for a paid plan in the SharpSports Dashboard
  2. Toggle from Sandbox to Live mode
  3. Get your production API keys
  4. Update your API key in your application
  5. Test with a real sportsbook account

8.2 Production Checklist

  • Webhook endpoint handles all event types
  • Error handling for failed refreshes
  • UI shows account status clearly
  • Account management widget implemented
  • Manual refresh controls in place
  • Rate limiting implemented (1-2 refreshes per day max)
  • User notifications for account issues
  • Secure storage of bettor IDs and internal IDs
  • HTTPS for all API calls
  • SDK properly integrated and configured

Common Integration Patterns

Pattern 1: Login-Time Refresh

// When user logs into your app
async function onUserLogin(userId) {
  const bettorId = await getBettorId(userId);

  if (bettorId) {
    // Trigger background refresh
    refreshAllAccounts(bettorId);

    // Show cached bets immediately
    const cachedBets = await getCachedBets(userId);
    displayBets(cachedBets);
  }
}

Pattern 2: Pull-to-Refresh

// Mobile app pull-to-refresh
async function onPullToRefresh(bettorId) {
  setRefreshing(true);

  try {
    await refreshAllAccounts(bettorId);
    // Wait for webhook or poll for updates
    await waitForRefreshComplete(bettorId, { timeout: 30000 });
    const betSlips = await getBetSlips(bettorId);
    updateUI(betSlips);
  } finally {
    setRefreshing(false);
  }
}

Pattern 3: Account Status Banner

// Show banner when account needs attention
function AccountStatusBanner({ account }) {
  if (!account.verified && !account.isUnverifiable) {
    return (
      <Banner type="warning">
        Account needs reverification
        <Button onClick={() => reverifyAccount(account.id)}>
          Reverify Now
        </Button>
      </Banner>
    );
  }

  if (account.isUnverifiable) {
    return (
      <Banner type="error">
        Please re-link your account
        <Button onClick={() => openLinkFlow()}>
          Re-link Account
        </Button>
      </Banner>
    );
  }

  return null;
}

Troubleshooting

Issue: Webhooks not received

  1. Verify webhook URL is publicly accessible
  2. Check URL is HTTPS (required for production)
  3. Ensure response is 200 within 10 seconds
  4. Check Dashboard webhook logs

Issue: Account becomes unverified

Common causes and solutions:

  • Password changed: User must re-link account
  • 2FA enabled: Implement 2FA handling flow
  • Terms acceptance required: User must log into sportsbook directly
  • Site maintenance: Wait and retry later

Issue: Incomplete bets

  • This is normal for new/exotic bet types
  • Display bookDescription field which always contains bet details
  • SharpSports continuously improves parsing coverage

Issue: Refresh takes too long

  • SDK-required books may take 30-60 seconds
  • Implement async handling with loading states
  • Show progress indicators during refresh
  • Process webhook responses asynchronously

Best Practices

  1. Security

    • Never expose private API keys
    • Always use the required internalId to link users
    • Validate webhook signatures
    • Use HTTPS for all communications
  2. SDK Requirements

    • Always use an official SharpSports SDK for account linking
    • Keep SDKs updated to the latest version
    • Follow platform-specific SDK documentation
  3. Performance

    • Cache bet data locally
    • Implement pagination for large bet histories
    • Use webhook events instead of polling
    • Trigger refreshes strategically (login time, user-initiated)
  4. User Experience

    • Use the account management widget for consistent UI
    • Provide clear manual refresh buttons
    • Handle errors gracefully with user-friendly messages
    • Notify users of account issues promptly
  5. Rate Limiting

    • Maximum 1-2 manual refreshes per account per day
    • Implement backoff for failed requests
    • Batch operations when possible
    • Track refresh frequency per user

Next Steps

  1. Explore Advanced Features:

    • Bet statistics and analytics
    • Multi-user betting groups
    • Closing line value tracking
    • Responsible gaming tools
  2. Review API Reference:

    • Complete endpoint documentation
    • Object schemas and examples
    • SDK method references
  3. Join the Developer Community:

    • Get help from other developers
    • Share integration patterns
    • Request new features

Support


Last updated: January 2025