Webhooks offer a lightweight, real-time way to trigger Octoparse AI apps directly from your own system. By sending an HTTP POST request to a unique webhook URL, you can start an app remotely, pass in input variables, and even specify which bot should run the task. This makes it easy to integrate automation into your internal systems, such as CRMs, ERPs, or other backend services.
Each webhook trigger is associated with a specific app. Once configured, it allows external systems to initiate that app’s execution with just a single API call.
Setting Up a Webhook Trigger
To use a webhook, you’ll first need to create a webhook trigger for the app you want to run. This is done under the Triggers section of your app configuration. Click + New Trigger button, choose the Webhook option and follow the setup steps.
Once completed, you’ll be given a unique webhook URL. If needed, you can also enable signature verification for added security, which will require your system to sign each request.
Be sure to enable the trigger after setup. The webhook will not work until it’s explicitly activated.
Generating the Signature
If you’ve enabled signature verification, each request must include a valid sign
field. This signature helps ensure that only authorized systems can trigger the app.
To generate the signature, concatenate the timestamp and your secret key with a newline in between, like this: timestamp + "\n" + secretKey
Then, hash the string using the HmacSHA256 algorithm and encode the result in Base64. The resulting string is what you’ll place in the sign
field of your request body.
Making a Webhook Request
Once you’ve obtained the webhook URL, you can send a POST request to it using JSON format. The request body can include a timestamp, an optional security signature, and a set of custom parameters for the app.
Here’s what a typical request body looks like:
{
"sign": "Base64-encoded HMAC-SHA256 signature",
"params": {
"CustomVar1": "value1",
"CustomVar2": "value2"
},
"timestamp": "Unix timestamp in seconds"
}
The timestamp
is required and should be the current Unix timestamp (in seconds). If signature verification is enabled in webhook setting, the sign
field must contain a valid signature. The params
object includes key-value pairs matching your app’s custom variables.
Request Frequency Limits
Webhook triggers are subject to rate limits to protect system stability. You can send up to 5 requests per second, with a maximum of 20 requests per minute. If these limits are exceeded, the server will return an error response indicating that the rate limit has been hit. To maintain performance, make sure your calling system implements appropriate retry or throttling logic.
Sample Implementation
Below are examples of how to trigger an app using Python, C#, and Java, showing how to construct the request body, generate the signature, and handle the response.
Python
import requests
import json
import hashlib
import hmac
import base64
import time
key = "your_secret_key"
url = "your_webhook_url"
payload = {
"InputVariable1": "value1",
"InputVariable2": "value2"
}
timestamp = str(int(time.time()))
def get_sign(secret, timestamp):
string_to_sign = timestamp + "\n" + secret
sign_data = hmac.new(string_to_sign.encode(), None, hashlib.sha256).digest()
return base64.b64encode(sign_data).decode()
rpa_webhook = {
"timestamp": timestamp,
"sign": get_sign(key, timestamp),
"params": payload,
}
try:
headers = {'Content-Type': 'application/json'}
response = requests.post(url, data=json.dumps(rpa_webhook), headers=headers)
if response.status_code == 200:
print("Webhook triggered successfully.")
else: res = response.json()
print("Failed to trigger the webhook.")
print(f"Error description: {res.get('description', 'No description provided')}")
print(f"Error code: {res.get('code', 'No error code')}")
except Exception as ex:
print(f"An exception occurred: {ex}")
raise
C# (.NET 6+)
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using WebhookDemo.Dtos;
var key = "your_secret_key";
var url = "your_webhook_url";
using var client = new HttpClient();
try
{
var @params = new Dictionary<string, object>
{
{ "InputVariable1", "Value1" },
{ "InputVariable2", "Value2" }
};
var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
var rpaWebhook = new RpaWebhookDto(
timestamp.ToString(),
GetSign(key, timestamp),
@params);
var result = await client.PostAsync(url,
new StringContent(JsonSerializer.Serialize(rpaWebhook), Encoding.UTF8, "application/json"));
if (result.IsSuccessStatusCode)
{
Console.WriteLine("Webhook triggered successfully.");
return;
}
var res = JsonSerializer.Deserialize<WebhookInvokeFailureDto>(
await result.Content.ReadAsStringAsync(),
new JsonSerializerOptions { PropertyNameCaseInsensitive = true }
);
Console.WriteLine("Failed to trigger the webhook.");
Console.WriteLine($"Error description:{res!.Description}");
Console.WriteLine($"Error Code:{res!.Code}");
}
catch (Exception ex)
{
Console.WriteLine($"Exception:{ex.Message}");
throw;
}
static string GetSign(string secret, long timestamp)
{
string stringToSign = timestamp + "\n" + secret;
using HMACSHA256 hmac = new(Encoding.UTF8.GetBytes(stringToSign));
byte[] signData = hmac.ComputeHash(Array.Empty<byte>());
return Convert.ToBase64String(signData);
}
namespace WebhookDemo.Dtos
{
public sealed record RpaWebhookDto(
string Timestamp,
string Sign,
Dictionary<string, object>? Params
);
public sealed record WebhookInvokeFailureDto(
string Code,
string Description,
string? RequestId
);
}
Java
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Instant;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import com.google.gson.Gson;
public class Main {
static HttpClient client = HttpClient.newHttpClient();
public static void main(String[] args) throws NoSuchAlgorithmException, IOException, InterruptedException {
String key = "your_secret_key";
String url = "your_webhook_url";
long timestamp = Instant.now().getEpochSecond();
String sign = getSign(key, timestamp);
Map<String, Object> params = new HashMap<>();
params.put("InpoutVariable1", "Value1");
params.put("InpoutVariable2", "Value2");
RpaWebhookDto rpaWebhook = new RpaWebhookDto(Long.toString(timestamp), sign, params);
String requestBody = new Gson().toJson(rpaWebhook);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
System.out.println("Webhook triggered successfully.");
return;
}
WebhookInvokeFailureDto res = new Gson().fromJson(response.body(), WebhookInvokeFailureDto.class);
System.out.println("Failed to trigger the webhook.");
System.out.println("Error description:" + res.getDescription());
System.out.println("Error code:" + res.getCode());
}
static String getSign(String secret, long timestamp) {
String stringToSign = timestamp + "\n" + secret;
try {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(stringToSign.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
mac.init(secretKeySpec);
byte[] result = mac.doFinal();
return Base64.getEncoder().encodeToString(result);
} catch (Exception e) {
throw new RuntimeException("getSign error", e);
}
}
static class RpaWebhookDto {
String Timestamp;
String Sign;
Map<String, Object> Params;
public RpaWebhookDto(String timestamp, String sign, Map<String, Object> params) {
Timestamp = timestamp;
Sign = sign;
Params = params;
}
}
static class WebhookInvokeFailureDto {
String Code;
String Description;
String RequestId;
}
}
Common Issues and Troubleshooting
If your webhook request fails, start by confirming that the trigger is enabled and the webhook URL is correct. For signed requests, check that the sign
value is generated using the correct secret and timestamp format. Errors such as 400 or 500 responses often indicate a missing or malformed field in the request body.
If you see an error code and message in the response, they will typically point you to the exact cause. Logging both the request payload and response body on your end can help diagnose any issues more quickly.
Learn More
For additional details on working with triggers and bots, see the following resource: