# Add a testimonial

URL: /systems/marketing/add-a-testimonial · Id: `guide:add-a-testimonial` · Status: `beta`

> Say "add a testimonial" and get a customer’s words on your page, shown with their name because they agreed to it.

Put a customer’s words where buyers decide. The quote shows only with the customer’s consent to display it.

Needs: [Put up a page](/start/guides/put-up-a-page)

**Before it runs**

- Who says yes: You. Your agent shows you the run and waits for your [Approval](/business/nouns/approval).
- You leave the chat: Never.
- What it costs: Nothing.
- To undo it: Withhold the Review. It leaves the page and stays on record.

## What you get
- 1 Review with the customer’s consent to show it (Review)
- 1 quote block on the page (Page)

## Your agent does
**For agents**

- Guide: `guide:add-a-testimonial`, status `beta`. Page: [/systems/marketing/add-a-testimonial.md](/systems/marketing/add-a-testimonial.md).
- Approval: ask the founder first. Show the run, then wait for their Approval; a refusal ends it.
- Leaves the chat: never.
- Needs first: [Put up a page](/start/guides/put-up-a-page).
- Run: call the steps in order, each through the API, SDK, CLI or MCP tab below; a later step passes the `$id` an earlier one returns. Each value marked example is the sample business’s: pass the founder’s own.

| Step | Verb | Inputs (type, required, this guide’s value) | Returns |
| --- | --- | --- | --- |
| 1 | [`Review.create`](/business/nouns/review/create) (`verb:Review.create`) | `rating` integer, required: example `5`; `body` text: example `"Leaseline caught three renewals we would have missed in the first month."`; `displayConsent` boolean: example `true` | `review` Review |
| 2 | [`Review.publish`](/business/nouns/review/publish) (`verb:Review.publish`) | `review` Review (an id), required: the `$id` step 1 returns | `review` Review |

Returns: the last call answers with `review` and its `action`, whose `status` is `done`, `pending` (waiting on an Approval or a Worker), `failed`, `canceled` or `refused`:

```json
{
  "api": "https://api.sb/leaseline.app",
  "review": {
    "$id": "https://api.sb/leaseline.app/reviews/review_1XPL2xTlfx",
    "$type": "Review",
    "rating": 5,
    "body": "Leaseline caught three renewals we would have missed in the first month.",
    "displayConsent": true,
    "status": "published"
  },
  "action": {
    "$id": "https://api.sb/leaseline.app/actions/act_br07HsG8MG",
    "operation": "Review.publish",
    "status": "done"
  },
  "links": {
    "self": "https://api.sb/leaseline.app/actions/act_br07HsG8MG"
  }
}
```

Next: offer “Put it on the pricing page instead”, or “Show the three newest five-star reviews”.

Calls: `Review.create` → `Review.publish`

Ask:

```text
Add a testimonial.
Put this customer quote on the homepage.
Show what customers say about us.
```

API:

```bash
# 1. Review.create
REVIEW=$(curl -X POST https://api.sb/leaseline.app/reviews \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"rating":5,"body":"Leaseline caught three renewals we would have missed in the first month.","displayConsent":true}' | jq -r '.review["$id"] | split("/") | last')

# 2. Review.publish
curl -X POST https://api.sb/leaseline.app/reviews/$REVIEW/publish \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
```

SDK:

```ts
import { $ } from 'startup-builder'

const review = await $.Review.create({ rating: 5, body: 'Leaseline caught three renewals we would have missed in the first month.', displayConsent: true })
await $.Review.publish({ review: review.$id })
```

CLI:

```bash
REVIEW=$(npx startup-builder do Review.create --json '{"rating":5,"body":"Leaseline caught three renewals we would have missed in the first month.","displayConsent":true}' | jq -r '.review["$id"] | split("/") | last')
npx startup-builder do Review.publish --json '{"review":"'"$REVIEW"'"}'
```

MCP:

```json
{
  "name": "do",
  "arguments": {
    "code": "const review = await $.Review.create({ rating: 5, body: 'Leaseline caught three renewals we would have missed in the first month.', displayConsent: true })\nreturn await $.Review.publish({ review: review.$id })"
  }
}
```

## Change it
- Put it on the pricing page instead.
- Show the three newest five-star reviews.
- Ask Riverside Property for a quote I can use.

## Under the hood
- Systems: [Reviews](/systems/reviews), [Sites](/products/site/sites)
- Nouns: [Review](/business/nouns/review), [Customer](/business/nouns/customer), [Page](/business/nouns/page)
- Events: [`Review.published`](/business/events/Review.published)

The quote is a [Review](/business/nouns/review) with `displayConsent` set, and [`Review.withhold`](/business/nouns/review/withhold) takes it down without deleting it.