BOOK A DEMO

Integrations

Webhooks

Type definitions and reference payloads for every event the Basta platform sends. TypeScript type guards and Ruby (RBS) signatures are provided for consuming them safely.

These definitions serve as documentation and reference implementations for integrators who need to consume Basta webhooks.

Looking to set up webhooks? See Managing Webhooks for how to subscribe to events, test your endpoint, and retry failed deliveries.

Available languages

  • TypeScript (webhooks.ts) — type definitions with type guards
  • RBS (webhooks.rbs) — Ruby type signatures for static type checking

Base structure

All webhooks follow the same base structure:

JSON
{
  "idempotencyKey": "unique-key-for-deduplication",
  "actionType": "BidOnItem",
  "data": {
    // Action-specific payload
  }
}
TypeScript
export type Action =
  | "Unspecified"
  | "BidOnItem"
  | "ItemsStatusChanged"
  | "SaleItemUpdated"
  | "SaleStatusChanged"
  | "SaleCreated"
  | "SaleUpdated"
  | "ItemAddedToSale"
  | "SaleItemRemoved"
  | "CancelBidOnItem"
  | "OrderCreated"
  | "OrderUpdated"
  | "OrderDeleted"
  | "OrderCancelled"
  | "SaleRegistrationCreated"
  | "SaleRegistrationUpdated"
  | "SaleRegistrationDeleted"
  | "SaleItemRegistrationCreated"
  | "SaleItemRegistrationDeleted";

export interface BastaAction<T = unknown> {
  idempotencyKey: string;
  actionType: Action;
  data: T;
}

Action types

The following action types are currently supported:

Bidding actions

  • BidOnItem — A new bid was placed on an item
  • CancelBidOnItem — Bids were cancelled on an item

BidOnItem payload details

The BidOnItem action is sent whenever a new bid is placed on an item. Here's a detailed breakdown of the payload structure.

Core fields

FieldTypeDescription
bidIdstringUnique identifier for this bid
saleIdstringID of the sale containing this item
itemIdstringID of the item being bid on
userIdstringID of the user who placed the bid
amountnumberThe actual bid amount placed (in minor currency units, e.g., cents)
maxAmountnumberThe maximum bid amount for proxy bidding (in minor currency units). Will be 0 for regular bids
bidDatestringISO 8601 timestamp when the bid was placed (RFC3339 format)
totalBidsnumberTotal number of bids on this item

Bid type

The bidType field indicates the type of bid:

ValueDescription
NORMALA standard bid placed by the user
MAXA maximum bid where the system will automatically bid up to the max amount
REACTIVEAn automatic bid triggered by the proxy bidding system
OFFERAn offer bid (for fixed-price or offer scenarios)

Sale state

The saleState object contains the current state of bidding on the item:

TypeScript
{
  newLeader: string;      // User ID of the new leading bidder
  prevLeader: string;     // User ID of the previous leader (empty if first bid)
  currentBidId: string;   // ID of the current winning bid
  currentBid: number;     // Current bid amount (in minor currency units)
  currentMaxBid: number;  // Current max bid amount if proxy bidding is active
  reserveMet: boolean;    // Whether the reserve price has been met (deprecated, use reserveStatus)
}

Reserve status

The reserveStatus field indicates whether the reserve price has been met:

ValueDescription
NOT_METThe reserve price has not been met yet
METThe reserve price has been met
NO_RESERVEThis item has no reserve price

Reactive bids

The reactiveBids array contains any automatic proxy bids that were triggered as a result of this bid. Each reactive bid has:

TypeScript
{
  bidId: string;      // ID of the reactive bid
  userId: string;     // User ID who set up the proxy bid
  amount: number;     // Amount of the reactive bid
  maxAmount: number;  // Maximum amount the user authorized
}

Out bid details

The outBidDetails field (can be null) contains information about a user who was outbid by this action:

TypeScript
{
  bidId: string;      // ID of the losing bid
  saleId: string;     // Sale ID
  itemId: string;     // Item ID
  userId: string;     // User ID who was outbid
  amount: number;     // Their bid amount
  maxAmount: number;  // Their max bid amount (if they used proxy bidding)
  bidDate: string;    // When they placed their bid (RFC3339 format)
  bidType: BidType;   // Type of bid they placed
}

Complete example

