Smart WebhooksAPI Reference

API Reference

All management endpoints require JWT authentication. The execution endpoint is public (authenticated via HMAC signature).

Management Endpoints

Base URL: https://api.aerostack.dev/api/smart-webhooks

List Webhooks

GET /api/smart-webhooks
Authorization: Bearer <JWT>

Returns all Smart Webhooks owned by the authenticated user, ordered by most recently updated.

Response (200):

{
  "webhooks": [
    {
      "id": "swh_9a2b3c4d5e6f7g8h9i",
      "owner_id": "usr_abc123",
      "workspace_id": "ws_def456",
      "name": "github-triage",
      "slug": "github-triage",
      "description": "Auto-triage GitHub issues",
      "source_type": "github",
      "source_events": "[\"opened\"]",
      "instructions": "When a new issue is created...",
      "llm_provider": "openai",
      "llm_model": "gpt-4o-mini",
      "max_tool_calls": 10,
      "timeout_ms": 30000,
      "signing_secret": "whsec_abc123",
      "status": "active",
      "enabled": 1,
      "created_at": "2026-03-15T10:00:00Z",
      "updated_at": "2026-03-15T10:00:00Z"
    }
  ]
}

Create Webhook

POST /api/smart-webhooks
Authorization: Bearer <JWT>
Content-Type: application/json

Request Body:

FieldTypeRequiredDefaultDescription
namestringYes1-100 characters
workspace_idstringYesMCP workspace ID (1-100 chars)
instructionsstringYesPlain English processing instructions (1-10000 chars)
descriptionstringNonullShort description (max 500 chars)
slugstringNoauto from nameURL slug (max 60 chars)
source_typestringNo"custom"github, stripe, shopify, or custom
source_eventsstring[]Nonull (accept all)Event types to process (max 50 items, each max 100 chars). Use ["*"] for all.
llm_providerstringNo"openai"openai, anthropic, gemini, groq, workers-ai, custom
llm_modelstringNo"gpt-4o-mini"Model identifier (max 100 chars)
max_tool_callsintegerNo101-50. Max agentic loop iterations
timeout_msintegerNo300001000-120000 (hard cap at 60000 during execution)
signing_secretstringNonullHMAC-SHA256 signing secret (max 256 chars)

Response (201):

{
  "webhook": {
    "id": "swh_9a2b3c4d5e6f7g8h9i",
    "name": "github-triage",
    "slug": "github-triage",
    "source_type": "github",
    "status": "active",
    "enabled": 1
  },
  "webhook_url": "https://api.aerostack.dev/api/webhooks/smart/github-triage"
}

The webhook_url is the URL to configure in your external service. This is where the service should send webhook events.


Get Webhook

GET /api/smart-webhooks/:id
Authorization: Bearer <JWT>

Returns a single webhook. Returns 404 if not found or not owned by the authenticated user.

Response (200):

{
  "webhook": { "id": "swh_...", "name": "...", "slug": "..." }
}

Update Webhook

PATCH /api/smart-webhooks/:id
Authorization: Bearer <JWT>
Content-Type: application/json

All fields from the create schema are optional. workspace_id cannot be changed after creation. Two additional fields are available for updates:

FieldTypeRequiredDescription
namestringNo1-100 characters
descriptionstringNoMax 500 chars
instructionsstringNo1-10000 chars
source_typestringNogithub, stripe, shopify, custom
source_eventsstring[]NoEvent types to process
llm_providerstringNoProvider enum
llm_modelstringNoModel identifier
max_tool_callsintegerNo1-50
timeout_msintegerNo1000-120000
signing_secretstringNoHMAC signing secret
statusstringNo"active" or "inactive"
enabledboolean / 0 / 1NoMaster on/off toggle

Response (200):

{
  "webhook": { "id": "swh_...", "name": "...", "slug": "..." }
}

Examples:

# Disable a webhook
curl -X PATCH https://api.aerostack.dev/api/smart-webhooks/swh_your_id \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled": false}'
# Change instructions and event filter
curl -X PATCH https://api.aerostack.dev/api/smart-webhooks/swh_your_id \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "instructions": "Updated instructions here...",
    "source_events": ["opened", "closed", "reopened"]
  }'

