# Trustpilot

Source: https://developers.swell.is/app-guides/trustpilot

The Trustpilot app asks your customers to review your store on Trustpilot after they order. When an order is fulfilled, paid or placed, whichever you choose, the app creates a Trustpilot email invitation for the customer, and Trustpilot sends it after the number of days you set.

Each order shows its invitation status and when the email goes out. Invitations can also ask customers to review the products they bought. Actions in the dashboard invite selected orders or orders placed before you set up the app, and send an invitation again from an order.

## How it works

| When | What the app does |
| --- | --- |
| An order reaches the step chosen in Send invitation when: fulfilled, paid or placed | Creates a Trustpilot email invitation for the customer, which Trustpilot sends after Days to wait, and saves the result on the order. |
| You choose Send Trustpilot invitation on an order | Creates an invitation that Trustpilot sends right away. |
| You select orders and click Send Trustpilot invitations | Invites the selected orders in the background. Trustpilot sends the emails right away. |
| You run Invite past orders | Invites the orders placed since a date that reached the Send invitation when step, in the background. Trustpilot sends the emails right away. |
| You run Test connection | Checks the API key and secret, shows your Trustpilot business, and lists your invitation templates. |

No invitations are sent while **Enabled** is off, or while the **API key**, **API secret** or **Business unit ID** is empty. In the test environment, orders are invited only while **Invite test orders** is on.

## Before you begin

- A Trustpilot plan with API access. The app uses Trustpilot's APIs, which need the API module add-on. Enterprise plans include it, and the free plan has no API access.
- An API application in Trustpilot Business, for its API key and secret. You create it in step 1.
- Your business unit ID, the ID of your Trustpilot business profile. **Test connection** can look it up when your storefront uses the domain on your Trustpilot profile.
- A customer email on each order. Orders without one aren't invited.
- For product reviews, Trustpilot product reviews on your plan, and SKUs on your products or variants.

## Set up

Install Trustpilot from the Swell App Store, and set it up in your test environment before the live one.

**1. Create an API application**

In Trustpilot Business, go to **Integrations > Developers > APIs**, create an application, give it a name, and click **Create application**. Under **Your applications**, expand the application and copy its API key and secret.

**2. Add them to the app**

In Swell, go to **Apps > Trustpilot > Settings**. Enter the **API key** and **API secret**, and the **Business unit ID** if you have it. **Enabled** is on by default. Click **Save settings**.

**3. Check the connection**

Choose **Actions > Test connection**. With **Business unit ID** empty, the app looks up your business on Trustpilot by your storefront's domain, and the message shows the ID it found, such as "Found Alder & Co. for alder.co. Business unit ID: …. Enter it in the settings and save." Enter the ID, click **Save settings**, and run **Test connection** again. The lookup doesn't check the API secret.

With the ID saved, the message names your business with its TrustScore and number of reviews, then checks the API secret and lists your invitation templates with their language and ID, such as "Connected to Alder & Co. TrustScore 4.6 from 1280 reviews. Templates: …". Errors show in a red error popup instead. See Troubleshooting below.

If the lookup doesn't find your business, for example because your storefront doesn't use the domain on your Trustpilot profile, enter the ID yourself. It's the `data-businessunit-id` value in the code of any TrustBox widget from Trustpilot Business.

**4. Choose when invitations go out**

On the **Invitations** tab, choose **Send invitation when** and **Days to wait**. To change the email, set **Sender name**, **Reply-to email**, **Language** and **Template ID**, using a template ID from the **Test connection** message. **Tags** and **Redirect URL** are optional.

To also ask for product reviews, turn on **Invite to product reviews** on the **Product reviews** tab. Click **Save settings**.

**5. Send a test invitation**

In the test environment, the app skips every order while **Invite test orders** is off, which is the default. With it on, the app sends invitations from the test environment the same way as from the live one, to the Trustpilot account whose API key you enter. Trustpilot emails the order's customer, and the invitation is a real one in your Trustpilot account. Test only with orders whose customer email is yours, and don't run **Invite past orders** or **Send Trustpilot invitations** on orders with your customers' emails.

