Triggering Webhooks and API Workflows from OpenClaw

Clawpedia · For Humans

Set up webhook triggers and API-based automation workflows powered by your OpenClaw agent.

Connecting OpenClaw to the Web

Webhooks and API workflows let OpenClaw interact with virtually any web service. Whether you want to trigger a deployment when you say "deploy to staging," send data to a CRM when a conversation ends, or chain multiple APIs together, webhooks are the glue that makes it happen.

---

What Are Webhooks?

A webhook is an HTTP callback — when an event occurs, a POST request is sent to a URL you specify. OpenClaw can both send and receive webhooks.

DirectionDescriptionExample
OutgoingOpenClaw sends data to an external serviceNotify Slack when a task completes
IncomingExternal service triggers OpenClawGitHub push triggers a deploy skill

---

Sending Webhooks (Outgoing)

From Skills


module.exports = {
  async execute(context) {
    const result = await doSomething();

    // Send webhook notification
    await context.http.post("https://hooks.slack.com/services/T.../B.../xxx", {
      text: "Task completed successfully!",
      result: result,
    });

    return { text: "Done! Slack has been notified." };
  },
};

From Automation Rules


automation:
  - trigger: event
    event: skill_completed
    skill: daily-backup
    webhook:
      url: https://hooks.example.com/backup-complete
      method: POST
      headers:
        Authorization: "Bearer YOUR_TOKEN"
      body:
        status: "{{result.status}}"
        timestamp: "{{timestamp}}"

Via CLI


openclaw webhook send https://example.com/hook \
  --data '{ "event": "test", "message": "Hello from OpenClaw" }'

---

Receiving Webhooks (Incoming)

OpenClaw can listen for incoming webhooks and trigger actions:


webhooks:
  server:
    enabled: true
    port: 3385
    secret: "your-webhook-secret"    # For signature verification

  endpoints:
    - path: /hooks/github
      action: skill
      skill: deploy-on-push
      filter:
        ref: "refs/heads/main"       # Only trigger on main branch

    - path: /hooks/stripe
      action: skill
      skill: payment-notification
      verify: stripe                  # Stripe signature verification

    - path: /hooks/custom
      action: message
      message: "Webhook received: {{body.event}}"
      notify: telegram

Setting Up a GitHub Webhook

---

API Workflows

Chain multiple API calls into a single workflow:


workflows:
  new-customer:
    trigger: "new customer {{name}} {{email}}"
    steps:
      - name: create_crm_contact
        method: POST
        url: https://api.hubspot.com/crm/v3/objects/contacts
        headers:
          Authorization: "Bearer {{config.hubspot_token}}"
        body:
          properties:
            email: "{{email}}"
            firstname: "{{name}}"
        save_as: crm_result

      - name: send_welcome_email
        method: POST
        url: https://api.sendgrid.com/v3/mail/send
        headers:
          Authorization: "Bearer {{config.sendgrid_token}}"
        body:
          to: "{{email}}"
          subject: "Welcome!"
          template_id: "d-abc123"

      - name: notify_team
        method: POST
        url: "{{config.slack_webhook}}"
        body:
          text: "New customer: {{name}} ({{email}}) - CRM ID: {{crm_result.id}}"

Trigger:


"New customer John Smith john@example.com"

---

Building API Workflows in Code


module.exports = {
  async execute(context) {
    const email = context.params.get("email");
    const name = context.params.get("name");

    // Step 1: Create CRM contact
    context.progress("Creating CRM contact...");
    const crmResult = await context.http.post(
      "https://api.hubspot.com/crm/v3/objects/contacts",
      {
        properties: { email, firstname: name },
      },
      {
        headers: { Authorization: `Bearer ${context.config.get("hubspot_token")}` },
      }
    );

    // Step 2: Add to mailing list
    context.progress("Adding to mailing list...");
    await context.http.post("https://api.mailchimp.com/3.0/lists/abc123/members", {
      email_address: email,
      status: "subscribed",
    });

    // Step 3: Notify team
    await context.http.post(context.config.get("slack_webhook"), {
      text: `New customer: ${name} (${email})`,
    });

    return { text: `Customer ${name} added to CRM, mailing list, and team notified.` };
  },
};

---

Webhook Security

Signature Verification


webhooks:
  endpoints:
    - path: /hooks/github
      verify: github
      secret: "your-github-secret"
    - path: /hooks/stripe
      verify: stripe
      secret: "whsec_your_stripe_secret"

IP Allowlisting


webhooks:
  security:
    allowed_ips:
      - "140.82.112.0/20"    # GitHub
      - "54.187.174.169"      # Stripe

Rate Limiting


webhooks:
  security:
    rate_limit: 100          # Max requests per minute
    burst: 20                # Max burst size

---

Testing Webhooks


# Test incoming webhook locally
curl -X POST http://localhost:3385/hooks/test \
  -H "Content-Type: application/json" \
  -d '{ "event": "test", "data": "hello" }'

# Test with OpenClaw
openclaw webhook test /hooks/github --payload sample-push.json

---

Tips

---

Troubleshooting

ProblemSolution
Webhook not receivedCheck port, firewall, and public URL
Signature verification failsVerify secret matches on both sides
Workflow step failsCheck API credentials and endpoint URLs
Duplicate webhook triggersImplement idempotency with request IDs
Timeout on API callIncrease timeout or add retry logic

Related Articles