Custom Webhooks API
Custom webhooks give every webhook handler you configure in Autessa a public HTTPS trigger URL. External systems (payment processors, CRMs, CI pipelines, form builders) call the URL when something happens; Autessa validates the request, transforms the payload into variables, and asynchronously executes the handler you attached — a tool, an agent, a manager, or an AutessaDB operation.
Webhook execution is asynchronous. A successful call returns 202 Accepted immediately with an executionId — the handler runs in the background. Use the execution history in the builder to inspect the outcome of each delivery.
Base URL
https://api.autessa.com/clients/custom-webhooks
All webhooks share this single endpoint. The resourceId query parameter selects which webhook handler receives the request, and the same URL accepts GET, POST, PUT, DELETE, and PATCH — so it fits whatever method the external system insists on sending. There are no sub-paths; the full trigger URL for a webhook is:
https://api.autessa.com/clients/custom-webhooks?resourceId={webhookId}
Authentication
Webhook endpoints use a dedicated webhook API key, generated when you create the webhook handler. Webhook keys have the shape:
wh:{keyId}:{keySecret}
Pass the full key (including the wh: prefix) in the Authorization header — no Bearer prefix:
Authorization: wh:your_key_id:your_key_secret
If the calling system cannot set headers, you can instead pass the same value as an authorization query parameter (matched case-insensitively). The header takes precedence when both are present.
Each webhook key is bound to exactly one webhook: the {keyId} segment must match the key registered for the webhook selected by resourceId, the secret is verified against its stored hash, and both the webhook and the key must be enabled. Regular client API keys and poweruser keys are rejected on this endpoint.
If the webhook has a validation script configured (for example, to verify an HMAC signature from the sender), it runs on every request after key validation. The script receives the raw body, all headers, and all query parameters, and the request is rejected with 401 if it fails. See Webhook Handlers.
- Header
- Query parameter
curl 'https://api.autessa.com/clients/custom-webhooks?resourceId=123' \
-H "Authorization: wh:your_key_id:your_key_secret" \
-H "Content-Type: application/json" \
-d '{"event": "ping"}'
curl 'https://api.autessa.com/clients/custom-webhooks?resourceId=123&authorization=wh:your_key_id:your_key_secret' \
-H "Content-Type: application/json" \
-d '{"event": "ping"}'
How execution works
Every request to the trigger URL goes through the same pipeline:
- Authenticate — the webhook is looked up by
resourceId, the webhook key is verified, and the optional validation script runs. Failures return401immediately. - Transform — the raw body, headers, and query parameters are transformed into a flat map of variables using the webhook's transform configuration (JSONPath mappings or an AutessaScript transform). This happens synchronously; a transform failure returns
500. - Log and queue — an execution record is written with status
QUEUEDand the execution message is placed on the processing queue. - Acknowledge — you receive
202 Acceptedwith theexecutionId. - Execute asynchronously — a background worker runs the configured handler resource (tool, agent, manager, or AutessaDB operation), substituting the transformed variables into the handler's configured inputs via
@@{variableName}references. The execution record is updated with the result.
The immediate response only tells you the request was accepted and queued — it never contains handler output. Correlate deliveries with the executionId when reviewing execution history. (Every response also carries a separate per-request X-Request-Id header.)
Trigger a webhook POST/clients/custom-webhooks
Delivers an event to a webhook handler. POST with a JSON body is the most common shape, but PUT, PATCH, and DELETE behave identically — the method is recorded in execution history and otherwise does not change processing.
Query Parameters
- Name
resourceId- Type
- integer
- Description
The ID of the webhook to trigger. This is baked into the trigger URL shown for the webhook in the builder.
- Name
authorization- Type
- string
- Description
The webhook API key, as an alternative to the
Authorizationheader (see Authentication).
- Name
*- Type
- string
- Description
Any additional query parameters are passed through to the validation script and payload transform as
queryParams.
Headers
- Name
Authorization- Type
- string
- Description
The webhook API key (
wh:{keyId}:{keySecret}). Required unless passed as theauthorizationquery parameter.
- Name
Content-Type- Type
- string
- Description
The body content type. JSON is recommended — JSONPath transforms expect a JSON body.
- Name
*- Type
- string
- Description
All request headers are passed through to the validation script and payload transform as
headers.
Request Body
The body is passed through as-is — there is no required schema. It is delivered untouched (up to 10 MB) to the validation script and payload transform as payload. Send whatever the external system produces; the webhook's transform configuration maps it to the variables your handler needs.
Response
- Name
success- Type
- boolean
- Description
trueif the request was validated, transformed, and queued for execution.
- Name
message- Type
- string
- Description
Human-readable status, e.g.
"Webhook execution queued successfully".
- Name
executionId- Type
- string
- Description
Unique ID for this delivery. Use it to find the delivery in the webhook's execution history.
- Name
webhookId- Type
- string
- Description
ID of the webhook that was triggered.
- Name
errors- Type
- array<string>
- Description
Array of error messages if any occurred.
The X-Request-Id response header carries a per-request correlation ID.
- cURL
- JavaScript
- Python
curl --request POST \
--url 'https://api.autessa.com/clients/custom-webhooks?resourceId=123' \
--header 'Content-Type: application/json' \
--header 'Authorization: wh:your_key_id:your_key_secret' \
--data '{
"event": "payment.succeeded",
"customer": {
"email": "jane@example.com",
"name": "Jane Doe"
},
"amountCents": 4900
}'
const response = await fetch(
'https://api.autessa.com/clients/custom-webhooks?resourceId=123',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'wh:your_key_id:your_key_secret'
},
body: JSON.stringify({
event: 'payment.succeeded',
customer: {
email: 'jane@example.com',
name: 'Jane Doe'
},
amountCents: 4900
})
}
);
const data = await response.json(); // 202 Accepted
console.log(data.executionId);
import requests
response = requests.post(
'https://api.autessa.com/clients/custom-webhooks',
params={'resourceId': 123},
headers={
'Content-Type': 'application/json',
'Authorization': 'wh:your_key_id:your_key_secret'
},
json={
'event': 'payment.succeeded',
'customer': {
'email': 'jane@example.com',
'name': 'Jane Doe'
},
'amountCents': 4900
}
)
data = response.json() # 202 Accepted
print(data['executionId'])
{
"success": true,
"message": "Webhook execution queued successfully",
"executionId": "3f1c9a52-8f0e-4a7d-9b6f-2d4c1e8a7b31",
"webhookId": "V1StGXR8Z5"
}
Trigger with GET GET/clients/custom-webhooks
Some senders (email link trackers, simple pingers, legacy systems) can only issue GET requests. The endpoint accepts them at the same URL — carry your event data in query parameters instead of a body.
Every query parameter (including resourceId and authorization themselves) is available to the validation script and payload transform as queryParams, so an AutessaScript transform can map them to handler variables.
Query Parameters
- Name
resourceId- Type
- integer
- Description
The ID of the webhook to trigger.
- Name
authorization- Type
- string
- Description
The webhook API key, if not sent as a header.
- Name
*- Type
- string
- Description
Your event data — arbitrary key-value pairs, passed through to the transform.
Response
Identical to the POST response: 202 Accepted with success, message, executionId, and webhookId.
- cURL
- JavaScript
- Python
curl --request GET \
--url 'https://api.autessa.com/clients/custom-webhooks?resourceId=123&event=user.signup&email=jane%40example.com' \
--header 'Authorization: wh:your_key_id:your_key_secret'
const params = new URLSearchParams({
resourceId: '123',
event: 'user.signup',
email: 'jane@example.com'
});
const response = await fetch(
`https://api.autessa.com/clients/custom-webhooks?${params}`,
{
headers: {
'Authorization': 'wh:your_key_id:your_key_secret'
}
}
);
const data = await response.json(); // 202 Accepted
import requests
response = requests.get(
'https://api.autessa.com/clients/custom-webhooks',
params={
'resourceId': 123,
'event': 'user.signup',
'email': 'jane@example.com'
},
headers={'Authorization': 'wh:your_key_id:your_key_secret'}
)
data = response.json() # 202 Accepted
{
"success": true,
"message": "Webhook execution queued successfully",
"executionId": "9d2b7e10-4c3a-4f58-a1e2-6b8f0d5c9e44",
"webhookId": "V1StGXR8Z5"
}
Configuring handlers
The trigger endpoint is only half of a webhook — the other half is the handler configuration you create in the builder, which controls:
- Handler resource — the tool, agent, manager, or AutessaDB operation to execute for each delivery, and the inputs it receives (with
@@{variableName}references to transformed variables). - Payload transform — JSONPath mappings over the JSON body, or an AutessaScript transform with access to
payload,headers, andqueryParams, producing the variable map. - Validation script — optional request-authenticity check (signature verification, allow-listing) that runs before anything is queued.
- API key lifecycle — the webhook key is shown once at creation and can be rotated at any time; rotating it invalidates the old key immediately.
See Webhook Handlers for the full configuration walkthrough.
Errors
Authentication and lookup failures are rejected by the webhook filter before anything is queued, with a 401 and a minimal error body:
{
"error": "Invalid API key for this webhook."
}
| Status | Body | When |
|---|---|---|
401 | {"error": "No webhook ID provided."} | The resourceId query parameter is missing. |
401 | {"error": "Invalid webhook ID."} | resourceId is not a valid webhook ID. |
401 | {"error": "Webhook not found."} | No webhook exists with that ID. |
401 | {"error": "Webhook is disabled."} | The webhook exists but is switched off. |
401 | {"error": "No API key provided."} | No Authorization header or authorization query parameter. |
401 | {"error": "Invalid API key format."} | The key is not a wh:{keyId}:{keySecret} webhook key (regular client keys are rejected here). |
401 | {"error": "Invalid API key for this webhook."} | The key belongs to a different webhook. |
401 | {"error": "Invalid API key."} | The key ID is unknown or the secret does not match. |
401 | {"error": "API key is disabled."} | The key exists but has been disabled. |
401 | Validation script message | The webhook's custom validation script rejected the request. |
500 | ExecuteWebhookResponse with success: false | The payload transform failed, or an internal error occurred while queuing. |
A 500 uses the same response shape as a success, so you can still log the executionId:
{
"success": false,
"message": "Failed to transform webhook payload",
"executionId": "3f1c9a52-8f0e-4a7d-9b6f-2d4c1e8a7b31",
"webhookId": "V1StGXR8Z5"
}
202 Accepted means the delivery was queued — not that the handler succeeded. Handler failures (a tool erroring, an agent timing out) are recorded in the webhook's execution history, not in the HTTP response.