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.

  1. Create an endpoint with a name and forward URLs
  2. Copy the inbound URL and paste it into Stripe, GitHub, or any service
  3. Runlater receives the webhook, stores the full payload, and forwards it to your app
  4. If forwarding fails, we retry with exponential backoff (configurable, 0-10 attempts)
  5. Choose serial (queued) or parallel delivery per endpoint
Why use this? External services don't retry forever. If your server is down when Stripe sends a webhook, you lose it. Runlater acts as a buffer — we always accept the webhook and forward it when your server is ready.

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.

Note: If an event fails, it will be retried with exponential backoff. Other events in the queue will continue to be delivered while the failed event waits to be retried.

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.

Use case: A third-party service sends GET webhooks but your app only accepts POST. Set 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 forwardingtransform()route() → forward
  1. verify() and filter() always see the original headers, body, and method — so signature checks work correctly.
  2. Custom Forwarding applies static defaults (method, headers, body) for the forwarded request.
  3. Lua transform() runs last. Any values it returns override the Custom Forwarding values. Fields it doesn’t return keep the Custom Forwarding value.
Free vs Pro: Free tier users can use Custom Forwarding (no Lua). Pro tier users get both — Lua 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