AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Speckle Syntax Webhooks

skill-impertio-studio-speckle-claude-skill-package-speckle-syntax-webhooks · by Impertio-Studio

>

No reviews yet
0 installs
21 views
0.0% view→install

Install

$ agentstack add skill-impertio-studio-speckle-claude-skill-package-speckle-syntax-webhooks

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-impertio-studio-speckle-claude-skill-package-speckle-syntax-webhooks)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
4mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Speckle Syntax Webhooks? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

speckle-syntax-webhooks

Quick Reference

Webhook CRUD Operations

| Operation | Mutation | Input Type | Returns | Required Role | |-----------|----------|-----------|---------|---------------| | Create | webhookCreate | WebhookCreateInput! | String! (webhook ID) | Stream Owner | | Update | webhookUpdate | WebhookUpdateInput! | String! | Stream Owner | | Delete | webhookDelete | WebhookDeleteInput! | String! | Stream Owner | | Query | project.webhooks | id: String (optional filter) | WebhookCollection | Stream Owner |

WebhookCreateInput Type

| Field | Type | Required | Description | |-------|------|----------|-------------| | streamId | String! | YES | The project/stream ID | | url | String! | YES | HTTPS endpoint URL that receives POST requests | | description | String | NO | Human-readable description | | triggers | [String!]! | YES | Array of trigger strings (MUST use internal names) | | secret | String | NO | Shared secret for HMAC signature verification | | enabled | Boolean | NO | Defaults to true |

All 14 Event Types (Trigger Strings)

ALWAYS use the Internal Trigger String when calling webhookCreate. NEVER use the Display Name.

| Internal Trigger String | Display Name | Description | |------------------------|--------------|-------------| | stream_update | projectupdate | Project metadata changed | | stream_delete | projectdelete | Project deleted | | branch_create | modelcreate | New model created | | branch_update | modelupdate | Model metadata updated | | branch_delete | modeldelete | Model deleted | | commit_create | versioncreate | New version created | | commit_update | versionupdate | Version metadata updated | | commit_receive | versionreceive | Version marked as received | | commit_delete | versiondelete | Version deleted | | comment_created | commentcreated | New comment/thread created | | comment_archived | commentarchived | Comment archived | | comment_replied | commentreplied | Reply added to comment thread | | stream_permissions_add | projectpermissionsadd | Collaborator added | | stream_permissions_remove | projectpermissionsremove | Collaborator removed |

Configuration Limits

| Limit | Value | |-------|-------| | Max webhooks per stream/project | 100 (MAX_STREAM_WEBHOOKS = 100) | | Webhook history query limit | Up to 25 events per query | | Required scope | streams:write | | Required role | Stream Owner |

Critical Warnings

NEVER use display names (e.g., version_create, model_update) as trigger strings -- the API uses legacy/internal terminology. ALWAYS use commit_create, branch_update, etc. The UI shows modern names, but the GraphQL API requires legacy names.

NEVER assume the webhook secret is returned in queries -- Speckle exposes only a hasSecret boolean field. The actual secret value is NEVER returned after creation. Store it securely at creation time.

NEVER skip payload validation in your webhook endpoint -- ALWAYS verify the webhook.id in the payload matches your expected webhook. Without validation, any POST to your endpoint could be processed as a legitimate event.

NEVER exceed 100 webhooks per project -- the server enforces MAX_STREAM_WEBHOOKS = 100. Attempting to create more will fail. If you need more event handlers, consolidate triggers into fewer webhooks.

NEVER expect sensitive fields in webhook payloads -- server.id, user.passwordDigest, user.email, and webhook.secret are ALWAYS stripped before delivery.


Webhook Lifecycle

1. Create a Webhook

mutation WebhookCreate($webhook: WebhookCreateInput!) {
  webhookCreate(webhook: $webhook)
}

Variables:

{
  "webhook": {
    "streamId": "",
    "url": "https://your-endpoint.com/webhook",
    "description": "CI/CD trigger on new versions",
    "triggers": ["commit_create", "branch_update"],
    "secret": "your-hmac-secret-here",
    "enabled": true
  }
}

Returns the webhook ID as String!. Store this ID for future update/delete operations.

2. Update a Webhook

mutation WebhookUpdate($webhook: WebhookUpdateInput!) {
  webhookUpdate(webhook: $webhook)
}

Variables:

{
  "webhook": {
    "id": "",
    "streamId": "",
    "url": "https://new-endpoint.com/webhook",
    "enabled": false
  }
}

All fields except id and streamId are optional -- only include fields you want to change.

3. Delete a Webhook

mutation WebhookDelete($webhook: WebhookDeleteInput!) {
  webhookDelete(webhook: $webhook)
}

Variables:

{
  "webhook": {
    "id": "",
    "streamId": ""
  }
}

4. Query Webhooks

