Proven Praise docs
Set up Proven Praise, put testimonials on your website, and check a verification record.
On this page
Getting started
- Go to Sign in and enter your email. Open the link that we send to you.
- Enter your business name.
- Select Connect Stripe. Install the Proven Praise Stripe App on your Stripe account. The app asks for read-only access to customers and charges. Proven Praise never asks for write access.
- In Settings, set the number of days after a payment before the request goes out. The default is 7 days.
- In Settings, write up to 3 questions for your customers.
- Proven Praise imports the charges from the last 90 days. The import does not send any email. To ask these customers, select Ask past customers.
- When a testimonial is ready, we send you an email. Open it in the dashboard. Look at the clips, the quote and the transcript. Select Approve or Reject.
- Go to Walls. Make a wall and add approved testimonials to it.
- Copy the embed code of the wall. Paste it into your website where you want the wall to show.
New payments create requests automatically on paid plans. Each customer gets one request only, even if they pay again.
Embed codes
Each embed code is one script tag. The widget renders in a shadow root, so your website styles do not change it.
Wall
Shows all testimonials on a wall.
<script src="https://provenpraise.com/embed.js" data-wall="WALL_ID" async></script>Single testimonial
Shows one testimonial as a card.
<script src="https://provenpraise.com/embed.js" data-testimonial="ID" async></script>Badge
Shows only the "Verified customer" badge for one testimonial. The badge links to the verification page.
<script src="https://provenpraise.com/embed.js" data-testimonial="ID" data-mode="badge" async></script>Choose where the widget shows
By default, the widget renders directly after the script tag. To render it in a different element, add data-target="#selector" with a CSS selector.
<div id="testimonials"></div>
<script src="https://provenpraise.com/embed.js" data-wall="WALL_ID" data-target="#testimonials" async></script>Replace WALL_ID and ID with the values from your dashboard. The widget data updates within 5 minutes of a change.
How verification works
When a customer sends a testimonial, Proven Praise makes a record that links it to the Stripe payment. Proven Praise signs the record with an Ed25519 private key. The record contains these fields:
{
"v": 1,
"testimonial_id": "uuid",
"business_slug": "acme",
"stripe_account": "acct_...",
"charge_id_hash": "sha256 of the Stripe charge ID",
"paid_on": "2026-10-01",
"amount_band": "$100-500",
"kind": "video",
"content_hash": "sha256 of the content",
"submitted_at": "2026-10-09T03:12:44Z"
}charge_id_hashis a SHA-256 hash of the Stripe charge ID. The record does not contain the charge ID.amount_bandis a range. The record does not contain the exact amount.content_hashis a SHA-256 hash of the raw video asset ID and the transcript, or of the text for a text testimonial.
The signature covers the canonical JSON of the record: keys sorted at every level, no spaces. Each verification page /v/ID checks the signature on the server and shows "Signature valid" or "Signature invalid".
Public keys
The public keys are at /.well-known/provenpraise-keys.json. Each key has a key ID, so we can rotate keys and old records stay valid.
{
"keys": [
{ "key_id": "KEY_ID", "alg": "Ed25519", "public_key_pem": "-----BEGIN PUBLIC KEY-----\n..." }
]
}Check a record yourself
On the verification page, open Check it yourself. Copy the record, the signature and the key ID into this Node.js script. Then run it.
// verify.mjs (Node.js 18 or later). Run: node verify.mjs
import { createPublicKey, verify } from "node:crypto";
// Copy these values from "Check it yourself" on the verification page /v/ID.
const record = { /* the record JSON */ };
const signature = "BASE64_SIGNATURE";
const keyId = "KEY_ID";
// Keys sorted at every level, no spaces.
function canonical(value) {
if (value === null || typeof value !== "object") return JSON.stringify(value);
if (Array.isArray(value)) return "[" + value.map(canonical).join(",") + "]";
const keys = Object.keys(value).sort();
return "{" + keys.map((k) => JSON.stringify(k) + ":" + canonical(value[k])).join(",") + "}";
}
const res = await fetch("https://provenpraise.com/.well-known/provenpraise-keys.json");
const { keys } = await res.json();
const key = keys.find((k) => k.key_id === keyId);
if (!key) throw new Error("Unknown key ID");
const publicKey = createPublicKey(key.public_key_pem);
const canonicalJson = canonical(record);
const ok = verify(null, Buffer.from(canonicalJson), publicKey, Buffer.from(signature, "base64"));
console.log(ok ? "Signature valid" : "Signature invalid");What customers see
- An email from "Your business via Proven Praise". It shows your questions, a link to record, our postal address and an unsubscribe link.
- If the customer does not open the link, one reminder follows 4 days later. No more emails after that.
- The link works for 21 days and for one testimonial only.
- The recorder page shows your business name and your questions. The customer records a video of up to 3 minutes, or writes a text instead. The customer can watch the video and record again.
- The customer enters a display name, an optional title and a rating. The customer chooses where you can use the testimonial: your website, social media or ads. Website permission is necessary to send.
The verification page shows the payment date, an amount range and "through Stripe". It never shows the customer's email, card, exact amount or charge ID. It also says that your business chose which testimonials to show.
How a customer removes a testimonial
- The customer selects Remove my testimonial on the verification page.
- The customer enters the email that they used to pay.
- If the email matches, Proven Praise sends a confirmation link to that email. The link works for 24 hours.
- The customer opens the link and confirms.
- Proven Praise marks the testimonial as withdrawn. It deletes the video files and removes the testimonial from all walls. You cannot show it again.
Read the privacy policy, the terms and the data processing agreement.