To allow test invitations, turn on **Invite test orders** on the **Invitations** tab, and click **Save settings**.

Place a test order as a customer with your email. On the order page, choose **Actions > Send Trustpilot invitation**, and click **Send**. The message reads "Invitation sent to" with the email, and the order's **Trustpilot** tab shows **Invitation** `Sent`, **Sent to Trustpilot** and **Email goes out**. Trustpilot emails the invitation right away. The logs in Swell show `Trustpilot: invitation for order … sent to …`.

To check automatic invitations, set **Days to wait** to `0`, save, and take another test order to the **Send invitation when** step, such as fulfilling it with **Fulfill items**.

**6. Go live**

Settings are saved separately for each environment. In the live environment, repeat steps 2 to 4. You can use the same API application. From then on, the app invites each order that reaches the **Send invitation when** step.

To invite recent orders placed before that, run **Actions > Invite past orders**. See Inviting past orders below.

## Using Trustpilot

### When invitations are created

The app creates one invitation per order, when the order reaches the step in **Send invitation when**:

| Send invitation when | The invitation is created when |
| --- | --- |
| Order is fulfilled | All items on the order are fulfilled, or the order is marked fulfilled. This is the default. |
| Order is paid | The order is paid in full, or marked paid. |
| Order is placed | The order is placed, or a draft order is submitted. |

Only the step you choose creates invitations. A change to the setting applies to orders that reach the new step afterward: an order that was already paid when you switch to **Order is paid** isn't invited automatically. **Invite past orders** covers those orders.

The invitation goes to the order customer's email, with the billing name, or else the account or shipping name. Its reference number in Trustpilot is the Swell order number.

### Days to wait

The app hands the invitation to Trustpilot as soon as the order reaches the step. **Days to wait** sets how many days later Trustpilot emails the customer, from `0` to `90`. With `0`, Trustpilot sends it right away. When the field is cleared, the app waits the default `3` days. The order's **Email goes out** field shows when the email is scheduled. A product review invitation is scheduled one minute later, since Trustpilot requires the service review invitation to come first.

Invitations sent from an order, for selected orders, or with **Invite past orders** go out right away, without the delay.

### Orders that aren't invited

- Canceled orders and draft orders.
- Orders without a customer email.
- Orders in the test environment, while **Invite test orders** is off.
- Orders already invited, with the status `Sent` or `Not confirmed`. Only **Send Trustpilot invitation** with **Send again if this order was already invited** sends them a second invitation.
- Orders that reached the **Send invitation when** step before you set up the app, while **Enabled** was off, or while a connection setting was empty. They aren't invited later on their own. Use **Invite past orders** or **Send Trustpilot invitations**.

An order whose invitation failed isn't tried again on its own. Send it from the order, or include it in **Invite past orders** or **Send Trustpilot invitations**, which try failed orders again.

### Invitation status on orders

Each order gets a **Trustpilot** tab, and the orders list a **Trustpilot** column with the invitation's status.

| Field | What it shows |
| --- | --- |
| Invitation | Sent when Trustpilot accepted the invitation, Failed when Trustpilot rejected it, and Not confirmed when Trustpilot didn't answer. Empty when the app hasn't created an invitation for the order. |
| Sent to Trustpilot | When the app handed the invitation to Trustpilot. |
| Email goes out | When Trustpilot emails the customer. |
| Error | Trustpilot's reason for the last failed invitation, or the note for a Not confirmed one. |

### Not confirmed invitations

When Trustpilot doesn't answer the invitation request, because of a network error, a timeout or a Trustpilot server error, the app can't tell whether Trustpilot created the invitation. It marks the order `Not confirmed`, with a note in **Error** to check Trustpilot before sending again, and doesn't send it again, so the customer isn't emailed twice.

To resolve it, look in Trustpilot Business for an invitation with the order number as its reference number. If there's none, send the invitation again from the order with **Send again if this order was already invited** checked.

### Sending an invitation from an order

To send an invitation for one order, open the order, choose **Actions > Send Trustpilot invitation**, and click **Send**. Trustpilot emails the customer right away, without **Days to wait**. The message reads "Invitation sent to" with the customer's email, and the **Trustpilot** tab shows the new status.

