Skip to content
routeup

Webhook development

Webhook providers need a public HTTPS URL to deliver to. routeup gives your local service one, so you can develop against real deliveries instead of mocking them.

Run your API (say on port 8080) and expose it:

Configure a public server first using Exposing publicly.

terminal
routeup serve example-app --port 8080 --expose

The examples below assume your saved token allows *.team.routeup.dev.

routeup prints the local URL, public URL, exposure scope, and targets:

terminal
route: example-app
local: https://example-app.localhost
public: https://example-app.team.routeup.dev
expose: all paths
targets:
/ http://localhost:8080
requests: live
press Ctrl-C to stop

Register the public URL as the webhook endpoint in the provider’s dashboard:

terminal
GitHub: Settings → Webhooks → Payload URL
Stripe: Developers → Webhooks → Add endpoint
Slack: Your App → Event Subscriptions → Request URL

Use the full path your handler listens on, e.g. https://example-app.team.routeup.dev/api/webhooks/github.

Tail public traffic as it arrives:

terminal
routeup logs example-app --public --follow
terminal
TIME ROUTE SOURCE STATUS ID METHOD DURATION PATH
12:41:03 example-app public 200 req_Ap7kQ3mN8vR2xLzC POST 38ms /api/webhooks/github

Because the route and namespace are configured, you request the same endpoint on each run instead of accepting a newly generated URL. Public claims remain subject to the server’s normal conflict rules.

routeup logs shows metadata only. To see the full payload and response for a delivery, enable capture in routeup.json:

Stop the current route owner, add this config, then restart routeup serve --expose before sending the delivery you want to inspect.

routeup.json
{
"name": "example-app",
"port": 8080,
"capture": {
"request": true,
"response": true,
"redact_headers": ["x-hub-signature-256", "authorization"]
}
}

In another terminal, or after stopping the follow command, grab the request id from the log line and inspect it:

terminal
routeup inspect req_Ap7kQ3mN8vR2xLzC
routeup inspect req_Ap7kQ3mN8vR2xLzC --curl

The curl form produces a command for sending the captured request to the local route. It includes every retained header. Signature or authorization headers appear only when capture retained them; add them to redact_headers above when they should not be stored or exported.

terminal
Request req_Ap7kQ3mN8vR2xLzC
Metadata
--------
Source: public
Route: example-app
Target: /:8080
Status: 200
Duration: 38ms
Method: POST
Path: /api/webhooks/github
Host: example-app.team.routeup.dev
Request
-------
Capture: complete
Body bytes: 63
Redacted: authorization, x-hub-signature-256
X-Github-Event: push
Body
----
{
"ref": "refs/heads/main",
"repository": {
"full_name": "acme/api"
}
}
Response
--------
Capture: complete
Body bytes: 11
Redacted: authorization, x-hub-signature-256
Content-Type: application/json
Body
----
{
"ok": true
}

If you only want the webhook path reachable and the rest of the app private, you can limit public exposure to a path prefix (for example /api/webhooks/*) so the rest of the service stays local-only:

Restart the route owner after changing this setting.

routeup.json
{
"name": "example-app",
"port": 8080,
"expose": {
"paths": ["/api/webhooks/*"]
}
}