openapi: 3.2.0 info: title: Huddlekit Webhook subscriptions API version: 1.0.0 summary: Read and create feedback comments, change their status and subscribe to comment webhooks. description: The Huddlekit REST API reads a workspace's projects, web apps, documents and comments, creates comments, changes a comment's status and manages webhook subscriptions. termsOfService: https://huddlekit.com/terms contact: name: Huddlekit email: hello@huddlekit.com url: https://huddlekit.com servers: - url: https://app.huddlekit.com/api/v1 description: Production security: - apiKey: [] tags: - name: Webhook Subscriptions description: Subscribe URLs to comment events (REST hooks). paths: /hooks: get: operationId: listWebhookSubscriptions tags: - Webhook Subscriptions summary: List this key's webhook subscriptions description: Lists the webhook subscriptions created with this API key, newest first. Webhooks created in the Huddlekit app or with other keys are not shown. Requires the `read` scope. responses: '200': description: This key's subscriptions. content: application/json: schema: $ref: '#/components/schemas/ListWebhookSubscriptionsResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' '503': $ref: '#/components/responses/ServiceUnavailable' post: operationId: createWebhookSubscription tags: - Webhook Subscriptions summary: Subscribe a URL to webhook events description: 'Subscribes an https:// URL to comment events (REST-hook style, as used by Zapier). Deliveries are signed with HMAC-SHA256 in the `X-Huddlekit-Signature` header; see the `webhooks` section for payloads. Idempotent per key and URL: subscribing the same URL again with the same key reactivates the existing subscription, replaces its event types and returns 200 without a secret. A new subscription returns 201 with its signing secret, shown only this once. The subscription also appears in the workspace''s webhook list in the Huddlekit app. Events caused by this same key are never delivered to it. Requires the `write` scope.' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateWebhookSubscriptionRequest' responses: '200': description: This key already had a subscription for this URL; it was reactivated. content: application/json: schema: $ref: '#/components/schemas/WebhookSubscriptionResubscribed' '201': description: The subscription was created. content: application/json: schema: $ref: '#/components/schemas/WebhookSubscriptionCreated' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': description: The key lacks the `write` scope, or the workspace has no active Team subscription (either the API plan check, with `requiredPlans`, or `{"error":"Webhook subscriptions require an active Team plan"}`). content: application/json: schema: anyOf: - $ref: '#/components/schemas/PlanRequiredError' - $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/TooManyRequests' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' /hooks/{id}: delete: operationId: deleteWebhookSubscription tags: - Webhook Subscriptions summary: Unsubscribe a webhook description: 'Deletes a webhook subscription that was created with this API key. Idempotent: returns 200 whether or not anything was deleted, with `deleted` saying which. It cannot delete webhooks created in the Huddlekit app or with another key. Not plan-gated: unlike every other call, it works even if the workspace is no longer on the Team plan, so automations can always be switched off. Requires the `write` scope.' parameters: - name: id in: path required: true description: Id of the subscription to delete (a UUID, from `createWebhookSubscription` or `listWebhookSubscriptions`). schema: type: string format: uuid responses: '200': description: Done. `deleted` is false if there was nothing to delete. content: application/json: schema: $ref: '#/components/schemas/DeleteWebhookSubscriptionResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/ForbiddenScope' '429': $ref: '#/components/responses/TooManyRequests' '503': description: The subscription could not be deleted. Retry. content: application/json: schema: $ref: '#/components/schemas/Error' example: error: Could not unsubscribe. Please retry. components: schemas: DeleteWebhookSubscriptionResponse: type: object required: - deleted - id properties: deleted: type: boolean description: True if a subscription was removed; false if none matched (already deleted, or not created by this key). id: type: string description: The id from the request path. example: deleted: true id: 6b1f9c2e-4d7a-4c1b-9e3f-2a8d5c7b1e04 WebhookSubscription: type: object description: A webhook subscription created with this API key. required: - id - url - event_types - is_active - created_at - disabled_at - consecutive_failures properties: id: type: string format: uuid description: Subscription id. Pass it to `DELETE /hooks/{id}` to unsubscribe. url: type: string format: uri description: The https:// URL events are POSTed to. event_types: type: array description: Event types delivered to this URL. An empty array means every event type. items: $ref: '#/components/schemas/EventType' is_active: type: boolean description: False when paused in the Huddlekit app. A switched-off subscription keeps `true` and has `disabled_at` set. created_at: type: string format: date-time description: When the subscription was created. disabled_at: type: - string - 'null' format: date-time description: When the subscription was disabled, or null. consecutive_failures: type: integer minimum: 0 description: Failed deliveries in a row. The subscription is switched off after 20 failures in a row spanning more than 24 hours. WebhookSubscriptionResubscribed: type: object description: This key already had a subscription for the same URL. It was reactivated and its event types replaced. The existing signing secret is kept and is not returned. required: - id - url - resubscribed properties: id: type: string format: uuid description: Id of the existing subscription. url: type: string format: uri description: The subscribed URL. resubscribed: type: boolean const: true description: Always true. PlanRequiredError: type: object description: Returned with 403 when the key's workspace is not on a plan that includes API access. required: - error - requiredPlans properties: error: type: string description: Human-readable message naming the required plan. requiredPlans: type: array description: Plan ids that include API access. items: type: string example: error: This feature requires the Team plan. requiredPlans: - team WebhookSubscriptionCreated: type: object description: A new subscription. This is the only time the signing secret is returned. required: - id - url - event_types - secret - secret_shown_once - known_platform properties: id: type: string format: uuid description: Subscription id. url: type: string format: uri description: The URL events will be POSTed to. event_types: type: array description: Event types delivered. Empty means every event type. items: $ref: '#/components/schemas/EventType' secret: type: string description: Signing secret (`whsec_` followed by 64 hex characters) used for the `X-Huddlekit-Signature` header on deliveries to this URL. Shown once and cannot be retrieved again; store it now. secret_shown_once: type: boolean const: true description: 'Always true: the secret will not be shown again.' known_platform: type: boolean description: True when the subscription was made by a platform Huddlekit recognises, such as Zapier. example: id: 6b1f9c2e-4d7a-4c1b-9e3f-2a8d5c7b1e04 url: https://hooks.example.com/huddlekit event_types: - comment.created - comment.status_changed secret: whsec_0000000000000000000000000000000000000000000000000000000000000000 secret_shown_once: true known_platform: false EventType: type: string enum: - comment.created - comment.status_changed - comment.text_changed - comment.screenshot_ready description: '`comment.created`: a comment was added. `comment.status_changed`: its status changed. `comment.text_changed`: its text was edited. `comment.screenshot_ready`: its screenshot finished capturing (website and webapp comments only). The **Send test event** button in the Huddlekit app also sends `ping`, with a made-up comment and no `source` or `permalink`; answer it with any 2xx and don''t treat it as a real event.' CreateWebhookSubscriptionRequest: type: object description: The URL to deliver events to and, optionally, which events. `target_url` and `url` are accepted as alternative spellings of `targetUrl`, and `events` as an alternative spelling of `event_types`. required: - targetUrl properties: targetUrl: type: string format: uri pattern: ^https://.+ description: The https:// URL to POST events to. Must be a public URL outside Huddlekit. target_url: type: string format: uri description: Alternative spelling of `targetUrl`, used when `targetUrl` is absent. url: type: string format: uri description: Alternative spelling of `targetUrl`, used when `targetUrl` and `target_url` are absent. event_types: type: array description: Event types to deliver. Omit it, or send an empty array, to receive every event type. Unknown values are a 400. items: $ref: '#/components/schemas/EventType' events: type: array description: Alternative spelling of `event_types`, used when `event_types` is absent. items: $ref: '#/components/schemas/EventType' example: targetUrl: https://hooks.example.com/huddlekit event_types: - comment.created - comment.status_changed Error: type: object description: Error body returned by every failed call. required: - error properties: error: type: string description: Short, human-readable error message. detail: type: string description: Extra explanation, when there is one. example: error: Unauthorized detail: Invalid or revoked API key ListWebhookSubscriptionsResponse: type: object required: - hooks properties: hooks: type: array description: Subscriptions created with this API key, newest first. Webhooks created in the Huddlekit app or with other keys are not included. items: $ref: '#/components/schemas/WebhookSubscription' responses: Forbidden: description: The key lacks the scope this call needs (`{"error":"Forbidden","detail":"This key lacks the \"read\" scope"}`), or the workspace has no active Team subscription (body includes `requiredPlans`). content: application/json: schema: anyOf: - $ref: '#/components/schemas/PlanRequiredError' - $ref: '#/components/schemas/Error' example: error: This feature requires the Team plan. requiredPlans: - team BadRequest: description: The request was invalid. `error` says which field and why. content: application/json: schema: $ref: '#/components/schemas/Error' example: error: parent_id is required ForbiddenScope: description: The key lacks the `write` scope. content: application/json: schema: $ref: '#/components/schemas/Error' example: error: Forbidden detail: This key lacks the "write" scope InternalError: description: The request could not be completed. content: application/json: schema: $ref: '#/components/schemas/Error' Unauthorized: description: No API key, a malformed `Authorization` header, or an invalid, revoked or expired key. content: application/json: schema: $ref: '#/components/schemas/Error' example: error: Unauthorized detail: 'Send your key as: Authorization: Bearer hk_live_…' ServiceUnavailable: description: A temporary failure, such as the API key, the workspace plan or the parent record could not be checked. Safe to retry. content: application/json: schema: $ref: '#/components/schemas/Error' example: error: Could not verify the workspace plan TooManyRequests: description: 'Rate limit exceeded. Limits: 200 reads and 30 writes per minute per API key, counted per endpoint group (`/me`, `/projects`, `/comments`, `/comments/{id}`, `/hooks`, `/events/recent`) and separately for reads and writes; `DELETE /hooks/{id}` counts toward the `/hooks` writes. Refused calls count too. Wait the number of seconds in `Retry-After`, then retry.' headers: Retry-After: description: Whole seconds until the limit resets (at least 1). schema: type: integer minimum: 1 content: application/json: schema: $ref: '#/components/schemas/Error' example: error: Too many requests securitySchemes: apiKey: type: http scheme: bearer bearerFormat: hk_live_ + 64 hex characters description: 'Workspace API key, created in the Huddlekit app and shown once. Send it as `Authorization: Bearer hk_live_<64 lowercase hex characters>`. The key identifies the workspace; there is no user session. GET calls need the `read` scope; POST, PATCH and DELETE calls need `write`.' externalDocs: description: REST API guide url: https://huddlekit.com/support/using-the-rest-api