Create a Webhook

Register a webhook endpoint with the createWebhook mutation to receive event notifications.


Use the createWebhook mutation to register an endpoint that receives event notifications from your organization. When a subscribed event occurs in a workspace you belong to, Blue POSTs a signed JSON payload to your URL. See Webhooks for the delivery model and payload shape.

The mutation returns a Webhook. The secret used to sign payloads is only returned in this response — store it immediately.

Request

The smallest valid call needs only a url. Omitting events subscribes the webhook to all event types (see Parameters).

mutation CreateWebhook {
  createWebhook(input: { url: "https://example.com/webhooks/blue" }) {
    id
    uid
    url
    secret
    status
    enabled
    createdAt
  }
}

createWebhook requires the X-Bloo-Company-ID header in addition to your token credentials — the webhook count is enforced per organization. The other webhook operations are user-scoped and do not need it.

curl -X POST https://api.blue.cc/graphql \
  -H "Content-Type: application/json" \
  -H "X-Bloo-Token-ID: YOUR_TOKEN_ID" \
  -H "X-Bloo-Token-Secret: YOUR_TOKEN_SECRET" \
  -H "X-Bloo-Company-ID: YOUR_COMPANY_ID" \
  -d '{"query": "mutation { createWebhook(input: { url: \"https://example.com/webhooks/blue\" }) { id secret } }"}'

Parameters

CreateWebhookInput

ParameterTypeRequiredDescription
urlString!YesThe HTTPS endpoint that receives webhook POST requests. Must resolve to a public address — URLs resolving to loopback, RFC-1918, link-local, or cloud-metadata ranges are rejected.
nameStringNoA human-readable label for the webhook.
events[WebhookEvent!]NoEvent types to subscribe to. Omitting this (or passing []) subscribes the webhook to every event type. Pass an explicit, non-empty array to scope delivery to specific events. See Webhook events.
projectIds[String!]NoWorkspace IDs to scope delivery to. You must be a member of every workspace listed. Omitting it (or passing []) scopes the webhook to all workspaces you belong to.
Empty events = all events

Leaving events unset does not create a silent webhook — it subscribes to the full event catalog. If you only want a few events, you must pass them explicitly. The same rule applies to projectIds: empty means all your workspaces.

Response

{
  "data": {
    "createWebhook": {
      "id": "clm4n8qwx000008l0g4oxdqn7",
      "uid": "wh_8f3a2c1e",
      "url": "https://example.com/webhooks/blue",
      "secret": "pat_a1b2c3d4e5f6g7h8i9j0",
      "status": "HEALTHY",
      "enabled": true,
      "createdAt": "2026-05-29T14:02:11.000Z"
    }
  }
}

A new webhook is enabled: true with status: HEALTHY immediately and starts receiving events. createWebhook does not make a test request to your URL — there is no creation-time health check. (Health checks run only on updateWebhook when you re-enable a webhook.) If deliveries later fail, the webhook is auto-disabled and set to UNHEALTHY.

Returns

createWebhook returns a Webhook:

FieldTypeDescription
idID!The webhook’s unique identifier.
uidString!Short public identifier.
nameStringThe label you set, or null.
urlString!The endpoint receiving events.
secretStringHMAC signing secret. Returned only herenull on every subsequent read.
statusWebhookStatusType!HEALTHY or UNHEALTHY.
events[WebhookEvent!]Subscribed event types ([] means all).
projectIds[String!]Scoped workspace IDs ([] means all).
enabledBooleanWhether delivery is active.
metadataJSONStored events/projectIds scoping metadata.
createdAtDateTime!Creation timestamp.
updatedAtDateTime!Last-update timestamp.

Full example

Subscribe a named webhook to a few events across two specific workspaces:

mutation CreateScopedWebhook($input: CreateWebhookInput!) {
  createWebhook(input: $input) {
    id
    uid
    name
    url
    secret
    status
    events
    projectIds
    enabled
    createdAt
  }
}
{
  "input": {
    "name": "Slack notifications",
    "url": "https://example.com/webhooks/blue",
    "events": ["TODO_CREATED", "TODO_DONE_STATUS_UPDATED", "COMMENT_CREATED"],
    "projectIds": ["project_123", "project_456"]
  }
}

Errors

CodeWhen
COMPANY_NOT_FOUNDThe X-Bloo-Company-ID header is missing or does not match an organization you belong to.
PLAN_LIMIT_REACHEDYour organization is at its plan’s enabled-webhook limit. The message reports the count and cap; upgrade to add more.
BAD_USER_INPUTurl is missing or is not a valid URL.
INTERNAL_SERVER_ERRORurl resolves to a private/internal address (message: URL resolves to a private/internal address) or uses a disallowed protocol.
FORBIDDENOne or more projectIds reference a workspace you are not a member of (message: You are not authorized.).

Permissions

You must be authenticated and send X-Bloo-Company-ID. You can only scope a webhook to workspaces you currently belong to. The webhook is owned by your user; only you can update or delete it, and only events from workspaces you are a member of are delivered (see Delivery scoping).