When the invitation isn't sent, the reason shows in a red error popup. If the order was already invited, nothing is sent, and the popup says "This order was already invited on …. Tick "Send again" to send another invitation." To send another invitation, check **Send again if this order was already invited** and click **Send**. Each invitation sent again is a new invitation in Trustpilot. Orders with a `Failed` invitation are sent without the checkbox.

Save your changes to the order first: the action is unavailable while the order has unsaved changes.

### Inviting selected orders

To invite orders from the list, go to **Orders**, select the orders, and click **Send Trustpilot invitations** in the bar above the list. The modal shows how many orders are selected. Click **Send Trustpilot invitations** to start.

- The selected orders don't need to have reached the **Send invitation when** step.
- Canceled orders, drafts, orders without a customer email and orders already invited (`Sent` or `Not confirmed`) are skipped. Orders whose invitation failed are tried again.
- When you select all orders that match the list's search and filters, all of them are included, not only the ones on the page.

### Inviting past orders

To invite orders placed before you set up the app, go to **Apps > Trustpilot**, choose **Actions > Invite past orders**, pick a date in **Orders placed since**, and click **Send invitations**.

- Every order placed since that date that reached the **Send invitation when** step and wasn't invited yet is invited, with no limit on the number. Canceled orders, drafts and orders without a customer email are skipped. Orders whose invitation failed are tried again.
- Keep the date to the last few weeks: Trustpilot accepts invitations for recent purchases.
- Running it again is safe. Orders with the status `Sent` or `Not confirmed` are skipped.

### Background runs

**Send Trustpilot invitations** and **Invite past orders** run in the background:

- When the run has started, the message reads "Invitations started. Follow them in the Workflows tab of the Trustpilot app." No message shows when it finishes or fails. Runs are listed on the app's **Workflows** tab with their status, started by `App function`. Click a run to see its steps and error, or cancel it.
- Each click starts a new run, even while another run is going. Runs going at the same time can invite the same order twice, so start a run after the previous one has finished.
- In the test environment, a run skips every order while **Invite test orders** is off.
- Orders are invited 50 at a time, oldest first, 5 at once. Each order's status is saved on the order as it's sent.
- The settings are read again before each 50. If you turn off **Enabled** or clear a connection setting during a run, it finishes the 50 orders it's sending, then stops and fails with the totals until then.
- When the run finishes, the logs show the totals: sent, skipped, failed and not confirmed. When a group of 50 is tried again, the orders the run already invited count as sent. If Trustpilot rejected every invitation it was sent, the run fails, and each order's **Error** field has the reason.
- If **Enabled** is off or a connection setting is empty, the run doesn't send anything and fails with the reason.

### Product reviews

With **Invite to product reviews** on, the invitation also asks the customer to review the products they bought. Each order item with a SKU and a product name is added once per SKU, with the variant's SKU or else the product's, the product's name and brand, the first variant or product image, and a link to the product page. Orders with no such item get the service review invitation only.

The link uses **Product page URL**, with `{slug}` or `{id}` replaced by the product's slug or ID, such as `https://shop.example.com/products/{slug}`. When it's empty, the link is your storefront's URL followed by `/products/` and the product's slug.

The product review invitation uses **Product template ID**, or your default product review template when it's empty.

### In the dashboard

| Where | What it's for |
| --- | --- |
| Apps > Trustpilot > Settings | The API key and secret, Business unit ID, Enabled, and the Invitations and Product reviews tabs. |
| Apps > Trustpilot > Actions | Test connection and Invite past orders. Save the settings first: the actions are unavailable while there are unsaved changes. |
| Apps > Trustpilot > Workflows | The runs of Invite past orders and Send Trustpilot invitations, with their status. |
| Orders | The Trustpilot column with each order's invitation status, and Send Trustpilot invitations for the selected orders. |
| Orders, Trustpilot tab | The invitation's status, when it was sent to Trustpilot, when the email goes out, and any error. |
| Orders, Actions > Send Trustpilot invitation | Sends an invitation for the order right away, or sends it again. |
| Developer > Console > Logs | Each invitation the app sends or skips, the totals of each run, and each error. |

