Customer Testimonials
The seven endpoints that add, approve and remove the testimonials shown on the site.
Overview
Testimonials are the reference texts shown on the site. Each carries a status: pending, approved or rejected. Only the approved ones appear on the site.
The text is kept per language, while the name, company and avatar are shared. What a visitor submits starts as pending and stays off the site until an administrator approves it.
These endpoints also let you add a testimonial through the panel: a reference that arrived on paper or by e-mail can be typed in and created approved outright.
Reference
Listing the Testimonials
Returns the customer testimonials on the site.
pending, approved, rejected.curl 'https://panel.example.com/api/v1/admin/website/cfeedbacks' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/website/cfeedbacks', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const { data } = await res.json();
const waiting = data.filter((f) => f.status === 'pending');$ch = curl_init('https://panel.example.com/api/v1/admin/website/cfeedbacks');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// There is NO status filter; sift the list yourself to find what waits for a decision.
$all = Api::Website()->GetCfeedbacks()['data'];
$waiting = array_filter($all, fn ($f) => $f['status'] === 'pending');Reading One Testimonial
Returns one testimonial with its text and avatar.
pending, approved, rejected.curl 'https://panel.example.com/api/v1/admin/website/cfeedbacks/4' \
-H "Authorization: Bearer $API_KEY"const res = await fetch(`https://panel.example.com/api/v1/admin/website/cfeedbacks/${id}`, {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/website/cfeedbacks/' . $id);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The TEXT and the sending ADDRESS come back only here; the list carries neither.
$fb = Api::Website()->GetCfeedback(['id' => $id])['data'];
$en = $fb['languages']['en']['message'] ?? '';Creating a Testimonial
Adds a customer testimonial through the panel.
pending, approved, rejected. Pending by default.curl -X POST 'https://panel.example.com/api/v1/admin/website/cfeedbacks' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"full_name":"Ayse Yilmaz","status":"approved","languages":{"tr":{"message":"Harika hizmet!"}}}'const res = await fetch('https://panel.example.com/api/v1/admin/website/cfeedbacks', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
full_name: 'John Doe',
company_name: 'Example Inc.',
status: 'approved',
languages: { en: { message: 'Great service!' } },
}),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/website/cfeedbacks');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'full_name' => 'John Doe',
'status' => 'approved',
'languages' => ['en' => ['message' => 'Great service!']],
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Leave the status out and it is born PENDING, unseen on the site; approve it as well.
Api::Website()->CreateCfeedback([
'full_name' => 'John Doe',
'status' => 'approved',
'languages' => ['en' => ['message' => 'Great service!']],
]);Updating a Testimonial
Changes a testimonial's status, text and details.
pending, approved, rejected. Pending by default.curl -X PATCH 'https://panel.example.com/api/v1/admin/website/cfeedbacks/4' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"status":"approved"}'const res = await fetch(`https://panel.example.com/api/v1/admin/website/cfeedbacks/${id}`, {
method: 'PATCH',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ status: 'approved' }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/website/cfeedbacks/' . $id);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['status' => 'approved']),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Approval is a STATUS change rather than a switch; it is the one thing that publishes.
Api::Website()->UpdateCfeedback(['id' => $id, 'status' => 'approved']);Deleting a Testimonial
Removes a testimonial.
curl -X DELETE 'https://panel.example.com/api/v1/admin/website/cfeedbacks/4' \
-H "Authorization: Bearer $API_KEY"const res = await fetch(`https://panel.example.com/api/v1/admin/website/cfeedbacks/${id}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/website/cfeedbacks/' . $id);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Rather than delete, REJECT it: the record stays off the site while the words survive.
Api::Website()->UpdateCfeedback(['id' => $id, 'status' => 'rejected']);Uploading the Avatar
Uploads the avatar shown beside a testimonial.
curl -X PUT 'https://panel.example.com/api/v1/admin/website/cfeedbacks/4/picture' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"image":"https://ornek.com/avatar.jpg"}'const res = await fetch(`https://panel.example.com/api/v1/admin/website/cfeedbacks/${id}/picture`, {
method: 'PUT',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ image: 'https://example.com/avatar.jpg' }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/website/cfeedbacks/' . $id . '/picture');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['image' => 'https://example.com/avatar.jpg']),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The avatar is NOT required; without one the theme puts its own placeholder there.
Api::Website()->SetCfeedbackPicture(['id' => $id, 'image' => $data]);Removing the Avatar
Removes a testimonial's avatar.
curl -X DELETE 'https://panel.example.com/api/v1/admin/website/cfeedbacks/4/picture' \
-H "Authorization: Bearer $API_KEY"const res = await fetch(`https://panel.example.com/api/v1/admin/website/cfeedbacks/${id}/picture`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/website/cfeedbacks/' . $id . '/picture');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// To REPLACE the avatar there is no need to delete first; the upload takes its place.
Api::Website()->DeleteCfeedbackPicture(['id' => $id]);Pitfalls
Leave the status field out and the testimonial is created pending, unseen on the site. For a reference typed in through the panel that is rarely what you want, so send the status approved at creation or update it straight after. For what a visitor submits, pending is the right start.
The listing takes only a search term, a page and a page size, and offers no status filter. Finding what waits for approval means pulling the list and sifting it yourself. On an installation with many testimonials, plan for walking the pages and sifting each one.
The list gives the name, company, e-mail and status, yet not the testimonial itself. Deciding what to approve means reading each record from the detail endpoint. Weigh that when writing an approval flow: the list alone cannot carry the decision.
A testimonial record carries the sender's e-mail and the address it came from. Neither is shown on the site, yet both can be read from the detail endpoint. That is personal data, so take care not to carry these two fields along when writing an integration that moves testimonials elsewhere.
A rejected testimonial stays off the site while the record remains: who wrote what, when, and what was decided all stay readable. Deleting takes all of that, and if the same person writes again you have no history to look at.
Related Articles
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.