Triggering Agents with Webhooks
Agent Webhooks provide a powerful mechanism to trigger an agentβs execution from external systems. Unlike the direct API which provides an immediate response, webhooks are designed for asynchronous operations. When you call a webhook, DocsGPT enqueues the agentβs task for background processing and immediately returns a task_id. You then use this ID to poll for the result.
This workflow is ideal for integrating with services that expect a quick initial response (e.g., form submissions) or for triggering long-running tasks without tying up a client connection.
Each agent has its own unique webhook URL. Generate it in the agentβs Access Details (the builderβs More actions menu), or with GET /api/agent_webhook?id=<agent_id>. The URL contains a secret token, and anyone who has the URL can run the agent; see Keep the URL secret.
API Endpoints
- Webhook URL:
http://localhost:7091/api/webhooks/agents/{AGENT_WEBHOOK_TOKEN} - Task Status URL:
http://localhost:7091/api/task_status
For DocsGPT Cloud, use https://gptcloud.arc53.com/ as the base URL.
Both endpoints are also in the REST API reference and in your instanceβs own Swagger UI (see the API overview).
The Webhook Workflow
The process involves two main steps: triggering the task and polling for the result.
Step 1: Trigger the Webhook
Send an HTTP POST request to the agentβs unique webhook URL with the required payload. The structure of this payload should match what the agentβs prompt and tools are designed to handle.
- Method:
POST, with a JSON body andContent-Type: application/json. Another content type returns415; a body that isnβt valid JSON, or isnull, returns400. - Response:
{"success": true, "task_id": "a1b2c3d4-e5f6-..."}
The whole JSON body becomes the agentβs input, serialized as JSON text; no field has a special meaning. The request {"question": "Summarize order 4567"} reaches the agent as the message {"question": "Summarize order 4567"}, so write the agentβs prompt to expect the payload your system sends.
cURL
curl -X POST \
http://localhost:7091/api/webhooks/agents/your_webhook_token \
-H "Content-Type: application/json" \
-d '{"question": "Your message to agent"}'Triggering with GET (query parameters)
The webhook listener also accepts GET requests, mapping the query string to the payload. This is handy for systems that can only issue a simple GET (for example a βping this URLβ integration):
curl "http://localhost:7091/api/webhooks/agents/your_webhook_token?question=Your+message+to+agent"As with POST, the response is a JSON object containing the task_id, and the query parameters, as a JSON object, become the agentβs input.
Preventing duplicate triggers (Idempotency-Key)
To make a trigger safe to retry, send an optional Idempotency-Key header. If the same key is seen again within 24 hours, DocsGPT does not enqueue a second task β it returns the original task_id instead. This prevents a retried or double-fired webhook from running the agent twice. If the response is "task_id": "deduplicated" instead, a request with the same key was being enqueued at the same moment and its record is already gone, most likely because that enqueue failed, so the agent may not have run at all. There is no task to poll (/api/task_status reports PENDING for it forever): send the request again.
curl -X POST \
http://localhost:7091/api/webhooks/agents/your_webhook_token \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-4567-created" \
-d '{"question": "Your message to agent"}'Step 2: Poll for the Result
Once you have the task_id, periodically send a GET request to the /api/task_status endpoint until the task status is SUCCESS or FAILURE.
status: The current state of the task:PENDING,PROGRESS,SUCCESSorFAILURE(Celery can also reportSTARTEDorRETRY).result:{"current": <percent>}while the status isPROGRESS, the outcome when it isSUCCESS, and the error text when it isFAILURE.
A successful run nests the agentβs output under result.result:
{
"status": "SUCCESS",
"result": {
"status": "success",
"result": {
"answer": "Order 4567 shipped on May 2...",
"sources": [],
"tool_calls": [],
"thought": ""
}
}
}When the agent ownerβs usage quota is exhausted, the agent does not run, but the task still ends with SUCCESS: check result.status.
{
"status": "SUCCESS",
"result": {"status": "quota_exceeded", "error": "..."}
}While a task is PENDING, /api/task_status returns 503 if no worker answers; a PENDING task and no reachable worker usually means the worker isnβt running.
Two more cases to handle:
- A run that fails inside the agent still ends
SUCCESS. When the model or a workflow node reports an error during the run, the task finishes with"status": "success"and an empty or partialanswer; the error itself is not in the result. An emptyanswerusually means the run failed; the agentβs logs in DocsGPT (Settings > Logs) show why. - A crashed run is retried. If the run raises an error (for example the model provider is unreachable), the worker retries the task up to 3 times, with a growing delay, before it ends
FAILURE. Each retry runs the agent again from the start, including any tool actions that already took effect, so prefer tools whose writes are safe to repeat.
cURL
# Replace the task_id with the one you received
curl http://localhost:7091/api/task_status?task_id=YOUR_TASK_IDHow a webhook run behaves
A webhook run happens in the background, with nobody watching it:
- It acts as the agentβs owner. Tools use the ownerβs connected accounts and saved credentials. A webhook is the ownerβs own automation, so the API write allowlist that limits API-key and widget callers does not apply to it.
- Nobody can approve. A tool action that needs approval is refused, and the agent is told so and carries on. So are client-side tools and tools whose connection needs signing in again.
- Chat-only tools are unavailable. The
schedulertool is not offered to the agent during a webhook run. - Usage counts against the ownerβs quota. When it is exhausted, the run is skipped (see the
quota_exceededresult above).
Keep the URL secret
The token in the URL is the only credential: anyone who has the URL can run the agent as its owner, with the ownerβs accounts and quota. The token never changes and there is no way to rotate it yet, so treat the URL like a password: keep it out of client-side code and logs, and call it only from systems you control. If it leaks, the only way to stop it is to delete the agent. You can export the agent first, delete it and import the file again; the new agent gets a new webhook URL.