Webhook receivers
Webhook receivers
Let an external system push changes into your app. A WebhookReceiver manifest provisions the endpoint, hands your app its URL and token, and runs your register script when the app is installed.
Apps that mirror data from an external system (a CRM, a farm-management platform) need to know when that
data changes. Instead of asking users to create a webhook in the workspace settings, an app declares a
kind: WebhookReceiver manifest and installs it with spec.install. When the app is installed, the
platform:
- creates a managed inbound endpoint for the workspace. It accepts the provider's raw JSON, so no Verentis envelope or signature is needed.
- writes the endpoint URL and token into your app's settings.
- runs your
registerscript, which subscribes the external system to that URL.
When the manifest is removed, for example on uninstall, the platform runs your unregister script (best
effort) and deletes the endpoint. Every accepted delivery raises a webhook-received event that an
ExecutionTrigger can react to.
The manifest
api-version: verentis.io/v1
kind: WebhookReceiver
metadata:
id: sugarcrm-changes
name: SugarCRM record changes
spec:
application: sugarcrm-catalog-export # the app's metadata.id
source: sugarcrm
mapping: # JSON pointers into the provider body
event-type: "{/bean}.{/event}"
resource-type: /bean
resource-id: /data/id
event-id: "{/bean}:{/data/id}:{/data/date_modified}:{/event}"
settings: # app settings that receive the endpoint details
url: webhook-url
token: webhook-token
register:
engine: python
file: /scripts/integrations/sugarcrm/register-webhooks.py
arguments: ["--receiver", "{webhook.receiver}"]
unregister:
engine: python
file: /scripts/integrations/sugarcrm/unregister-webhooks.py
run-as:
service: sugarcrm-webhooks
scopes: [setting.read, file.read, file.write, file.write]
The app manifest declares the two settings as managed, so install doesn't ask for them:
spec:
settings:
- key: webhook-url
display-name: Webhook URL
managed: true
- key: webhook-token
display-name: Webhook token
secret: true
managed: true
metadata.idThe receiver id. It is unique per workspace and is what triggers refer to as receiver. The endpoint id is
derived from the workspace and this id, so it stays stable across updates and reinstalls.
spec.applicationThe owning app's metadata.id. It is required when spec.settings is set, because setting keys are
relative to the app.
spec.sourceThe source recorded on accepted events (e.g. sugarcrm).
spec.mappingTemplates that pull the event fields out of the raw body. A template is a JSON pointer (/data/id), a
literal, or text with pointers in braces ({/bean}.{/event}). Pointers missing from the body resolve to
empty text, and an empty event-type becomes provider.event. event-id is the deduplication key: a
redelivery with the same key is accepted once. If it resolves to empty, a hash of the raw body is used.
spec.settings.url / spec.settings.tokenApp setting keys (declared in your app manifest's spec.settings) that receive the endpoint URL and
token. Declare them with managed: true and make the token a secret. Users are then never asked for them
during install, and they appear read-only in the workspace settings.
spec.register / spec.unregisterScripts to run, in the same shape as an ExecutionTrigger's execute. {webhook.receiver} and
{webhook.endpointId} are substituted in arguments.
spec.run-asThe workspace service the register/unregister runs act as.
Authentication
The provider posts to https://<api-host>/v1/webhooks/inbound/<endpoint-id>/provider-events?token=<token>.
The URL written to the url setting already includes the token, so give the whole URL to the provider. The
token is the only credential, so treat the URL as a secret: don't log it or write it to files that users can
read.
Register scripts
Register scripts run every time the manifest is reconciled (install, upgrade, re-sync), so make them idempotent. Upsert subscriptions by a stable name and remove stale ones. If the external system can't be subscribed automatically, for example because the account lacks admin rights, write clear manual instructions somewhere the user will see them and exit successfully.
Settings changes
Changing the app's connection settings does not re-run register automatically. A scheduled job that
re-ensures the subscription (and polls for missed changes) is the recommended safety net.
Reacting to deliveries
api-version: verentis.io/v1
kind: ExecutionTrigger
metadata:
id: sugarcrm-changed
spec:
on:
- event: webhook-received
receiver: sugarcrm-changes
event-type: "*"
execute:
engine: python
file: /scripts/integrations/sugarcrm/sync-changed.py
arguments: ["--module", "{webhook.resourceType}", "--id", "{webhook.resourceId}", "--event", "{webhook.eventType}"]
run-as:
service: sugarcrm-webhooks
The run receives ids, not the payload. Fetch the changed record from the external system, which also protects you against forged or stale payloads.
Uninstall ordering
If unregister fails, the external system keeps posting to a deleted endpoint and gets 404s until
someone removes the subscription there.