Inbound Endpoints
Receive webhooks from external services, store every payload, and forward them to your app with retries and serialized delivery.
How It Works
Create an endpoint and you get a unique URL. Point external services (Stripe, GitHub, etc.) at that URL. When a webhook arrives, Runlater stores the raw payload and forwards it to your app — with automatic retries if your server is down.
- Create an endpoint with a name and forward URLs
- Copy the inbound URL and paste it into Stripe, GitHub, or any service
- Runlater receives the webhook, stores the full payload, and forwards it to your app
- If forwarding fails, we retry with exponential backoff (configurable, 0-10 attempts)
- Choose serial (queued) or parallel delivery per endpoint
Quick Start
1. Create an endpoint
curl -X POST https://runlater.eu/api/v1/endpoints \ -H "Authorization: Bearer pk_xxx.sk_xxx" \ -H "Content-Type: application/json" \ -d '{ "name": "Stripe webhooks", "forward_urls": ["https://myapp.com/webhooks/stripe"], "retry_attempts": 5, "use_queue": true }'
The response includes an
inbound_url
— this is the URL you give to Stripe (or any external service).
2. Configure the external service
Copy the inbound URL and paste it into the webhook settings of the external service. The URL looks like:
https://runlater.eu/in/ep_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3. Webhooks start flowing
Every request to the inbound URL is stored and forwarded to your forward URLs. The original HTTP method, headers, and body are preserved.
Delivery Modes
Serial delivery (queue enabled — default)
When use_queue
is enabled (the default),
events are forwarded one at a time — only one event per endpoint runs at any moment.
This prevents race conditions for services like Stripe, where overlapping requests could cause double-billing.
Under the hood, each endpoint uses a named queue based on the endpoint name to guarantee serialized execution.
Parallel delivery (queue disabled)
Set use_queue
to false
when event ordering doesn't matter. Events are forwarded concurrently for faster throughput.
Ideal for stateless webhooks like analytics events or notifications.
Retry Configuration
Each endpoint has a configurable number of retry attempts (0-10, default: 5). When forwarding fails, Runlater retries with exponential backoff. Set to 0 to disable retries entirely.
Custom Forwarding
Override the HTTP method, headers, or body for all forwarded requests — no code required. Set these on any endpoint to apply static defaults to every event before it’s forwarded.
| Field | Effect |
|---|---|
forward_method |
Replaces the original HTTP method (e.g. always forward as POST) |
forward_headers |
Merged with the original headers — custom headers win on conflict |
forward_body |
Replaces the original request body entirely |
Leave a field empty to forward the original value. Custom Forwarding is available on all tiers.
forward_method to
POST and every event is forwarded as a POST request — no Lua needed.
Processing Order
When an event arrives, Lua verification and filtering run on the original request.
Custom Forwarding and Lua transform() only affect what gets forwarded:
receive → verify(original) → filter(original) → custom forwarding → transform() → route() → forward
verify()andfilter()always see the original headers, body, and method — so signature checks work correctly.- Custom Forwarding applies static defaults (method, headers, body) for the forwarded request.
- Lua
transform()runs last. Any values it returns override the Custom Forwarding values. Fields it doesn’t return keep the Custom Forwarding value.
transform() takes priority when it returns values.
Lua Scripting Pro
Write Lua scripts to verify signatures, filter unwanted events, transform payloads, and route to specific URLs. See the full Lua Scripting documentation for the complete reference, examples, and error handling details.
Event Replay
Every inbound event is stored with the full request payload. You can replay any event from the dashboard or via the API — useful for reprocessing after a bug fix.
curl -X POST https://runlater.eu/api/v1/endpoints/:id/events/:event_id/replay \ -H "Authorization: Bearer pk_xxx.sk_xxx"
Inbound URL
The inbound URL accepts any HTTP method (GET, POST, PUT, PATCH, DELETE). No authentication is needed — the slug in the URL is the authentication, just like monitor ping tokens.
Responses
| Status | Body | Meaning |
|---|---|---|
200 |
{"id": "...", "status": "received"}
|
Event stored and queued for forwarding |
403 |
{"id": "...", "status": "rejected"}
|
Event rejected by Lua script (default for verify; script can override status code) |
404 |
{"error": "Not found"}
|
Invalid slug |
410 |
{"error": "Endpoint disabled"}
|
Endpoint is disabled |
Endpoints API
Manage endpoints programmatically via the REST API. All endpoints require an API key passed as a Bearer token. See the API Reference for authentication details.
List Endpoints
curl https://runlater.eu/api/v1/endpoints \ -H "Authorization: Bearer pk_xxx.sk_xxx"
Create Endpoint
| Field | Type | Description |
|---|---|---|
name |
string | Display name (required) |
forward_urls |
array | List of URLs to forward events to (required, at least one) |
retry_attempts |
integer | Number of retry attempts, 0-10 (default: 5) |
use_queue |
boolean | Enable serialized delivery (one at a time). Set to false for parallel. (default: true) |
enabled |
boolean | Whether the endpoint accepts events (default: true) |
forward_method |
string | Override HTTP method for forwarded requests (e.g. "POST") |
forward_headers |
object | Headers merged with originals (custom headers override on conflict) |
forward_body |
string | Replace original body for forwarded requests |
script |
string | Lua script for webhook processing (Pro only) |
secrets |
object | Encrypted key-value pairs accessible in verify() (Pro only, write-only) |
curl -X POST https://runlater.eu/api/v1/endpoints \ -H "Authorization: Bearer pk_xxx.sk_xxx" \ -H "Content-Type: application/json" \ -d '{ "name": "GitHub webhooks", "forward_urls": ["https://myapp.com/webhooks/github"], "retry_attempts": 3, "use_queue": false }'
Get Endpoint
curl https://runlater.eu/api/v1/endpoints/:id \ -H "Authorization: Bearer pk_xxx.sk_xxx"
Update Endpoint
curl -X PUT https://runlater.eu/api/v1/endpoints/:id \ -H "Authorization: Bearer pk_xxx.sk_xxx" \ -H "Content-Type: application/json" \ -d '{ "name": "Updated Name", "forward_urls": ["https://myapp.com/webhooks/new-url"] }'
Delete Endpoint
curl -X DELETE https://runlater.eu/api/v1/endpoints/:id \ -H "Authorization: Bearer pk_xxx.sk_xxx"
List Events
curl https://runlater.eu/api/v1/endpoints/:id/events \ -H "Authorization: Bearer pk_xxx.sk_xxx"
Replay Event
curl -X POST https://runlater.eu/api/v1/endpoints/:id/events/:event_id/replay \ -H "Authorization: Bearer pk_xxx.sk_xxx"
For the full API specification including request/response schemas, visit the interactive API docs.
Use Cases
Stripe webhooks
Never miss a payment event. Runlater buffers Stripe webhooks and forwards them to your app, even during deployments or downtime.
GitHub / GitLab events
Receive push, PR, and issue events reliably. Replay events to reprocess after a bug fix.
Third-party integrations
Any service that sends webhooks — Shopify, Twilio, SendGrid, Slack — can be received and forwarded with full history and retry support.
Tier Limits
| Free | Pro | |
|---|---|---|
| Endpoints | 3 | Unlimited |
| Event history | 7 days | 30 days |
| Lua scripting | — | Verify, filter, transform, route |