Docs/SideBet/Quickstart

Quickstart

Go from zero to your first round-up in under 10 minutes

Overview

1

Get API Keys

Grab your secret key and webhook secret from the dashboard.

2

Configure Round-Up Strategy

Set how round-ups are calculated for your consumers.

3

Link Consumer Bank Account

Connect a bank account via CoinFlow for ACH debits.

4

Initiate Round-Ups on Bet Events

Send transactions to SideBet when bets are placed.

5

Handle Webhooks

Receive real-time updates as ACH payments settle.

Step 1: Get API Keys

Log in to the Hedge Payments dashboard and navigate to Settings → API Keys. You will need two keys:

API Key (Secret)

Used for server-to-server requests. Prefix: sk_live_ or sk_test_. Never expose this in client-side code.

Webhook Secret

Used to validate incoming webhook signatures. Prefix: whsec_. Found under Settings → Webhooks.

Environment Variablesbash
# Store these in your environment
export HEDGE_API_KEY=#98C379]">"sk_test_your_api_key_here"
export HEDGE_WEBHOOK_SECRET=#98C379]">"whsec_your_webhook_secret_here"

Step 2: Configure Round-Up Strategy

Set your merchant's round-up strategy via the configuration endpoint. This determines how round-ups are calculated for all your consumers:

Configure Strategybash
curl -X POST https://api.hedgepayments.com/api/roundup/configure \
  -H #98C379]">"Authorization: Bearer sk_test_your_api_key" \
  -H #98C379]">"Content-Type: application/json" \
  -d '{
    #98C379]">"merchantId": "merch_xyz789",
    #98C379]">"strategy": "nearest-dollar",
    #98C379]">"perTransactionMaxCents": 1000,
    #98C379]">"dailyMaxCents": 5000
  }'
Responsejson
{
  #98C379]">"merchantId": "merch_xyz789",
  #98C379]">"strategy": "nearest-dollar",
  #98C379]">"perTransactionMaxCents": 1000,
  #98C379]">"dailyMaxCents": 5000,
  #98C379]">"settlementType": "USD",
  #98C379]">"updated": true
}

Available strategies

nearest-dollar, nearest-5, percentage, fixed-amount, dynamic. For percentage, fixed-amount, and dynamic, include a strategyValue field (e.g., "strategyValue": 5 for 5% or 5x multiplier).

Step 3: Link Consumer Bank Account

Before initiating round-ups, consumers must link their bank account via CoinFlow. All fields are required for ACH compliance (NACHA rules):

Link Bank Accountbash
curl -X POST https://api.hedgepayments.com/api/customer/v2/bankAccount \
  -H #98C379]">"Authorization: Bearer sk_test_your_api_key" \
  -H #98C379]">"Content-Type: application/json" \
  -d '{
    #98C379]">"firstName": "Jane",
    #98C379]">"lastName": "Doe",
    #98C379]">"email": "jane@example.com",
    #98C379]">"routingNumber": "021000021",
    #98C379]">"account_number": "123456789",
    #98C379]">"address1": "123 Main St",
    #98C379]">"city": "New York",
    #98C379]">"state": "NY",
    #98C379]">"zip": "10001"
  }'
Responsejson
{
  #98C379]">"customerId": "cust_j4k5l6m7",
  #98C379]">"bankAccountId": "ba_n8o9p0q1",
  #98C379]">"status": "LINKED",
  #98C379]">"last4": "6789"
}

Step 4: Initiate Round-Ups on Bet Events

When a consumer places a bet, send the transaction to SideBet. The round-up is calculated server-side based on your configured strategy:

Initiate Round-Upbash
curl -X POST https://api.hedgepayments.com/api/roundup/initiate \
  -H #98C379]">"Authorization: Bearer sk_test_your_api_key" \
  -H #98C379]">"Content-Type: application/json" \
  -d '{
    #98C379]">"betAmount": 2347,
    #98C379]">"consumerId": "cust_j4k5l6m7",
    #98C379]">"strategy": "nearest-dollar",
    #98C379]">"merchantId": "merch_xyz789"
  }'
