Action Webhooks
Action webhooks let external systems create AgentPress actions by posting JSON events to a configured webhook URL. Accepted deliveries are visible on the unified Actions ledger with their ingress payload, action status, approval state, execution details, and outbound callback results in one row.
For SDK-based sending and callback verification, see Using the SDK.
Endpoint
Send events to the action webhook URL shown in the console:
POST https://api.agent.press/webhooks/actions/{org}/{webhookIdentifier}{org} can be the organization slug or ID. {webhookIdentifier} is the
identifier shown on the webhook detail page.
The older /webhooks/ingest/{org}/{identifier} listener URL is a hidden
compatibility path for existing integrations. New SDK calls and manual sender
scripts should use /webhooks/actions/{org}/{webhookIdentifier}.
Compatibility Impact
No SDK method was removed, and existing client.webhooks.send() calls continue
to work for action webhooks that use the default Svix verification scheme. The
client-impacting changes are operational:
- New action webhook configuration is managed on the action webhook itself, not through a separate listener surface.
- Existing listener aliases and copied
/webhooks/ingest/{org}/{identifier}URLs remain accepted for compatibility, but new integrations should not build against that hidden route. - If a sender's webhook is changed from Svix to
hmac_sha256,shared_token, ornone, SDK callers must pass the matchingauthoption and manual cURL scripts must send the matching headers. 202withbuffered: truemeans AgentPress accepted the delivery but has not created an action yet. Do not assume every accepted response includes anactionId.- For
verificationScheme: "none", the URL is the credential. Creating, switching, or rotating a no-header webhook can change thewebhookIdentifier; copy the latest URL after those operations.
Configure a Webhook
In the AgentPress console:
- Open Actions.
- Click New action webhook to create one, or Manage webhooks to edit existing webhooks.
- Choose the action identity, target agent, run-as user, optional event filter, verification scheme, rate limit, schedule, approval rules, and outbound callbacks.
- Copy the action webhook URL from the webhook detail page.
- Copy the secret shown on create or rotate. Secrets are only shown once.
New action webhooks default to Svix verification. You can switch a webhook to HMAC SHA-256, shared token, or no-header verification from the webhook detail page.
The Send Test dialog uses the webhook's configured verification scheme when it posts to the public webhook URL. If you select an internal AgentPress user in the dialog, the test creates the action directly for that user and does not exercise public webhook signature verification. To test sender authentication end-to-end, either leave the internal user unselected in the dialog or use the SDK/cURL examples below against the copied action webhook URL.
Payload
All action webhooks receive JSON:
interface ActionWebhookPayload {
eventType: string;
externalId?: string;
userId?: string;
authProvider?: string;
actionRuleId?: string;
instructions?: string;
/** Per-request tool-approval overrides. See "Per-request approval overrides". */
toolApprovals?: Record<string, "allow" | "ask" | "agent">;
data?: Record<string, unknown>;
}Use externalId for idempotency when the sender may retry the same event. If a
matching action already exists, AgentPress returns the existing actionId
instead of creating a duplicate.
User Resolution
AgentPress resolves the action's run-as user in this order:
userIdplusauthProviderfrom the payload, resolved through external auth.userIdas an internal AgentPress user UUID.- The default run-as user configured on the action webhook.
If no user can be resolved, the delivery is accepted into the webhook event log
and returns 202 with buffered: true and reason: "user_unresolved". The row
appears in the Actions ledger so an operator can fix configuration and replay or
let the worker retry.
Per-request approval overrides
Each approval-gated tool the action's agent can call resolves to one of three modes:
allow— the tool runs automatically, no human approval.ask— the tool always pauses for human approval before running.agent— the agent decides, per call, whether the action needs approval, following its own prompt/instructions (for example: auto-post 4–5★ replies but ask for approval on 1–3★).
For agent mode, AgentPress augments the tool with a hidden per-call decision the
model fills from the agent's prompt policy; a fail-closed predicate enforces
it — only an explicit "no approval needed" runs automatically, while anything else
(or an unsure agent) pauses for a human:
agent mode needs the agent's prompt to encode the policy — selecting the
mode alone is not enough. See the Tool Approvals guide
for the full walkthrough.
The default mode for each tool is configured on the action rule in the console
(Actions → your webhook → Approval rules). A sender can override a tool's mode
per event with toolApprovals:
{
"eventType": "review.created",
"data": { "rating": 2 },
"toolApprovals": { "respondToReview": "ask" }
}Per-request overrides are only honored when the webhook has Allow per-request overrides enabled (off by default). A user's explicit "always deny" preference always wins over any override. Invalid modes are dropped; unknown tool names are accepted but ignored at runtime (they match no tool).
Verification Schemes
| Scheme | Headers | Notes |
|---|---|---|
svix | svix-id, svix-timestamp, svix-signature | Default for new action webhooks and SDK sends. |
hmac_sha256 | x-webhook-timestamp, x-webhook-signature | HMAC-SHA256 over ${timestamp}.${rawBody}. |
shared_token | Authorization: Bearer <token> or x-webhook-token | Token is compared against the webhook secret. |
none | none | Capability URL. The unguessable URL is the credential. Use only for intentionally public senders. |
When verificationScheme is none, creating, switching, or rotating the
webhook mints an unguessable webhook identifier. Manual scripts must use the
latest URL copied from the webhook detail page after rotation.
Manual Sender Examples
The SDK is the recommended sender because it handles the default Svix signing flow automatically:
import { AgentPress } from "@agentpress/sdk";
const client = new AgentPress({
org: "your-org-slug",
webhookSecret: process.env.AGENTPRESS_WEBHOOK_SECRET!,
});
await client.webhooks.send({
action: "review_response",
payload: {
eventType: "review.created",
externalId: "review-123",
data: { rating: 5, text: "Great service." },
},
});For manual scripts, use the same action webhook endpoint and match the configured verification scheme.
HMAC SHA-256 cURL
export AGENTPRESS_API_URL="https://api.agent.press"
export AGENTPRESS_ORG="your-org-slug"
export AGENTPRESS_WEBHOOK="review_response"
export AGENTPRESS_WEBHOOK_SECRET="whsec_your_secret"
body='{"eventType":"review.created","externalId":"review-123","data":{"rating":5,"text":"Great service."}}'
timestamp="$(date +%s)"
signature="$(
printf '%s.%s' "$timestamp" "$body" |
openssl dgst -sha256 -hmac "$AGENTPRESS_WEBHOOK_SECRET" -hex |
awk '{print $2}'
)"
curl -sS -X POST "$AGENTPRESS_API_URL/webhooks/actions/$AGENTPRESS_ORG/$AGENTPRESS_WEBHOOK" \
-H "Content-Type: application/json" \
-H "x-webhook-timestamp: $timestamp" \
-H "x-webhook-signature: v1=$signature" \
--data "$body"Shared Token cURL
curl -sS -X POST "$AGENTPRESS_API_URL/webhooks/actions/$AGENTPRESS_ORG/$AGENTPRESS_WEBHOOK" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AGENTPRESS_WEBHOOK_SECRET" \
--data '{"eventType":"review.created","externalId":"review-123","data":{"rating":5}}'No-Header Capability URL cURL
Only use this for webhooks intentionally configured with
verificationScheme: "none":
curl -sS -X POST "$AGENTPRESS_CAPABILITY_URL" \
-H "Content-Type: application/json" \
--data '{"eventType":"review.created","externalId":"review-123","data":{"rating":5}}'Responses
| Code | Meaning |
|---|---|
200 | Action created, or an existing action was returned for the same externalId. |
202 | Delivery accepted and buffered because configuration or resolution is incomplete. |
400 | Invalid JSON or payload shape. |
401 | Missing, stale, or invalid verification headers. |
403 | Webhook disabled, origin blocked, or sender IP blocked. |
404 | Organization or webhook identifier not found. |
413 | Payload exceeds the configured maximum size. |
429 | Per-IP or per-webhook rate limit exceeded. |
500 | Internal persistence error. |
Action Created
{
"success": true,
"actionId": "uuid-of-created-action"
}Duplicate External ID
{
"success": true,
"actionId": "uuid-of-existing-action",
"alreadyExists": true
}Buffered Delivery
{
"success": true,
"buffered": true,
"eventId": "uuid-of-webhook-event",
"reason": "user_unresolved"
}Common buffered reasons include no_action_rule_configured,
action_rule_not_found, action_rule_disabled, user_unresolved, and
action_create_failed.
Debugging in the Actions Ledger
After sending a webhook, open Actions in the console.
- A successful webhook-created action appears as a normal action row with ingress metadata attached.
- A buffered, skipped, failed, or dead-lettered delivery appears as a delivery-only row until it creates an action.
- Open a row to inspect the summary, ingress payload, redacted headers, verification scheme, lifecycle events, approval state, conversation, result, and outbound callbacks.
- Replay is available only for replayable delivery failures, skipped deliveries, or dead-lettered rows.
Outbound Callbacks
AgentPress can send signed HTTP callbacks as actions move through their lifecycle. A callback can subscribe to any mix of these public event types:
| Event Type | Meaning |
|---|---|
action.pending_approval | A tool call is staged and needs approval. |
action.approved | The action was approved or is currently executing. Not terminal. |
action.completed | The action finished successfully. |
action.failed | The action failed during processing or execution. |
action.rejected | The staged action was rejected. |
action.expired | The staged action expired before approval. |
Outbound callbacks use Svix-style signatures. Verify them with
client.webhooks.constructEvent(), verify(), or verifyOrThrow() from the
SDK. For setup details and payload examples, see
Receiving Callbacks.
Operational Notes
- New action webhooks default to
verificationScheme: "svix". client.webhooks.send()posts to/webhooks/actions/{org}/{identifier}.- Existing SDK listener aliases are compatibility APIs; new integrations should
use
client.webhooks.send(). - Manual scripts copied from the older listener URL should update the URL and verification headers to match the configured action webhook.
- Per-webhook rate limiting defaults to 100 requests per minute and is capped at 1000 requests per minute.
- Secrets are encrypted at rest and only shown on create or rotate.