//SCHEMADocs
Console

Webhooks

A webhook endpoint is a URL //SCHEMA sends events to as they happen — a release going live, a delivery being processed, a member joining. Each delivery is a signed POST carrying the event; the event types and their payloads are listed in Webhook events.

Endpoints belong to your organization, and can be narrowed to some of its catalogs. Each has a signing secret, shown once, when the endpoint is created or its secret rotated.

Every owner of your organization is emailed when an endpoint is created, or changed so that it receives more than before — a new URL, more event types or catalogs, or turned back on. A webhook is a standing copy of your events sent somewhere else, so the people who could stop one hear about it at once. If no owner can be emailed, the change is refused.

Webhook configuration is not available to agents over MCP.

See Receive webhooks and How webhooks are delivered.

The WebhookEndpoint object#

A destination for your organization's events. Never carries its signing secret.

Attributes

  • endpointPkInt!
    Unique identifier.
  • urlString!
    Where events are sent.
  • descriptionStringnullable
    What it is for, if set.
  • eventTypes[String!]!
    The event types it receives; see Webhook events.
  • catalogPks[Int!]nullable
    The catalogs whose events it receives, or null for every catalog of your organization, including ones created later. Membership events, which belong to no catalog, reach it either way.
  • enabledBoolean!
    Whether it is being sent to.
  • enabledAtDateTime!
    When it was created or last turned back on. It receives only events that happened after this.
  • disabledAtDateTimenullable
    When it was turned off, or null.
  • disabledReasonStringnullable
    Why it was turned off — by whom, or automatically after five days of failed deliveries.
  • failingSinceDateTimenullable
    Since when every delivery to it has failed, while that is so. Five days of it turns the endpoint off and emails your owners.
  • createdAtDateTime!
    When it was created.
  • updatedAtDateTime!
    When it was last changed.
  • Its deliveries, newest first. Kept for 30 days.
    Arguments
    • firstInt
      At most this many, up to 100. Defaults to 20.
    • beforeInt
      Only deliveries older than this deliveryPk — pass the last one you received to page.
    • stateString
      Only deliveries in this state — pending, succeeded or failed.

The WebhookDelivery object#

One event's delivery to one endpoint.

Attributes

  • deliveryPkInt!
    Unique identifier.
  • eventIdString!
    The event's id, sent as webhook-id. The same on every attempt.
  • eventTypeString!
    The event type, e.g. release.available.
  • occurredAtDateTime!
    When the event happened.
  • stateString!
    pending (still being tried), succeeded (answered 2xx) or failed (out of attempts, or refused).
  • attemptsInt!
    Attempts made.
  • lastAttemptAtDateTimenullable
    When the last attempt was made.
  • lastStatusIntnullable
    The HTTP status your receiver last answered with, if it answered.
  • lastErrorStringnullable
    Why the last attempt failed: http 503, timeout after 10s, redirect to … (redirects are never followed), refused: … (an address webhooks cannot be sent to).
  • lastResponseExcerptStringnullable
    Up to 4 KiB of your receiver's last answer.
  • lastLatencyMsIntnullable
    How long the last attempt took, in milliseconds.
  • nextAttemptAtDateTimenullable
    When the next attempt is due, while pending.
  • succeededAtDateTimenullable
    When it was delivered, if it was.

The WebhookEventType object#

An event type an endpoint can subscribe to.

Attributes

  • typeString!
    The wire name, e.g. release.state_changed.
  • descriptionString!
    One line on when it fires.

The CreatedWebhookEndpoint object#

A new endpoint, and the only copy of its signing secret.

Attributes

The CreateWebhookEndpointInput input object#

An endpoint to create.

Fields

  • urlString!required
    Where to send. https:// on the default port; not a private, loopback or link-local address.
  • descriptionString
    What it is for, e.g. Storefront sync.
  • eventTypes[String!]!required
    At least one, from webhookEventTypes.
  • catalogPks[Int!]
    Only events from these of your catalogs. Omit for every catalog, including ones created later.

The UpdateWebhookEndpointInput input object#

Changes to an endpoint. Omitted fields are left as they are.

Fields

  • endpointPkInt!required
    The endpoint to change.
  • A new destination. The signing secret stays the same.
  • descriptionString
    A new description; null clears it.
  • eventTypes[String!]
    The event types it should receive, replacing the current list.
  • catalogPks[Int!]
    The catalogs it should receive events from; null for every catalog.
  • enabledBoolean
    false turns it off, failing what was pending; true turns it back on, receiving events from then on.

List event types#

querywebhookEventTypes→[WebhookEventType!]!any credential

Every event type an endpoint can subscribe to, with a one-line summary. webhook.test is not among them — it is sent on request to one endpoint.

Arguments

None.

Returns

A list of WebhookEventType objects.

Request
query {
  webhookEventTypes {
    type
    description
  }
}
Response
{
  "data": {
    "webhookEventTypes": [
      {
        "type": "release.available",
        "description": "A release is active and its availability date has arrived."
      }
    ]
  }
}

List endpoints#

querywebhookEndpoints→[WebhookEndpoint!]!config_read

Your organization's webhook endpoints, oldest first. Never includes a signing secret.

Arguments

None.

Returns

A list of WebhookEndpoint objects.

Request
query {
  webhookEndpoints {
    endpointPk
    url
    eventTypes
    catalogPks
    enabled
    failingSince
  }
}
Response
{
  "data": {
    "webhookEndpoints": [
      {
        "endpointPk": 4,
        "url": "https://hooks.paperradio.example/schema",
        "eventTypes": ["release.available", "release.state_changed"],
        "catalogPks": null,
        "enabled": true,
        "failingSince": null
      }
    ]
  }
}

