Widget API

The widget API is the same API your embedded widget calls. You can call it directly from your backend to ingest feedback from other sources (in-product surveys, support tools, importers from Canny / Featurebase).

Base URL

https://shippulse.app/api/v1

Custom domains do not proxy the API. Always call shippulse.app/api/v1 from your server.

Authentication

Two modes:

  • Public widget calls — no key required. Origin-checked against the project's domain allowlist. Read-only on roadmap and changelog; write-only on feedback submission (one submission per session, rate-limited).
  • Server-to-server calls — pass Authorization: Bearer <project-api-key>. Generate keys under Settings → API keys. Keys are project-scoped (one key cannot read another project's data). Keys are write-capable; treat them like secrets.

Endpoints

Feedback

  • POST /feedback — submit a feature request or bug. Body: { project_slug, title, body, category, email }. Returns { id, status: "received" }. Rate-limited.
  • GET /feedback/public/:project_slug — public roadmap entries. No auth. Returns paginated list with id, title, status, vote_count, shipped_at.
  • POST /feedback/:id/vote — record an upvote. Body: { email }. Idempotent per email.

Roadmap

  • GET /roadmap/:project_slug — full public roadmap, grouped by status (planned, in-progress, shipped). Cached at the edge sixty seconds.
  • PATCH /roadmap/:id — mark a feature shipped (or move it between statuses). Requires server-to-server auth. Body: { status, shipped_at? }. Triggers the proof-loop auto-DM if status: "shipped".

Changelog

  • GET /changelog/:project_slug — published changelog entries, newest first.
  • GET /changelog/:project_slug/rss.xml — RSS feed.
  • POST /changelog — create an entry. Server-to-server auth. Body: { project_slug, title, body, related_feedback_ids }.

Testimonials

  • GET /testimonials/:project_slug — public testimonials.
  • GET /testimonials/:project_slug/by-feature/:feedback_id — testimonials linked to a specific feature card.

Rate limits

Public widget calls: 30 requests per minute per IP, 5 submissions per hour per email. Server-to-server calls: 600 requests per minute per API key, burstable to 1200. Limits surfaced via X-RateLimit-Remaining and X-RateLimit-Reset response headers; 429 with a Retry-After header when exceeded.

Errors

JSON shape on every non-2xx:

{ "error": "rate_limited", "message": "Too many submissions from this email; retry after 14m." }

Error codes used: unauthorized, forbidden, not_found, rate_limited, bad_request, internal. The HTTP status mirrors the code.

Versioning

The API is versioned in the URL (/api/v1). Breaking changes ship as /api/v2; the previous version is supported for at least twelve months after the new version GAs. Deprecation notices appear in response headers (Deprecation, Sunset) on the old version.

Webhooks

Subscribe under Settings → Webhooks. Events fired:

  • feedback.created, feedback.voted
  • roadmap.status_changed, roadmap.shipped
  • testimonial.received, testimonial.published
  • changelog.published

Payloads signed with X-ShipPulse-Signature (HMAC-SHA256). Retry policy: exponential backoff, up to 24h, then surfaced in the dashboard.

Next