Docs

Quickstart

Everything below runs against the live API. Keys are issued with waitlist invites while I'm in beta — join here and you'll get one with your invite email.

Tip

Prefer not to read docs at all? Point your coding agent at your project with the Plurism skill and it does this whole page for you — behind an approval gate.

01 One key, plain HTTPS

Every service is a resource under api.plurism.dev, authenticated with a Bearer key scoped per project. Create a support thread:

curl -X POST https://api.plurism.dev/support/threads \
  -H "Authorization: Bearer $PLURISM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Reset password button does nothing on Safari",
    "category": "bug",
    "reporter_email": "user@example.com",
    "reporter_name": "Alice"
  }'

The response includes a ref (like ACME-42) for a human to quote, and a lookup_url carrying a capability token. Send the URL, not the ref: refs are sequential, so the token is what stops one reporter reading another's thread. On that page they can reply and attach files.

02 Or the typed SDK

The TypeScript SDK covers support, waitlist, feedback, flags, content, changelog and files. Server-side only — never ship your key to a browser.

Heads up@plurism/sdk isn't on npm yet. It ships with your invite while I'm in beta, and lands on npm at general availability. The import path below is the shape it'll have either way.

import { createPlurismClient } from "@plurism/sdk";

const plurism = createPlurismClient({
  baseUrl: "https://api.plurism.dev",
  apiKey: process.env.PLURISM_API_KEY!, // server-side only
});

// Support thread (returns a public ref like ACME-42)
const thread = await plurism.support.threads.create({
  body: "Reset password button does nothing on Safari",
  category: "bug",
  reporter_email: "user@example.com",
  reporter_name: "Alice",
});

// Waitlist signup
await plurism.waitlist.add({ email: "early@adopter.dev", referrer: "x" });

// Feedback
await plurism.feedback.submit({ rating: 9, comment: "Love it" });

// Feature flag
const flag = await plurism.flags.evaluate("new-checkout", { user_id: "u_1" });

// Analytics — your own traffic, back out
const { summary } = await plurism.analytics.traffic({ range: "30d" });

03 Same Cloudflare account? Skip the network

Service bindings are account-scoped, so this applies when your Worker runs in the same Cloudflare account as Plurism — self-hosting, or an arrangement we've set up together. It buys zero-egress, single-digit-ms calls. Everyone else uses plain HTTPS above, which is the normal path:

// wrangler.jsonc — only if your Worker is in the SAME Cloudflare account
{ "services": [{ "binding": "PLURISM", "service": "plurism-api" }] }

// then:
const plurism = createPlurismClient({
  binding: env.PLURISM,
  apiKey: env.PLURISM_API_KEY,
});

Authentication

One key per project, sent as Authorization: Bearer <key>. Secret keys (sk_…) are server-side only and unlock the full SDK. Publishable keys (pa_…) are safe in the browser and carry only three ingest-side scopes: analytics:ingest, waitlist:ingest and feedback:ingest. That is what the drop-in Elements widgets use, and it is also the key the analytics tracker takes — analytics never needs a secret key in your pages. Rotating a key is instant from the admin.

Zero to wired

The agent skill

Plurism ships as a skill for your coding agent. Point it at your project — it reads your stack, proposes the wiring, and only writes the route, the form and the env after you approve. Nothing lands in your codebase without you saying yes.

It's the same three steps above, done for you: pick the service, generate the call in your framework's idiom, drop the key into your environment. The skill is issued alongside your invite while I'm in beta.

What's covered today

  • Support

    Threads, replies, statuses, tags, inbound email and a public lookup page. Full REST surface.

  • Analytics

    First-party traffic, acquisition, funnel and revenue analytics: a lightweight pixel writes, a dashboard and `plurism.analytics` read. Past your monthly event ceiling, ingest keeps returning 202 but stops storing — watch the usage endpoint.

  • Feedback

    0–10 NPS ratings with an optional comment, plus a stats endpoint per project.

  • Feature flags

    CRUD plus an edge-cached evaluate with a stable rollout percentage on user_id.

  • Waitlist

    Signup, list and invite (fires the invite email); status moves pending → invited → joined.

  • Content

    Blog, news, FAQ and how-to served as HTML with schema.org JSON-LD for SEO and AEO.

  • Changelog

    A public JSON feed with a 60-second cache — embed it anywhere. Admin CRUD, publish events.

  • Files

    Upload and stream in and out; allow-listed content types with an SVG scrub on the way in.

  • Webhooks

    HMAC-verified inbound relay and Stripe-style signed outbound, with a retry table for failed deliveries.

  • Notifiers

    Rule-based email, Discord and generic HTTP fan-out — SSRF-guarded, with per-event template substitution.

  • Email

    Transactional email from your own DKIM-verified domain, on AWS SES. Verify a sending domain in the portal or over the API, then send. Bounce and complaint handling, and a per-project do-not-send list.

Reference

Error envelope

Non-2xx responses carry JSON. Route gates return a flat { "error": "message" }; the framework handler returns { "error": { "code", "message" } }. The SDK normalises both, so you always read a plain string.

Rate limits

The public Elements endpoints (the <plurism-*> widgets) are capped per project and return 429 when a window is exceeded. Authenticated API calls are metered against your plan's quota.

Webhook signing

Outbound webhooks are signed t=<unix>,v1=<hex> (Stripe-style HMAC). Verify with verifyWebhookSignature from the SDK and reject anything more than five minutes old.

Every endpoint is described in the OpenAPI document at api.plurism.dev/openapi.json — no key needed to read it. Point your client generator, your API explorer, or your coding agent straight at it. Anything unclear — ask me, replies usually land same-day.