- Getting started
- Best practices
- Tenant
- About the Tenant Context
- Searching for Resources in a Tenant
- Managing Robots
- Connecting Robots to Orchestrator
- Storing Robot Credentials in CyberArk
- Storing Unattended Robot Passwords in Azure Key Vault (read only)
- Storing Unattended Robot Credentials in HashiCorp Vault (read only)
- Storing Unattended Robot Credentials in AWS Secrets Manager (read only)
- Deleting Disconnected and Unresponsive Unattended Sessions
- Robot Authentication
- Robot Authentication With Client Credentials
- SmartCard Authentication
- Audit
- Settings - Tenant Level
- Resource Catalog Service
- Folders Context
- Automations
- Processes
- Jobs
- Triggers
- Logs
- Monitoring
- Queues
- Assets
- Storage Buckets
- Test Suite - Orchestrator
- Other Configurations
- Integrations
- Classic Robots
- Host administration
- Organization administration
- Troubleshooting
Webhooks
Webhooks enable you to better integrate your UiPath® automation with your entire application ecosystem. You can subscribe to Orchestrator events and send them to any external DCM, BPM, or CRM solution and inform different users, for example, that there is a new queue item that can be processed, a trigger has failed, or a process has been updated.
Webhooks allow external systems to subscribe and listen to different types of Orchestrator events. The Webhooks page enables you to easily set them up and view the ones that have been previously created. You can also disable webhooks, search for a specific one, edit or delete them.
Events are available for jobs, robots, queues, queue items, processes, and triggers. For the complete list of event types and a few examples, please check this page.
Each event sends a payload to a specified URL containing information. Some properties are common for all, while others are particular to each event type.
Webhook events are created per folder, so if you have a webhook event associated to a resource that is shared across folders, such as a queue, a separate webhook event is generated for each of those folders.
If the request to forward an event fails, the circuit breaker for that particular webhook opens, disabling the webhook for one hour.
- Any webhook events that should have been sent while the circuit breaker is open are skipped and not retried once the circuit breaker closes.
- Webhook events are not stored, and cannot be retried or exported. Furthermore, if the call to the external platform fails, the event is lost. Webhooks are designed for real-time processing.
Property Name |
Property Type |
Description and Example |
---|---|---|
Type |
string |
The event type that triggered the notification. This property is displayed for all types of events. Example:
|
EventId |
string |
An identifier uniquely generated for each event when it occurred. This property is displayed for all types of events. Example:
|
Timestamp |
RFC 8601 date |
The date and time at which the event was generated. This property is displayed for all types of events. Example:
|
TenantId |
integer |
The id of the tenant on which the event was generated. The default tenant is 1. This property is displayed for all types of events. Example:
|
UserId |
integer |
The user id whose action triggered the event. This parameter is not displayed if the event is triggered by either a Robot or a trigger. This property is displayed for all types of events. Example:
|
FolderId |
integer |
The id of the folder in which the event was generated. This parameter is not displayed for events triggered by modern robots. Example:
|
To perform various operations on the Webhooks page, you need to be granted the corresponding permissions on webhooks:
- View - Enables you to view webhooks and their details, as well as retrieve them using the API, send a ping request, or get the list of all the events a webhook can subscribe to.
- Create - This permission enables you to add new webhooks. Please note that you also require View permissions.
- Edit - Grants you the right to edit webhooks from the UI or by using the API. Please note that you also require View permissions.
- Delete - A permission that enables you to delete webhooks. Please note that you also require View permissions.
X-UiPath-Signature
HTTP header.
Client apps that receive Orchestrator requests must check the requests' authenticity. The request signing follows the following pattern:
- The client app receives a webhook request from Orchestrator;
- The client app computes a signature based on the request;
-
The client app tries to match the signature it computed with the request signature:
- If the signatures do not match, the client app should not process the request.
- If the signatures match, the client app should process the request.
Computing the signature should be done as follows:
- Retrieve the
X-UiPath-Signature
HTTP header. - To obtain the raw signature bytes, decode the value of the header from Base64.
-
Retrieve the raw request body.
Note: Orchestrator requests are always encoded using UTF-8. - Compute the hash using SHA256 and the signing key (UTF-8 encoded).
-
Compare the computed signature to the value from
X-UiPath-Signature
HTTP header:- If the signatures do not match, do not process the request.
- If the signatures match, the client app should process the request.
using System;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
public async Task<bool> IsValidRequestAsync(HttpRequestMessage request, string secret)
{
if (!request.Headers.TryGetValues("X-UiPath-Signature", out var headerValues))
return false;
var orchestratorSignature = Convert.FromBase64String(headerValues.First());
using (var sha = new HMACSHA256(key: Encoding.UTF8.GetBytes(secret)))
{
var computedSignature = sha.ComputeHash(await request.Content.ReadAsByteArrayAsync());
return ByteArrayEquals(orchestratorSignature, computedSignature);
}
}
using System;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
public async Task<bool> IsValidRequestAsync(HttpRequestMessage request, string secret)
{
if (!request.Headers.TryGetValues("X-UiPath-Signature", out var headerValues))
return false;
var orchestratorSignature = Convert.FromBase64String(headerValues.First());
using (var sha = new HMACSHA256(key: Encoding.UTF8.GetBytes(secret)))
{
var computedSignature = sha.ComputeHash(await request.Content.ReadAsByteArrayAsync());
return ByteArrayEquals(orchestratorSignature, computedSignature);
}
}
const { createServer } = require('http');
const { createHmac } = require('crypto');
const PORT = 9090
const WEBHOOK_SECRET = '<same secret as configured in Orchestrator>'
const isValidRequest = (body /* Buffer */, secret /* string */, expectedSignature /* string */) =>
expectedSignature == null || createHmac('sha256', secret)
.update(body)
.digest('base64') === expectedSignature
const server = createServer((req, resp) => {
let body = new Buffer([])
req.on('data', chunk => body = Buffer.concat([body, chunk]))
req.on('end', () => {
if (!isValidRequest(body, WEBHOOK_SECRET, req.headers['x-uipath-signature'])) {
console.error('Invalid signature')
resp.statusCode = 401 // Unauthorized
} else {
let payload = JSON.parse(body.toString('utf8'))
// Process request
console.log(payload)
resp.statusCode = 202 // Accepted
}
resp.end()
})
})
server.listen(PORT)
const { createServer } = require('http');
const { createHmac } = require('crypto');
const PORT = 9090
const WEBHOOK_SECRET = '<same secret as configured in Orchestrator>'
const isValidRequest = (body /* Buffer */, secret /* string */, expectedSignature /* string */) =>
expectedSignature == null || createHmac('sha256', secret)
.update(body)
.digest('base64') === expectedSignature
const server = createServer((req, resp) => {
let body = new Buffer([])
req.on('data', chunk => body = Buffer.concat([body, chunk]))
req.on('end', () => {
if (!isValidRequest(body, WEBHOOK_SECRET, req.headers['x-uipath-signature'])) {
console.error('Invalid signature')
resp.statusCode = 401 // Unauthorized
} else {
let payload = JSON.parse(body.toString('utf8'))
// Process request
console.log(payload)
resp.statusCode = 202 // Accepted
}
resp.end()
})
})
server.listen(PORT)