Delete Webhook

DELETE /api/smart-webhooks/:id
Authorization: Bearer <JWT>

Permanently deletes the webhook and all its run history.

Response (200):

{
  "deleted": true
}

List Runs

GET /api/smart-webhooks/:id/runs?limit=50
Authorization: Bearer <JWT>
Query ParamTypeDefaultMax
limitinteger50100

Response (200):

{
  "runs": [
    {
      "id": "whr_1a2b3c4d5e6f7g8h9i",
      "webhook_id": "swh_9a2b3c4d5e6f7g8h9i",
      "event_type": "opened",
      "payload_summary": "{\"action\":\"opened\",\"issue\":{\"title\":\"...\"}}",
      "actions_taken": "Classified issue as bug. Applied labels. Assigned to team.",
      "tool_calls": "[{\"name\":\"github_add_labels\",\"success\":true}]",
      "tokens_input": 1456,
      "tokens_output": 234,
      "cost_cents": 0.52,
      "latency_ms": 4521,
      "status": "success",
      "error": null,
      "created_at": "2026-03-15T10:30:12Z"
    }
  ]
}

Run fields:

FieldDescription
event_typeExtracted from payload (type, event.type, event_type, or action)
payload_summaryFirst 500 characters of the stringified payload
actions_takenAI response summarizing what it did (first 2000 chars)
tool_callsJSON array of tool call records with name, success, latency
tokens_inputTotal input tokens across all LLM calls
tokens_outputTotal output tokens
cost_centsEstimated platform cost
latency_msTotal execution time
statussuccess or error

Execution Endpoint

Process Webhook

POST /api/webhooks/smart/:slug
Content-Type: application/json
X-Hub-Signature-256: sha256=<hex_digest>  (optional)

This is the URL you configure in your external service (GitHub, Stripe, etc.).

Request Body: Any valid JSON payload from the webhook source. Non-JSON payloads are wrapped as { raw: "<body>" }.

Maximum request body size: 2 MB. Oversized payloads are silently accepted with { ok: true }.

Response (200) — Processed:

{
  "ok": true,
  "actions_taken": "Classified issue #42 as 'bug'. Applied labels. Assigned to team.",
  "tool_calls": 3,
  "cost_cents": 0.52
}

Response (200) — Skipped (event filtered):

{
  "ok": true,
  "skipped": true
}

Response (200) — Silent rejection (any error condition):

{
  "ok": true
}
⚠️

All error conditions return { ok: true } with HTTP 200. This includes: webhook not found, webhook disabled, invalid HMAC signature, and rate limiting. Check the run history to verify actual processing.

Signature Headers

If a signing_secret is configured, the endpoint checks these headers (first match wins):

HeaderStandard
X-Hub-Signature-256GitHub
X-Signature-256Generic
X-Webhook-SignatureGeneric

Expected format: sha256=<hex_digest> (HMAC-SHA256 of the raw request body).

Event Type Extraction

The event type is extracted from the payload in this order:

  1. payload.type
  2. payload.event.type
  3. payload.event_type
  4. payload.action

If none are found, the event type defaults to "unknown".

Rate Limits

ScopeLimitWindow
Per webhook30 requests1 minute

Error Codes Summary

Management Endpoints

CodeMeaning
400Validation failed or no fields to update
404Not found or not owner

Execution Endpoint

The execution endpoint always returns HTTP 200 with { ok: true } for security. No HTTP error codes are used.


Templates

Smart Webhook templates are available via the shared templates endpoint:

GET /api/agent-endpoints/templates/list?type=webhook

Pre-built webhook templates include:

TemplateSourceDescription
Payment Failed HandlerStripeNotify customers on failed payments
PR Merged NotifierGitHubAnnounce merged PRs to team channels
New Order ProcessorShopifyProcess and route new orders

Templates provide pre-written instructions and suggested MCP servers to get started quickly.