Retrieve an endpoint#

querywebhookEndpoint→WebhookEndpointconfig_read

One endpoint, with its delivery log. null if your organization has no endpoint by that id.

Arguments

  • endpointPkInt!required
    The endpoint.

Returns

A WebhookEndpoint, or null.

Request
query {
  webhookEndpoint(endpointPk: 4) {
    url
    deliveries(first: 2) {
      deliveryPk
      eventType
      state
      attempts
      lastStatus
      lastError
    }
  }
}
Response
{
  "data": {
    "webhookEndpoint": {
      "url": "https://hooks.paperradio.example/schema",
      "deliveries": [
        {
          "deliveryPk": 1182,
          "eventType": "release.available",
          "state": "pending",
          "attempts": 2,
          "lastStatus": 503,
          "lastError": "http 503"
        },
        {
          "deliveryPk": 1181,
          "eventType": "release.state_changed",
          "state": "succeeded",
          "attempts": 1,
          "lastStatus": 204,
          "lastError": null
        }
      ]
    }
  }
}

Create an endpoint#

mutationcreateWebhookEndpoint→CreatedWebhookEndpoint!config_write

Create an endpoint. Copy secret from the response immediately — it is never shown again.

The URL must be https:// on the default port, and must not be a private, loopback or link-local address. Every owner of your organization is emailed, in the same transaction, with the destination, what it receives, and who created it; if no owner can be emailed, the endpoint is not created. At most 10 endpoints per organization.

Arguments

Returns

A CreatedWebhookEndpoint, including the secret.

Request
mutation {
  createWebhookEndpoint(input: {
    url: "https://hooks.paperradio.example/schema"
    eventTypes: ["release.available", "release.state_changed"]
  }) {
    secret
    endpoint {
      endpointPk
      enabled
    }
  }
}
Response
{
  "data": {
    "createWebhookEndpoint": {
      "secret": "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSwq3c0Jm7ZP4c=",
      "endpoint": {
        "endpointPk": 4,
        "enabled": true
      }
    }
  }
}

Update an endpoint#

mutationupdateWebhookEndpoint→WebhookEndpoint!config_write

Change an endpoint's URL, description, event types or catalogs, or turn it off or back on. Fields you omit are left as they are.

A change that lets it receive more than before — a new URL, more event types or catalogs, or turning it back on — emails every owner, in the same transaction. Narrowing announces nothing. Turning an endpoint off fails what was still pending; turning it back on receives events from then on, never what it missed — use redeliverWebhook for those.

Arguments

  • What to change; see UpdateWebhookEndpointInput.
    Show child parameters
    • endpointPkInt!required
      The endpoint to change.
    • A new destination. The signing secret stays the same.
    • descriptionString
      A new description; null clears it.
    • eventTypes[String!]
      The event types it should receive, replacing the current list.
    • catalogPks[Int!]
      The catalogs it should receive events from; null for every catalog.
    • enabledBoolean
      false turns it off, failing what was pending; true turns it back on, receiving events from then on.

Returns

The updated WebhookEndpoint.

Request
mutation {
  updateWebhookEndpoint(input: { endpointPk: 4, enabled: false }) {
    enabled
    disabledReason
  }
}
Response
{
  "data": {
    "updateWebhookEndpoint": {
      "enabled": false,
      "disabledReason": "Turned off by Sam Lee <[email protected]>."
    }
  }
}

Rotate an endpoint's secret#

mutationrotateWebhookSecret→String!config_write

Replace the signing secret, returning the new one once. For 24 hours deliveries carry a signature from each secret, so your receiver can switch over without dropping one.

Arguments

  • endpointPkInt!required
    The endpoint.

Returns

The new secret, beginning whsec_.

Request
mutation {
  rotateWebhookSecret(endpointPk: 4)
}
Response
{
  "data": {
    "rotateWebhookSecret": "whsec_C2FvCcBdMdD1e9xY3bQh7nLk5RtWp0uA8JsiXgZoEyM="
  }
}

Delete an endpoint#

mutationdeleteWebhookEndpoint→Boolean!config_write

Delete an endpoint and its delivery log. Nothing pending is sent.

Arguments

  • endpointPkInt!required
    The endpoint.

Returns

true if an endpoint of your organization was deleted.

Request
mutation {
  deleteWebhookEndpoint(endpointPk: 4)
}
Response
{
  "data": {
    "deleteWebhookEndpoint": true
  }
}

Send a test event#

mutationsendTestWebhook→String!config_write

Queue a webhook.test event to this one endpoint. It goes through the same path as every other event — signed, retried and logged — so a test that arrives and verifies means your integration works. The endpoint must be enabled.

Arguments

  • endpointPkInt!required
    The endpoint.

Returns

The event's id, as your receiver will see it in webhook-id.

Request
mutation {
  sendTestWebhook(endpointPk: 4)
}
Response
{
  "data": {
    "sendTestWebhook": "evt_4ee8793102184b15940831a1e5f3ce54"
  }
}

Redeliver an event#

mutationredeliverWebhook→Boolean!config_write

Send one delivery again, with the same webhook-id, as a fresh run of attempts. Safe on a delivery that already succeeded: your receiver should be deduplicating on the id. The endpoint must be enabled.

Arguments

  • deliveryPkInt!required
    The delivery, from the endpoint's deliveries.

Returns

true once it is queued.

Request
mutation {
  redeliverWebhook(deliveryPk: 1182)
}
Response
{
  "data": {
    "redeliverWebhook": true
  }
}