Overview
RLink can expose webhook endpoints underapp/api/webhooks/* for third-party systems that need to notify the app about an event.
Examples include:
- Form or lead ingestion
- Payment or reservation updates
- Marketing or email callbacks
- Internal automation events
Webhook design checklist
Before you add a new webhook route, define:- The event source
- The exact URL path
- The auth model: secret header, signature, or allowlist
- Expected payload shape
- Retry behavior from the provider
- Whether the event is idempotent
Recommended request flow
Use this sequence for new webhooks:- Verify the request signature or secret
- Parse and validate the payload
- Reject duplicates if the provider can retry
- Perform the minimum safe work
- Return a fast
2xxresponse - Defer slow follow-up work when possible
Authentication patterns
Shared secret
The sender includes a shared secret in a header such asAuthorization or X-Webhook-Secret. Your route compares it against an environment variable.
Use this when:
- You control both systems
- The provider does not support signed payloads
Signed payload
The sender signs the raw request body with a secret. Your route recomputes the signature and compares it before trusting the payload. Use this when:- The provider supports request signing
- Replay protection matters
- You need stronger tamper detection
IP allowlist
Use this only as an additional control, not the only control. Cloud providers can change ranges, and proxies complicate source IP handling.Payload validation
Validate webhook payloads before processing them. At minimum, check:- Required fields are present
- IDs have the format you expect
- Timestamps are valid
- Enum values are allowed
- The event type is supported
Idempotency and retries
Most webhook providers retry on:- Timeout
- Network failure
- Any non-
2xxstatus code
- Store provider event IDs and reject duplicates
- Upsert instead of blindly inserting
- Check current state before mutating records
- Make side effects safe to repeat
Logging and observability
Log enough to debug, but never log secrets. Safe fields to log:- Event ID
- Event type
- Route name
- Source system
- Result status
- Secret headers
- Raw tokens
- Full personal data unless required
Local testing
To test a webhook locally:- Run the app on a public tunnel or preview URL
- Point the provider to that public URL
- Send a sample signed request
- Confirm the route returns
2xx - Verify the expected database or side effect change
curl is enough if the webhook uses a shared secret:
Failure handling
Use the response code intentionally:200or204: accepted400: invalid payload401or403: bad or missing auth409: duplicate event, if you want to signal that explicitly500: unexpected processing error
500 for known validation failures.
Edge cases
Out-of-order events
Some providers do not guarantee ordering. Do not assumeupdated always arrives after created.
Duplicate delivery
Retries and provider bugs can deliver the same event more than once. Treat idempotency as required, not optional.Clock skew
If you validate timestamps in signatures, allow a small tolerance window so valid requests are not rejected due to clock drift.Large payloads
Some events include nested objects or attachments. Reject oversized bodies early if you do not need them.Preview environments
Do not point production webhooks at a preview URL unless you intend to test there. Preview URLs change and can silently break integrations.Best practices
- Keep webhook handlers small
- Validate before mutating data
- Make handlers idempotent
- Return
2xxquickly - Rotate webhook secrets regularly
- Document each provider contract near the route implementation
Next steps
API overview
Sessions, CORS, and route types
Proxy and request flow
How requests reach protected routes
Deployment
Environment variables and production setup
Testing
How to test secrets, retries, and failures
