A public API your CTO will approve.
Every Plauditly widget is backed by a single JSON endpoint anyone can hit. No API key. No SDK to install. No rate-limit headers to debug at 2 AM. If you can write fetch(), you can build whatever the embed widget doesn't.
None required
Public read endpoint. Treat the widget public_id as the access token; rotate it from the dashboard if it leaks.
5 min edge
Cloudflare-grade edge caching with stale-while-revalidate. Busts the instant you approve, edit, or hide a testimonial.
JSON, typed
Stable shape with semantic versioning at the URL level. Breaking changes ship at /api/widgets/v2/ — never inline.
The endpoint
One route. Accepts either a widget public ID (wgt_…) or a project slug for backwards compatibility.
curl https://plauditly.app/api/widgets/wgt_YOUR_ID{
"project": {
"name": "Latitude",
"slug": "latitude",
"brand_color": "#e0492a"
},
"widget": {
"public_id": "wgt_a8f3c…",
"type": "wall",
"config": { "count": 50, "accent": "#e0492a" },
"showBadge": false
},
"testimonials": [
{
"id": "tst_a1b2c3…",
"author_name": "Sarah Chen",
"author_role": "Founder",
"author_company": "Latitude",
"rating": 5,
"body": "Wired up Plauditly in twelve minutes…",
"pinned": false,
"created_at": "2026-05-12T14:22:01Z"
}
]
}Privacy invariant: author_email is collected on the form but structurally absent from this response — it lives in a separate column the public API never reads. Adding it to a response would be a security regression, not a feature request.
In your language
// Fetch in any JS runtime — Node, browser, Bun, Deno.
const res = await fetch("https://plauditly.app/api/widgets/wgt_YOUR_ID");
const { project, testimonials } = await res.json();
console.log(`${testimonials.length} testimonials for ${project.name}`);import httpx
r = httpx.get("https://plauditly.app/api/widgets/wgt_YOUR_ID")
data = r.json()
print(f"{len(data['testimonials'])} testimonials for {data['project']['name']}")// React Server Component example — re-validates every 5 minutes
async function Wall() {
const res = await fetch("https://plauditly.app/api/widgets/wgt_YOUR_ID", {
next: { revalidate: 300 },
});
const { testimonials } = await res.json();
return (
<ul>
{testimonials.map((t) => (
<li key={t.id}>
<p>{t.body}</p>
<small>{t.author_name}</small>
</li>
))}
</ul>
);
}Rate limits & abuse handling
- Reads: unmetered. Edge cache absorbs traffic spikes; your database stays quiet even when your customer's landing page goes viral on Hacker News.
- Writes: the public submission endpoint (
POST /api/submissions) is honeypot-protected and rate-limited per IP. Suspicious traffic gets soft-rejected — never silently dropped. - Abuse: if you spot a leaked widget ID being used to scrape testimonials beyond your intent, rotate it from the dashboard — old ID returns 410 Gone within 60 seconds.
Beyond the embed
The embed widget is one consumer of this API. Other things you can build with the same endpoint:
- Static-site bake-in: fetch at build time, render HTML directly into your Astro/Hugo/Eleventy output. Zero client-side JS, perfect Lighthouse.
- RSS / OPML of praise: turn your wall into an RSS feed for changelog aggregators or customer-success dashboards.
- Slack/Discord notifier: poll the endpoint, post a message every time a new approved testimonial appears.
- Investor / board updates: drop the JSON into a Notion page or board doc — proof of customer love, sourced from production.