Webhook Targets

Seatmap.pro can notify your own systems when venues, schemas and seatmaps change. This page covers what a webhook target must look like and what happens when a delivery fails.

Events

Event Sent when
venue.created A venue is created.
venue.updated A venue is changed.
venue.deleted A venue is deleted.
schema.created A schema is created.
schema.updated A schema is changed.
schema.deleted A schema is deleted.
seatmap.stored A seatmap is saved.

Target requirements

Breaking: from 1.70.0 a webhook target must be a public HTTPS destination. A target that does not meet both conditions is rejected when you save it, and any delivery to it is recorded with the error type TARGET_NOT_ALLOWED.

A target is accepted when:

  • The URL is a valid URI with a host.
  • The scheme is https. Plain http is rejected, unless a self-hosted operator has enabled it for internal targets — see below.
  • Every address the host resolves to is publicly routable.

A host is rejected when any of its addresses is loopback, link-local, site-local (private ranges such as 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16), multicast, carrier-grade NAT, or otherwise reserved. IPv6 unique-local addresses are rejected too, as are IPv4-mapped IPv6 addresses whose underlying IPv4 address is blocked. A host that cannot be resolved at all is rejected.

If your endpoint is not public

Terminate TLS on a public hostname and forward internally from there — a reverse proxy or an API gateway in front of your service is enough. Do not expect an internal hostname to work because it resolves publicly to a private address; the check is on the resolved address, not the name.

Self-hosted deployments that genuinely need to deliver inside their own network can set seatmap.webhooks.allow-private-targets to true on the editor service. This turns the address check off, so enable it only when the whole network path is under your control.

If the receiver is only reachable over plain http, also set seatmap.webhooks.allow-insecure-targets to true. Both settings are required together: setting the second one on its own is a configuration error and the editor service will not start.

An http target stays restricted to your internal network even with both settings on: every address the host resolves to must be a private or otherwise non-routable one, so http://receiver.internal:8080/hook is accepted while a public http address is rejected. Traffic to an http target is not encrypted in transit, which is why it is confined this way.

Retries

A failed delivery is retried with exponential backoff, three times by default. The defaults are:

Setting Default Meaning
timeoutMs 30000 Per-attempt timeout.
maxRetries 3 Retries after the first attempt.
backoffInitialMs 1000 Delay before the first retry.
backoffMultiplier 2.0 Multiplier applied to each subsequent delay.
retryOnHttpStatuses 500, 502, 503, 504 Statuses that are retried.
skipRetryOnHttpStatuses 400, 401, 403, 404 Statuses that are treated as final.

Timeouts, network errors and connection errors are retried. A TARGET_NOT_ALLOWED failure is not — the target is invalid, so waiting will not help. After the last retry the event goes to the dead-letter list rather than being dropped silently.

What is stored on a delivery attempt

Each attempt records the status, the error type and a snippet of the response body, so you can see why a delivery failed without instrumenting your own endpoint.

Credential-bearing response headers are stored as [redacted]: authorization, proxy-authorization, set-cookie, set-cookie2, www-authenticate, proxy-authenticate and x-amz-security-token. If your endpoint echoes a token in one of these headers, it does not end up in the delivery log.