API & MCP

On this page

ShipPulse exposes three programmatic surfaces:

  1. Public REST v1 — key-authenticated HTTP for reading your project's data.
  2. MCP server — an agent-native Model Context Protocol endpoint (read + write tools) for Claude / Cursor / any MCP client.
  3. Outbound webhooks — signed event POSTs to your own endpoints.

Note: the public REST surface is intentionally small today (one read endpoint). For richer reads and for writes, use the MCP server. We document only what exists — if it isn't listed here, it isn't built yet.

Authentication (REST + MCP)

Both the REST API and the MCP server authenticate with a project API key. Mint one under Settings → API keys (shown once at creation). Pass it as either header:

Authorization: Bearer sk_live_...
# or
x-api-key: sk_live_...
  • The project is resolved from the key — you never pass a project id, and one key can't reach another project's data.
  • Keys carry a scope: read < write < admin (a higher scope satisfies a lower one). Read endpoints/tools need read; write tools need write.
  • Keys are SHA-256 hashed at rest and compared in constant time. Treat them like secrets; revoke under Settings → API keys.
  • Rollback flag SHIPPULSE_API_KEYS=off returns 503 for all key-authenticated routes.

The base host is always https://shippulse.dev. Custom domains serve your public pages but do not proxy the API.

Public REST v1

Base URL:

https://shippulse.dev/api/public/v1

GET /feedback

List your project's public, approved feedback posts (newest first). Scope: read. Private posts and anything still pending moderation or flagged as spam are never returned — the same posts a visitor sees on your public board.

Query parameters:

  • limit — page size, default 50, clamped to 1100.

Per-key rate limit: 120 requests per 60 seconds (429 + Retry-After / X-RateLimit-* headers when exceeded), matching the MCP server.

curl https://shippulse.dev/api/public/v1/feedback?limit=20 \
  -H "Authorization: Bearer sk_live_..."
{
  "ok": true,
  "version": "v1",
  "project_id": "…",
  "count": 1,
  "feedback": [
    {
      "id": "…",
      "title": "Dark mode",
      "body": "…",
      "status": "planned",
      "vote_count": 42,
      "is_public": true,
      "created_at": "2026-06-01T12:00:00Z",
      "updated_at": "2026-06-02T09:30:00Z"
    }
  ]
}

This is the only public REST endpoint today. Roadmap, changelog, and write access are available through the MCP server below.

MCP server

Endpoint:

POST https://shippulse.dev/api/mcp

A spec-compliant JSON-RPC 2.0 MCP server: initialize, notifications/initialized, ping, tools/list, tools/call (batches supported). Authenticate with the same project API key (header as above). Per-key rate limit: 120 requests per 60 seconds (429 + Retry-After when exceeded). Disable with SHIPPULSE_MCP=off (404).

Tools (8) — six read, two write:

  • list_feedback (read) — list posts (keyset next_cursor, status filter, newest/votes sort)
  • search_feedback (read) — ILIKE search across title/body
  • get_feedback (read) — one post by id
  • list_roadmap (read) — roadmap items
  • get_roadmap_item (read) — one roadmap item
  • list_changelog (read) — published changelog entries
  • create_roadmap_item (write) — create a roadmap item
  • promote_feedback (write) — create a roadmap item from a feedback post and link them

Tools operate only on the project the key belongs to. create_roadmap_item and promote_feedback require a write key.

Errors

JSON shape on every REST non-2xx:

{ "ok": false, "error": "missing_key" }

Codes: missing_key (401, with WWW-Authenticate: Bearer), invalid_key (401), insufficient_scope (403 — the key's scope doesn't allow this call), api_keys_disabled (503), internal (500). MCP errors follow the JSON-RPC error object (code, message).

Webhooks

Subscribe under Settings → Webhooks. All seven events below fire today:

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

Payloads are signed with X-ShipPulse-Signature (HMAC-SHA256 over the raw request body, keyed by your per-endpoint secret). The event name is also sent in the X-ShipPulse-Event header.

Delivery & retry — best-effort, not a durable queue. Each event is POSTed inline at the moment it happens. We make up to 3 attempts (1 initial + 2 retries) with a fixed ~300 ms pause between attempts and a 4 s timeout per attempt; a non-2xx or a timeout triggers the next attempt. There is no exponential backoff and no multi-hour requeue — if all 3 attempts fail, the event is dropped. Every attempt-set is logged; recent deliveries (status, attempt count, last error) are shown under Settings → Webhooks. Make your endpoint fast and idempotent, and reconcile via the API if you need at-least-once guarantees.

Generic signed webhooks are also the supported bridge to Zapier / Make / n8n (point them at a webhook catch hook) — there is no native Zapier app yet.

Next