Appearance
Webhooks
ordyn-webhooks lets external systems trigger Ordyn jobs through HTTP webhooks.
The webhook service receives public HTTP requests, normalizes them, authenticates them according to each webhook definition, and forwards events to Ordyn.
Use webhooks when another application should start an Ordyn job for a known endpoint, for example:
- a monitoring system detects a condition and asks Ordyn to remediate the affected machine
- a deployment platform notifies Ordyn after an infrastructure change
- a company portal starts a controlled endpoint action without giving the caller direct Ordyn server access
- another automation tool passes structured data into an Ordyn job
Webhooks are available in Administration > Services on the Webhooks tab.
How it works
At a high level:
- An admin creates a webhook service client in Ordyn.
- An admin issues a service-client enrollment token scoped to that webhook service client.
- The
ordyn-webhooksservice enrolls through the configured edge service by using the scoped token once. - Ordyn publishes signed runtime webhook configuration to the connected service client.
- External systems call the public webhook URL.
- The webhook service validates the request and forwards a signed normalized event to Ordyn.
- Ordyn stores the webhook event and starts matching endpoint trigger rules.
The webhook service accepts public ingress traffic. It does not require external callers to reach the Ordyn server directly.
The service-client control path uses edge:
- the webhook service connects outward to edge for enrollment and runtime messages
- Ordyn sends runtime configuration
- received webhook events are sent back through the same service-client channel
Service clients
A webhook service client represents one running ordyn-webhooks instance.
Create it in Administration > Services on the Webhooks tab by selecting Create client.
The service client needs:
- name
- edge service
- public base URL
- enabled state
The public base URL is the externally reachable base address for that webhook service, for example:
text
https://ordyn-webhooks.example.comOrdyn uses this value to display the full URL for each webhook. The service accepts webhook calls under:
text
<public base URL>/v1/hooks/<webhook slug>After creating a service client, issue a service-client enrollment token for it from the enrollment tokens page. Run the service enrollment command with that token. The command stores the service-client certificate state on disk, and the token is only needed for that enrollment.
Each webhook service client has a detail page that shows connection state, version, current certificate serial, certificate expiration, enrollment timestamps, and the configured public base URL. Admins can enable or disable the service client and revoke the current certificate from the detail page. A revoked certificate requires the service client to enroll again before it can connect. See service-client certificate lifetime and renewal for the renewal workflow.
Runtime configuration
The service needs these values at runtime:
| Environment variable | Purpose |
|---|---|
ORDYN_WEBHOOK_EDGE_HOST | Edge host used for service-client enrollment and the service-client websocket. |
ORDYN_WEBHOOK_SERVICE_CLIENT_ID | The service client ID from Ordyn. |
ORDYN_WEBHOOK_PUBLIC_BASE_URL | Public base URL shown in Ordyn for webhook URLs. |
Start the service, then enroll it after configuring those values:
bash
docker compose exec webhooks node dist/index.js enrollFor install answer file setup, pipe the enrollment token into the command:
bash
printf '%s' '<enrollment-token>' | docker compose exec -T webhooks node dist/index.js enroll --token-stdinCommon optional values:
| Environment variable | Purpose |
|---|---|
ORDYN_WEBHOOK_STATE_PATH | Persistent enrollment state file. Defaults to /data/service-client-state.json. |
ORDYN_WEBHOOK_BODY_LIMIT | Maximum accepted request body size. |
ORDYN_RUNTIME_LOG_DIR | Directory for service runtime logs. |
ORDYN_RUNTIME_LOG_RETENTION_DAYS | Retention for logs written by the service. |
PORT | HTTP listen port inside the service container. |
Backend webhook event retention is configured separately:
| Environment variable | Purpose |
|---|---|
ORDYN_WEBHOOK_EVENT_RETENTION_DAYS | Number of days to keep stored webhook event payloads in Ordyn. Defaults to 30. Set to 0 or lower to disable pruning. |
Keep the state path on persistent storage. If the state file is removed, the service must enroll again.
Installation
Prerequisites:
Checkout the webhook deployment folder from the Ordyn compose repository:
bash
if [ ! -d /opt/ordyn-compose/.git ]; then
git clone --filter=blob:none --sparse https://github.com/ordyn-project/compose.git /opt/ordyn-compose
fi
cd /opt/ordyn-compose
git sparse-checkout add webhooksCreate the environment file:
bash
cd /opt/ordyn-compose/webhooks
cp .env.example .envSet these values in .env:
dotenv
SERVICE_DOMAIN=ordyn-webhooks.example.com
ORDYN_WEBHOOK_EDGE_HOST=ordyn-edge.example.com
ORDYN_WEBHOOK_SERVICE_CLIENT_ID=<service-client-id>
ORDYN_WEBHOOK_PUBLIC_BASE_URL=https://ordyn-webhooks.example.comStart the service:
bash
docker compose pull
python3 /opt/cosign-docker-verify/verify.pyContinue with docker compose up -d only when the webhook image verifies successfully and no failed verification message appears.
bash
docker compose up -dIssue a service-client enrollment token for the webhook service client in Ordyn. Enroll the service once:
bash
printf '%s' '<enrollment-token>' | docker compose exec -T webhooks node dist/index.js enroll --token-stdinThe webhook service needs public HTTPS ingress for /v1/hooks/. The provided compose file routes that path through Traefik.
Public ingress
The service exposes incoming webhook calls at:
text
/v1/hooks/:slugThe slug is generated by Ordyn when the webhook is created. It is part of the copied webhook URL.
Only that ingress path needs to be publicly reachable. Service-client enrollment and control traffic are outbound from the webhook service to edge.
Source-IP authentication uses caller addresses forwarded by Traefik.
Configure rate limiting on public webhook routes when a webhook endpoint is exposed to untrusted networks or high-volume callers.
Webhook definitions
A webhook definition belongs to one webhook service client and one approved endpoint.
Create it in Administration > Services on the Webhooks tab by selecting Create webhook.
A webhook has:
- service client
- endpoint
- name
- allowed HTTP methods
- authentication mode
- optional source IP allowlist
- optional job variable mappings
- enabled state
The endpoint binding is part of the webhook definition. A received webhook can start jobs for the configured endpoint. Endpoint selection from the incoming payload is not part of this workflow.
Disabled webhooks are not accepted by the ingress service and do not trigger jobs.
Allowed methods
Each webhook can allow one or more HTTP methods:
GETPOSTPUTPATCHDELETE
The default method is POST.
If a request uses a method that is not allowed, the service rejects it before forwarding an event to Ordyn.
Authentication
Webhook authentication is configured per webhook definition.
Supported modes:
| Mode | Behavior |
|---|---|
| Unauthenticated | No token is required. Use only for trusted networks or low-risk integrations. |
| Bearer token | The caller sends Authorization: Bearer <token>. |
| Header token | The caller sends the token in the configured header, for example X-Ordyn-Webhook-Token. |
| Source IP allowlist | The caller source IP must match one configured IP address or CIDR range. |
Bearer-token and header-token values are hashed before they are stored in Ordyn. Tokens are not shown again after saving.
Source IP allowlists support individual IP addresses and CIDR ranges, for example:
text
203.0.113.10
203.0.113.0/24
2001:db8::/32Source-IP checks use the caller address forwarded by Traefik.
Request payloads
The webhook service stores and forwards a normalized request shape.
It records:
- webhook ID and slug
- receive timestamp
- HTTP method
- source IP
- content type
- sanitized headers
- query parameters
- parsed body
- raw body
JSON request bodies are parsed as JSON. application/x-www-form-urlencoded bodies are parsed into fields. Other body types are forwarded as text in the normalized request.
Sensitive caller tokens are used for authentication and should not be treated as job input.
Job trigger rules
Webhook-triggered jobs are configured from the endpoint's automation or trigger area.
Create a job trigger rule with:
- event
Webhook received - the webhook definition to match
- the job to run
- optional maximum random delay
Webhook trigger rules apply to endpoint scopes. The rule matches only when:
- the webhook definition is active
- the webhook's endpoint is approved
- the rule is enabled
- the rule is attached to the same endpoint
- the rule references the received webhook definition
When multiple matching rules exist for the endpoint, Ordyn evaluates them in their configured order. The optional random delay can spread bursts when an external system sends many events.
Job variables
Triggered jobs receive webhook trigger details under:
text
trigger.webhookThe run also has trigger.type set to webhook_received and trigger.source set to webhook. See Variables for the full trigger field list.
Webhook definitions can also map selected request values to short job variables under:
text
webhook.<name>For example, a mapping with:
| Name | Path |
|---|---|
build_id | body.build.id |
makes the value available as:
text
{{ webhook.build_id }}Mapping paths are evaluated against the normalized request, so useful prefixes are usually:
bodyqueryheaderssource_ipmethodcontent_type
Use mappings for values that job authors should consume directly. Use trigger.webhook.* when a job needs the full request context.
Example
An external system sends:
bash
curl -X POST \
https://ordyn-webhooks.example.com/v1/hooks/3d72... \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
--data '{"build":{"id":"2026.06.25.1"},"action":"restart-service"}'With a variable mapping:
| Name | Path |
|---|---|
build_id | body.build.id |
action | body.action |
the triggered job can use:
text
{{ webhook.build_id }}
{{ webhook.action }}
{{ trigger.webhook.source_ip }}Events and diagnostics
Ordyn stores each received webhook event with the normalized request, mapped variables, matching trigger rules, dispatched trigger rules, and any dispatch error.
Webhook events are retained for 30 days by default. Ordyn removes events outside the retention window according to ORDYN_WEBHOOK_EVENT_RETENTION_DAYS.
The webhook definition shows the last receive timestamp and last error. Common last-error causes are:
- the webhook's endpoint is not approved
- no enabled trigger rule matched the webhook and endpoint
- the webhook was received while the definition was inactive
Service-client connection state is shown on the Webhooks page. It includes connection status, version, certificate serial, last enrollment, last connection, last seen time, and last error.
Support bundles
Webhook service clients participate in service-client log bundles.
Use support bundles when troubleshooting:
- webhook service enrollment problems
- service-client connection loss
- runtime configuration not reaching the service
- received requests not triggering jobs
- authentication failures reported by the webhook service
Select the webhook service client as a log source when creating a service-client log bundle.
Security recommendations
Use token authentication or source-IP allowlists for production webhooks.
Prefer:
- HTTPS on public webhook routes
- long random bearer or header tokens
- source-IP allowlists when the caller has stable egress addresses
- one webhook per integration purpose
- narrow job trigger rules on the intended endpoint
- mapped variables for the specific fields a job needs
Avoid:
- unauthenticated public webhooks
- passing secrets in request bodies unless the job genuinely requires them
- using a shared webhook for unrelated external systems
- exposing service-client control paths publicly
Limitations
Webhook definitions are endpoint-bound.
Limitations:
- a webhook definition targets one approved endpoint
- endpoint selection is not extracted from the incoming payload
- webhook trigger rules are endpoint-scope rules
- authentication is per webhook definition, not per trigger rule
- request bodies are normalized for job input, but Ordyn does not transform arbitrary payload formats beyond JSON and form parsing
Use variable mappings to adapt different caller payload shapes into stable job variables.