## Settings

Settings are in **Apps > Trustpilot > Settings** and are saved separately for each environment.

**API key**, **API secret**, **Business unit ID** and **Enabled** are at the top. The other settings are on the **Invitations** and **Product reviews** tabs.

| Setting | Description | Default |
| --- | --- | --- |
| API key | The API key of your application in Trustpilot Business > Integrations > Developers > APIs. Required. | None |
| API secret | The secret shown next to the API key. Required. | None |
| Business unit ID | Your Trustpilot business profile ID. Leave it empty and run Test connection to look it up by your storefront's domain. No invitations are sent without it. | None |
| Enabled | Turns off all invitations without uninstalling the app. Test connection still works while it's off. | On |
| Invitations > Send invitation when | When the invitation is created: Order is fulfilled, Order is paid or Order is placed. | Order is fulfilled |
| Invitations > Days to wait | How many days later Trustpilot sends the email, from 0 to 90. 0 sends it right away, and a cleared field uses 3. Applies to automatic invitations only. | 3 |
| Invitations > Sender name | The sender of the email. When it's empty, Trustpilot's default is used. | None |
| Invitations > Reply-to email | Where customer replies go. When it's empty, Trustpilot's default is used. | None |
| Invitations > Language | The locale of the email and review page, such as en-US, en-GB or de-DE. | en-US |
| Invitations > Template ID | The invitation template. When it's empty, the app uses your default template for the Language, else another default template, else a template for the Language. Test connection lists the template IDs. | None |
| Invitations > Invite test orders | Also sends invitations for orders in Swell's test environment. They go to the customer's real email. While it's off, the app skips every order in the test environment. It has no effect in the live environment. | Off |
| Invitations > Tags | Comma-separated tags added to service reviews, such as swell, webshop. | None |
| Invitations > Redirect URL | The page customers see after writing their review. When it's empty, Trustpilot's page is used. | None |
| Product reviews > Invite to product reviews | Adds a product review invitation for items with a SKU and a product name. | Off |
| Product reviews > Product template ID | The product review template. When it's empty, your default product review template is used. | None |
| Product reviews > Product page URL | The product link, with {slug} or {id}, such as https://shop.example.com/products/{slug}. When it's empty, your storefront's URL followed by /products/ and the slug. | None |

## Limitations

- The app sends email invitations only, one per order. A second invitation for the same order is sent only with **Send again if this order was already invited** on the order page.
- Data goes one way, from Swell to Trustpilot. Reviews, and changes made to invitations in Trustpilot, don't reach Swell.
- In the test environment, orders are invited only while **Invite test orders** is on. Those invitations are real ones in the Trustpilot account you connect, and Trustpilot emails the order's customer.
- An invitation isn't changed or withdrawn when its order is edited, canceled or refunded afterward. With a delay, the email can go out after the order is canceled.
- Orders that reached the **Send invitation when** step before you set up the app, while it was off, or before you changed the setting aren't invited on their own.
- **Days to wait** is 90 days at most, and applies to automatic invitations only.
- **Test connection** looks up your business unit by your storefront's domain only.
- Product reviews include only items with a SKU and a product name.
- If Trustpilot can't be reached, rate-limits the app or has a server error while the app gets an access token or your templates, or rate-limits an invitation, Swell runs the function again later, at growing intervals. If it keeps failing for about 4 days, Swell turns off the function and emails the store's admins. To turn it back on, update or reinstall the app.
- If Trustpilot doesn't answer the invitation request itself, the order is marked `Not confirmed` and the invitation isn't sent again. Other errors, such as a rejected API key, are logged, and the order isn't tried again on its own.

## Troubleshooting

**Test connection** and **Send Trustpilot invitation** show their errors in a red error popup in the dashboard. The background runs show theirs on the app's **Workflows** tab: click the run to see its error. The app also logs each invitation it sends or skips and each error. In the Swell dashboard, the logs are under **Developer > Console > Logs**.

### Orders aren't invited

