Webhooks
Bidyear supports two webhook directions:
- Outbound — Bidyear sends events to your server when platform events occur (lot sold, bid placed, invoice paid, etc.)
- Inbound — External platforms (Stripe, cross-listing simulcast) POST events to Bidyear endpoints
Outbound webhooks
How it works
- Create a webhook subscription via
POST /api/v1/webhook-subscriptions(requiressellerability). - Save the secret returned at creation — it is shown only once.
- When a subscribed event fires, Bidyear sends an HTTPS POST to your URL with a JSON payload.
- Verify authenticity using the
X-Bidyear-Signatureheader. - Respond with HTTP 200–299 within 10 seconds. Failed deliveries are logged and retried up to 3 times.
Verifying the signature
Every outbound request includes:
X-Bidyear-Signature: sha256={hex-digest}
X-Bidyear-Event: lot.sold
Compute the expected signature:
// PHP
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret);
if (!hash_equals($expected, $request->header('X-Bidyear-Signature'))) {
abort(401, 'Invalid signature');
}
// Node.js
const sig = 'sha256=' + crypto.createHmac('sha256', secret)
.update(rawBody).digest('hex');
if (sig !== req.headers['x-bidyear-signature']) {
return res.sendStatus(401);
}
Available webhook events
| Event | Fires when |
|---|---|
lot.sold | A lot hammer is dropped and a winner confirmed |
lot.unsold | A lot closes without a winner |
auction.published | An auction is published/made active |
bid.placed | A bid is placed on any of your lots |
invoice.paid | An invoice is fully paid |
invoice.payment_failed | A payment attempt on an invoice fails |
user.verified | A user's identity verification is approved |
seller.approved | A seller account is approved |
subscription.updated | A team subscription status changes |
Example outbound payload — lot.sold
POST https://your-server.com/webhook
X-Bidyear-Signature: sha256=abcd1234...
X-Bidyear-Event: lot.sold
Content-Type: application/json
{
"event": "lot.sold",
"fired_at": "2026-07-12T14:00:00Z",
"data": {
"lot_id": 55,
"lot_title": "80 Acres — Jones County TX",
"winner_bid": 42000.00,
"auction_id": 12
}
}
Lists all webhook subscriptions owned by the authenticated user/team.
Response 200
{
"success": true,
"data": [
{
"id": 1,
"url": "https://your-server.com/webhook",
"events": ["lot.sold", "bid.placed"],
"is_active": true,
"created_at": "2026-07-01T10:00:00Z"
}
]
}
Creates a subscription. The response includes a secret — copy it now, it is shown only once.
Request body
{
"url": "https://your-server.com/webhook",
"events": ["lot.sold", "bid.placed"],
"is_active": true
}
Response 201
{
"success": true,
"data": {
"id": 2,
"url": "https://your-server.com/webhook",
"events": ["lot.sold", "bid.placed"],
"is_active": true,
"secret": "whs_abcdef1234567890...",
"created_at": "2026-07-12T09:00:00Z"
}
}
Updates url, events, or is_active on an existing subscription.
Deletes the subscription. No further events will be dispatched to the URL.
Returns the delivery log for a subscription — useful for debugging failed deliveries.
Response 200 (item)
{
"id": 99,
"event": "lot.sold",
"url": "https://your-server.com/webhook",
"status_code": 200,
"success": true,
"response_body": "OK",
"attempted_at": "2026-07-12T14:00:01Z",
"duration_ms": 142
}
Inbound webhooks
These endpoints receive events from external services. They do not require Sanctum authentication — each one uses its own verification mechanism.
Receives Stripe webhook events. Verified via the Stripe-Signature header using STRIPE_WEBHOOK_SECRET. Handled by StripeWebhookController.
Common handled events
payment_intent.succeeded— marks invoice as paidinvoice.paid— subscription invoice paidcustomer.subscription.updated— plan upgrade/downgradecustomer.subscription.deleted— subscription cancelled
Response
HTTP 200 — event processed HTTP 400 — invalid Stripe-Signature header
Receives a bid event from a cross-listing platform (e.g. AuctionTime, Proxibid). The platform slug identifies the platform record in the database. HMAC signature is verified in WebhookController::handleIncomingBid().
Path parameter
| Param | Description |
|---|---|
| platform | Platform slug (e.g. auctiontime, proxibid) |
Response
HTTP 200 — bid recorded HTTP 401 — invalid HMAC HTTP 422 — lot not found or auction closed
Receives a lot-sold/hammer event from a cross-listing platform. HMAC verified. Handled by WebhookController::handleIncomingSold().