Webhooks
Integrate external services with Moxxy agents via HMAC-signed inbound webhooks.
Overview
┌─────────────┐ POST /v1/hooks/{token} ┌─────────────┐ ┌─────────────┐
│ External │ ─────────────────────────▶ │ Moxxy │ ──▶ │ Agent │
│ Service │ X-Signature: sha256=... │ Gateway │ │ Run │
└─────────────┘ └─────────────┘ └─────────────┘Webhooks allow external services (GitHub, monitoring tools, CI/CD pipelines, custom applications) to trigger agent runs by sending HTTP POST requests to a unique URL. Payloads are verified via HMAC-SHA256 signatures.
Registering a Webhook
Webhooks are registered by the agent itself using the webhook.register primitive during a run:
webhook.register("github-push")The primitive returns:
- token -- Unique URL path component for
/v1/hooks/{token} - secret -- HMAC secret for the external service to sign payloads
Configure the external service to send payloads to http://your-server:3000/v1/hooks/{token} with the HMAC signature in the X-Signature header.
Receiving Webhooks
POST /v1/hooks/{token}This endpoint does not require Bearer token authentication. Instead, the request body is verified via HMAC signature.
Headers
| Header | Required | Description |
|---|---|---|
X-Signature | Yes | sha256={hex_digest} of the request body |
Content-Type | Yes | application/json |
Example
BODY='{"event":"push","ref":"refs/heads/main","repo":"user/project"}'
SIGNATURE=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | awk '{print $2}')
curl -X POST http://127.0.0.1:3000/v1/hooks/whk_abc123 \
-H "Content-Type: application/json" \
-H "X-Signature: sha256=$SIGNATURE" \
-d "$BODY"Response (200)
{
"status": "accepted",
"delivery_id": "del_xyz789"
}When accepted, Moxxy starts a new run for the associated agent with the webhook payload as context.
Managing Webhooks
List Webhooks for an Agent
GET /v1/agents/{name}/webhookscurl http://127.0.0.1:3000/v1/agents/devops/webhooks[
{
"slug": "github-push",
"token": "whk_abc123",
"created_at": "2025-03-15T10:00:00Z",
"last_delivery": "2025-03-15T12:00:00Z",
"delivery_count": 42
}
]Delete a Webhook
DELETE /v1/agents/{name}/webhooks/{slug}curl -X DELETE http://127.0.0.1:3000/v1/agents/devops/webhooks/github-pushThe webhook token is immediately invalidated. Subsequent requests to the hook URL return 404.
Token Rotation
Rotate a webhook's token and HMAC secret using the webhook.rotate primitive:
webhook.rotate("github-push")This generates a new token and secret. The old token is invalidated immediately. Update the external service with the new URL and secret.
HMAC Signature Verification
External services must sign the raw request body using HMAC-SHA256:
- Compute
HMAC-SHA256(secret, raw_request_body) - Hex-encode the digest
- Send as
X-Signature: sha256={hex_digest}
Moxxy recomputes the HMAC server-side and compares. Mismatches result in a 401 response.
Signing Examples
Node.js:
const crypto = require('crypto');
function signPayload(secret, body) {
return 'sha256=' + crypto.createHmac('sha256', secret)
.update(body)
.digest('hex');
}Python:
import hmac
import hashlib
def sign_payload(secret: str, body: bytes) -> str:
digest = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return f"sha256={digest}"Go:
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
)
func signPayload(secret string, body []byte) string {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(body)
return fmt.Sprintf("sha256=%s", hex.EncodeToString(mac.Sum(nil)))
}Delivery Tracking
All webhook deliveries are recorded in the webhook_deliveries table, providing a complete audit trail.
| Field | Description |
|---|---|
delivery_id | Unique delivery identifier |
webhook_slug | The webhook that received the delivery |
source_ip | IP address of the sender |
signature_valid | Whether the HMAC signature passed verification |
run_id | Run ID created to process the payload (if accepted) |
status_code | HTTP status code returned to the sender |
received_at | Timestamp of the delivery |
Deliveries with invalid signatures are still recorded (with signature_valid: false) for security monitoring. These requests are rejected with 401 but the attempt is logged.
Use Cases
GitHub Push Notifications
Configure a GitHub webhook to notify your devops agent of pushes:
- Agent registers webhook:
webhook.register("github-push") - Configure in GitHub: Repository > Settings > Webhooks
- URL:
https://your-server/v1/hooks/{token} - Secret: the HMAC secret from registration
- Content type:
application/json - Events: select "Just the push event"
- URL:
Monitoring Alerts
Route alerts from Prometheus AlertManager, PagerDuty, or other monitoring tools to an ops agent for automated triage.
CI/CD Pipeline Events
Notify agents of build completions, deployment statuses, or test results from Jenkins, GitLab CI, or GitHub Actions.
Security Best Practices
- Always verify signatures -- Never disable HMAC verification
- Use HTTPS in production -- Encrypt webhook traffic in transit
- Rotate secrets periodically -- Use
webhook.rotateto cycle credentials - Monitor delivery logs -- Watch for failed signature validations, which may indicate tampering
- Review security events --
security.violationevents in the SSE stream indicate blocked attempts