Webhooks

A webhook lets a third-party service push events into your topology in real time, instead of you polling for changes. Orchesty exposes a stable HTTPS endpoint, owns the subscribe / unsubscribe handshake with the external API, and routes the incoming payload into the correct topology node for the right Application install.

For the trade-off between webhooks and scheduled polling, see Patterns: Scheduled processes. For the canvas UI mechanics — picker, badges, label actions — see Building nodes: Event nodes.

When to use a webhook #

Use a webhook when:

  • The third-party service supports outbound HTTP callbacks for the events you need.
  • You want sub-second latency between an event happening upstream and your topology starting work.
  • You want to avoid the cost (rate limits, bandwidth, missed updates) of polling.

Use a scheduled process instead when the upstream API does not support webhooks, or when batching is acceptable.

The webhook URL #

Every subscribed webhook has a single canonical callback URL:

{startingPoint}/topologies/{topology}/nodes/{node}/token/{token}/run
  • Name-based. Pinned to the topology and node names, so republishing a new topology version keeps the registration valid.
  • Token-protected. The token is generated by the platform when the webhook is subscribed and is the only authentication enforced on the route. Treat the URL as a credential.
  • Owned by the platform. You don't construct it yourself — the SDK ships it to the upstream API during subscribe, and the Admin UI exposes it through Copy URL once a webhook is Subscribed.

Older builds exposed /webhook/<application>/<token> and /webhook/topologies/.... Both are dead routes today; if you find them in legacy docs or third-party screenshots, they will not resolve.

What you implement #

To turn an Application into a webhook-aware Application, extend the webhook base class (Node.js) or implement the webhook interface (PHP):

SDKRecommendedStatus
Node.jsAWebhookApplication (extends ABasicApplication, implements IWebhookApplication)Canonical
PHPWebhookApplicationInterface implemented alongside ApplicationAbstractLegacy flow — see note below

The new AWebhookApplication base class (Node.js) wires the WebhookManager for you, which is what lets the SDK respond to the platform's syncSubscribeWebhook / syncUnsubscribeWebhook / syncListWebhookEvents calls without extra glue. Set getApplicationType() to ApplicationTypeEnum.WEBHOOK so the platform routes inbound events to the topology entry node instead of treating it as cron-driven.

Node.js
import AWebhookApplication from '@orchesty/nodejs-sdk/dist/lib/Application/Base/AWebhookApplication';
import WebhookSubscription from '@orchesty/nodejs-sdk/dist/lib/Application/Model/Webhook/WebhookSubscription';
import { ApplicationTypeEnum } from '@orchesty/nodejs-sdk/dist/lib/Application/Base/ApplicationTypeEnum';

export default class MyApp extends AWebhookApplication {
    public getName(): string { return 'my-app'; }
    public getPublicName(): string { return 'My App'; }
    public getDescription(): string { return 'Webhook example.'; }
    public getApplicationType(): ApplicationTypeEnum { return ApplicationTypeEnum.WEBHOOK; }

    public getWebhookSubscriptions(): WebhookSubscription[] {
        return [
            WebhookSubscription.create('order.created', { source: 'my-app' }, 'Fired when a new order is placed'),
            WebhookSubscription.create('order.updated', {}, 'Fired on order status / item changes'),
            WebhookSubscription.create('ping'),
        ];
    }

    // ... getWebhookSubscribeRequestDto / processWebhookSubscribeResponse
    // ... getWebhookUnsubscribeRequestDto / processWebhookUnsubscribeResponse
    // ... auth methods (isAuthorized, getFormStack, getAuthorizationType)
}

PHP — legacy flow. The PHP SDK does not yet ship an AWebhookApplication abstract base class. Continue implementing WebhookApplicationInterface directly; the node and topology arguments of the WebhookSubscription constructor are accepted for backwards compatibility but ignored — the topology and node come from the UI through WebhookConfig. A PHP equivalent of the Node.js base class is planned but not yet shipped.

