# Webhooks

Send testimonial events to your own app or automation tool. How project and form webhooks differ, how delivery and retries work, and which plans have them.

A webhook sends a message to a web address you choose whenever something happens to a testimonial: a customer submits one, you approve it, edit it, archive it or delete it. Point it at your own server, or at an automation tool that accepts webhooks such as Zapier, Make or n8n, to add new testimonials to your CRM, post them in a team channel or keep another system up to date. ReTestimonial has no built-in connection to a CRM or a chat tool, such as HubSpot, Salesforce or Slack: a webhook is how you connect one.

Each message is an HTTPS `POST` request with a JSON body that describes the event and the testimonial. It's signed with a secret that only you and ReTestimonial know, so your receiver can check where it came from.

## Project webhooks and form webhooks

There are two kinds. Both send the same kind of request, signed the same way.

|                                  | Project webhooks                                                                                                                                                 | Form webhooks                                                                                        |
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| Set up in                        | Project settings, **Developer** tab, **Webhooks**                                                                                                                | The form builder, **Notifications** tab, **Webhook**                                                 |
| What they send                   | The events you choose, for the project's testimonials (what an import or a review sync does by itself only with **Include bulk imports and review sync events**) | `testimonial.submitted`, for that form's submissions only                                            |
| How many                         | Up to your plan's limit per project                                                                                                                              | One per form, on top of that limit                                                                   |
| Delivery log, retries and replay | **Developer** tab                                                                                                                                                | **Developer** tab (the form's webhook is listed there too, named **Form:** and the form's name) |

Use a **project webhook** to follow the project's testimonials and what happens to them afterwards, whatever their source: forms, the ones you add yourself, file imports and review platforms. Only what an import or a review sync does by itself (bringing testimonials in, updating them, being undone) waits for **Include bulk imports and review sync events** on the endpoint; approving, editing, archiving or deleting an imported testimonial yourself is sent without it (see [Imported testimonials](#imported-testimonials)). Use a **form webhook** when one form should feed one place, such as a form whose answers go to your CRM. A project webhook can also subscribe to `testimonial.submitted` to receive the submissions of every form in the project.

## Events

| Event                   | Sent when                                                                                                                                                                                                                                                                                                                                         |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `testimonial.created`   | A new testimonial arrives, from any source.                                                                                                                                                                                                                                                                                                       |
| `testimonial.submitted` | A customer submits a form. It carries the form and their answers; the same submission also sends `testimonial.created`.                                                                                                                                                                                                                           |
| `testimonial.approved`  | A testimonial becomes approved, including one that arrives already approved.                                                                                                                                                                                                                                                                      |
| `testimonial.updated`   | Anything else changes: an edit, a tag, a custom field value, a video that finished processing, moving it back to pending or out of the archive, or marking it as not spam. (A form submission that went straight to **Spam** sends nothing until you restore it; it then sends `testimonial.created` and `testimonial.submitted`, as on arrival.) |
| `testimonial.archived`  | You archive or reject a testimonial (rejecting archives it).                                                                                                                                                                                                                                                                                      |
| `testimonial.spam`      | A testimonial is marked as spam.                                                                                                                                                                                                                                                                                                                  |
| `testimonial.deleted`   | A testimonial is deleted.                                                                                                                                                                                                                                                                                                                         |

### Imported testimonials

**What you do with an imported testimonial is always sent.** Approving, editing, archiving or deleting one sends its event like any other testimonial's, to every endpoint that has that event ticked. **Include bulk imports and review sync events** has no effect on this: it never holds back something you do by hand. If approving an imported review sends nothing, the endpoint doesn't have `testimonial.approved` ticked.

**The setting is only about what an import or a review sync does by itself.** While it's off, as it is on a new endpoint, the endpoint isn't told when a file import or a sync (such as Google or G2) brings testimonials in: no `testimonial.created` for them, and no `testimonial.approved` for the ones that arrive already approved. It also isn't told when a file import updates testimonials you already have, or when an import is undone. A review you approve yourself after it arrived is sent either way, with the setting on or off.

## How delivery works

- **In the background.** Each event becomes a delivery to each endpoint that subscribes to it, usually sent within a minute.
- **Signed.** Every request carries an `X-Signature` header made with the endpoint's signing secret. See [Webhook signatures, headers and payloads](/help/integrations/verify-webhook-signatures).
- **A 2xx answer is a success.** Your endpoint has 10 seconds to answer with a 2xx status code. Any other status, no answer in time, or a redirect counts as a failure.
- **Retries.** A failed delivery is tried again after 1 minute, 10 minutes and 1 hour, four attempts in all. After the last one it's marked **FAILED**, and you can retry or replay it from the delivery log.
- **At least once.** A retry or a replay can bring the same delivery twice, and deliveries can arrive out of order. Each delivery has an id that never changes, so your receiver can skip repeats.
- **Turned off after repeated failures.** After 15 failed attempts in a row, the endpoint is disabled and its waiting deliveries are canceled. The workspace owner gets an email, and the owner and the project's Admins get a notification in the app. Fix the receiver, reactivate the endpoint, and replay what was canceled.

Successful deliveries stay in the log for 30 days, failed and canceled ones for 90 days. When you delete a testimonial, its earlier deliveries are removed from the log too, and only its `testimonial.deleted` delivery stays.

## Endpoint statuses

| Status               | What it means                                                                                                                                                                                                                                                |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **ACTIVE**           | Deliveries go out as events happen.                                                                                                                                                                                                                          |
| **PAUSED**           | You paused it. Events keep queuing and are sent when you activate it again.                                                                                                                                                                                  |
| **DISABLED**         | Turned off after repeated failures, or a form webhook you switched off in the form builder. Nothing new is queued and waiting deliveries were canceled; you can replay them after reactivating it.                                                           |
| **SUSPENDED (plan)** | Your plan no longer includes webhooks, or allows fewer endpoints than you have (the oldest keep working). Its waiting deliveries are kept, and it resumes on its own after you upgrade: when you next open the **Webhooks** tab, or at the next daily check. |

## Which plans include webhooks

Project and form webhooks are on Premium and Business. The workspace owner and the project's Admins can set them up.

| Plan | Project webhook endpoints per project |
| ---- | ------------------------------------- |
| Free  | 0                                   |
| Pro  | 0                                   |
| Premium | 1                                  |
| Business | 5                                  |

Form webhooks don't count toward this limit: each form can have one.

These webhooks send events out of ReTestimonial. To go the other way, and have your store or app tell ReTestimonial to email a customer for a testimonial, see [Send invites automatically with a webhook](/help/collect/send-invites-automatically-with-a-webhook).

## In this section

- [Set up a project webhook](/help/integrations/set-up-a-project-webhook): add an endpoint, copy its signing secret, send a test, and retry or replay failed deliveries.
- [Webhook signatures, headers and payloads](/help/integrations/verify-webhook-signatures): check the signature in your receiver, and what each event's JSON contains.
- [Send a form's submissions to a webhook](/help/integrations/form-webhooks): set up a form's own webhook in the form builder.
