Skip to main content

Overview

Webhooks allow external systems to receive real-time notifications when events occur in Auction Excellence. Instead of polling the API for changes, configure webhook endpoints to receive HTTP POST requests with event data.

Real-time

Instant notifications when events occur

Secure

HMAC signature verification for authenticity

Reliable

Automatic retries with exponential backoff

Flexible

Filter events by type and auction

How Webhooks Work

1

Event Occurs

An action happens in Auction Excellence (e.g., submission created)
2

Webhook Triggered

A database trigger fires and queues the webhook delivery
3

HTTP POST Sent

Your endpoint receives a POST request with event data
4

Acknowledgment

Return a 2xx status code to confirm receipt

Available Events

Submission Events

EventTriggerDescription
submission.createdNew lot submissionFired when a team member submits a lot count
submission.updatedSubmission modifiedFired when a submission is edited (rare)
Payload Example:
{
  "event": "submission.created",
  "timestamp": "2025-01-15T10:30:00Z",
  "auction_id": "auction-uuid",
  "data": {
    "id": "submission-uuid",
    "location_id": "location-uuid",
    "location_name": "North Lot",
    "user_id": "user-uuid",
    "submitted_by": "John Smith",
    "submitted_at": "2025-01-15T10:30:00Z",
    "entries": [
      {
        "type_id": "type-uuid",
        "type_name": "Dealer",
        "car_count": 45,
        "image_url": "https://..."
      },
      {
        "type_id": "type-uuid",
        "type_name": "Retail",
        "car_count": 30,
        "image_url": null
      }
    ],
    "total_car_count": 75,
    "image_url": "https://..."
  }
}

Inspection Events

EventTriggerDescription
inspection.createdNew inspectionFired when a quality inspection is submitted
inspection.defect_addedDefect recordedFired when a defect is added to an inspection
Payload Example:
{
  "event": "inspection.created",
  "timestamp": "2025-01-15T10:30:00Z",
  "auction_id": "auction-uuid",
  "data": {
    "id": "inspection-uuid",
    "location_id": "location-uuid",
    "location_name": "North Lot",
    "user_id": "user-uuid",
    "inspector_name": "Jane Inspector",
    "vin_number": "1HGBH41JXMN109186",
    "barcode": "A12345",
    "submitted_at": "2025-01-15T10:30:00Z",
    "defect_count": 3,
    "defects": [
      {
        "category": "Body Damage",
        "notes": "Scratch on driver door"
      }
    ]
  }
}

Problem Report Events

EventTriggerDescription
problem.createdNew problem reportFired when a problem report is submitted
problem.status_changedStatus updatedFired when status changes (open → in_progress → closed)
problem.assignedAssignment changedFired when problem is assigned/reassigned
problem.action_completedAction marked completeFired when an action item is completed
Payload Example:
{
  "event": "problem.status_changed",
  "timestamp": "2025-01-15T10:30:00Z",
  "auction_id": "auction-uuid",
  "data": {
    "id": "problem-uuid",
    "issue_name": "Delayed Vehicle Processing",
    "area": "Intake",
    "location_id": "location-uuid",
    "location_name": "North Lot",
    "previous_status": "open",
    "new_status": "in_progress",
    "prepared_by": {
      "id": "user-uuid",
      "name": "John Smith"
    },
    "assigned_to": {
      "id": "user-uuid",
      "name": "Jane Manager"
    },
    "action_count": 5,
    "completed_action_count": 2,
    "updated_at": "2025-01-15T10:30:00Z"
  }
}

Chat Events

EventTriggerDescription
message.createdNew message sentFired when a message is sent in any channel
message.editedMessage editedFired when a message content is modified
message.deletedMessage deletedFired when a message is soft-deleted
channel.createdNew channelFired when a channel is created
channel.archivedChannel archivedFired when a channel is archived
Payload Example:
{
  "event": "message.created",
  "timestamp": "2025-01-15T10:30:00Z",
  "auction_id": "auction-uuid",
  "data": {
    "id": "message-uuid",
    "channel_id": "channel-uuid",
    "channel_name": "general",
    "user_id": "user-uuid",
    "sender_name": "John Smith",
    "content": "Hello team!",
    "message_type": "text",
    "is_thread_reply": false,
    "parent_message_id": null,
    "mentions": [],
    "created_at": "2025-01-15T10:30:00Z"
  }
}

Member Events

EventTriggerDescription
member.invitedInvitation sentFired when a user is invited to an auction
member.joinedMember joinedFired when an invitation is accepted
member.role_changedRole updatedFired when a member’s role changes
member.removedMember removedFired when a member is removed
Payload Example:
{
  "event": "member.joined",
  "timestamp": "2025-01-15T10:30:00Z",
  "auction_id": "auction-uuid",
  "data": {
    "user_id": "user-uuid",
    "email": "[email protected]",
    "full_name": "New Member",
    "role": "team_member",
    "invited_by": {
      "id": "inviter-uuid",
      "name": "Admin User"
    },
    "joined_at": "2025-01-15T10:30:00Z"
  }
}

Webhook Payload Structure

All webhook payloads follow a consistent structure:
{
  "event": "event.type",
  "timestamp": "2025-01-15T10:30:00Z",
  "webhook_id": "delivery-uuid",
  "auction_id": "auction-uuid",
  "data": {
    // Event-specific data
  }
}

