ShipPulse
  • Pricing
  • Docs
  • Blog
  • Compare

Product

TestimonialsChangelogStatus PagesFeedbackRoadmapPricing

Resources

DocsBlogAPI ReferenceSDKHelp Center

Company

AboutContact

Legal

TermsPrivacyCookie PolicyDPASub-processors

Product updates

Changelog updates only. Unsubscribe any time.

ShipPulse operated by Igor Bogdanov, Limassol, Cyprus. [email protected]. Cyprus registration number pending — will be published once issued.

ShipPulse

© 2026 ShipPulse. All rights reserved.

OverviewQuick StartCore ConceptsWidget ReferencePlatform GuidesAPI ReferenceAPI PlaygroundError HandlingPaginationRate LimitingJavaScript SDKWebhooksZapier, n8n & MakeCustom DomainsTeam ManagementBilling & PlansNotification ChannelsAI FeaturesOverviewFrom SenjaFrom Testimonial.toFrom HeadwayFrom Canny

Introduction

  • Overview
  • Quick Start
  • Core Concepts

Embed Widgets

  • Widget Reference
  • Platform Guides

REST API

  • API Reference
  • API Playground
  • Error Handling
  • Pagination
  • Rate Limiting

SDK & Webhooks

  • JavaScript SDK
  • Webhooks
  • Zapier, n8n & Make

Guides

  • Custom Domains
  • Team Management
  • Billing & Plans
  • Notification Channels
  • AI Features

Migrations

  • Overview
  • From Senja
  • From Testimonial.to
  • From Headway
  • From Canny

Need help?

[email protected]
Docs / Webhooks Reference

Webhooks Reference

Receive real-time events from ShipPulse in your application.

Overview

ShipPulse sends HTTP POST requests to your endpoint whenever specific events occur in your project — such as a new testimonial, incident, or monitor status change. You can use webhooks to:

  • Send custom Slack notifications
  • Trigger CI/CD pipelines on changelog publish
  • Sync data to your own database
  • Automate support workflows on incidents

Setting up a webhook

  1. Go to Dashboard → Project Settings → Notifications
  2. Click Add channel and select Webhook
  3. Enter your endpoint URL and optionally a signing secret
  4. Select which events to subscribe to
  5. Click Test to verify your endpoint receives events

Payload format

All webhook payloads are JSON with this structure:

json
{
  "event": "testimonial.received",
  "timestamp": "2026-04-01T12:00:00.000Z",
  "project": {
    "id": "uuid",
    "name": "My SaaS",
    "slug": "my-saas"
  },
  "data": {
    "id": "uuid",
    "authorName": "Sarah Chen",
    "content": "Incredible product!",
    "rating": 5
  },
  "title": "⭐ New testimonial from Sarah Chen",
  "body": "Incredible product!",
  "url": "https://shippulse.dev/dashboard/projects/my-saas/testimonials"
}

Signature verification

When you configure a webhook secret, ShipPulse signs each payload using HMAC-SHA256 and sends the signature in the X-ShipPulse-Signature header:

http
POST /your-webhook-endpoint HTTP/1.1
Content-Type: application/json
X-ShipPulse-Event: testimonial.received
X-ShipPulse-Signature: sha256=abc123...
User-Agent: ShipPulse-Webhook/1.0

Verify the signature to ensure the request came from ShipPulse:

typescript
import { createHmac } from "crypto"

function verifySignature(
  rawBody: string,
  signature: string,
  secret: string
): boolean {
  const expected = `sha256=${createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex")}`

  // Constant-time comparison (prevents timing attacks)
  if (expected.length !== signature.length) return false
  let diff = 0
  for (let i = 0; i < expected.length; i++) {
    diff |= expected.charCodeAt(i) ^ signature.charCodeAt(i)
  }
  return diff === 0
}

Or use the @shippulse/node SDK:

typescript
import { ShipPulseNode } from "@shippulse/node"

const sp = new ShipPulseNode({ apiKey: process.env.SHIPPULSE_API_KEY! })

// Express / Hono / Elysia handler
app.post("/webhooks/shippulse", async (req) => {
  const raw = await req.text()
  const sig = req.headers.get("x-shippulse-signature") ?? ""

  if (!sp.verifyWebhook(raw, sig, process.env.SHIPPULSE_WEBHOOK_SECRET!)) {
    return new Response("Unauthorized", { status: 401 })
  }

  const event = sp.parseWebhook(raw)
  console.log("Received:", event.event, event.data)

  return new Response("OK")
})

Retry policy

If your endpoint does not return a 2xx response, ShipPulse retries with exponential backoff:

AttemptDelayType
1stImmediateIn-process
2nd+1 secondIn-process
3rd+5 secondsIn-process
4th+1 minuteCron
5th+5 minutesCron
6th+30 minutesCron
7th+2 hoursCron
8th+12 hoursCron
9th (final)+24 hoursCron

After 9 attempts, the delivery is marked as permanently failed. You can manually resend from the delivery log in your notification channel settings.

Delivery log

Every webhook attempt (success or failure) is logged. View the delivery history at Dashboard → Project Settings → Notifications → History.

You can resend any past delivery from the history view, which is useful for replaying events into a new integration.

Events reference

EventTriggerKey data
incident.createdA new incident is openedtitle, status, impact, body
incident.resolvedAn incident is marked as resolvedtitle, resolved_at
incident.updatedAn incident update is postedtitle, status, update
monitor.downA monitor transitions to downname, url, status
monitor.upA monitor recovers to upname, url, status, downtime_ms
maintenance.scheduledMaintenance window is scheduledtitle, scheduled_start, scheduled_end
maintenance.startedMaintenance window beginstitle, scheduled_end
maintenance.completedMaintenance window endstitle
changelog.publishedA changelog entry is publishedtitle, slug, type
testimonial.receivedA new testimonial is submittedauthor_name, content, rating
testimonial.approvedA testimonial is approvedauthor_name, testimonial_id
testimonial.rejectedA testimonial is rejectedauthor_name, testimonial_id
feedback.createdA feedback post is submittedtitle, author_name, board_name
feedback.votedA feedback post reaches a vote milestone (every 5 votes)title, vote_count
feedback.status_changedA feedback post status changestitle, from_status, to_status
feedback.commentedA comment is posted on a feedback postpost_title, author_name, is_official

Best practices

  • Always verify signatures in production to prevent spoofed requests.
  • Return 2xx quickly — process events asynchronously. If processing takes more than 10 seconds, the delivery will time out and be retried.
  • Handle duplicates — retries may deliver the same event multiple times. Use the timestamp and data.id fields for deduplication.
  • Log everything — keep your own delivery log during development.