Check that **Enabled** is on and that **API key**, **API secret** and **Business unit ID** are filled in, and click **Save settings**. When a connection setting is empty, the logs show "Trustpilot: missing" followed by the setting for each order that reaches the **Send invitation when** step. Then check that the order reached that step. In the test environment, also check that **Invite test orders** is on.

The logs show "Trustpilot: order … skipped," with the reason, such as "order is canceled", "order has no customer email", "test environment order (Invite test orders is off)" or "already invited". When Trustpilot refuses the access token, the logs show "Trustpilot: invitation for order … failed:" with Trustpilot's reason, and the order gets no status. Fix the cause with **Test connection**, then invite those orders with **Invite past orders**.

### An order's invitation shows Failed

Trustpilot rejected the invitation, and the order's **Error** field has its reason, such as an invalid customer email or template ID. Fix the cause, then choose **Actions > Send Trustpilot invitation** on the order.

### An order's invitation shows Not confirmed

Trustpilot didn't answer, and may have created the invitation. Look in Trustpilot Business for an invitation with the order number as its reference number. If there's none, send it again from the order with **Send again if this order was already invited** checked. See Not confirmed invitations above.

### The customer hasn't received the email

Check **Email goes out** on the order's **Trustpilot** tab. Trustpilot sends the email at that time, **Days to wait** after the invitation was created.

### "Add your Trustpilot API key and secret and save the settings first."

**Test connection** checks the saved settings. Enter the key and secret and click **Save settings** before you test.

### "No Trustpilot business unit found for …"

Trustpilot has no business profile for your storefront's domain. Enter the **Business unit ID** yourself: it's the `data-businessunit-id` value in the code of a TrustBox widget from Trustpilot Business. "Enter your Business unit ID, then save the settings." alone means your store has no storefront URL to look up.

### "Business unit … was not found in Trustpilot. Check the ID."

Check the **Business unit ID** for typos, or clear it and run **Test connection** to look it up.

### "Trustpilot rejected the API key or secret …"

Copy the API key and secret again from **Integrations > Developers > APIs** in Trustpilot Business, paste them, click **Save settings**, and test again. Also check that your Trustpilot plan includes the API module. The free plan has no API access.

### "Trustpilot request failed, try again later: …"

Trustpilot couldn't be reached, rate-limited the app or had a server error. The reason follows the message. Try again in a minute.

### "Trustpilot request failed: …"

Trustpilot answered with another error, and its reason follows the message.

### "No invitation templates found."

**Test connection** found no invitation templates for your business unit. Without a **Template ID**, the app sends invitations without a template ID. Check your templates in Trustpilot Business.

### "Trustpilot did not accept the invitation: …"

Trustpilot rejected the invitation from the order page, and its reason follows the message. The order shows `Failed` with the same reason in **Error**.

### "Trustpilot didn't confirm …"

Trustpilot didn't answer the invitation request, or didn't answer the last one for this order. Look for the invitation in Trustpilot Business before you send again with **Send again if this order was already invited**.

### "Not sent: …"

The order can't be invited, and the reason follows the message: "order is canceled", "order is a draft", "order has no customer email" or "test environment order (Invite test orders is off)". For the last one, turn on **Invite test orders**, click **Save settings**, and send it again.

### "The Trustpilot app is turned off in its settings."

Turn on **Enabled**, click **Save settings**, and try again. "Add the … in Apps → Trustpilot first." means a connection setting is empty.

### "Invitations not sent: …"

The run didn't send anything, because **Enabled** is off or a connection setting is empty, and the message says which. Fix the setting, click **Save settings**, and run it again.

### "Invitations stopped: …"

**Enabled** was turned off or a connection setting was cleared during the run. The message gives the reason and the totals until then. Fix the setting and run it again. Orders already invited are skipped.

### "Invitations failed on page …"

Trustpilot refused the access token or the templates, for example because of a rejected API key or a wrong **Business unit ID**. The message explains the cause and gives the totals until then. Fix it with **Test connection** and run it again.