query ProjectWebhooks($projectId: String!) {
  project(id: $projectId) {
    webhooks {
      totalCount
      items {
        id
        url
        description
        triggers
        enabled
        hasSecret
        history(limit: 5) {
          totalCount
          items {
            id
            status
            statusInfo
            retryCount
            lastUpdate
          }
        }
      }
    }
  }
}

Filter for a specific webhook: webhooks(id: "").


Payload Structure

When a webhook fires, the receiving endpoint gets a POST request with this JSON body:

{
  "streamId": "",
  "stream": {
    "id": "abc123",
    "name": "My Project",
    "description": "Project description"
  },
  "userId": "",
  "user": {
    "id": "user123",
    "name": "Jane Doe",
    "bio": "Engineer",
    "company": "ACME",
    "avatar": "https://..."
  },
  "server": {
    "name": "Speckle",
    "canonicalUrl": "https://app.speckle.systems"
  },
  "webhook": {
    "id": "webhook123",
    "streamId": "abc123",
    "url": "https://your-endpoint.com/webhook",
    "description": "CI/CD trigger",
    "triggers": ["commit_create"]
  },
  "event": {
    "event_name": "commit_create",
    "data": { }
  }
}

Stripped Fields (Security)

The following fields are ALWAYS removed from payloads before delivery:

  • server.id
  • user.passwordDigest
  • user.email
  • webhook.secret

Security: HMAC Signature Verification

When you provide a secret during webhook creation, Speckle signs the payload using HMAC. Your endpoint MUST verify this signature to ensure the request is authentic.

Verification Pattern

  1. Extract the signature from the request headers
  2. Compute HMAC-SHA256 of the raw request body using your stored secret
  3. Compare the computed signature with the received signature using constant-time comparison
  4. Reject requests where signatures do not match
import hmac
import hashlib

def verify_webhook_signature(payload_body: bytes, secret: str, received_signature: str) -> bool:
    """Verify the HMAC signature of a Speckle webhook payload."""
    computed = hmac.new(
        secret.encode("utf-8"),
        payload_body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(computed, received_signature)

ALWAYS use constant-time comparison (hmac.compare_digest) -- NEVER use == for signature comparison, as it is vulnerable to timing attacks.


Webhook History and Retry Behavior

Querying Delivery History

Each webhook maintains a delivery history accessible via webhook.history(limit: N):

{
  project(id: $projectId) {
    webhooks(id: $webhookId) {
      items {
        history(limit: 25) {
          totalCount
          items {
            id
            webhookId
            status
            statusInfo
            retryCount
            lastUpdate
            payload
          }
        }
      }
    }
  }
}

WebhookEvent Fields

| Field | Type | Description | |-------|------|-------------| | id | String! | Unique event ID | | webhookId | String! | Parent webhook ID | | status | Int! | HTTP response status code from your endpoint | | statusInfo | String! | Additional status information or error message | | retryCount | Int! | Number of delivery attempts made | | lastUpdate | DateTime! | Timestamp of the last delivery attempt | | payload | String! | The JSON payload that was sent |

Retry Behavior

When a webhook delivery fails (non-2xx response or connection error), Speckle retries the delivery. The retryCount field on WebhookEvent tracks how many attempts have been made. Monitor webhook.history to detect persistent delivery failures and take corrective action.

ALWAYS return a 2xx HTTP status code from your webhook endpoint promptly -- long-running processing MUST be deferred to a background queue. A slow response or timeout triggers retries and may cause duplicate processing.


Webhook Integration Pattern

The standard pattern for integrating with Speckle webhooks:

1. Create webhook via webhookCreate mutation (store the returned ID)
2. Receive POST requests at your endpoint
3. Validate the payload:
   a. Verify HMAC signature (if secret was configured)
   b. Confirm webhook.id matches your expected webhook
4. Extract event data from the payload
5. Return 2xx immediately
6. Process the event asynchronously (background job/queue)
7. Query additional details via GraphQL if needed

Collection Types

| Type | Fields | Access Pattern | |------|--------|---------------| | WebhookCollection | items: [Webhook!]!, totalCount: Int! | project.webhooks | | WebhookEventCollection | items: [WebhookEvent], totalCount: Int! | webhook.history(limit: N) |


Reference Links

  • [references/methods.md](references/methods.md) -- GraphQL mutations, input types, and query fields for webhooks
  • [references/examples.md](references/examples.md) -- Complete working examples for webhook CRUD and payload handling
  • [references/anti-patterns.md](references/anti-patterns.md) -- Common webhook configuration mistakes and how to avoid them

Official Sources

  • Speckle Server GitHub -- Webhooks Schema: github.com/specklesystems/speckle-server/.../webhooks.graphql
  • Speckle Server GitHub -- Webhook Services: github.com/specklesystems/speckle-server/.../webhooks/services/webhooks.ts
  • Speckle Server GitHub -- Webhook Types: github.com/specklesystems/speckle-server/.../webhooks/domain/types.ts
  • Speckle Frontend -- Webhook Composables: github.com/specklesystems/speckle-server/.../webhooks.ts

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.