Receive proactive notifications via outbound webhook
Receive push notifications from Moveworks when a new system-initiated message is available, and reconcile content via the events endpoint.
The Conversations API is in Controlled Availability. Endpoints, behaviors, and configuration surfaces may change during CA. Contact your Moveworks account team to participate.
Receive push notifications from Moveworks when a new system-initiated message is available for one of your users. Outbound webhook push is the recommended delivery path for proactive notifications: lower latency to your users and lower load on Moveworks compared to polling. On each notification, retrieve the full content via the events endpoint.
Before reading this page, review Proactive notifications overview for architecture, routing behavior, and prerequisites.
Register the outbound webhook
Navigate to Setup → Core Platform → Outbound Webhooks in your Moveworks Admin Portal and click Create. Configure the following fields:
You can update subscribed event types or delete a webhook endpoint through the same dashboard.
Event types
Webhook payload
Each delivery is a POST request to your endpoint with a JSON body.
Envelope structure
The payload is a thin envelope: it signals that a system-initiated message exists for a user, but does not embed the full message content. After receiving a webhook, call the events endpoint to retrieve the message(s) in canonical order.
Request headers
Every webhook delivery includes the following HTTP headers:
Signature verification
Moveworks uses asymmetric RSA signature verification (RSA-SHA256). Moveworks holds a private key and signs each webhook payload. Your integration verifies the signature using the corresponding public key, fetched from the Moveworks JWKS endpoint for your tenant.
JWKS endpoint. Your tenant’s JWKS endpoint is at your Admin Portal domain, at the standard /.well-known/jwks.json path:
The endpoint is publicly accessible (no auth required) and returns a standard JWKS document with one or more registered public keys, each identified by its kid field.
Retrieve the public key
Use the webhook-kid header value on the incoming delivery to look up the matching key (by its kid field) in https://{org}.moveworks.com/.well-known/jwks.json for your tenant.
During a key-rotation grace period, the webhook-signature header may contain more than one signature. Verify against each and accept the request if any signature is valid.
Key rotation
Moveworks rotates the webhook signing key on the interval you configure. Rotation is transparent to your integration as long as your verifier looks up the public key by the webhook-kid header on each request.
What happens on rotation:
- Moveworks generates a new signing key with a new
kidin the JWKS document. - New webhook deliveries are signed with the new key. The
webhook-kidheader on those deliveries reflects the new key. - During the Rotation Grace Period, the previous key remains available at
https://{org}.moveworks.com/.well-known/jwks.jsonso your verifier can still validate late-arriving webhooks (for example, retried deliveries) that were signed with the previous key. - When the grace period expires, the previous key is removed from the JWKS endpoint.
What your verifier needs to do:
- Look up the public key by the
webhook-kidheader on each request; do not hardcode a single key. - If you cache JWKS responses, invalidate on an unknown
webhook-kidso a newly rotated key is picked up on demand. - The signature verification steps above are unchanged across rotations; only the key lookup differs.
After receiving a webhook
The example below uses https://api.moveworks.ai, which is only correct for orgs on the US Production data center. Replace it with the base URL for your data center from the Base URLs table (for example, https://api.am-eu-central.moveworks.ai for EU). Requests to the wrong host return 404 or invalid_audience.
Once a webhook is verified and acknowledged, retrieve the message content via the events endpoint:
Substitute:
<WEBHOOK_ID>— theidfrom the webhook envelope. Passed asending_at(inclusive upper bound), bounding the query to events at or before this webhook.<YOUR_CHECKPOINT>— theevent_idyou last successfully processed for this user. Passed asstarting_after(exclusive lower bound).
See Receive via polling for the full response schema and checkpoint semantics.
Delivery semantics
Acknowledgment. Your webhook endpoint must respond with a 2xx status code within 15 seconds. No response or a non-2xx response is treated as a failed delivery.
At-least-once delivery. Moveworks delivers webhooks with at-least-once semantics: the same event may be delivered more than once across retries. Implement idempotency using webhook-id. On receipt, check whether you have already processed that ID and discard duplicates.
Retry schedule. Failed deliveries retry with pure exponential backoff, doubling the wait time between each attempt. The full schedule spans up to 11 retries capped at a 24-hour total window:
The final retry is truncated so total elapsed time lands exactly on the 24-hour mark rather than continuing the pure doubling pattern.
No further attempts are made after 24 hours. Use the events endpoint with your last stored checkpoint to recover any events that exhausted all retries.
HTTP status handling.
Scope. Webhooks fire at the org level: a single registered endpoint receives events for all users. The events endpoint, in contrast, is scoped to a single user, consistent with all other Conversations API endpoints. Per-user recovery still uses each user’s stored last_event_id.
Recommended patterns
Acknowledge first, process asynchronously
Return 200 OK immediately after signature verification and idempotency checks. Perform all downstream work (fetching content, pushing to clients) asynchronously. The 15-second timeout applies to your response only.
Idempotency
Persist processed webhook-id values and short-circuit duplicates on receipt. The webhook-id is stable across all retries of the same event.
Per-user checkpoint
Maintain a {user_id, last_event_id} record per user, following the same rules described in Per-user checkpoint on the polling page. The webhook envelope’s id is the value you use as the upper bound (ending_at=<id>) when fetching content via the events endpoint after a webhook.