Skip to content

Outbound Webhooks — Technical Reference

Architecture Overview

Outbound webhooks enable users to POST selected row data to external HTTP endpoints. The feature extends the existing bulk action pipeline with a new WEBHOOK_SEND operation.

Message Flow

Frontend (spread app)
  ↓ POST /api/data/bulk/{viewUuid}/webhook-send
BulkActionResource (Quarkus REST)

BulkActionService (validates permissions, looks up WebhookConfig)

WebhookDeliveryProducer (sends to webhook-delivery-queue)

RabbitMQ Exchange "webhook-delivery" → Queue "webhook-delivery-queue"

WebhookDeliveryConsumer (Spring Boot)

BulkWebhookSendService (fetch rows → serialize → HMAC → HTTP POST)

TaskCompletionProducer (sends BULK_WEBHOOK_SEND completion)

BulkActionHandler (persists WebhookDelivery, broadcasts SSE)

Frontend (receives completion, updates delivery log)

Separate Queue

Webhook deliveries use a dedicated webhook-delivery-queue rather than the existing bulk-actions-queue. This ensures webhook sends don't compete with schema migrations or other bulk operations.

Database Schema

webhook_config

ColumnTypeNotes
idBIGINT PKautoIncrement
uuidUUID UNIQUE
view_idBIGINT FK → view(id) CASCADE
nameVARCHAR(100)Display name
urlVARCHAR(2000)Endpoint URL
headers_jsonTEXTJSON object of custom headers
hmac_secretVARCHAR(256)Optional HMAC-SHA256 secret
enabledBOOLEAN DEFAULT true
created_at / updated_atTIMESTAMPTZ

webhook_delivery

ColumnTypeNotes
idBIGINT PKautoIncrement
uuidUUID UNIQUE
webhook_config_idBIGINT FK → webhook_config(id) CASCADE
job_idUUIDReferences BulkActionJob
attempt_numberINT DEFAULT 1
status_codeINTHTTP response status
response_bodyTEXTTruncated to 4KB
error_messageVARCHAR(500)
duration_msINTRound-trip time
delivered_atTIMESTAMPTZ

REST API

Webhook Config CRUD

  • GET /api/data/webhooks/{viewUuid} — List configs
  • POST /api/data/webhooks/{viewUuid} — Create config
  • PUT /api/data/webhooks/{viewUuid}/{webhookUuid} — Update config
  • DELETE /api/data/webhooks/{viewUuid}/{webhookUuid} — Delete config
  • PATCH /api/data/webhooks/{viewUuid}/{webhookUuid}/toggle?enabled=true — Toggle
  • GET /api/data/webhooks/{viewUuid}/{webhookUuid}/deliveries — Delivery log

Webhook Send

  • POST /api/data/bulk/{viewUuid}/webhook-send — Initiate bulk webhook send

Security

SSRF Protection

WebhookConfigService.validateUrl() blocks:

  • Private IP ranges (10.x, 172.16-31.x, 192.168.x)
  • Loopback addresses (127.x, localhost)
  • Link-local addresses (169.254.x)
  • Internal hostnames (*.local, *.internal)

HMAC Signing

When an HMAC secret is configured, the payload is signed with HMAC-SHA256:

X-SchemaStack-Signature: sha256=<hex-encoded-hmac>

Permissions

  • Webhook config CRUD requires CONFIGURE_VIEW permission (ADMIN role)
  • Sending to webhooks requires BULK_WEBHOOK_SEND permission (EDITOR+ with view.exportable)

Key Files

FileModulePurpose
WebhookConfig.javametadata-persistenceEntity
WebhookDelivery.javametadata-persistenceEntity
WebhookConfigRepository.javametadata-persistenceRepository
WebhookDeliveryRepository.javametadata-persistenceRepository
WebhookConfigService.javametadata-serviceCRUD + SSRF + HMAC
WebhookConfigResource.javametadata-restREST endpoints
WebhookDeliveryProducer.javametadata-producerRabbitMQ producer
BulkWebhookSendService.javaprocessor-coreRow fetch + HTTP delivery
WebhookDeliveryConsumer.javaprocessor-consumerRabbitMQ consumer
BulkActionHandler.javametadata-consumerCompletion handler + SSE

SchemaStack Internal Developer Documentation