Common Fields

FieldTypeDescription
eventstringEvent type identifier
timestampISO 8601When the event occurred
webhook_idUUIDUnique ID for this delivery (for deduplication)
auction_idUUIDThe auction where the event occurred
dataobjectEvent-specific payload

Configuring Webhooks

Webhook configuration is available to auction administrators through the admin dashboard or via API.

Via Admin Dashboard

1

Navigate to Settings

Go to SettingsIntegrationsWebhooks
2

Add Endpoint

Click Add Webhook and enter your endpoint URL
3

Select Events

Choose which events should trigger this webhook
4

Save and Test

Save the configuration and use the Test button to verify

Via API

curl -X POST 'https://your-project.supabase.co/rest/v1/webhook_endpoints' \
  -H "apikey: YOUR_ANON_KEY" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "auction_id": "auction-uuid",
    "url": "https://your-server.com/webhooks/ae",
    "events": ["submission.created", "inspection.created"],
    "secret": "your-signing-secret",
    "is_active": true
  }'

Security

Signature Verification

All webhook requests include an HMAC-SHA256 signature in the X-Webhook-Signature header. Always verify this signature before processing the payload. Header Format:
X-Webhook-Signature: sha256=5d7d...abc123

Verification Code

import crypto from 'crypto'

function verifyWebhookSignature(
  payload: string,
  signature: string,
  secret: string
): boolean {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex')

  const providedSignature = signature.replace('sha256=', '')

  return crypto.timingSafeEqual(
    Buffer.from(expectedSignature),
    Buffer.from(providedSignature)
  )
}

// Express.js example
app.post('/webhooks/ae', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-webhook-signature']
  const payload = req.body.toString()

  if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature')
  }

  const event = JSON.parse(payload)
  console.log('Received event:', event.event)

  // Process the event...

  res.status(200).send('OK')
})

Additional Headers

HeaderDescription
X-Webhook-IDUnique ID for this delivery
X-Webhook-TimestampUnix timestamp when sent
X-Webhook-EventEvent type (e.g., submission.created)
Content-TypeAlways application/json
User-AgentAuctionExcellence-Webhook/1.0

Handling Webhooks

Response Requirements

  • Return a 2xx status code (200-299) to acknowledge receipt
  • Response must be returned within 30 seconds
  • Response body is ignored

Retry Policy

If your endpoint doesn’t respond with a 2xx status:
AttemptDelay
1Immediate
21 minute
35 minutes
430 minutes
52 hours
612 hours
After 6 failed attempts, the webhook is marked as failed and no more retries occur.
Repeated failures may result in automatic endpoint disabling. Monitor your endpoint health.

Idempotency

Webhooks may be delivered more than once due to retries. Use the webhook_id field to detect and handle duplicates:
const processedWebhooks = new Set<string>()

function handleWebhook(event: WebhookEvent) {
  if (processedWebhooks.has(event.webhook_id)) {
    console.log('Duplicate webhook, skipping')
    return
  }

  processedWebhooks.add(event.webhook_id)
  // Process the event...
}

Testing Webhooks

Test Endpoint

Send a test webhook to verify your endpoint configuration:
curl -X POST 'https://your-project.supabase.co/rest/v1/rpc/test_webhook' \
  -H "apikey: YOUR_ANON_KEY" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "endpoint_id": "endpoint-uuid",
    "event_type": "submission.created"
  }'

Local Development

Use a tunneling service like ngrok for local testing:
# Start ngrok tunnel
ngrok http 3000

# Use the generated URL as your webhook endpoint
# https://abc123.ngrok.io/webhooks/ae

Webhook Logs

View recent webhook deliveries in the admin dashboard: SettingsIntegrationsWebhooksDelivery History Each log entry shows:
  • Event type
  • Delivery status (success/failed)
  • Response status code
  • Response time
  • Error message (if failed)

Best Practices

Never process a webhook without verifying the HMAC signature. This prevents forged requests.
Return a 200 response immediately, then process the event asynchronously. This prevents timeouts.
app.post('/webhooks/ae', async (req, res) => {
  res.status(200).send('OK') // Respond immediately

  // Process asynchronously
  setImmediate(() => processEvent(req.body))
})
Store the webhook_id and check for duplicates before processing.
For high-volume scenarios, push webhooks to a queue (Redis, SQS, etc.) and process separately.
Set up alerts for webhook delivery failures to catch integration issues early.
Store webhook secrets in environment variables, not in code.

Troubleshooting

  1. Verify your endpoint URL is correct and publicly accessible
  2. Check that the endpoint is enabled in webhook settings
  3. Ensure the event types you need are selected
  4. Review the delivery history for error messages
  1. Ensure you’re using the raw request body, not parsed JSON
  2. Verify you’re using the correct webhook secret
  3. Check that the signature header name is correct (X-Webhook-Signature)
  1. Implement idempotency using the webhook_id
  2. Check if your endpoint is responding slowly (causing retries)
  3. Ensure you’re returning 2xx status codes
Endpoints are disabled after repeated failures. Fix the issue, then:
  1. Go to SettingsWebhooks
  2. Find the disabled endpoint
  3. Click Enable and save
  4. Send a test webhook to verify

Next Steps