API Documentation

Complete reference for the Scraper Portal API

Overview

Base URL:

/api/v1

Authentication

X-API-Key: your_api_key_here

Events

Get Active Events

GET/api/v1/events

Parameters

NameTypeDescription
limitintegerNumber of events (1-100, default: 50)
offsetintegerPagination offset (default: 0)
venuestringFilter by venue name
sortBystringSort field: date, name, venue, lastUpdated
sortOrderstringSort direction: asc, desc

Example

curl -H "X-API-Key: your_api_key_here" \
     "/api/v1/events?limit=10"

Response

{
  "data": [
    {
      "eventId": "EVENT123",
      "name": "Concert Event",
      "date": "2025-12-15",
      "time": "7:00 PM",
      "isoDate": "2025-12-15T19:00:00.000Z",
      "location": "Main Arena", 
      "numberOfSeats": 150
    }
  ],
  "meta": {
    "pagination": {
      "total": 17,
      "limit": 10,
      "offset": 0,
      "hasMore": true,
      "nextOffset": 10
    },
    "filters": {
      "venue": null,
      "sortBy": "date",
      "sortOrder": "asc"
    }
  }
}

Inventory

Get Event Inventory

GET/api/v1/inventory

Parameters

NameTypeRequiredDescription
eventIdstringEvent mapping ID
listingIdstring-Filter by specific listing ID
minPricenumber-Minimum price filter
maxPricenumber-Maximum price filter
quantityinteger-Required quantity (1-20)
sortBystring-Sort field: price, section, row
sortOrderstringascSort direction: asc, desc

Example

curl -H "X-API-Key: your_api_key_here" \
     "/api/v1/inventory?eventId=EVENT123&minPrice=50&maxPrice=200"

Orders

Create Order

POST/api/v1/orders

Request Body Options

Option 1: Using listingId (Recommended)
{
  "eventId": "EVENT123",
  "listingId": "674e1234567890abcdef1234",
  "quantity": 2,
  "customer": {
    "email": "buyer@example.com",
    "phone": {
      "number": "5551234567",
      "countryCode": "+1"
    }
  }
}
Option 2: Using section/row
{
  "eventId": "EVENT123",
  "quantity": 2,
  "section": "101", 
  "row": "A",
  "customer": {
    "email": "buyer@example.com",
    "phone": {
      "number": "5551234567",
      "countryCode": "+1"
    }
  }
}

Example

curl -X POST -H "Content-Type: application/json" \
     -H "X-API-Key: your_api_key_here" \
     -d '{"eventId":"EVENT123","listingId":"674e1234567890abcdef1234","quantity":2,"customer":{"email":"buyer@example.com","phone":{"number":"5551234567","countryCode":"+1"}}}' \
     /api/v1/orders

Update Order Status

PATCH/api/v1/orders

Update the status of an existing order. This endpoint requires API authentication and supports the same status flow as the admin dashboard.

Request Body

{
  "orderId": "order_1769082692221",
  "status": "accepted"
}

Valid Status Values

confirmed
accepted
fulfilled
cancelled

Status Flow

Typical Order Flow: confirmed → accepted → fulfilled

Orders can be cancelled at any stage. Each status change triggers a webhook notification.

Example Request

curl -X PATCH -H "Content-Type: application/json" \
     -H "X-API-Key: your_api_key_here" \
     -d '{"orderId":"order_1769082692221","status":"accepted"}' \
     /api/v1/orders

Response Example

{
  "success": true,
  "message": "Order order_1769086588534 updated to accepted successfully",
  "order": {
    "orderId": "order_1769086588534",
    "orderNumber": "TIC-KRLCH4H78",
    "eventId": "4546456",
    "eventName": "Boston Bruins Vs Vegas Golden Knights Boston",
    "eventDate": "2026-01-22T10:00:00.000Z",
    "eventVenue": "TD Garden",
    "eventLocation": "Boston, MA",
    "section": "Club Box 19",
    "row": "A",
    "listingId": "697200166edd0569d00c3d24",
    "quantity": 2,
    "status": "accepted",
    "totalAmount": 150.66,
    "customer": {
      "email": "buyer@example.com",
      "phone": {
        "number": "5551234567",
        "countryCode": "+1"
      }
    },
    "createdAt": "2026-01-22T12:56:28.540Z",
    "updatedAt": "2026-01-22T13:07:50.088Z",
    "previousStatus": "confirmed"
  },
  "webhook": {
    "event": "order.accepted",
    "sent": true
  },
  "timestamp": "2026-01-22T13:07:50.475Z"
}

Webhook Notifications

Unified Status Updates: Our system notifies your endpoint instantly whenever an order status changes, whether triggered via API or manually by an Admin in the Dashboard.

Delivery

Signed HTTP POST with JSON payload to your configured URL. HTTPS required in production.

X-Webhook-Signature: sha256=...

Retries

Up to 5 retries with exponential backoff on non-200 responses. Respond within 30 seconds.

Sample Notification Payload

{
  "event": "order.accepted",
  "orderId": "order_1769086190205",
  "order": {
    "eventId": "4546456",
    "eventName": "Boston Bruins Vs Vegas Golden Knights Boston",
    "eventDate": "2026-01-22T10:00:00.000Z",
    "eventVenue": "TD Garden",
    "eventLocation": "Boston, MA",
    "section": "Club Box 19",
    "row": "A",
    "listingId": "697200166edd0569d00c3973",
    "quantity": 2,
    "status": "accepted",
    "totalAmount": 148.24,
    "customer": {
      "email": "buyer@example.com",
      "phone": {
        "number": "5551234567",
        "countryCode": "+1"
      }
    },
    "createdAt": "2026-01-22T12:49:50.220Z",
    "updatedAt": "2026-01-22T12:52:52.509Z",
    "previousStatus": "confirmed"
  },
  "timestamp": "2026-01-22T12:52:52.509Z"
}