JSON
{
  "idempotencyKey": "bid-12345-67890",
  "actionType": "BidOnItem",
  "data": {
    "bidId": "bid_abc123",
    "saleId": "sale_xyz789",
    "itemId": "item_def456",
    "userId": "user_123",
    "amount": 15000,
    "maxAmount": 20000,
    "bidDate": "2024-03-15T14:30:00Z",
    "bidType": "MAX",
    "saleState": {
      "newLeader": "user_123",
      "prevLeader": "user_456",
      "currentBidId": "bid_abc123",
      "currentBid": 15000,
      "currentMaxBid": 20000,
      "reserveMet": true
    },
    "totalBids": 7,
    "reactiveBids": [],
    "outBidDetails": {
      "bidId": "bid_xyz999",
      "saleId": "sale_xyz789",
      "itemId": "item_def456",
      "userId": "user_456",
      "amount": 14000,
      "maxAmount": 14000,
      "bidDate": "2024-03-15T14:25:00Z",
      "bidType": "NORMAL"
    },
    "reserveStatus": "MET"
  }
}

Important notes

  • All monetary amounts are in minor currency units (e.g., cents for USD, pence for GBP). Divide by 100 to get the major currency unit.
  • The bidDate is in RFC3339 format (ISO 8601) with timezone information.
  • When a user is outbid by a reactive bid, they will receive this webhook with outBidDetails populated.
  • The reactiveBids array will be populated if this bid triggered any automatic proxy bids.

The full BidOnItemActionPayload and its related types in TypeScript:

TypeScript
export type BidType = "NORMAL" | "MAX" | "REACTIVE" | "OFFER";
export type ReserveStatus = "NOT_MET" | "MET" | "NO_RESERVE";

export interface SaleState {
  newLeader: string;
  prevLeader: string;
  currentBidId: string;
  currentBid: number;
  currentMaxBid: number;
  reserveMet: boolean;
}

export interface ReactiveBid {
  bidId: string;
  userId: string;
  amount: number;
  maxAmount: number;
}

export interface OutBidDetails {
  bidId: string;
  saleId: string;
  itemId: string;
  userId: string;
  amount: number;
  maxAmount: number;
  bidDate: string;
  bidType: BidType;
}

export interface BidOnItemActionPayload {
  bidId: string;
  saleId: string;
  itemId: string;
  userId: string;
  amount: number;
  maxAmount: number;
  bidDate: string;
  bidType: BidType;
  saleState: SaleState;
  totalBids: number;
  reactiveBids: ReactiveBid[];
  outBidDetails: OutBidDetails | null;
  reserveStatus: ReserveStatus;
}

Item actions

  • ItemAddedToSale — An item was added to a sale
  • SaleItemRemoved — An item was removed from a sale
  • SaleItemUpdated — Item details were updated
  • ItemsStatusChanged — Item status changed (e.g., open, closing, closed)

Sale actions

  • SaleCreated — A new sale was created
  • SaleUpdated — Sale details were updated
  • SaleStatusChanged — Sale status changed (e.g., published, open, closed)

Order actions

  • OrderCreated — A new order was created
  • OrderUpdated — Order details were updated
  • OrderDeleted — An order was deleted
  • OrderCancelled — An order was cancelled

Registration actions

  • SaleRegistrationCreated — User registered for a sale
  • SaleRegistrationUpdated — Registration was updated
  • SaleRegistrationDeleted — Registration was deleted
  • SaleItemRegistrationCreated — User registered for a specific item
  • SaleItemRegistrationDeleted — Item registration was deleted

Usage examples

TypeScript

Each action has a matching typed alias (e.g. BidOnItemAction) and a helper type guard so you can narrow the payload:

TypeScript
import { BastaAction, isBidOnItemAction, BidOnItemActionPayload } from './webhooks';

function handleWebhook(webhook: BastaAction) {
  if (isBidOnItemAction(webhook)) {
    // TypeScript now knows webhook.data is BidOnItemActionPayload
    console.log(`Bid placed: ${webhook.data.bidId}`);
    console.log(`Amount: ${webhook.data.amount}`);
  }
}

Ruby (with RBS)

Ruby
# In your Gemfile:
# gem 'rbs'
# gem 'steep' # for type checking

# sig/webhooks.rbs contains the type signatures

webhook_data = JSON.parse(request.body.read)

action = BastaWebhooks::BastaAction.new(
  idempotency_key: webhook_data['idempotencyKey'],
  action_type: webhook_data['actionType'],
  data: webhook_data['data']
)

case action.action_type
when 'BidOnItem'
  # Type checker will understand the structure
  payload = BastaWebhooks::BidOnItemActionPayload.new(**action.data.symbolize_keys)
  puts "Bid placed: #{payload.bid_id}"
  puts "Amount: #{payload.amount}"
end

To use RBS for type checking:

Shell
# Validate RBS syntax
rbs validate

# Type check with Steep
steep check

For questions about webhooks or to report issues with type definitions, email us at hi@basta.app.