The interface itself asks for five things — full method signatures live in the reference pages:

  1. Available subscriptions. getWebhookSubscriptions() returns one entry per event the Application advertises.
  2. Subscribe request. Build the HTTP request that registers a new webhook with the third-party API.
  3. Subscribe response. Parse the third-party response and return the external webhook id.
  4. Unsubscribe request. Build the HTTP request that removes a webhook by its external id.
  5. Unsubscribe response. Confirm the unsubscribe succeeded so the platform can flip the live registration off.

For full method signatures see Reference: Node.js / AWebhookApplication, Reference: Node.js / WebhookSubscription, or Reference: PHP / WebhookApplicationInterface.

Subscription lifecycle #

Orchesty splits a webhook into two layers: the intent (what the user configured for which topology and node) and the live registration (the external webhook id and token returned by the upstream API). Both move together but are persisted separately, which is what allows the platform to enable / disable an entire topology, detect orphans, and replay parameters when the user re-subscribes.

The end-to-end flow as seen by the user:

  1. Pick the subscription in the editor. Drop a Webhook node, double-click it (or right-click → Pick subscription), choose <application>.<event> from the search-friendly submenu. The node name is auto-set to the canonical form and is not user-renameable. Save and publish the topology — at this point the schema is purely declarative; no WebhookConfig exists yet.
  2. Subscribe. Open the topology detail page, click Subscribe on the webhook node. A small modal asks for an optional Parameters (JSON object) field. On submit, the platform lazily materialises a WebhookConfig from the Node document, calls the Application's getWebhookSubscribeRequestDto(...) upstream, parses the response with processWebhookSubscribeResponse(...), and stores the resulting Webhook (live registration + token).
  3. Receive events. The third-party service POSTs to the resulting token-protected URL. The platform validates the token, persists the message, and routes it to the webhook node as the starting message of the topology.
  4. Unsubscribe. Click Unsubscribe in the topology detail. One click, no confirm, idempotent — a second click against an already-off webhook is a no-op. The platform calls getWebhookUnsubscribeRequestDto(...) upstream and flips enabled = false on the config (kept around so the Subscribe modal can pre-fill last-known parameters).

Re-subscribing with different parameters #

There is no "edit while subscribed" path. To change parameters, click Unsubscribe, then Subscribe. The modal pre-fills the previously persisted parameters, so re-confirming the same payload is a one-click operation. This keeps the upstream API in lockstep with what the UI shows.

Cascade on enable / disable #

Enabling or disabling the topology cascades to every webhook node it owns. The platform calls WebhookConfigManager::cascadeForTopology(topologyName, enable), which subscribes / unsubscribes every enabled config in one batch. Partial failures (e.g. one of three configs fails to subscribe upstream) surface as toasts on the detail page; the rest of the topology stays operational.

Orphan handling #

A subscribed webhook becomes an orphan when its nodeName is not present in the currently enabled version of the topology — usually because the topology was republished and the webhook node was renamed or removed, or because a manual schema import dropped the node bypassing the editor cascade.

The detail page surfaces orphans in a yellow banner with a one-click Cleanup action. Cleanup best-effort unsubscribes the live registration and removes the WebhookConfig.

Edge case — no enabled version. When no version of the topology is enabled (paused for editing, freshly cloned, or permanently disabled), orphan detection is skipped. Otherwise simply disabling a topology would scream at the user with cleanup banners for registrations they will need back the moment they re-enable. The banner re-appears the next time a version is enabled.

Operational notes #

  • Idempotency. Some third-party services retry their callbacks. Make sure your starting node tolerates duplicate deliveries (a unique id check on the inbound event is the usual answer).
  • Verification. If the third-party service signs callbacks, validate the signature in your starting node and stop the message if validation fails.
  • Backpressure. If the upstream sends bursts, the platform queue absorbs them; downstream parallelism is controlled by your per-node prefetch and any rate limiters you configure on the connectors that follow.

See also #

© 2025 Orchesty Solutions. All rights reserved.