Making a call after the AI agent runs
A postrun webhook can be added to your agent to execute custom logic before showing each response to the customer. This webhook can extract custom responses from an external content repository, such as an API or a database. The external service can process the agent's output before sending it to the channel.
For example, you can define actions with custom IDs in the responses instead of text. The postrun webhook can pass these IDs to an external database to retrieve stored text responses. This feature is particularly useful when you need to create dynamic and contextually relevant responses.
You can use this webhook in coordination with the prerun webhook. For instance, if the prerun webhook strips personally identifiable information from the customer's input, the postrun webhook can add it back. This way, you can create a seamless and personalized interaction between the agent and the customer. For more information about prerun webhooks, see Making a call before the AI agent runs.
Before you begin
- You must have an external service with an exposed API endpoint to call.
- The programmatic call to the external service must meet these requirements:
- The call must be a POST HTTPS request.
- The call must be completed in 30 seconds or less.
- The format of the request and response must be in JSON. For example:
Content-Type: application/json
.
Defining the webhook
To create a webhook, you must create a new webhook artifact by using the watsonx Orchestrate API. For more information about managing the webhooks, see the following API endpoints:
- Create an artifact of category webhook
- Get an artifact's details
- Update an artifact
- Delete an artifact from the catalog
- List all artifacts
You must use the following structure in your request body:
{
"category": "webhook",
"type": "post-run",
"name": "Name of the webhook",
"description": "Description of what this webhook does.",
"icon": "Optional icon in SVG string format",
"configurations" : {
"options": {
"error_handling": "fail_on_error",
},
"callout_settings": {
"certificates": [],
"certification_method": "{unauthorized}", // inclusive/exclusive/unauthorized
"response_size_limit": 400, // Optional
"request_size_limit": 100, // Optional
"timeout": 45,
"server_url": "{webhook_server_url}",
"authentication": {
"type": "basic",
"name": "foo",
"basic": {
"username": {
"type": "value",
"value": "pqr"
},
"password": {
"type": "value",
"value": "ddddd"
}
}
}
}
}
}
Procedure to create a webhook
First, you must get your API Key from your watsonx Orchestrate instance. For more information about how to get your API Key, see Authenticating to the API.
Then, you must get your authentication token from the watsonx Orchestrate API.
curl --request POST \
--url https://iam.platform.saas.ibm.com/siusermgr/api/1.0/apikeys/token \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{ "apikey": "MY_APY_KEY" }'
To create a postrun webhook, you must first use the API to create a postrun webhook artifact. In the following example, ORCHESTRATE_TOKEN
is the token that you obtained from the watsonx Orchestrate API, and WEBHOOK_SERVER_TOKEN
is the token required by your webhook service API:
curl --request POST \
--url ${WO_API_ENDPOINT}/v1/catalog/artifacts?category=webhook \
--header "Authorization: Bearer ${SECURE_IDT}" \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '@./my-content-header.json'
Where my-content-header.json
contains the following data:
{
"category": "webhook",
"type": "post-run",
"name": "post-run webhook with bearer auth",
"scope": "tenant",
"configurations": {
"options": {
"error_handling": "fail_on_error"
},
"callout_settings": {
"server_url": "https://${WEBHHOOK_SERVER_ENDPOINT}",
"authentication": {
"name" : "none",
"type": "bearer",
"bearer": {
"token": {
"type": "value",
"value": "${WEBHOOK_SERVER_TOKEN}"
}
}
}
}
}
}
If your webhook server does not require a token to authenticate to the endpoint (not recommended), you can use the following authentication schema:
"authentication": {
"type": "basic",
"name": "foo",
"basic": {
"username": {
"type": "value",
"value": "pqr"
},
"password": {
"type": "value",
"value": "ddddd"
}
}
}
In both cases, the API must return the information of the webhook created:
{
"id": "WEBHOOK_ID",
"create_by": "USERID",
"created_at": "2025-01-27T15:23:29.224Z",
"updated_at": "2025-01-27T15:23:29.224Z",
"update_by": "USERID",
"state": "PUBLISH",
"visibility": true
}
Testing the webhook
The webhook triggers only when your agent processes a run and prepares a response to return to the channel. If you enable the setting that returns an error when the webhook call fails, the agent’s processing is halted entirely if the webhook encounters any issues. Test the process that you are calling regularly to check if it's working as expected. You can change this setting to prevent all your run calls from failing, ensuring that the webhook call is successful even if there are temporary issues.
Request body
Understanding the format of the postrun webhook request body can help your external code process it efficiently. The payload contains the response body that your agent returns for the v2 /run
(stateful and stateless) API call. The
event name run_processed
indicates that the postrun webhook generates the request. For more information about the run request body, refer to the API reference.
Response body
The response body comes back asynchronously in one of two ways:
-
The response comes back as Server Sent Events (SSE) when source of the response is an LLM:
{ "payload" : { "id": "1729176140444-0", "event": "message.delta", "data": { "thread_id": "cb30625b-4f54-4202-94e4-7d743bd9970e", "run_id": "95e01d2e-6e38-4428-8890-df09fd3307e4", "delta": "\n\n1. Deutsche Bahn offers ICE (Intercity-Express) and IC (Intercity) trains, which are high-speed trains that can cover the distance between Berlin and Copenhagen in approximately 5 hours and 30 minutes." } }, "options" : {} }
The
payload
object contains the following information:id
: A unique identifier for the request.event
: The event name indicating that the postrun webhook generates the request.data
: The actual data being processed by the postrun webhook.
In this example, the
data
object contains the following information:thread_id
: A unique identifier for the thread.run_id
: A unique identifier for the run.delta
: The actual data being processed by the postrun webhook.
-
The response comes back as a web socket when the source of the response is from an AI assistant:
{ "payload" : { "tenant_id": "TENANT_ID", "assistant_id": "ASSISTANT_ID", "thread_id": "THREAD_ID", "run": { "id": "RUN_ID", "tenant_id": "TENANT_ID", "assistant_id": "ASSISTANT_ID", "thread_id": "THREAD_ID", ... "result": { "data": { "message": { "id": "MESSAGE_ID", "role": "assistant", "content": [ { "text": "I'm afraid I don't understand. Please rephrase your question.", "response_type": "text" } ], ... "additional_properties": { ... } }, "message_id": "MESSAGE_ID", "assistant_response": { "output": { "generic": [ { "text": "I'm afraid I don't understand. Please rephrase your question.", "response_type": "text" } ], }, "context": { ... }, "user_id": "USER_ID" } }, "type": "message_created" }, "guardrails": null } }, "options" : {} }