API & MCP
On this page
ShipPulse exposes three programmatic surfaces:
- Public REST
v1— key-authenticated HTTP for reading your project's data. - MCP server — an agent-native Model Context Protocol endpoint (read + write tools) for Claude / Cursor / any MCP client.
- 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 needread; write tools needwrite. - 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=offreturns503for 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/v1GET /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, default50, clamped to1–100.
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/mcpA 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 (keysetnext_cursor,statusfilter,newest/votessort)search_feedback(read) — ILIKE search across title/bodyget_feedback(read) — one post by idlist_roadmap(read) — roadmap itemsget_roadmap_item(read) — one roadmap itemlist_changelog(read) — published changelog entriescreate_roadmap_item(write) — create a roadmap itempromote_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.votedroadmap.status_changed,roadmap.shippedtestimonial.received,testimonial.publishedchangelog.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.