Fulfilled Notification Payload

When an order is fulfilled, the webhook includes transfer method details showing how the ticket was delivered.

{
  "event": "order.fulfilled",
  "orderId": "order_1769086190205",
  "order": {
    "eventId": "4546456",
    "eventName": "Boston Bruins Vs Vegas Golden Knights Boston",
    "eventDate": "2026-01-22T10:00:00.000Z",
    "eventVenue": "TD Garden",
    "eventLocation": "Boston, MA",
    "section": "Club Box 19",
    "row": "A",
    "listingId": "697200166edd0569d00c3973",
    "quantity": 2,
    "status": "fulfilled",
    "totalAmount": 148.24,
    "customer": {
      "email": "buyer@example.com",
      "phone": {
        "number": "5551234567",
        "countryCode": "+1"
      }
    },
    "transferMethod": "mobile_transfer",
    "transferNote": "Transferred via mobile transfer",
    "previousStatus": "accepted",
    "createdAt": "2026-01-22T12:49:50.220Z",
    "updatedAt": "2026-01-22T14:30:00.000Z"
  },
  "timestamp": "2026-01-22T14:30:00.000Z"
}

Webhook Payload Reference

FieldTypeDescription
eventstringEvent type (order.confirmed, order.accepted, etc.)
orderIdstringUnique order identifier
order.eventIdstringEvent identifier
order.eventNamestringFull event name
order.eventDatestringEvent date in ISO 8601 format
order.eventVenuestringVenue name where event takes place
order.sectionstringSeating section
order.rowstringSeating row
order.listingIdstringListing identifier reference
order.quantitynumberNumber of tickets
order.statusstringCurrent order status
order.totalAmountnumberTotal order amount in USD
order.customer.emailstringCustomer email address
order.customer.phoneobjectCustomer phone with number and countryCode
order.transferMethodstringHow ticket was transferred (fulfilled orders only): mobile_transfer, digital_download, email, pickup
order.transferNotestringTransfer details/instructions (fulfilled orders only)
order.createdAtstringOrder creation timestamp
order.updatedAtstringLast update timestamp
order.previousStatusstringPrevious status (for status change events only)
timestampstringWebhook notification timestamp

Getting Started with Webhooks

Webhook endpoints are configured by your account manager. You will receive an API Key and a Webhook Signing Secret for signature verification.

Signature Verification Example (Node.js)

const express = require('express');
const crypto = require('crypto');
const app = express();

const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;

// IMPORTANT: Use express.raw() to get the raw body for signature verification
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const timestamp = req.headers['x-webhook-timestamp'];
  const rawBody = req.body.toString();

  // 1. Verify signature
  const expected = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(timestamp + '.' + rawBody)
    .digest('hex');

  const isValid = crypto.timingSafeEqual(
    Buffer.from('sha256=' + expected),
    Buffer.from(signature)
  );

  if (!isValid) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // 2. Process the event
  const payload = JSON.parse(rawBody);
  console.log('Received:', payload.event, payload.orderId);

  // 3. Return 200 quickly
  res.json({ received: true });
});

app.listen(3000, () => console.log('Webhook listener running on port 3000'));

Webhook Security

Every webhook delivery includes these security headers:

HeaderDescription
X-Webhook-SignatureHMAC-SHA256 signature: sha256=<hex>
X-Webhook-TimestampUnix epoch (seconds) when the webhook was sent
X-Webhook-EventEvent type, e.g. order.fulfilled
X-Webhook-DeliveryUnique delivery UUID (use for idempotency)

Signature Computation

The signature is computed as: HMAC-SHA256(secret, timestamp + "." + rawBody). The timestamp is included in the HMAC to prevent replay attacks.

Signature & Replay Verification (Node.js)

const crypto = require('crypto');

const TOLERANCE_SECONDS = 1800; // 30 minutes (generous for manual workflows)

function verifyWebhook(rawBody, headers, secret) {
  const signature = headers['x-webhook-signature'];
  const timestamp = Number(headers['x-webhook-timestamp']);

  // 1. Reject old deliveries (replay protection)
  const age = Math.floor(Date.now() / 1000) - timestamp;
  if (isNaN(timestamp) || age > TOLERANCE_SECONDS) {
    throw new Error('Webhook timestamp too old (>30 min) — possible replay');  
  }

  // 2. Compute expected signature: HMAC(secret, timestamp.body)
  const expected = crypto
    .createHmac('sha256', secret)
    .update(timestamp + '.' + rawBody)
    .digest('hex');

  // 3. Constant-time comparison
  const a = Buffer.from(`sha256=${expected}`);
  const b = Buffer.from(signature);
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
    throw new Error('Invalid webhook signature');
  }

  return JSON.parse(rawBody);
}

// Express handler:
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
  try {
    const payload = verifyWebhook(
      req.body.toString(), req.headers, WEBHOOK_SECRET
    );

    switch (payload.event) {
      case 'order.confirmed':  break;
      case 'order.fulfilled':  break; // check payload.order.transferMethod
      case 'order.cancelled':  break;
    }

    res.json({ received: true });
  } catch (err) {
    res.status(401).json({ error: err.message });
  }
});

Webhook Events

order.confirmed

Order received and confirmed by system

order.accepted

Order accepted and processing begins

order.purchase_issues

Issues encountered during processing

order.fulfilled

Order successfully completed and delivered

order.cancelled

Order cancelled by admin or system

order.refunded

Order refunded to customer

Common Status Events

order.confirmed
order.accepted
order.fulfilled
order.cancelled