On temporary errors, such as when Trustpilot can't be reached, rate-limits the app or has a server error, each group of 50 orders is tried up to 5 more times before the run fails. Open the run on the **Workflows** tab to see the step that failed.

### "Invitations finished, but Trustpilot rejected all …"

Trustpilot rejected every invitation the run sent. Each order's **Error** field has the reason. A wrong **Business unit ID** or **Template ID** rejects them all.

### Product links are missing

Without **Product page URL**, the link is your storefront's URL with `/products/` and the slug, so products without a slug get no link. With it, a product gets no link when it has no value for the placeholder. Set **Product page URL** to match your storefront's product pages.

### An action is unavailable

Save the settings or the order first.

## Uninstalling

Uninstalling the app stops new invitations. It removes the app's functions and settings, including the API key and secret, the **Trustpilot** tab and column on orders, and the **Test connection**, **Invite past orders**, **Send Trustpilot invitation** and **Send Trustpilot invitations** actions. Uninstalling applies to the environment you are in, so remove the app from the test and live environments separately.

The invitation values saved on orders are kept, and show again if you reinstall. Invitations already handed to Trustpilot stay there, including ones scheduled for a later date, and Trustpilot still sends them. The app doesn't cancel them.

The app isn't notified when it's uninstalled. If you no longer need the API application, remove it in Trustpilot Business under **Integrations > Developers > APIs**. To pause invitations without uninstalling, turn off **Enabled**.

## For developers

| Function | Runs on | What it does |
| --- | --- | --- |
| order-invitations | order.submitted, order.paid and order.delivered | Acts only on the event that matches invite_on while enabled is true, and checks the other settings after that, so a missing setting is logged once per order. Reads the order with account, items.product and items.variant, skips canceled, draft, email-less, test environment and already invited orders before getting a token, and creates the invitation with delay_days. |
| send-invitation | The Send Trustpilot invitation action on an order | Reads the order from the action's record_id and creates the invitation with no delay. With send_again true, it sends even when the order was already invited. Returns the message when the invitation is sent, and throws a SwellError with status 400 for every other outcome, which the dashboard shows as a red error popup. |
| start-invitations | The Invite past orders action and the Send Trustpilot invitations bulk action | Starts invite-orders with workflows.create, passing env, store_url, and either since from the modal or, for the bulk action, its selection query as query. Returns "Invitations started. Follow them in the Workflows tab of the Trustpilot app." |
| invite-orders | Runs started by start-invitations | A workflow. Reads orders 50 at a time in id order, one step per page, 5 invitations at once, each step retried up to 5 times with exponential backoff from 30 seconds. |
| test-connection | The Test connection action | Reads the business unit, or looks it up by the storefront's domain, then gets a token and lists the templates. Returns the result as the message, and throws a SwellError with status 400 for missing credentials, rejected credentials, an unknown or missing business unit and failed requests. |

The app adds `trustpilot_status` (`sent`, `failed` or `unconfirmed`), `trustpilot_sent_at`, `trustpilot_send_time` and `trustpilot_error` to orders, under `$app.trustpilot`. Settings are read from `trustpilot` in the app settings, with defaults for values not saved yet. `delay_days` is rounded down and capped at 90, and an empty value (`null` or `""`) uses the default `3`. `tags` is split on commas. `order-invitations`, `send-invitation` and `invite-orders` stop when `enabled` is `false`, or when `api_key`, `api_secret` or `business_unit_id` is empty.

The environment is the function's `Swell-Env` header, `test` in the test environment. With `test` and `invite_test_orders` `false`, every order is skipped with `test environment order (Invite test orders is off)`. `order.test`, which marks test payments, isn't checked.

Each function run and each workflow page gets a new access token with the client credentials grant. The token isn't stored, and Trustpilot doesn't issue refresh tokens for this grant. The calls:

- `POST https://api.trustpilot.com/v1/oauth/oauth-business-users-for-applications/accesstoken` with HTTP Basic auth of the API key and secret and `grant_type=client_credentials`.
- `GET https://invitations-api.trustpilot.com/v1/private/business-units/{id}/templates` with the bearer token, only when `service_template_id` is empty, or `product_reviews` is on and `product_template_id` is empty. Of the templates of the right kind (a `type` containing `product` for product templates), the app picks the default one for `locale`, else any default one, else one for `locale`. With no match, `templateId` is left out.
- `POST https://invitations-api.trustpilot.com/v1/private/business-units/{id}/email-invitations` with the bearer token.
- `GET https://api.trustpilot.com/v1/business-units/{id}` and `GET https://api.trustpilot.com/v1/business-units/find?name={domain}` with the `apikey` header, for Test connection. The domain is the hostname of `req.store.url`, the primary storefront's URL, without `www.`.

An invitation request looks like this. Empty settings are left out, and `preferredSendTime` is left out when the delay is 0. The product review invitation's `preferredSendTime` is one minute after the service review invitation's, since Trustpilot requires the service review invitation to come first:

```json
{
  "consumerEmail": "maya.patel@example.com",
  "consumerName": "Maya Patel",
  "referenceNumber": "100238",
  "locale": "en-US",
  "senderName": "Alder & Co.",
  "replyTo": "hello@alder.co",
  "type": "email",
  "serviceReviewInvitation": {
    "templateId": "507f191e810c19729de860ea",
    "preferredSendTime": "2026-10-15T14:12:00.000Z",
    "redirectUri": "https://alder.co/thank-you",
    "tags": ["swell", "webshop"]
  },
  "productReviewInvitation": {
    "templateId": "507f191e810c19729de860eb",
    "preferredSendTime": "2026-10-15T14:13:00.000Z",
    "redirectUri": "https://alder.co/thank-you",
    "products": [{
      "sku": "LAMP-OAK",
      "name": "Oak Desk Lamp",
      "imageUrl": "https://cdn.schema.io/alder/lamp.jpg",
      "productUrl": "https://alder.co/products/oak-desk-lamp"
    }]
  }
}
```

The invitation request has no idempotency key, so the order's `trustpilot_status` keeps an order from being invited twice. `sent` and `unconfirmed` orders are skipped by later events and runs unless `send_again` is `true`. On the invitation request, a 429 is rethrown, since Trustpilot created nothing: Swell retries the function, and the workflow retries the page, skipping orders invited before. Skipped orders with `trustpilot_status` `sent` and a `trustpilot_sent_at` after the run's start count as `sent`. A network error, timeout or 5xx is saved as `unconfirmed` and not retried. Any other error is saved as `failed` with Trustpilot's message. If saving the status fails, the error is logged and not thrown, so the invitation isn't sent again by a retry; the order shows no status, and a later run can invite it.

In `order-invitations`, network errors, 429 and 5xx on the token or templates are rethrown, so Swell retries the function. Other errors are logged with `console.error` and the refused call, such as `(POST /v1/oauth/oauth-business-users-for-applications/accesstoken)`, and the function succeeds.

Workflow requests have no headers and no `store.url`, so `start-invitations` passes `env` (from `Swell-Env`), `store_url` (`req.store.url`) and the orders to invite: `query` for a bulk run (`$action.source` is `bulk`), from `$action.selection.query`, or else `since`. `invite-orders` reads them only when `workflow.trigger` is `function`, and uses `query` as is. Otherwise the query is an `$and` of the state filter (`delivered: true`, `paid: true` or `draft: {$ne: true}`), `canceled: {$ne: true}` and `date_created: {$gte: since}`, with `since` from the modal, or 30 days ago when it isn't a date. Pages are sorted `id asc` with an `id` `$gt` cursor appended to `$and`. Permanent Trustpilot errors on the token or templates are returned instead of thrown, so the run fails right away. The step `load settings` returns only `enabled`, the names of missing settings, `invite_on` and the run's start time `started_at`, so the run's step output never holds the API key, secret or a token. The workflow returns `sent`, `skipped`, `failed` and `unconfirmed`, and throws with `Invitations not sent: …` or `Invitations stopped: …` when the app is off or a connection setting is empty.

## Support

Swell builds and maintains the Trustpilot app. For help with the app, email support@swell.is. For questions about your Trustpilot account, plan, invitation templates or reviews, contact Trustpilot.