Response — $23.47 bet, $0.53 round-up (nearest-dollar)json
{
  #98C379]">"id": "roundup_9f8e7d6c",
  #98C379]">"roundUpCents": 53,
  #98C379]">"betAmountCents": 2347,
  #98C379]">"status": "pending",
  #98C379]">"skipped": false,
  #98C379]">"consumerId": "cust_j4k5l6m7",
  #98C379]">"merchantId": "merch_xyz789"
}

Step 5: Handle Webhooks

SideBet sends webhook events as each ACH payment progresses. Set up an endpoint to receive them:

EventWhenAction
roundup.initiatedACH debit submitted to bankUpdate status to processing
roundup.completedFunds received and settledCredit consumer's balance
roundup.failedPayment could not be processedLog error, notify consumer
roundup.returnedBank returned the debitReverse the credit, notify consumer

Full Working Example

Here's a complete Node.js integration that ties all five steps together -- configure strategy, link a bank account, initiate round-ups on bet events, and handle webhooks:

Full Integration — server.jsjavascript
import express from class="text-[class="text-[#5C6370] italic">#98C379]">'express';
import crypto from class="text-[class="text-[#5C6370] italic">#98C379]">'crypto';

const app = express();
app.use(express.json());

const API_BASE = class="text-[class="text-[#5C6370] italic">#98C379]">'class="text-[#61AFEF]">https://api-sandbox.hedgepayments.com';
const API_KEY = process.env.HEDGE_API_KEY;
const WEBHOOK_SECRET = process.env.HEDGE_WEBHOOK_SECRET;
const MERCHANT_ID = class="text-[class="text-[#5C6370] italic">#98C379]">'merch_xyz789';

const headers = {
  class="text-[class="text-[#5C6370] italic">#98C379]">'Authorization': class="text-[#98C379]">`Bearer ${API_KEY}`,
  class="text-[class="text-[#5C6370] italic">#98C379]">'Content-Type': class="text-[#98C379]">'application/json',
};

class="text-[#5C6370] italic">// Step class="text-[#D19A66]">2: Configure round-up strategy (run once)
async function configureStrategy() {
  const res = await fetch(class="text-[class="text-[#5C6370] italic">#98C379]">`${API_BASE}/api/roundup/configure`, {
    method: class="text-[class="text-[#5C6370] italic">#98C379]">'POST',
    headers,
    body: JSON.stringify({
      merchantId: MERCHANT_ID,
      strategy: class="text-[class="text-[#5C6370] italic">#98C379]">'nearest-dollar',
      perTransactionMaxCents: class="text-[#D19A66]">1000,
      dailyMaxCents: class="text-[#D19A66]">5000,
    }),
  });
  return res.json();
}

class="text-[#5C6370] italic">// Step class="text-[#D19A66]">3: Link a consumer's bank account
app.post(class="text-[class="text-[#5C6370] italic">#98C379]">'/link-bank', async (req, res) => {
  const response = await fetch(class="text-[class="text-[#5C6370] italic">#98C379]">`${API_BASE}/api/customer/v2/bankAccount`, {
    method: class="text-[class="text-[#5C6370] italic">#98C379]">'POST',
    headers,
    body: JSON.stringify({
      firstName: req.body.firstName,
      lastName: req.body.lastName,
      email: req.body.email,
      routingNumber: req.body.routingNumber,
      account_number: req.body.accountNumber,
      address1: req.body.address1,
      city: req.body.city,
      state: req.body.state,
      zip: req.body.zip,
    }),
  });

  const data = await response.json();
  res.json(data);
});

class="text-[#5C6370] italic">// Step class="text-[#D19A66]">4: Initiate a round-up when a bet is placed
app.post(class="text-[class="text-[#5C6370] italic">#98C379]">'/place-bet', async (req, res) => {
  const { consumerId, betAmountCents } = req.body;

  class="text-[#5C6370] italic">// Place the bet in your system first...
  class="text-[#5C6370] italic">// Then initiate the round-up:
  const response = await fetch(class="text-[class="text-[#5C6370] italic">#98C379]">`${API_BASE}/api/roundup/initiate`, {
    method: class="text-[class="text-[#5C6370] italic">#98C379]">'POST',
    headers,
    body: JSON.stringify({
      betAmount: betAmountCents,
      consumerId,
      strategy: class="text-[class="text-[#5C6370] italic">#98C379]">'nearest-dollar',
      merchantId: MERCHANT_ID,
    }),
  });

  const roundUp = await response.json();

  res.json({
    betPlaced: true,
    roundUp: {
      id: roundUp.id,
      roundUpCents: roundUp.roundUpCents,
      skipped: roundUp.skipped,
    },
  });
});

class="text-[#5C6370] italic">// Step class="text-[#D19A66]">5: Handle webhooks with signature validation
app.post(class="text-[class="text-[#5C6370] italic">#98C379]">'/webhooks/sidebet', (req, res) => {
  class="text-[#5C6370] italic">// Validate HMAC-SHA256 signature
  const signature = req.headers[class="text-[class="text-[#5C6370] italic">#98C379]">'x-hedge-signature'];
  const payload = JSON.stringify(req.body);
  const expected = crypto
    .createHmac(class="text-[class="text-[#5C6370] italic">#98C379]">'sha256', WEBHOOK_SECRET)
    .update(payload)
    .digest(class="text-[class="text-[#5C6370] italic">#98C379]">'hex');

  if (signature !== expected) {
    return res.status(class="text-[#D19A66]">401).send(class="text-[class="text-[#5C6370] italic">#98C379]">'Invalid signature');
  }

  class="text-[#5C6370] italic">// Respond class="text-[#D19A66]">200 immediately
  res.status(class="text-[#D19A66]">200).send(class="text-[class="text-[#5C6370] italic">#98C379]">'OK');

  class="text-[#5C6370] italic">// Process the event
  const { event, data } = req.body;

  switch (event) {
    case class="text-[class="text-[#5C6370] italic">#98C379]">'roundup.initiated':
      console.log(class="text-[class="text-[#5C6370] italic">#98C379]">`Round-up initiated: ${data.roundupId}`);
      break;
    case class="text-[class="text-[#5C6370] italic">#98C379]">'roundup.completed':
      console.log(class="text-[class="text-[#5C6370] italic">#98C379]">`Round-up settled: ${data.roundupId} — $${data.amount}`);
      class="text-[#5C6370] italic">// Credit the consumer's balance
      break;
    case class="text-[class="text-[#5C6370] italic">#98C379]">'roundup.failed':
      console.log(class="text-[class="text-[#5C6370] italic">#98C379]">`Round-up failed: ${data.roundupId}`);
      break;
    case class="text-[class="text-[#5C6370] italic">#98C379]">'roundup.returned':
      console.log(class="text-[class="text-[#5C6370] italic">#98C379]">`Round-up returned: ${data.roundupId}`);
      class="text-[#5C6370] italic">// Reverse any credit
      break;
  }
});

app.listen(class="text-[#D19A66]">3000, () => console.log(class="text-[class="text-[#5C6370] italic">#98C379]">'Server running on port class="text-[#D19A66]">3000'));

Sandbox Testing

Use the sandbox environment to test your integration without moving real money:

Sandbox Base URL

https://api-sandbox.hedgepayments.com

CoinFlow Sandbox

api-sandbox.coinflow.cash

Sandbox bank accounts

Any routing number and account number will work in the sandbox environment. No real bank verification occurs. ACH webhooks are simulated and fire within seconds instead of days.