Skip to content
Back to site

Sources

A source is one third-party provider you connect, such as Stripe or GitHub, together with what Railhook needs to prove a webhook really came from it. Creating a source gives you an ingress URL to paste into the provider.

  1. The provider sends a webhook to the source’s ingress URL.

  2. Railhook verifies it, as the source is configured to. A webhook that fails verification is refused and not stored.

  3. The webhook is stored as it arrived, as an incoming event. The dashboard lists these under Received.

  4. Railhook creates one forward for each destination of the source, and works on each until it succeeds or is abandoned. See Destinations.

import { Railhook } from '@railhook/node';
const client = new Railhook({ apiKey: process.env.RAILHOOK_API_KEY, baseUrl: process.env.RAILHOOK_URL });
const source = await client.incomingSources.create(projectId, {
name: 'Stripe',
providerType: 'STRIPE',
verificationMode: 'PROVIDER',
hmacSecret: process.env.STRIPE_WEBHOOK_SECRET,
});
console.log(source.ingressUrl);

Paste ingressUrl into the provider’s webhook settings, then add at least one destination.

Field What it does
name Required. Display name, up to 255 characters.
slug URL-friendly name, lower case letters, digits and dashes, up to 64 characters. Generated when left out.
providerType GENERIC, GITHUB, GITLAB, STRIPE, SHOPIFY, SLACK or TWILIO.
verificationMode NONE, HMAC_GENERIC or PROVIDER. Left out, it follows hmacSecret: with a secret, PROVIDER for a provider that has a preset and HMAC_GENERIC for GENERIC; without one, NONE. See Verification.
hmacSecret The secret the provider signs with. Write-only: the API never returns it.
hmacHeaderName, hmacSignaturePrefix Where the signature is, for HMAC_GENERIC.
rateLimitPerSecond Requests per second this source accepts.
status ACTIVE or DISABLED.

The ingress URL is WEBHOOK_INGRESS_BASE_URL followed by /ingress/ and an opaque token. The token is the only thing that names the source, so treat the URL as a credential. Verification is what stops someone who learns the URL from sending you events.

Each code is what the provider’s retry logic sees.

Status Meaning
200 Slack’s url_verification handshake to a SLACK source, answered {"challenge":"…"} once its signature is verified. This is how Slack enables the Request URL, so the source needs PROVIDER verification with the app’s signing secret. The handshake is not an event: nothing is stored, forwarded or counted.
202 Accepted and stored. The body carries requestId.
401 Verification is configured and the signature did not check out, or a signature already seen arrived on a webhook that is not a resend of a stored one. Nothing is stored.
403 The organization is suspended. Answered 403, not 410, so a provider that deletes its subscription on 410 still has it when the suspension is lifted.
404 No source has that token, or its project has been deleted.
410 The source exists but is disabled.
413 The body is larger than the limit, 512 KB by default.
429 The source’s rate limit is spent, with Retry-After: 1. Also returned, with Retry-After: 3600, when the organization cannot accept more webhooks right now; a resend of a webhook already stored is still answered 202.
Variable Default Effect
WEBHOOK_INCOMING_MAX_PAYLOAD_SIZE_BYTES 524288 Largest body the ingress accepts.
WEBHOOK_INCOMING_RATE_LIMIT_PER_SECOND 100 Rate limit for a source that sets none of its own. 0 disables this default.

Providers send the same webhook again. When a request carries an id Railhook recognises, a second arrival with the same id is answered 202 with the stored event instead of forwarding it again. The signature is still verified, but a resend is refused neither because that signature was seen before nor because the organization cannot accept new webhooks right now. Railhook recognises these ids:

Provider Id
Generic X-Webhook-Id header
Stripe id in the JSON body (evt_…), on a request signed with Stripe-Signature
GitHub X-GitHub-Delivery header
GitLab webhook-id header, or Idempotency-Key (GitLab 17.4 and later)
Shopify X-Shopify-Webhook-Id header
Twilio I-Twilio-Idempotency-Token header
Slack event_id in the JSON body

A provider that sends none of these is not deduplicated.