# Set up review prompts and Discord announcements

> Point the review prompt at your Trustpilot page, see how review invitations are doing, and post announcements to a Discord channel through a webhook.

Source: https://www.coritan.com/docs/organizations/reviews-and-announcements/

In the dashboard:

- /dashboard/organizations/…/settings/reviews: https://www.coritan.com/dashboard/organizations

Two small tools let you talk to your customers where they already are. The *review prompt* asks a customer to leave a review on your Trustpilot page. An *announcement* is a message your team posts to a Discord channel through a webhook.

Your team manages both in the staff console, under Marketing. The owner and scripts use the API, which this page describes.

## Before you begin

- You need the Admin or Owner role in the organization. Billing, support and read-only members cannot read or change these settings.
- For reviews, you need your Trustpilot review link. It starts with `https://` and is on `trustpilot.com`.
- For announcements, you need a Discord webhook. In Discord, open the channel's settings, then Integrations, then Webhooks, make a webhook and copy its address. It starts with `https://discord.com/api/webhooks/`.

## Set it up in your dashboard

Owners and admins use the page in the dashboard. Your team can do the same in the staff console, as [Marketing audience in the staff console](/docs/organizations/staff-console/marketing-audience/) describes. A member with another role does not see the page, and its address opens **Overview**.

1. In the [dashboard](https://www.coritan.com/dashboard/organizations), open the organization, then **Settings**, then **Reviews and announcements**.
2. Under **Reviews**, turn on **Ask customers for a review**, paste your "Trustpilot review link" and set "Days old an account is before we ask" and "Days we stay quiet after a customer closes the prompt". Select **Save changes**. The page says "The review prompt turned on." when the switch was the only change, and "Review settings saved." otherwise. A link the API refuses, or a switch turned on with no link, shows its sentence under "Trustpilot review link".
3. Read **Review invitation email** on the same card. It says whether the invitation flow is on and counts its emails as **Scheduled**, **Sent**, **Skipped** and **Failed**, with **Last sent**. Turn the flow on or off in **Email flows**, which the card links to.
4. Under **Discord webhook**, paste the "Discord webhook address", add a "Channel name" if you like, and select **Save changes**. The card then shows **Saved** with the last four characters of the webhook's ID, and never the address. **Replace** opens the field for a new address. **Remove** is staged until you select **Save changes**, and **Keep it** undoes it. The channel name is for your team and is not sent to Discord.
5. Under **Post an announcement**, fill in "Title" (optional), "Message" and "Link" (optional). The page counts the message against 1,800 characters. Select **Post announcement…**, check the text and the channel in the question, and select **Post announcement**.

When it works, the page says "Announcement posted." and the post appears under **Announcements posted** with the channel, who posted it and when. The list holds the last 20 posts, and a post that Discord did not take shows as **Failed** with its reason.

Posting needs a saved webhook, so the button stays off until you save one. You can post 10 an hour, and the page shows the API's sentence and how long to wait when you pass that. When Discord does not take a message, the card says **Discord did not take the message** and gives the reason in a sentence, and nothing was posted.

## Set up the review prompt

The review prompt asks a signed-in customer on your storefront to leave a review. It waits until the customer's account is old enough, and after a customer closes it, it stays quiet for a while in that browser. It shows only while it is on and has a link.

`GET /reviews` reads the settings and `PUT /reviews` changes them. Send only what changes.

| Setting | What it does |
| --- | --- |
| `enabled` | Turns the prompt on or off. It cannot be on without `review_url`. |
| `review_url` | Your Trustpilot review link. It must be `https` and on `trustpilot.com`, at most 500 characters. A link typed without `https://` gets it. Null or an empty string removes the link. |
| `min_account_age_days` | How many days old an account is before the prompt asks, 0 to 365. The default is 1. |
| `dismiss_days` | How many days the prompt stays quiet after a customer closes it, 1 to 365. The default is 30. |

```bash title="Turn the review prompt on"
curl -X PUT "https://api.coritan.com/api/v1/orgs/acme/reviews" \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled": true, "review_url": "https://www.trustpilot.com/evaluate/example.com", "min_account_age_days": 7}'
```

```json
{
  "enabled": true,
  "review_url": "https://www.trustpilot.com/evaluate/example.com",
  "min_account_age_days": 7,
  "dismiss_days": 30,
  "invitations": {
    "enabled": false, "scheduled": 0, "sent": 0, "skipped": 0, "failed": 0, "last_sent_at": null
  },
  "changed": ["enabled", "review_url", "min_account_age_days"]
}
```

`changed` lists the settings that differ from before. Saving what is already saved changes nothing and writes no audit entry. A value that does not fit answers `422` with `detail`, the sentence to show, and `field`, the setting it belongs to. The storefront applies a change to new page loads within a minute.

### Review invitations

The review invitation is an email to a customer some time after their first paid order, sent by one of your email flows. It uses the same review link, and it is sent only while `enabled` is on and the link is set. `invitations` in the answer shows how it is doing:

`enabled`
: Whether the review invitation flow is switched on.

`scheduled`, `sent`, `skipped` and `failed`
: How many invitation emails are in each state. All four are 0 until the flow has run.

`last_sent_at`
: When an invitation email last went out, or `null`.

## Set up announcements

Save your Discord webhook once. Your team can then post a message to its channel from the staff console, and a script can post through the API.

`PUT /announcements` saves the webhook:

| Setting | What it does |
| --- | --- |
| `webhook_url` | The Discord webhook address. It must be an `https` address on Discord's own hosts that starts with `https://discord.com/api/webhooks/`. Null or an empty string removes it. Left out, the saved one stays. |
| `channel_label` | A name for the channel, such as `#announcements`, at most 80 characters. Null or an empty string removes it. |

The webhook address is a secret. We seal it, never show it again, and never write it to the audit log. `GET /announcements` answers `{configured, channel_label, webhook_hint}`. `webhook_hint` is the last four characters of the webhook's ID, so you can tell which webhook is saved:

```json
{ "configured": true, "channel_label": "#announcements", "webhook_hint": "3456" }
```

An address that is not a Discord webhook answers `422` with `field` `webhook_url`. To replace the webhook, save a new address. Removing it stops announcements until you save another.

### Post a message

`POST /announcements/post` sends one message to the saved webhook.

```bash title="Post an announcement"
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/announcements/post" \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title": "Servers are back", "content": "The maintenance is over. Thank you for waiting.", "link": "https://status.example.com"}'
```

| Field | What it holds |
| --- | --- |
| `content` | The message, 1 to 1,800 characters. Discord's own formatting works in it. Required. |
| `title` | A bold first line, at most 120 characters. Optional. |
| `link` | A link added after the message. It starts with `https://`, at most 500 characters. Optional. |

The title, the text and the link make one message, and together they must fit Discord's 2,000 characters, or the answer is `422`. Nothing in the message can mention a role or a person: `@everyone` and `@here` show as plain text and ping nobody.

A post answers one of these:

`200` with `{"posted": true}`
: Discord took the message.

`409`
: No webhook is saved. Save one first.

`422`
: The message does not fit. `field` names the part to change.

`429`
: The organization has posted 10 messages in the last hour. Wait and try again. The limit counts every attempt for the organization, whoever posts.

`502`
: Discord did not take the message, and `detail` says why in a sentence, such as that the webhook no longer works. Nothing was posted. We never show what Discord answered.

### Read what was posted

`GET /announcements/history` lists the announcements newest first. It takes `limit`, 1 to 100 and 20 by default. Each entry has `status` (`posted` or `failed`), the `title`, `content` and `link` that were sent, the `channel_label` saved then, `error` (why a failed post failed), `actor_type` (`staff`, `user` or `admin` for Coritan staff), `actor` (`{id, name}` or `null`) and `created_at`.

## Result

For reviews, the answer shows your settings and `changed` names what you changed. For announcements, a post answers `{"posted": true}` and the message appears in your Discord channel. Every change and every post is in the [audit log](/docs/organizations/audit-log/):

| Entry | What it records |
| --- | --- |
| `reviews.updated` | The settings that changed and their new values. |
| `announcements.updated` | The settings that changed, and whether the webhook was set, replaced or removed. Never the address. |
| `announcement.posted` | The title, text, link and channel label of a message Discord took. |
| `announcement.failed` | The same, and `error`, for a message Discord did not take. |

## Troubleshooting

`422` with `field` `review_url`
: The link must start with `https://` and be on `trustpilot.com`. A link on another site is refused. The prompt also cannot be on without a link, and a link cannot be removed while it is on.

`422` with `field` `webhook_url`
: Copy the webhook address again from Discord. It starts with `https://discord.com/api/webhooks/`, then a number and a token.

`502` and the sentence says the webhook no longer works
: The webhook was deleted in Discord, or its channel was. Make a new webhook and save its address.

`429` on a post
: Ten posts an hour is the limit for the organization. The history shows what was already posted.

The prompt does not appear
: It needs `enabled` and a link. A customer sees it only after their account is `min_account_age_days` old, and not for `dismiss_days` after they close it.

## With the API

The staff console's routes under `/api/v1/orgs/{org_slug}/staff/marketing/reviews` and `/api/v1/orgs/{org_slug}/staff/marketing/announcements` answer the same, for the Admin and Owner roles, and platform staff have the same routes for any organization in the admin console. All of them need an access token, sent as `Authorization: Bearer $CORITAN_TOKEN`.

| Operation | What it does |
| --- | --- |
| `GET /reviews` | The review settings and the invitation figures. |
| `PUT /reviews` | Change the review settings. |
| `GET /announcements` | Whether a webhook is saved, its channel label and its hint. |
| `PUT /announcements` | Save, replace or remove the webhook, and set the channel label. |
| `POST /announcements/post` | Post a message to the webhook. |
| `GET /announcements/history` | The messages posted or refused, newest first. |

## Related

- [Read the organization audit log](/docs/organizations/audit-log/)
- [How customers and orders are attributed](/docs/organizations/attribution/)
- [Connect a Discord server](/docs/organizations/integrations/discord/)

## Next steps

- [Make campaign links](/docs/organizations/campaigns/) to announce a launch with a link you can measure.
- [Connect a Discord server](/docs/organizations/integrations/discord/) to link your community's server to your organization.

## API

- `GET /api/v1/orgs/{org_slug}/reviews`: Read the Trustpilot review settings and how the invitations are doing (https://www.coritan.com/docs/api/reference/organizations/organizations-members/reviews/#op-get-api-v1-orgs-org-slug-reviews)
- `PUT /api/v1/orgs/{org_slug}/reviews`: Change the Trustpilot review settings (https://www.coritan.com/docs/api/reference/organizations/organizations-members/reviews/#op-put-api-v1-orgs-org-slug-reviews)
- `GET /api/v1/orgs/{org_slug}/announcements`: Read the Discord webhook settings for announcements (https://www.coritan.com/docs/api/reference/organizations/organizations-members/announcements/#op-get-api-v1-orgs-org-slug-announcements)
- `PUT /api/v1/orgs/{org_slug}/announcements`: Save or remove the Discord webhook for announcements (https://www.coritan.com/docs/api/reference/organizations/organizations-members/announcements/#op-put-api-v1-orgs-org-slug-announcements)
- `POST /api/v1/orgs/{org_slug}/announcements/post`: Post an announcement to Discord (https://www.coritan.com/docs/api/reference/organizations/organizations-members/announcements/#op-post-api-v1-orgs-org-slug-announcements-post)
- `GET /api/v1/orgs/{org_slug}/announcements/history`: Read the announcements that were posted (https://www.coritan.com/docs/api/reference/organizations/organizations-members/announcements/#op-get-api-v1-orgs-org-slug-announcements-history)
- `GET /api/v1/orgs/{org_slug}/staff/marketing/reviews`: Read the Trustpilot review settings and how the invitations are doing (https://www.coritan.com/docs/api/reference/organizations/org-staff-marketing/staff/#op-get-api-v1-orgs-org-slug-staff-marketing-reviews)
- `PUT /api/v1/orgs/{org_slug}/staff/marketing/reviews`: Change the Trustpilot review settings (https://www.coritan.com/docs/api/reference/organizations/org-staff-marketing/staff/#op-put-api-v1-orgs-org-slug-staff-marketing-reviews)
- `GET /api/v1/orgs/{org_slug}/staff/marketing/announcements`: Read the Discord webhook settings for announcements (https://www.coritan.com/docs/api/reference/organizations/org-staff-marketing/staff/#op-get-api-v1-orgs-org-slug-staff-marketing-announcements)
- `PUT /api/v1/orgs/{org_slug}/staff/marketing/announcements`: Save or remove the Discord webhook for announcements (https://www.coritan.com/docs/api/reference/organizations/org-staff-marketing/staff/#op-put-api-v1-orgs-org-slug-staff-marketing-announcements)
- `POST /api/v1/orgs/{org_slug}/staff/marketing/announcements/post`: Post an announcement to Discord (https://www.coritan.com/docs/api/reference/organizations/org-staff-marketing/staff/#op-post-api-v1-orgs-org-slug-staff-marketing-announcements-post)
- `GET /api/v1/orgs/{org_slug}/staff/marketing/announcements/history`: Read the announcements that were posted (https://www.coritan.com/docs/api/reference/organizations/org-staff-marketing/staff/#op-get-api-v1-orgs-org-slug-staff-marketing-announcements-history)
