Endpoint security
Everything on an endpoint that is about trust: its signing secret, the proof that whoever registered it owns it, the certificate Railhook presents to it, and the network rules every delivery passes.
Rotate the signing secret
Section titled “Rotate the signing secret”-
Call
POST /api/v1/projects/{projectId}/endpoints/{id}/rotate-secret, or rotate it in the dashboard. The response carries the newsecretandstandardWebhooksSecret. -
For the endpoint’s grace period, 24 hours by default, every delivery carries two signatures: one made with the new secret and one with the retired secret. A receiver verifying with either succeeds.
-
Deploy the new secret to the receiver inside that window. When it closes, the retired secret stops signing, and a receiver still using it fails verification.
The official SDKs accept either signature during the window. See Verify signatures for what the headers look like.
Prove you own the endpoint
Section titled “Prove you own the endpoint”A URL anyone can type is a URL anyone can point at somebody else’s server. Verification proves that whoever registered the endpoint can read responses from it.
WEBHOOK_ENDPOINT_VERIFICATION_REQUIRED |
A new endpoint starts as |
|---|---|
false (default) |
SKIPPED, and receives deliveries straight away. |
true |
PENDING, and receives nothing until it is verified or skipped. |
Deliveries go only to an endpoint that is VERIFIED or SKIPPED. A delivery to any other endpoint fails without being retried. Changing an endpoint’s URL resets its status the same way, so a verified endpoint cannot be pointed somewhere else and keep delivering.
-
Call
POST /api/v1/projects/{projectId}/endpoints/{id}/verify. Railhook sends this to the endpoint’s URL and waits up to 10 seconds:What Railhook sends POST /webhooks HTTP/1.1Content-Type: application/json{"type":"webhook.verification","challenge":"<token>","timestamp":"2026-09-13T10:30:00Z"} -
Answer with the challenge, either as JSON or as the bare token:
What to answer HTTP/1.1 200 OKContent-Type: application/json{"challenge":"<token>"} -
A matching answer sets the endpoint to
VERIFIED. Anything else sets it toFAILED, and you can run the check again.
To deliver without the check, call POST /api/v1/projects/{projectId}/endpoints/{id}/skip-verification with a reason. The reason is kept on the endpoint, so an unverified endpoint is a recorded decision rather than a step that silently did not happen.
Present a client certificate (mTLS)
Section titled “Present a client certificate (mTLS)”For an endpoint that requires Railhook to prove who it is at the TLS layer, configure a client certificate with POST /api/v1/projects/{projectId}/endpoints/{id}/mtls:
| Field | |
|---|---|
clientCert |
Required. PEM. Presented on every delivery to this endpoint. |
clientKey |
Required. PEM, matching the certificate. |
caCert |
Optional. PEM. Supply it when the endpoint’s certificate is signed by an authority outside the platform’s trust store, such as an internal CA. |
The endpoint then reports mtlsEnabled: true; the certificate and key are not returned. Remove them with DELETE on the same path.
Where deliveries may go
Section titled “Where deliveries may go”Every endpoint URL is checked when it is saved and again before an attempt is made. Loopback, link-local and private address ranges are refused unless the operator allows them. This is a deployment setting, not a per-endpoint one, because it is the operator’s decision rather than a tenant’s.
| Variable | Default | Effect |
|---|---|---|
WEBHOOK_ALLOW_PRIVATE_IPS |
false |
true allows every private address. Refused at startup when APP_ENV=production. |
WEBHOOK_ALLOWED_HOSTS |
empty | Comma-separated host names exempt from the check, matched as written in the URL. The supported way to reach one internal service. |
The same check applies to incoming destinations and to HTTP steps in workflows.
Limit load on an endpoint
Section titled “Limit load on an endpoint”| Setting | Effect |
|---|---|
rateLimitPerSecond on the endpoint |
Deliveries per second to this endpoint, 0 to 10000. 0 removes the limit. |
WEBHOOK_MAX_CONCURRENT_PER_ENDPOINT |
Attempts in flight at once to one endpoint, default 5. |
Work turned away by either limit is deferred, not failed: it does not use up an attempt.
Allowed source IPs
Section titled “Allowed source IPs”Secrets at rest
Section titled “Secrets at rest”Endpoint signing secrets, client certificates and client keys are stored encrypted with the deployment’s encryption key. A caCert is public and is stored as given. The operator sets it with WEBHOOK_ENCRYPTION_KEY, or with versioned keys in WEBHOOK_ENCRYPTION_KEYS and WEBHOOK_ENCRYPTION_KEY_ACTIVE_VERSION. See Configuration.