# Welcome

## What is LoyaltySurf?

[**LoyaltySurf**](https://www.loyaltysurf.io/) **is all-in-one advocate, loyalty, and rewards program software for businesses to launch advocate and reward programs for their users.**

> LoyaltySurf lets you reward users when they submit reviews, post on LinkedIn, create a video, and perform other advocate activities.
>
> You can also reward users based on specific actions they take beyond word-of-mouth advocacy.

With LoyaltySurf's powerful APIs and integrations, you can programmatically automate any custom reward to your users for completing any type of action.

## Examples

### Advocacy program examples

If a user submits a testimonial, writes a review, submits a video, or posts on LinkedIn, you can send them a $10 gift card for each action.

#### Here are some ideas of what you can reward your users for:

<figure><img src="/files/y1bOfXwG0rKv9GKx2YCn" alt=""><figcaption></figcaption></figure>

### Loyalty and reward program examples

* **For SaaS companies:** Reward your users for completing certain actions like the following:
  * If a user uses a specific feature or goes through a workflow, they can unlock additional features, get extra trial days, or get an increase in their usage limits.
* **For B2C and FinTech companies:** Implement a points-based loyalty program or reward your users for performing specific actions by offering account credits, bonus points, or financial incentives.
* **For B2B and Enterprise companies**: Reward prospects for taking a demo call with you. Simply update the deal status in your CRM (like HubSpot), and a gift card will automatically be sent to them.

The possibilities are endless for what you can reward.

Here are some additional examples made famous by successful companies:

<figure><img src="/files/499kJqat6as9OYyMcl5Y" alt=""><figcaption><p>Note: These are for informational purposes and do not reflect LoyaltySurf customers</p></figcaption></figure>

{% hint style="info" %}
Not a LoyaltySurf user yet? [Sign up](https://www.loyaltysurf.io/?ref=docs)
{% endhint %}

## How long does integration take?

LoyaltySurf can be fully implemented in an afternoon.

You can reward people the manual way through the dashboard. Or you can programmatically set things up by following your program's installation instructions, which is just two steps:

1. Trigger loyalty actions for your reward(s), which can be done using the REST API or our no-code Zapier integration.
2. Automate rewards, which can be done using our webhooks integration or our other no-code integrations (Zapier, PayPal, Tango Card, Stripe, Chargebee, Recurly).

![You will be provided with step-by-step instructions specific to the program you set up](/files/xxgmH4bJRDrF0DFAzR1K)

LoyaltySurf provides your development team with a complete development toolkit ([REST API](https://docs.loyaltysurf.io/integrate/rest-api), [Webhooks](https://docs.loyaltysurf.io/automate-rewards/webhooks), [Zapier](https://docs.loyaltysurf.io/automate-rewards/zapier), and third-party integrations).

On this developer docs site, you'll find helpful guides on how to integrate your LoyaltySurf program and automate reward fulfillment -- tutorials and code examples included.

Visit our [Help Center](https://support.loyaltysurf.io/) for additional FAQs and support.


# Tutorials

Tutorials for common types of loyalty and reward programs

## Tutorial 1: How to set up a points-based loyalty program

Let's say you want to give rewards to your customers in the form of points. And if a customer earns 100 points, they can unlock a reward, which can be a custom coupon or discount.

LoyaltySurf supports [participant metadata](https://docs.loyaltysurf.io/integrations/rest-api/api-guidelines#metadata), which makes this loyalty program possible to implement.

Let's imagine you will give your users 10 points each time they do something, and that it will take 100 points to unlock a reward.

### How to set up this loyalty program:

1. Create your first LoyaltySurf program and at the first step in the program editor, create a new reward. In the advanced reward settings, make sure the loyalty actions required is 1 (this is the default).
2. Next, we need to add your users into your LoyaltySurf program:
   1. For your existing users, you'll need to import them by clicking *Add > Import Participants* from your [admin dashboard](https://app.loyaltysurf.io/dashboard)*.*
   2. For new users, you'll need to call [`/POST Add participant`](https://docs.loyaltysurf.io/integrations/rest-api/api-reference#add-participant) every time someone new signs up
3. Whenever your user performs an action, call [`/POST Update participant`](https://docs.loyaltysurf.io/http:/update%20participant%20by%20email) to update their [metadata](https://docs.loyaltysurf.io/integrations/rest-api/api-guidelines#metadata) value. For example:`Participant.metadata.points = Participant.metadata.points + 10`.
   1. On the API response, check if `(Participant.metadata.points > 100)` then call [`/POST trigger loyalty action by email`](https://docs.loyaltysurf.io/integrations/rest-api/api-reference#loyalty-actions), which will unlock the reward for the participant.
4. Then after the reward is unlocked, implement the following:
   1. Set up [webhooks](https://docs.loyaltysurf.io/integrations/webhooks) to automate reward fulfillment (so that the user gets their reward).
   2. Call [`/POST Update participant`](https://docs.loyaltysurf.io/http:/update%20participant%20by%20email) and decrement  `Participant.metadata.points` by 100 to make sure the participant's points are reset.


# REST API

Use the REST API to add new participants, trigger loyalty actions, get program data, and get participant data from a secure environment.

## Getting started

{% hint style="info" %}
**Note:** The REST API is only available to users on a LoyaltySurf paid plan.
{% endhint %}

### Step 1: Get your API key

1. Go to your [LoyaltySurf Account](https://app.loyaltysurf.io/settings#api-keys) page
2. Generate a new API key (if you don't already have one) or click on your existing API key to copy it to your clipboard

{% hint style="info" %}
Your API key holds many privileges, so be sure to keep it secure! Do not share your API key in publicly accessible areas such as GitHub, Bitbucket, Web Browsers, and Front End client code.
{% endhint %}

{% hint style="danger" %}
Do not use the RESTful API in browser applications. Exposing your secret API key within front end code exposes it to security risks. Anybody with a bit of programming knowledge could potentially hijack your API key and begin making requests on your behalf.
{% endhint %}

### Step 2: Set up authentication

The LoyaltySurf REST API uses your API key to authenticate requests. Here's how to set up authentication:

1. Set a plain text header named `Authorization` with the contents being **`Bearer <YOUR_API_ACCESS_KEY>`** where **`<YOUR_API_ACCESS_KEY>`** is your API key.

#### Example Authenticated Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X "GET" "https://api.loyaltysurf.io/v1/campaign/4pdlhb" -H "Authorization: Bearer TWZ4X4NXESMX03MT66HHS6Z9Z91E"
```

{% endtab %}

{% tab title="Java" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://api.loyaltysurf.io/v1/campaign/4pdlhb")
  .get()
  .addHeader("Authorization", "Bearer TWZ4X4NXESMX03MT66HHS6Z9Z91E")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
const request = require("request");

const options = { 
  method: 'GET',
  url: 'https://api.loyaltysurf.io/v1/campaign/4pdlhb',
  headers: { 
    Authorization: 'Bearer TWZ4X4NXESMX03MT66HHS6Z9Z91E' 
  }
};

request(options, function (error, response, body) {
  if (error) throw new Error(error);
  console.log(body);
});
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://api.loyaltysurf.io/v1/campaign/4pdlhb"
headers = {
    'Authorization': "Bearer TWZ4X4NXESMX03MT66HHS6Z9Z91E"
    }
response = requests.request("GET", url, headers=headers)

print(response.text)
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php

$request = new HttpRequest();
$request->setUrl('https://api.loyaltysurf.io/v1/campaign/4pdlhb');
$request->setMethod(HTTP_METH_GET);
$request->setHeaders(array(
  'Authorization' => 'Bearer TWZ4X4NXESMX03MT66HHS6Z9Z91E'
));

try {
  $response = $request->send();
  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
```

{% endtab %}

{% tab title="Go" %}

```go
package main

import (
	"fmt"
	"net/http"
	"io/ioutil"
)

func main() {
	url := "https://api.loyaltysurf.io/v1/campaign/4pdlhb"
	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Add("Authorization", "Bearer TWZ4X4NXESMX03MT66HHS6Z9Z91E")
	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)
	fmt.Println(res)
	fmt.Println(string(body))

}
```

{% endtab %}
{% endtabs %}

## Base URL

All endpoints for the LoyaltySurf REST API start with the same base URL:

```
https://api.loyaltysurf.io/v1
```

## **Next steps**

* [View Tutorials](https://docs.loyaltysurf.io/integrate/rest-api/tutorials)
* [View Objects](https://docs.loyaltysurf.io/integrate/rest-api/api-objects)
* [View API Reference](https://docs.loyaltysurf.io/integrate/rest-api/api-reference)

[![Run in Postman](https://run.pstmn.io/button.svg)](https://www.postman.com/growsurf/growsurf-public/collection/xvgm0uy/loyaltysurf-rest-api)


# Tutorials

How to implement the LoyaltySurf REST API in common use-case scenarios.

## Table of contents

The following examples use **NodeJS**.

| [Example 1: Trigger a loyalty action](/developer-tools/rest-api/tutorials#example-1-trigger-a-loyalty-action)      |
| ------------------------------------------------------------------------------------------------------------------ |
| [Example 2: Get a participant's details](/developer-tools/rest-api/tutorials#example-2-get-a-participants-details) |

## Example 1: Trigger a loyalty action

{% hint style="info" %}

### **Box as an example**

> ***"***&#x55;pload a file and receive an additional free trial da&#x79;*."*
> {% endhint %}

### [Step 1: Make sure you have authentication set up](https://docs.loyaltysurf.io/integrate/rest-api#getting-started)

### Step 2: Trigger loyalty action

Trigger a loyalty action by calling the endpoint [**POST** Trigger Loyalty Action by Email](https://docs.loyaltysurf.io/integrations/rest-api/api-reference#trigger-loyalty-action-by-email).

Let's imagine that you want to reward a user with a free trial day if they use a feature in your product for uploading a file. This allows the user to get acquainted with your product and you can reward them for the interaction.

You can accomplish this by triggering a loyalty action for your user. The example below is what that code could look like when using NodeJS.

**Code Example**

{% code title="upload-file.js" lineNumbers="true" %}

```javascript
const request = require("request");

const options = {
  method: 'POST',
  url: 'https://api.loyaltysurf.io/v1/campaign/4pdlhb/loyalty-action', // Replace '4pdlhb' with your LoyaltySurf program ID
  headers: { 
    Authorization: 'Bearer <YOUR_API_KEY>' // Replace '<YOUR_API_KEY>' with your API key -- get this from https://app.loyaltysurf.io/settings
  },
  json: true
};

const uploadFile = () => {
  // ...code that allows the user to upload a file...

  options.body = {
    participantEmail: 'gavin@hooli.com', // Replace 'gavin@hooli.com' with your user's email address
    rewardId: 'crew_jw83va', // Replace 'crew_jw83va' with a reward ID from your LoyaltySurf program
  };

  // Send the API request to trigger the loyalty action
  request(options, (error, response, body) => {
    if (error) {
      throw new Error(error);
    }
    // Check to see if the loyalty action was triggered successfully
    const { success, message } = body.success;
    if (success) {
      console.log('loyalty action trigger success!');
    } else {
      console.log('loyalty action trigger failed :( ', message);
    }
  });
};
```

{% endcode %}

**At line 5,** replace `4pdlhb` with your LoyaltySurf program ID. This can be found within the browser's URL bar of any webpage that you are viewing your LoyaltySurf program from.

**At line 7**, replace  `<YOUR_API_KEY>` with your API key, which you can get from your [account settings page](https://app.loyaltysurf.io/settings).

**At line 16,** set `participantEmail` with your user's email address (the person who just completed the loyalty action).

**At line 17**, set `rewardId` with the Reward ID that you want to trigger a loyalty action for. You can find this value in the Rewards tab or the Installation tab of the LoyaltySurf program editor.

Once you trigger a loyalty action, your user will get added to your LoyaltySurf program if they do not already exist. Any future loyalty actions that are triggered by the same email address will increment the existing participant's loyalty action count.

### Set up reward fulfillment

Once the loyalty action is triggered, and if the program reward's loyalty action conversion threshold is 1, then a reward will be generated for the participant. You can set up [Webhooks](https://docs.loyaltysurf.io/automate-rewards/webhooks) to automate the reward of giving out the free trial day.

{% hint style="info" %}
Alternatively, you may also use [Zapier](https://docs.loyaltysurf.io/automate-rewards/zapier), [PayPal](https://docs.loyaltysurf.io/integrations/paypal), [Tango Card](https://docs.loyaltysurf.io/integrations/tango-card), [Stripe](https://docs.loyaltysurf.io/integrations/stripe), [Chargebee](https://docs.loyaltysurf.io/integrations/chargebee), or [Recurly](https://docs.loyaltysurf.io/integrations/recurly) to automate rewards.
{% endhint %}

## Example 2: Get a participant's details

With the REST API, you can retrieve a participant's LoyaltySurf rewards or loyalty action count to display on your website or mobile app using the [**`GET`**`Participant by email`](https://docs.loyaltysurf.io/integrations/rest-api/api-reference#get-participant-by-email) or [**`GET`**`Participant by ID`](https://docs.loyaltysurf.io/integrations/rest-api/api-reference#get-participant-by-id) endpoints.

### [Step 1: Make sure you have authentication setup](https://docs.loyaltysurf.io/integrate/rest-api#getting-started)

### Step 2: Retrieve a participant by email

The example below is what that code could look like in NodeJS.

**Code Example**

{% code title="signup.js" lineNumbers="true" %}

```javascript
const request = require("request");

let options = {
  method: 'GET',
  url: 'https://api.loyaltysurf.io/v1/campaign/4pdlhb/participant/gavin@hooli.com', // Replace '4pdlhb' with your LoyaltySurf program ID and replace 'gavin@hooli.com' with your user's email address
  headers: { 
    Authorization: 'Bearer <YOUR_API_KEY>' // Replace '<YOUR_API_KEY>' with your API key -- get this from https://app.loyaltysurf.io/settings
  },
  json: true
};

const getUserDetails = () => {
  // ...code that gets your users' details...

  // Get the LoyaltySurf participant's details
  request(options, (error, response, body) => {
    if (error) {
      throw new Error(error);
    }
    // Output the response that is returned
    console.log(body);
  });
};
```

{% endcode %}

**At line 5:**

* Replace `4pdlhb` with your LoyaltySurf program ID. This can be found within the browser's URL bar of any webpage that you are viewing your LoyaltySurf program from.
* Replace `gavin@hooli.com` with your user's email address (the person you want to retrieve loyalty program details for).

**At line 7**, replace  `<YOUR_API_KEY>` with your API key, which you can get from your [account settings page](https://app.loyaltysurf.io/settings).

**At line 21**, the `console.log(body)` will output a response that looks like the below example:

```javascript
{
  "id": "0o6zk7",
  "firstName": "Gavin",
  "lastName": "Belson",
  "loyaltyActionCount": 64,
  "monthlyLoyaltyActionCount": 64,
  "prevMonthlyLoyaltyActionCount": 0,
  "rank": 1,
  "monthlyRank": 1,
  "rewards": [
    {
      "id": "prew_gbmggn",
      "rewardId": "crew_4bvj34",
      "status": "FULFILLED",
      "unread": true,
      "isFulfilled": true,
      "isAvailable": true,
      "approved": true,
      "approvedAt": 1673512243809,
      "fulfilledAt": 1673512243809,
      "participantId": "0o6zk7"
    },
    {
      "id": "prew_c9ruja",
      "rewardId": "crew_4bvj34",
      "status": "FULFILLED",
      "unread": true,
      "isFulfilled": true,
      "isAvailable": true,
      "approved": true,
      "approvedAt": 1673513384713,
      "fulfilledAt": 1673513384713,
      "participantId": "0o6zk7"
    },
    {
      "id": "prew_ri4fqm",
      "rewardId": "crew_eaqcym",
      "status": "FULFILLED",
      "unread": true,
      "isFulfilled": true,
      "isAvailable": true,
      "approved": true,
      "approvedAt": 1673514372041,
      "fulfilledAt": 1673514372041,
      "participantId": "0o6zk7"
    },
    {
      "id": "prew_ye9wtm",
      "rewardId": "crew_eaqcym",
      "status": "FULFILLED",
      "unread": true,
      "isFulfilled": true,
      "isAvailable": true,
      "approved": true,
      "approvedAt": 1673514689008,
      "fulfilledAt": 1673514689008,
      "participantId": "0o6zk7"
    },
    {
      "id": "prew_as64qz",
      "rewardId": "crew_eaqcym",
      "status": "FULFILLED",
      "unread": true,
      "isFulfilled": true,
      "isAvailable": true,
      "approved": true,
      "approvedAt": 1673516703039,
      "fulfilledAt": 1673516703039,
      "participantId": "0o6zk7"
    }
  ],
  "email": "gavin.belson@hoolie.com",
  "createdAt": 1670839357123,
  "loyaltyActionSource": "MANUAL",
  "fraudRiskLevel": "LOW",
  "fraudReasonCode": "UNIQUE_IDENTITY",
  "isWinner": true,
  "loyaltyActionCountPerReward": {
    "crew_xfj7ic": 24,
    "crew_b3iq3m": 18,
    "crew_p046cu": 8,
    "crew_0256ri": 1,
    "crew_4bvj34": 9,
    "crew_2k8jln": 1,
    "crew_eaqcym": 3
  },
  "monthlyLoyaltyActionCountPerReward": {
    "crew_xfj7ic": 24,
    "crew_b3iq3m": 18,
    "crew_p046cu": 8,
    "crew_0256ri": 1,
    "crew_4bvj34": 9,
    "crew_2k8jln": 1,
    "crew_eaqcym": 3
  },
  "prevLoyaltyActionCount": 0,
  "metadata": {
    "zipCode": 55555
  }
}
```


# Objects

## `Campaign`

The `Campaign` Object contains detailed information about a LoyaltySurf program.

| Name                   | Type      | Description                                                                                                     |
| ---------------------- | --------- | --------------------------------------------------------------------------------------------------------------- |
| **id**                 | `string`  | The unique identifier of the program                                                                            |
| **name**               | `string`  | The program name                                                                                                |
| **loyaltyActionCount** | `integer` | The total loyalty action count                                                                                  |
| **participantCount**   | `integer` | The total participant count                                                                                     |
| **winnerCount**        | `integer` | The total number of winners††                                                                                   |
| **status**             | `string`  | The program status: `DRAFT`, `IN_PROGRESS`, `COMPLETE`, `DELETED`                                               |
| **currencyISO**        | `string`  | The program currency as a [ISO 4217](https://www.iso.org/iso-4217-currency-codes.html) code (e.g, `USD`, `GBP`) |
| **rewards**            | `array`   | The list of [Rewards](/developer-tools/rest-api/api-objects#reward) associated with the program                 |

{% hint style="info" %}
†† **Winners** = all participants with at least one approved reward.
{% endhint %}

<details>

<summary>Campaign Object Example</summary>

```json
{
    "id": "abc123",
    "name": "Pied Piper Advocate Program",
    "loyaltyActionCount": 121,
    "participantCount": 199,
    "winnerCount": 1,
    "status": "IN_PROGRESS",
    "rewards": [
        {
            "id": "crew_xyz789",
            "title": "LinkedIn Post Mention",
            "description": "Make a LinkedIn post mentioning Pied Piper",
            "subdescription": "Post must be less than 1 week old from date of submission",
            "instructions": "<div><p><strong>Helpful tips:</strong></p><ul><li>Talk about how you used to do things before using Pied Piper</li><li>Mention specific ROIs (e.g, time saved, revenue generated)</li></ul></div>",
            "cta": "Get $25",
            "submissionType": "URL",
            "submissionExampleUrl": "https://linkedin.com/posts/sarah_s-my-review-of-pied-piper-8195769799870726145-Sr9b",
            "submissionFormUrl": "https://linkedin.com/shareArticle",
            "submissionFormFields": [
                {
                    "key": "linkedinPostUrl",
                    "label": "Your LinkedIn Post URL",
                    "placeholder": "Enter your LinkedIn Post URL here",
                    "type": "text",            
                    "isRequired": true,
                    "isVisible": true
                }
            ],
            "submissionFormButtonText": "Submit",
            "submissionFormMessages": {
                "required": "is required",
                "reCaptchaRequired": "You must pass the reCAPTCHA verification.",
                "success": "Thanks! We have received your response.",
                "error": "There was an error. Please try submitting again.",
                "alreadySubmitted": "You already submitted this form."
            },
            "conversionsRequired": 1,    
            "isUnlimited": false,
            "limit": 1,
            "limitDuration": "IN_TOTAL",
            "numberOfWinners": 3,
            "order": 1,
            "couponCode": "PROMO_20_OFF",
            "imageUrl": "http://res.cloudinary.com/growsurf/image/upload/v1552764861/development/hxdcjrayfhksvxu5u6oz.png",
            "metadata": {
              "rewardForTierA": 50,
              "rewardForTierB": 100,
              "bonusPeriodMessage": "Offering 2x reward bonuses in our promotion period!"
            }            
        }
    ]
}
```

</details>

***

## `Reward`

The `Reward` Object (also known as `CampaignReward`) contains detailed reward information about a single reward for a program.

{% hint style="info" %}
**Note:** This `Reward` Object is different from a [`ParticipantReward`](/developer-tools/rest-api/api-objects#participantreward) Object, which is a reward earned by a participant.
{% endhint %}

| Name                         | Type      | Description                                                                                                                                                                                                            |
| ---------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **id**                       | `string`  | <p>The unique identifier of the program reward.<br><br>You can find this ID from <em>Program Editor > 1. Rewards</em> and clicking the reward.</p>                                                                     |
| **title**                    | `string`  | The title of the program reward. Only used for internal purposes and never displayed to participants.                                                                                                                  |
| **description**              | `string`  | A description of the reward                                                                                                                                                                                            |
| s**ubdescription**           | `string`  | A sub-description of the reward                                                                                                                                                                                        |
| **instructions**             | `string`  | Instructions for the participant to unlock the reward (in HTML format)                                                                                                                                                 |
| **cta**                      | `string`  | The call-to-action (CTA) for the reward                                                                                                                                                                                |
| **submissionType**           | `string`  | <p>The type of reward submission the participant must complete.</p><p><br>Options: <code>"URL"</code>, <code>"FORM"</code></p>                                                                                         |
| **submissionExampleUrl**     | `string`  | Only applicable if `submissionType === "URL"`. The URL of an example of what a successful reward submission looks like                                                                                                 |
| **submissionFormUrl**        | `string`  | Only applicable if `submissionType === "FORM"`.  The URL where the participant is expected to submit a form to redeem their reward.                                                                                    |
| **submissionFormFields**     | `array`   | Only applicable if `submissionType === "FORM"`. A list of reward form field objects that the participant must submit to redeem their reward.                                                                           |
| **submissionFormButtonText** | `string`  | The text for the form submission button.                                                                                                                                                                               |
| **submissionFormMessages**   | `object`  | Only applicable if `submissionType === "FORM"`. An object with various validation  messages for the input fields in `submissionFormFields`.                                                                            |
| **isUnlimited**              | `boolean` | `true` if this reward can be earned by a single participant an unlimited amount of times                                                                                                                               |
| **limit**                    | `integer` | The number of times a participant can earn this reward (this property is overridden with `-1` if `isUnlimited` is `true`)                                                                                              |
| **conversionsRequired**      | `integer` | The number of loyalty actions a participant must complete to earn this reward                                                                                                                                          |
| **limitDuration**            | `string`  | <p>Whether the reward can be earned in total or on a monthly basis.<br><br>Options: "<code>IN\_TOTAL</code>", "<code>PER\_MONTH</code>"</p>                                                                            |
| **numberOfWinners**          | `integer` | If  `limitDuration` is `PER_MONTH`, this is the manimum number of total participants who can earn the reward in the given month.                                                                                       |
| **couponCode**               | `string`  | A coupon code                                                                                                                                                                                                          |
| **imageUrl**                 | `string`  | The reward image URL                                                                                                                                                                                                   |
| **order**                    | `integer` | <p>If there are multiple rewards, this represents the order in which the reward should be displayed.</p><p><br>This value is <code>null</code> by default, until set within the Design step of the program editor.</p> |
| **metadata**                 | `object`  | The reward metadata.                                                                                                                                                                                                   |

<details>

<summary><code>Reward</code> Object Example</summary>

```json
{
    "id": "crew_xyz789",
    "title": "LinkedIn Post Mention",
    "description": "Make a LinkedIn post mentioning Pied Piper",
    "subdescription": "Post must be less than 1 week old from date of submission",
    "instructions": "<div><p><strong>Helpful tips:</strong></p><ul><li>Talk about how you used to do things before using Pied Piper</li><li>Mention specific ROIs (e.g, time saved, revenue generated)</li></ul></div>",
    "cta": "Get $25",
    "submissionType": "URL",
    "submissionExampleUrl": "https://linkedin.com/posts/sarah_s-my-review-of-pied-piper-8195769799870726145-Sr9b",
    "submissionFormUrl": "https://linkedin.com/shareArticle",
    "submissionFormFields": [
        {
            "key": "linkedinPostUrl",
            "label": "Your LinkedIn Post URL",
            "placeholder": "Enter your LinkedIn Post URL here",
            "type": "text",            
            "isRequired": true,
            "isVisible": true
        }
    ],
    "submissionFormButtonText": "Submit",
    "submissionFormMessages": {
        "required": "is required",
        "reCaptchaRequired": "You must pass the reCAPTCHA verification.",
        "success": "Thanks! We have received your response.",
        "error": "There was an error. Please try submitting again.",
        "alreadySubmitted": "You already submitted this form."
    },
    "conversionsRequired": 1,    
    "isUnlimited": false,
    "limit": 1,
    "limitDuration": "IN_TOTAL",
    "numberOfWinners": 3,
    "order": 1,
    "couponCode": "PROMO_20_OFF",
    "imageUrl": "http://res.cloudinary.com/growsurf/image/upload/v1552764861/development/hxdcjrayfhksvxu5u6oz.png",
    "metadata": {
      "rewardForTierA": 50,
      "rewardForTierB": 100,
      "bonusPeriodMessage": "Offering 2x reward bonuses in our promotion period!"
    }
}
```

</details>

***

## `Participant`

The `Participant` Object contains detailed information about a program participant.

| Name                                    | Type        | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| --------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **id**                                  | `integer`   | The unique identifier of the participant                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| **firstName**                           | `string`    | The first name of the participant                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| **lastName**                            | `string`    | The last name of the participant                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| **loyaltyActionCount**                  | `integer`   | The total number of loyalty actions made by the participant                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| **monthlyLoyaltyActionCount**           | `integer`   | The total number of loyalty actions made this month by the participant (resets at the end of the month)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| **prevMonthlyLoyaltyActionCount**       | `integer`   | The total number of loyalty actions made the previous month by the participant.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| **email**                               | `string`    | The email of the participant                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| **createdAt**                           | `timestamp` | The date the participant was added to the program (UTC milliseconds)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| **fraudRiskLevel**                      | `string`    | A value that represents the integrity of the participant: `LOW`, `MEDIUM`,`HIGH`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| **fraudReasonCode**                     | `string`    | <p>A value representing the reason for the fraudRiskLevel: UNIQUE\_IDENTITY, DUPLICATE\_EMAIL, DUPLICATE\_IDENTITY<br><br>- <code>UNIQUE\_IDENTITY</code> = They have a unique identity (no other participant has the same identity as them).<br>- <code>DUPLICATE\_EMAIL</code> = Their email is not unique, and is identical with another participant's email (e.g., <gavin@hooli.com> = <gavin+1@hooli.com>).<br>- <code>DUPLICATE\_IDENTITY</code><br> = Their identity is not unique, and matches that of another participant's.<br> <code>SIMILAR\_EMAIL</code> = Their browser fingerprint matches another participant's, and their email looks suspiciously similar (e.g., <gavin@hooli.com>, <gavin.belson2@gmail.com>)<br>- <code>SIMILAR\_FIRST\_NAME</code> = Their browser fingerprint matches another participant's, and their first name looks suspiciously similar.<br>- <code>SIMILAR\_LAST\_NAME</code> = Their browser fingerprint matches another participant's, and their last name looks suspiciously similar.<br>- <code>MANUAL\_UPDATE</code> = They were manually marked as a fraudster from the LoyaltySurf dashboard.<br>- <code>WHITELISTED</code> = They were allowed to join the program because one of their properties matched a whitelisted value.<br>- <code>BLACKLIST\_MATCH</code> = They were not allowed to join the program because one of their properties matched a blacklisted value.<br>- <code>BLOCKED\_IP</code> = They were not allowed to join the program because their IP address was recently blocked by antifraud IP throttling.</p> |
| **isWinner**                            | `boolean`   | `true` if the participant has earned one or more rewards                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| **loyaltyActionCountsPerReward**        | `array`     | A breakdown of how many loyalty actions overall was performed by the participant per reward.  It's an object with the program reward ID as the key, and the number of loyalty actions performed as the value.  This key will not exist if the participant has not performed any loyalty actions, instead of being an empty object `{}`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| **monthlyLoyaltyActionCountsPerReward** | `array`     | A breakdown of how many loyalty actions for the current month was performed by the participant per reward.  It has the same shape as `loyaltyActionCountsPerReward`.  This key will not exist if the participant has not performed any loyalty actions, instead of being an empty object `{}`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| **loyaltyActionSource**                 | `string`    | The source of how the participant joined the program: `PARTICIPANT`, `DIRECT`,`IMPORT`,`MANUAL`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| **rewards**                             | `array`     | A list of `ParticipantReward` objects that the participant has earned                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| **notes**                               | `string`    | A value containing internal notes about the participant, added via the [LoyaltySurf Dashboard](https://app.loyaltysurf.io/dashboard)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| **metadata**                            | `object`    | <p>An Object containing any custom key-value data, useful when you want to save additional data for the participant (e.g, <code>company</code>, <code>companySize</code>)</p><p><br><em>Metadata is never used by LoyaltySurf and usage is optional. Metadata is returned in REST API calls. For more information, please see</em> <a href="/pages/-LfZ01vnHVkarKLqPFbR#metadata"><em>API Guidelines</em></a><em>.</em></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| **rank**                                | `integer`   | The rank of the participant.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| **monthlyRank**                         | `integer`   | <p>The monthly rank of the participant. </p><p></p><p><em><strong>This rank resets to 0 at the end of each month.</strong></em></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| **prevMonthlyRank**                     | `integer`   | <p>The previous monthly rank of the participant. <br><br><em><strong>This rank will not be be returned if the participant did not exist within your program during the previous month.</strong></em></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |

<details>

<summary><code>Participant</code> Object Example</summary>

```json
{
    "id": "f8g9nl",
    "firstName": "Gavin",
    "lastName": "Belson",
    "loyaltyActionCount": 3,
    "monthlyLoyaltyActionCount": 3,
    "prevMonthlyLoyaltyActionCount": 0,
    "rank": 10001,
    "monthlyRank": 20001,
    "email": "gavin@hoolie.com",
    "createdAt": 1552404738928,
    "fraudRiskLevel": "LOW",
    "fraudReasonCode": "UNIQUE_IDENTIY",
    "isWinner": true,
    "loyaltyActionCountPerReward": {
        "crew_m5xm9l": 1,
        "crew_w01fil": 2
    },
    "monthlyLoyaltyActionCountPerReward": {
        "crew_m5xm9l": 1,
        "crew_w01fil": 2
    },
    "loyaltyActionSource": "DIRECT",
    "metadata": {
       "company": "Hooli, Inc",
       "companySize": 10000
    },
    "rewards": [
        {
            "id": "prew_9x8v1b",
            "rewardId": "crew_m5xm9l",
            "status": "FULFILLED",
            "unread": true,
            "isAvailable": true,
            "approved": true,
            "isFulfilled": true
        },
        {
            "id": "prew_vsdj34",
            "rewardId": "crew_w01fil",
            "status": "FULFILLED",
            "unread": true,
            "isAvailable": true,
            "approved": true,
            "isFulfilled": true
        },
        {
            "id": "prew_sj3kap",
            "rewardId": "crew_w01fil",
            "status": "FULFILLED",
            "unread": true,
            "isAvailable": true,
            "approved": true,
            "isFulfilled": true
        }
    ]
}
```

</details>

***

## `ParticipantReward`

The `ParticipantReward` Object represents a reward that the participant has earned.

{% hint style="info" %}
**Notes:**

* This `ParticipantReward` Object is different from a program [`Reward`](/developer-tools/rest-api/api-objects#reward) Object and contains information that is only pertinent to the participant that earned the reward.
* In [Webhooks](https://docs.loyaltysurf.io/integrations/webhooks), `ParticipantReward` Objects will also contain program `Reward` Object details.
  {% endhint %}

| Name            | Type        | Description                                                                                                                                                                                                                           |
| --------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **id**          | `string`    | <p>The unique identifier of the participant's reward.<br><br>This will be different for every new reward that the participant earns. You can find this ID by going to your admin dashboard and viewing the participant's rewards.</p> |
| **rewardId**    | `string`    | The ID of the [`CampaignReward`](/developer-tools/rest-api/api-objects#reward) that this participant has earned                                                                                                                       |
| **status**      | `string`    | The status of the participant's reward: `PENDING`,`FULFILLED`                                                                                                                                                                         |
| **isAvailable** | `boolean`   | `true` if the participant's reward is available for participant to claim or redeem                                                                                                                                                    |
| **approved**    | `boolean`   | `true` if the participant's reward has been approved                                                                                                                                                                                  |
| **approvedAt**  | `timestamp` | The date and time the reward was approved for this participant (UTC milliseconds).  It is `null` for unapproved rewards.                                                                                                              |
| **isFulfilled** | `boolean`   | `true` if the reward has been fulfilled.                                                                                                                                                                                              |
| **fulfilledAt** | `timestamp` | The date and time the reward was fulfilled for this participant (UTC milliseconds).  It is `null` for either unapproved or unfulfilled rewards.                                                                                       |
| **unread**      | `boolean`   | `false` if the participant has not seen the reward in a LoyaltySurf window otherwise `false`.                                                                                                                                         |

<details>

<summary><code>ParticipantReward</code> Object Example</summary>

```json
{
    "id": "prew_rr35mg",
    "rewardId": "crew_c6w1qo",
    "status": "PENDING",
    "unread": true,
    "approved": false,
    "approvedAt": null,
    "fulfilledAt": null,
    "isAvailable": false,
    "isFulfilled": false
}
```

</details>

***

## `ParticipantRewardFormSubmission` <a href="#participantreward" id="participantreward"></a>

The `ParticipantRewardFormSubmission` Object represents a reward form submission that the participant has filled out and sent from the advocate portal.

**Note:** This `ParticipantRewardFormSubmission` Object does not mean the participant has earned any rewards yet. You will need to approve their submission or trigger the loyalty action in order for the reward to be unlocked for them.

| Name                 | Type     | Description                                                                                                                                                       |
| -------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **id**               | `string` | The unique identifier of the reward form submission                                                                                                               |
| **participantId**    | `string` | The unique identifier of the [`Participant`](#participant) that submitted the form                                                                                |
| **participantEmail** | `string` | The email address of the [`Participant`](#participant) that submitted the form                                                                                    |
| **rewardId**         | `string` | The ID of the [`Reward`](https://docs.loyaltysurf.io/integrations/rest-api/api-objects#reward) the form submission is for                                         |
| **status**           | `string` | The status of the reward: `UNREVIEWED`,`REVIEWED`                                                                                                                 |
| **formData**         | `object` | <p>An Object containing the form submission details.</p><p></p><p>The key-value data corresponds with the fields in <code>Reward.submissionFormFields</code>.</p> |

<details>

<summary><code>ParticipantRewardFormSubmission</code> Object Example</summary>

```json
{
    "id": "prfs_def678",
    "participantId": "f8g9nl",
    "participantEmail": "gavin@hoolie.com",
    "rewardId": "crew_xyz789",
    "status": "UNREVIEWED",
    "formData": {
      "linkedinPostUrl": "https://linkedin.com/posts/sarah_s-my-review-of-pied-piper-8195769799870726145-Sr9b"
    }
}
```

</details>


# API Reference

This reference documents the LoyaltySurf REST API, including all available public methods and examples of each.

## Open in Postman

Easily test these API methods dynamically by using our Postman Collection.  Just change the `Token` in the Authorizations tab, and the `campaign_id` variable to the program you're working on.

[![Run in Postman](https://run.pstmn.io/button.svg)](https://www.postman.com/growsurf/growsurf-public/collection/xvgm0uy/loyaltysurf-rest-api)

***

## CAMPAIGNS ↓

### Get Campaign

<mark style="color:blue;">`GET`</mark> `https://api.loyaltysurf.io/v1/campaign/:id`

Retrieves a program for the given program ID.

#### Path Parameters

| Name                                 | Type   | Description                       |
| ------------------------------------ | ------ | --------------------------------- |
| id<mark style="color:red;">\*</mark> | string | The ID of the program to retrieve |

#### Response

{% tabs %}
{% tab title="200" %}
Returns the program.

```json
{
    "id": "abc123",
    "name": "Pied Piper Advocate Program",
    "loyaltyActionCount": 121,
    "participantCount": 199,
    "winnerCount": 1,
    "status": "IN_PROGRESS",
    "currencyISO": "USD",
    "rewards": [
        {
            "id": "crew_xyz789",
            "description": "Make a LinkedIn post mentioning Pied Piper",
            "subdescription": "Post must be less than 1 week old from date of submission",
            "instructions": "<div><p><strong>Helpful tips:</strong></p><ul><li>Talk about how you used to do things before using Pied Piper</li><li>Mention specific ROIs (e.g, time saved, revenue generated)</li></ul></div>",
            "cta": "Get $25",
            "submissionType": "URL",
            "submissionExampleUrl": "https://linkedin.com/posts/sarah_s-my-review-of-pied-piper-8195769799870726145-Sr9b",
            "submissionFormUrl": "https://linkedin.com/shareArticle",
            "submissionFormFields": [
                {
                    "key": "linkedinPostUrl",
                    "label": "Your LinkedIn Post URL",
                    "placeholder": "Enter your LinkedIn Post URL here",
                    "type": "text",
                    "isRequired": true,
                    "isVisible": true
                }
            ],
            "submissionFormButtonText": "Submit",
            "submissionFormMessages": {
                "required": "is required",
                "reCaptchaRequired": "You must pass the reCAPTCHA verification.",
                "success": "Thanks! We have received your response.",
                "error": "There was an error. Please try submitting again.",
                "alreadySubmitted": "You already submitted this form."
            },
            "isUnlimited": false,
            "limit": 1,
            "conversionsRequired": 1,
            "imageUrl": "http://res.cloudinary.com/loyaltysurf/image/upload/v1552764861/development/hxdcjrayfhksvxu5u6oz.png"
        }
    ]
}
```

{% endtab %}
{% endtabs %}

### Get Campaigns

<mark style="color:blue;">`GET`</mark> `https://api.loyaltysurf.io/v1/campaigns`

Retrieves a list of your programs. Programs that have been deleted will not be returned in this response.

#### Response

{% tabs %}
{% tab title="200" %}
Returns the programs.

```json
{
    "campaigns": [
        {
            "id": "abc123",
            "name": "Pied Piper Advocate Program",
            "loyaltyActionCount": 20500,
            "participantCount": 40000,
            "winnerCount": 1500,
            "status": "IN_PROGRESS",
            "currencyISO": "USD",
            "rewards": [
                {
                    "id": "crew_xyz789",
                    "description": "Make a LinkedIn post mentioning Pied Piper",
                    "subdescription": "Post must be less than 1 week old from date of submission",
                    "instructions": "<div><p><strong>Helpful tips:</strong></p><ul><li>Talk about how you used to do things before using Pied Piper</li><li>Mention specific ROIs (e.g, time saved, revenue generated)</li></ul></div>",
                    "cta": "Get $25",
                    "submissionType": "URL",
                    "submissionExampleUrl": "https://linkedin.com/posts/sarah_s-my-review-of-pied-piper-8195769799870726145-Sr9b",
                    "submissionFormUrl": "https://linkedin.com/shareArticle",
                    "submissionFormFields": [
                        {
                            "key": "linkedinPostUrl",
                            "label": "Your LinkedIn Post URL",
                            "placeholder": "Enter your LinkedIn Post URL here",
                            "type": "text",
                            "isRequired": true,
                            "isVisible": true
                        }
                    ],
                    "submissionFormButtonText": "Submit",
                    "submissionFormMessages": {
                        "required": "is required",
                        "reCaptchaRequired": "You must pass the reCAPTCHA verification.",
                        "success": "Thanks! We have received your response.",
                        "error": "There was an error. Please try submitting again.",
                        "alreadySubmitted": "You already submitted this form."
                    },
                    "isUnlimited": false,
                    "limit": 1,
                    "conversionsRequired": 1,
                    "imageUrl": "http://res.cloudinary.com/loyaltysurf/image/upload/v1552764861/development/hxdcjrayfhksvxu5u6oz.png"
                }
            ]
        },
        {
            "id": "ljtqn5",
            "name": "Pied Piper Advocate Program #2",
            "loyaltyActionCount": 30500,
            "participantCount": 60000,
            "winnerCount": 750,
            "status": "IN_PROGRESS",
            "currencyISO": "USD",
            "rewards": [
                {
                    "id": "crew_qiar1r",
                    "description": "Make an X (Twitter) post about Pied Piper",
                    "subdescription": "Post must be less than 1 week old from date of submission",
                    "instructions": "<div><p><strong>Helpful tips:</strong></p><ul><li>Talk about how you used to do things before using Pied Piper</li><li>Mention specific ROIs (e.g, time saved, revenue generated)</li></ul></div>",
                    "cta": "Get $15",
                    "submissionType": "URL",
                    "submissionExampleUrl": "https://x.com/Sarah_S/status/2307836134014308344",
                    "submissionFormUrl": "https://x.com/compose/post",
                    "submissionFormFields": [
                        {
                            "key": "twitterPostUrl",
                            "label": "Your Twitter Post URL",
                            "placeholder": "Enter your Twitter Post URL here",
                            "isRequired": true,
                            "isVisible": true
                        }
                    ],
                    "submissionFormButtonText": "Submit",
                    "submissionFormMessages": {
                        "required": "is required",
                        "reCaptchaRequired": "You must pass the reCAPTCHA verification.",
                        "success": "Thanks! We have received your response.",
                        "error": "There was an error. Please try submitting again.",
                        "alreadySubmitted": "You already submitted this form."
                    },
                    "isUnlimited": false,
                    "limit": 1,
                    "conversionsRequired": 1,
                    "imageUrl": "http://res.cloudinary.com/loyaltysurf/image/upload/v1552764861/development/hxdcjrayfhksvxu5u6oz.png"
                }
            ]
        }
    ]
}
```

{% endtab %}
{% endtabs %}

***

***

## LOYALTY ACTIONS ↓

### Trigger Loyalty Action by Email

<mark style="color:green;">`POST`</mark> `https://api.loyaltysurf.io/v1/campaign/:id/loyalty-action`

Triggers a loyalty action for a person, awarding loyalty action credit to them and adds them to the program as a participant if they do not already exist.

If the required number of loyalty actions of the program reward is reached, then the reward will be unlocked.

#### Path Parameters

| Name                                 | Type   | Description           |
| ------------------------------------ | ------ | --------------------- |
| id<mark style="color:red;">\*</mark> | string | The ID of the program |

#### Request Body

| Name                                               | Type    | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| -------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| participantEmail<mark style="color:red;">\*</mark> | string  | The email address of the person that performed the loyalty action. If the person already exists as a participant, then their loyalty action count will be incremented.                                                                                                                                                                                                                                                                                                 |
| rewardId<mark style="color:red;">\*</mark>         | string  | The program reward ID that the participant will earn upon completing the required number of loyalty actions.                                                                                                                                                                                                                                                                                                                                                           |
| addParticipantIfNoneExists                         | boolean | Adds the person to the program as a participant if they do not already exist. Defaults to `true`.                                                                                                                                                                                                                                                                                                                                                                      |
| firstName                                          | string  | <p>(Applies only if <code>addParticipantIfNoneExists</code> is <code>true</code>. Optional, but recommended)</p><p><br>The first name of the new participant. If provided, this property will be used for anti-fraud measurements.</p>                                                                                                                                                                                                                                 |
| lastName                                           | string  | <p>(Applies only if <code>addParticipantIfNoneExists</code> is <code>true</code>. Optional, but recommended)<br><br>The last name of the new participant. If provided, this property will be used for anti-fraud measurements.</p>                                                                                                                                                                                                                                     |
| ipAddress                                          | string  | <p>(Applies only if <code>addParticipantIfNoneExists</code> is <code>true</code>. Optional, but recommended)<br><br>The IP address of the new participant. If provided, this property will be used for anti-fraud measurements.</p>                                                                                                                                                                                                                                    |
| fingerprint                                        | string  | <p>(Applies only if <code>addParticipantIfNoneExists</code> is <code>true</code>. Optional, but recommended)<br><br>The browser fingerprint of the new participant. If provided, this property will be used for anti-fraud measurements.<br><br>We recommend using a front-end library like <a href="https://github.com/fingerprintjs/fingerprintjs">fingerprintjs</a> to get the fingerprint value. Example value: <code>cfb163bd47ba666c52cb932c521e47f4</code>.</p> |
| metadata                                           | object  | <p>(Applies only if <code>addParticipantIfNoneExists</code> is <code>true</code>. Optional)<br><br>A shallow Object containing custom key/values to include with the participant data.</p>                                                                                                                                                                                                                                                                             |

#### Response

{% tabs %}
{% tab title="200" %}
Returns an object with a `success` attribute equal to `true` if the loyalty action was triggered, otherwise `false`.

The response also contains the updated participant \[who just performed the loyalty action] or the newly-created participant if `addParticipantIfNoneExists` was specified.

```json
{
  "success": true,
  "message": "Successfully awarded loyalty reward.",
  "participant": {
    "id": "cq3e6a",
    "campaignId": "abc123",
    "email": "foobaekrkerj@gmail.com",
    "firstName": "Foo",
    "lastName": "Bar",
    "createdAt": 1671008290019,
    "updatedAt": 1671008290407,
    "loyaltyActionCount": 1,
    "monthlyLoyaltyActionCount": 1,
    "prevMonthlyLoyaltyActionCount": 0,
    "prevLoyaltyActionCount": 0,
    "loyaltyActionCountPerReward": {
        "crew_xfj7ic": 1
    },
    "monthlyLoyaltyActionCountPerReward": {
        "crew_xfj7ic": 1
    },
    "loyaltyActionSource": "DIRECT",
    "fraudRiskLevel": "LOW",
    "fraudReasonCode": "UNIQUE_IDENTITY",
    "isWinner": false,
    "rank": -1,
    "monthlyRank": -1,
    "prevMonthlyRank": -1,
    "rewards": [],
    "reviewedRewardFormSubmissionCount": 0,
    "unreviewedRewardFormSubmissionCount": 0,
    "metadata": {},
    "unsubscribed": false
  }
}
```

{% endtab %}

{% tab title="400" %}
A `400` will be returned if validation fails on an input.

```javascript
{
  "name": "BadRequestError",
  "code": "BAD_REQUEST_ERROR",
  "message": "Invalid email foo",
  "errors": […],
  "status": 400,
  "supportUrl": "https://app.loyaltysurf.io/settings#contact_support"
}
```

{% endtab %}

{% tab title="409" %}
A `409` error will be returned if the request is a duplicate.

```javascript
{
  "name": "DuplicateRequestError",
  "code": "DUPLICATE_REQUEST_ERROR",
  "message": "Duplicate request is already in progress. Loyalty action credit is already being triggered for the participant.",
  "status": 409,
  "supportUrl": "https://app.loyaltysurf.io/settings#contact_support"
}
```

{% endtab %}

{% tab title="422" %}
If the new participant is detected to be a high-level fraudster, and if anti-fraud settings are configured on the campaign, the participant will be blocked from joining with a status code of `422`.\
\
View the list of available `fraudRiskLevel` and `fraudReasonCode` options on the [Participant](https://docs.loyaltysurf.io/developer-tools/rest-api/api-objects#participant) Object. `matchedParticipantIds` will contain a list of matching fraudsters, but will be empty if an antifraud blacklist rule gets a match first.

```javascript
{
  "name": "ParticipantBlockedError",
  "code": "PARTICIPANT_BLOCKED_ERROR",
  "message": "Participant sarah.smith@email.com is blocked by antifraud rules.",
  "status": 422,
  "supportUrl": "https://app.loyaltysurf.io/settings#contact_support",
  "fraudRiskLevel": "HIGH",
  "fraudReasonCode": "BLACKLIST_MATCH",
  "matchedParticipantIds": [],
  "email": "sarah.smith@email.com",
  "ipAddress": "203.0.113.10",
  "fingerprint": null,
  "blockedAt": "2025-11-13T06:22:31.001Z"
}
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
**Metadata:** Please see our [API Guidelines](/developer-tools/rest-api/api-guidelines#metadata)[ ](/developer-tools/rest-api/api-guidelines#metadata)for more information about `metadata.`
{% endhint %}

### Trigger Loyalty Action by Participant ID

<mark style="color:green;">`POST`</mark> `https://api.loyaltysurf.io/v1/campaign/:id/loyalty-action`

Triggers a loyalty action for an existing participant.

If the required number of loyalty actions of the program reward is reached, then the reward will be unlocked.

#### Path Parameters

| Name                                 | Type   | Description           |
| ------------------------------------ | ------ | --------------------- |
| id<mark style="color:red;">\*</mark> | string | The ID of the program |

#### Request Body

| Name                                            | Type   | Description                                                                                                  |
| ----------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------ |
| participantId<mark style="color:red;">\*</mark> | string | The ID of the participant that performed the loyalty action.                                                 |
| rewardId<mark style="color:red;">\*</mark>      | String | The program reward ID that the participant will earn upon completing the required number of loyalty actions. |

#### Response

{% tabs %}
{% tab title="200" %}
Returns an object with a `success` attribute equal to `true` if the loyalty action was triggered, otherwise `false`.

The response also contains the updated participant \[who just performed the loyalty action].

```json
{
  "success": true,
  "message": "Successfully awarded loyalty reward.",
  "participant": {
    "id": "cq3e6a",
    "campaignId": "abc123",
    "email": "foobaekrkerj@gmail.com",
    "firstName": "Foo",
    "lastName": "Bar",
    "createdAt": 1671008290019,
    "updatedAt": 1671008290407,
    "loyaltyActionCount": 1,
    "monthlyLoyaltyActionCount": 1,
    "prevMonthlyLoyaltyActionCount": 0,
    "prevLoyaltyActionCount": 0,
    "loyaltyActionCountPerReward": {
        "crew_xfj7ic": 1
    },
    "monthlyLoyaltyActionCountPerReward": {
        "crew_xfj7ic": 1
    },
    "loyaltyActionSource": "DIRECT",
    "fraudRiskLevel": "LOW",
    "fraudReasonCode": "UNIQUE_IDENTITY",
    "isWinner": false,
    "rank": -1,
    "monthlyRank": -1,
    "prevMonthlyRank": -1,
    "rewards": [],
    "reviewedRewardFormSubmissionCount": 0,
    "unreviewedRewardFormSubmissionCount": 0,
    "metadata": {},
    "unsubscribed": false
  }
}
```

{% endtab %}

{% tab title="400" %}
A `400` will be returned if validation fails on an input.

```javascript
{
  "name": "BadRequestError",
  "code": "BAD_REQUEST_ERROR",
  "message": "Invalid email foo",
  "errors": […],
  "status": 400,
  "supportUrl": "https://app.loyaltysurf.io/settings#contact_support"
}
```

{% endtab %}

{% tab title="409" %}
A `409` error will be returned if the request is a duplicate.

```javascript
{
  "name": "DuplicateRequestError",
  "code": "DUPLICATE_REQUEST_ERROR",
  "message": "Duplicate request is already in progress. Loyalty action credit is already being triggered for the participant.",
  "status": 409,
  "supportUrl": "https://app.loyaltysurf.io/settings#contact_support"
}
```

{% endtab %}
{% endtabs %}

***

## PARTICIPANTS ↓

### Get Participant by ID

<mark style="color:blue;">`GET`</mark> `https://api.loyaltysurf.io/v1/campaign/:id/participant/:participantId`

Retrieves a single participant from a program using the given participant ID.

#### Path Parameters

| Name                                            | Type   | Description                                            |
| ----------------------------------------------- | ------ | ------------------------------------------------------ |
| id<mark style="color:red;">\*</mark>            | string | The ID of the program to retrieve the participant from |
| participantId<mark style="color:red;">\*</mark> | string | The ID of the participant to retrieve                  |

#### Response

{% tabs %}
{% tab title="200" %}
Returns the participant object.

```json
{
    "id": "f8g9nl",
    "firstName": "Gavin",
    "lastName": "Belson",
    "loyaltyActionCount": 2,
    "monthlyloyaltyActionCount": 2,
    "prevMonthlyLoyaltyActionCount": 0,
    "rank": 10001,
    "monthlyRank": 20001,
    "monthlyRank": -1,
    "email": "gavin@hoolie.com",
    "createdAt": 1552404738928,
    "fraudRiskLevel": "LOW",
    "fraudReasonCode": "UNIQUE_IDENTIY",
    "isWinner": true,
    "loyaltyActionCountPerReward": {
        "crew_xfj7ic": 1
    },
    "monthlyLoyaltyActionCountPerReward": {
        "crew_xfj7ic": 1
    },
    "loyaltyActionSource": "DIRECT",
    "ipAddress": "127.0.0.1",
    "fingerprint": "cfb163bd47ba666c52cb932c521e47f4",
    "metadata": {
       "company": "Hooli, Inc",
       "companySize": 10000
    },
    "unsubscribed": false,
    "rewards": [
        {
            "id": "prew_9x8v1b",
            "rewardId": "crew_m5xm9l",
            "status": "FULFILLED",
            "unread": true,
            "isAvailable": true,
            "approved": true,
            "isFulfilled": true
        },
        {
            "id": "prew_vsdj34",
            "rewardId": "crew_w01fil",
            "status": "FULFILLED",
            "unread": true,
            "isAvailable": true,
            "approved": true,
            "isFulfilled": true
        },
        {
            "id": "prew_sj3kap",
            "rewardId": "crew_w01fil",
            "status": "FULFILLED",
            "unread": true,
            "isAvailable": true,
            "approved": true,
            "isFulfilled": true
        }
    ]
}
```

{% endtab %}
{% endtabs %}

### Get Participant by Email

<mark style="color:blue;">`GET`</mark> `https://api.loyaltysurf.com/v1/campaign/:id/participant/:participantEmail`

Retrieves a single participant from a program using the given participant email.

#### Path Parameters

| Name                                               | Type   | Description                                            |
| -------------------------------------------------- | ------ | ------------------------------------------------------ |
| id<mark style="color:red;">\*</mark>               | string | The ID of the program to retrieve the participant from |
| participantEmail<mark style="color:red;">\*</mark> | string | The email address of the participant to retrieve       |

#### Response

{% tabs %}
{% tab title="200" %}
Returns the participant object.

```json
{
    "id": "f8g9nl",
    "firstName": "Gavin",
    "lastName": "Belson",
    "loyaltyActionCount": 2,
    "monthlyloyaltyActionCount": 2,
    "prevMonthlyLoyaltyActionCount": 0,
    "rank": 10001,
    "monthlyRank": 20001,
    "monthlyRank": -1,
    "email": "gavin@hoolie.com",
    "createdAt": 1552404738928,
    "fraudRiskLevel": "LOW",
    "fraudReasonCode": "UNIQUE_IDENTIY",
    "isWinner": true,
    "loyaltyActionCountPerReward": {
        "crew_xfj7ic": 1
    },
    "monthlyLoyaltyActionCountPerReward": {
        "crew_xfj7ic": 1
    },
    "loyaltyActionSource": "DIRECT",
    "ipAddress": "127.0.0.1",
    "fingerprint": "cfb163bd47ba666c52cb932c521e47f4",    
    "metadata": {
       "company": "Hooli, Inc",
       "companySize": 10000
    },
    "unsubscribed": false,
    "rewards": [
        {
            "id": "prew_9x8v1b",
            "rewardId": "crew_m5xm9l",
            "status": "FULFILLED",
            "unread": true,
            "isAvailable": true,
            "approved": true,
            "isFulfilled": true
        },
        {
            "id": "prew_vsdj34",
            "rewardId": "crew_w01fil",
            "status": "FULFILLED",
            "unread": true,
            "isAvailable": true,
            "approved": true,
            "isFulfilled": true
        },
        {
            "id": "prew_sj3kap",
            "rewardId": "crew_w01fil",
            "status": "FULFILLED",
            "unread": true,
            "isAvailable": true,
            "approved": true,
            "isFulfilled": true
        }
    ]
}
```

{% endtab %}
{% endtabs %}

### Get Participants

<mark style="color:blue;">`GET`</mark> `https://api.loyaltysurf.io/v1/campaign/:id/participants`

Retrieves a list of participants in the program.

#### Path Parameters

| Name                                 | Type   | Description           |
| ------------------------------------ | ------ | --------------------- |
| id<mark style="color:red;">\*</mark> | string | The ID of the program |

#### Query Parameters

| Name   | Type    | Description                                                                                                                                                                                                                                                                                                           |
| ------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| nextId | string  | <p>(Optional)<br><br>The ID of the participant to start the next result set with. This can be used to skip through the list or to page the list results. Each response will provide a <code>nextId</code> value if there are more participants otherwise the <code>nextId</code> value will be <code>null</code>.</p> |
| limit  | integer | <p>(Optional)<br><br>The number of participants to return. Must be a value less than or equal to 100 which is currently the maximum we allow with this request.</p>                                                                                                                                                   |

#### Response

{% tabs %}
{% tab title="200" %}
Returns the participant objects.

```json
{
    "participants": [
        {
            "id": "f8g9nl",
            "firstName": "Gavin",
            "lastName": "Belson",
            "loyaltyActionCount": 2,
            "monthlyloyaltyActionCount": 2,
            "prevMonthlyLoyaltyActionCount": 0,
            "rank": 10001,
            "monthlyRank": 20001,
            "monthlyRank": -1,
            "email": "gavin@hoolie.com",
            "createdAt": 1552404738928,
            "fraudRiskLevel": "LOW",
            "fraudReasonCode": "UNIQUE_IDENTIY",
            "isWinner": true,
            "loyaltyActionCountPerReward": {
                "crew_xfj7ic": 1
            },
            "monthlyLoyaltyActionCountPerReward": {
                "crew_xfj7ic": 1
            },
            "loyaltyActionSource": "DIRECT",
            "metadata": {
               "company": "Hooli, Inc",
               "companySize": 10000
            },
            "unsubscribed": false,
            "rewards": [
                {
                    "id": "prew_9x8v1b",
                    "rewardId": "crew_m5xm9l",
                    "status": "FULFILLED",
                    "unread": true,
                    "isAvailable": true,
                    "approved": true,
                    "isFulfilled": true
                },
                {
                    "id": "prew_vsdj34",
                    "rewardId": "crew_w01fil",
                    "status": "FULFILLED",
                    "unread": true,
                    "isAvailable": true,
                    "approved": true,
                    "isFulfilled": true
                },
                {
                    "id": "prew_sj3kap",
                    "rewardId": "crew_w01fil",
                    "status": "FULFILLED",
                    "unread": true,
                    "isAvailable": true,
                    "approved": true,
                    "isFulfilled": true
                }
            ]
        },
        {
            "id": "wskljf9",
            "firstName": "Spongebob",
            "lastName": "Squarepants",
            "loyaltyActionCount": 0,
            "monthlyLoyaltyActionCount": 0,
            "prevMonthlyLoyaltyActionCount": 0,
            "rank": 1540,
            "monthlyRank": 1540,
            "prevMonthlyRank": 1799,
            "email": "spongebob@nickelodeon.com",
            "createdAt": 1552404738928,
            "fraudRiskLevel": "LOW",
            "fraudReasonCode": "UNIQUE_IDENTIY",
            "isWinner": true,            
            "loyaltyActionSource": "MANUAL",
            "metadata": {},
            "unsubscribed": false,
            "rewards": []
        }
    ],
    "limit": 2,
    "nextId": "1u7v0q"
}
```

{% endtab %}
{% endtabs %}

### Get Leaderboard

<mark style="color:blue;">`GET`</mark> `https://api.loyaltysurf.io/v1/campaign/:id/leaderboard`

Retrieves a list of participants in the program ordered by loyalty action count in ascending order.&#x20;

* **Monthly Loyalty Action Count Leaderboard**\
  \
  You can retrieve the program leaderboard ordered by the monthly loyalty action count by providing a query parameter `leaderboardType` with a value of `CURRENT_MONTH`. This will retrieve a list of participants ordered by monthly loyalty action.\
  \
  Monthly loyalty action counts are automatically reset at the end of each month for each participant within your program, therefore results of the monthly loyalty action count may vary.<br>
* **Previous Monthly Loyalty Action Count Leaderboard**\
  \
  Similar to the monthly program leaderboard, providing a query parameter of `leaderboardType` with a value of `PREV_MONTH` will retrieve a list of participants ordered by the previous monthly loyalty action count.\
  \
  Participants that did not exist within the program during the previous month will not be returned within the previous monthly leaderboard response.

#### Path Parameters

| Name                                 | Type   | Description           |
| ------------------------------------ | ------ | --------------------- |
| id<mark style="color:red;">\*</mark> | string | The ID of the program |

#### Query Parameters

| Name            | Type   | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| --------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| nextId          | string | <p>(Optional)<br><br>The ID of the participant to start the next result set with. This can be used to skip through the list or to page the list of results. Each response will provide a <code>nextId</code> value if there are more participants otherwise, <code>nextId</code> will be <code>null</code>.</p>                                                                                                                                                                                                                                                                                                                        |
| limit           | string | <p>(Optional)<br><br>The number of participants to return. Must be a value less than or equal to 100 and greater than 1. 100 is currently the maximum limit per reach request.</p>                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| leaderboardType | string | <p>(Optional)<br><br>Returns the leaderboard for the specified type if provided.<br><br><strong>Options</strong><br><code>ALL\_TIME</code> - Returns the all-time leaderboard, based on all-time loyalty action counts. <em>Default</em><br><br><code>CURRENT\_MONTH</code> -  Returns the current month's leaderboard, based on the current month's loyalty action counts.<br><br><code>PREV\_MONTH</code> - Returns the previous month's leaderboard, based on the previous month's loyalty action counts (With this option, participants that did not exist within the program during the previous month will not be returned).</p> |

#### Response

{% tabs %}
{% tab title="200" %}
Example response of the standard leaderboard with returned participants ordered by their loyalty action count.

If the `leaderboardType=CURRENT_MONTH` query parameter is provided, the resulting list would be ordered by monthly loyalty action count.

Similarly, if `leaderboardType=PREV_MONTH` is provided, the resulting list would be ordered by the previous monthly loyalty action count.

```json
{
    "participants": [
        {
            "id": "f8g9nl",
            "firstName": "Gavin",
            "lastName": "Belson",
            "loyaltyActionCount": 2,
            "monthlyloyaltyActionCount": 2,
            "prevMonthlyLoyaltyActionCount": 0,
            "rank": 10001,
            "monthlyRank": 20001,
            "monthlyRank": -1,
            "email": "gavin@hoolie.com",
            "createdAt": 1552404738928,
            "fraudRiskLevel": "LOW",
            "fraudReasonCode": "UNIQUE_IDENTIY",
            "isWinner": true,
            "loyaltyActionCountPerReward": {
                "crew_xfj7ic": 1
            },
            "monthlyLoyaltyActionCountPerReward": {
                "crew_xfj7ic": 1
            },
            "loyaltyActionSource": "DIRECT",
            "ipAddress": "127.0.0.1",
            "fingerprint": "cfb163bd47ba666c52cb932c521e47f4",            
            "metadata": {
               "company": "Hooli, Inc",
               "companySize": 10000
            },
            "unsubscribed": false,
            "rewards": [
                {
                    "id": "prew_9x8v1b",
                    "rewardId": "crew_m5xm9l",
                    "status": "FULFILLED",
                    "unread": true,
                    "isAvailable": true,
                    "approved": true,
                    "isFulfilled": true
                },
                {
                    "id": "prew_vsdj34",
                    "rewardId": "crew_w01fil",
                    "status": "FULFILLED",
                    "unread": true,
                    "isAvailable": true,
                    "approved": true,
                    "isFulfilled": true
                },
                {
                    "id": "prew_sj3kap",
                    "rewardId": "crew_w01fil",
                    "status": "FULFILLED",
                    "unread": true,
                    "isAvailable": true,
                    "approved": true,
                    "isFulfilled": true
                }
            ]
        },
        {
            "id": "wskljf9",
            "firstName": "Spongebob",
            "lastName": "Squarepants",
            "loyaltyActionCount": 0,
            "monthlyLoyaltyActionCount": 0,
            "prevMonthlyLoyaltyActionCount": 0,
            "rank": 10002,
            "monthlyRank": 1540,
            "prevMonthlyRank": 1799,
            "email": "spongebob@nickelodeon.com",
            "createdAt": 1552404738928,
            "fraudRiskLevel": "LOW",
            "fraudReasonCode": "UNIQUE_IDENTIY",
            "isWinner": true,            
            "loyaltyActionSource": "MANUAL",
            "ipAddress": "113.2.2.9",
            "fingerprint": "dau221bd47ba661c51ca933d531e47f5",
            "metadata": {},
            "unsubscribed": false,
            "rewards": []
        }
    ],
    "limit": 2,
    "nextId": "1u7v0q"
}
```

{% endtab %}
{% endtabs %}

### Add Participant

<mark style="color:green;">`POST`</mark> `https://api.loyaltysurf.io/v1/campaign/:id/participant`

Adds a participant to the program.

{% hint style="info" %}
**Tips:**

* The only required field is `email` .
* Though they are optional, we recommend passing in the fields `ipAddress`, `fingerprint`,  `firstName` , and `lastName` . These fields are used for anti-fraud purposes.
  {% endhint %}

#### Path Parameters

| Name                                 | Type   | Description                                         |
| ------------------------------------ | ------ | --------------------------------------------------- |
| id<mark style="color:red;">\*</mark> | string | The ID of the program to add the new participant to |

#### Request Body

| Name                                    | Type   | Description                                                                                                                                                                                                                                                                                                                                                                                 |
| --------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| email<mark style="color:red;">\*</mark> | string | The email address of the new participant                                                                                                                                                                                                                                                                                                                                                    |
| firstName                               | string | <p>(Optional, but recommended)</p><p><br>The first name of the new participant. If provided, this property will be used for anti-fraud measurements.</p>                                                                                                                                                                                                                                    |
| lastName                                | string | <p>(Optional, but recommended)</p><p><br>The last name of the new participant. If provided, this property will be used for anti-fraud measurements.</p>                                                                                                                                                                                                                                     |
| ipAddress                               | string | <p>(Optional, but recommended)</p><p><br>The IP address of the new participant. If provided, this property will be used for anti-fraud measurements.</p>                                                                                                                                                                                                                                    |
| fingerprint                             | string | <p>(Optional, but recommended)</p><p><br>The browser fingerprint of the new participant. If provided, this property will be used for anti-fraud measurements.<br><br>We recommend using a front-end library like <a href="https://github.com/fingerprintjs/fingerprintjs">fingerprintjs</a> to get the fingerprint value. Example value: <code>cfb163bd47ba666c52cb932c521e47f4</code>.</p> |
| metadata                                | object | <p>(Optional)<br><br>A shallow Object containing custom key/values to include with the participant data.<br><br>The following keys are restricted: <code>gdprAgreements</code></p>                                                                                                                                                                                                          |

#### Request Examples

{% tabs %}
{% tab title="cURL" %}
Here is an example `cURL` command you can use to call this API endpoint. Remember to replace `YOUR_PROGRAM_ID` with your program ID, `gavin@hooli.com` with the email address of the new participant you're adding, and `YOUR_API_KEY` with your API key.

We pass in `firstName`, `lastName`, `ipAddress` and `fingerprint` for anti-fraud purposes. `metadata` is used to save any custom data that can be retrieved later.

```bash
curl -X POST "https://api.loyaltysurf.io/v1/campaign/YOUR_PROGRAM_ID/participant" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
   "email": "gavin@hooli.com",
   "firstName": "Gavin",
   "lastName": "Belson",
   "ipAddress": "203.0.113.10",
   "metadata": {
      "companyName": "Hooli",
      "industry": "Software"
   }
}'
```

{% endtab %}
{% endtabs %}

#### Response

{% tabs %}
{% tab title="200" %}
Returns the participant object that was added to the program.

```json
{
    "id": "3vxff9",
    "firstName": "Gavin",
    "lastName": "Belson",
    "loyaltyActionCount": 0,
    "monthlyLoyaltyActionCount": 0,
    "prevMonthlyLoyaltyActionCount": 0,
    "rank": 10001,
    "monthlyRank": 10001,
    "rewards": [],
    "email": "gavin@hooli.com",
    "createdAt": 1558665537426,
    "loyaltyActionSource": "DIRECT",
    "fraudRiskLevel": "LOW",
    "fraudReasonCode": "UNIQUE_IDENTITY",
    "isWinner": false,
    "fraudRiskLevel": "LOW",
    "fraudReasonCode": "UNIQUE_IDENTITY",    
    "ipAddress": "127.0.0.1",
    "fingerprint": "cfb163bd47ba666c52cb932c521e47f4",    
    "metadata": {
       "company": "Hooli, Inc",
       "companySize": 10000
    }
    "unsubscribed": false,
}

```

{% endtab %}

{% tab title="400" %}
A `400` will be returned if validation fails on an input.

```javascript
{
  "name": "BadRequestError",
  "code": "BAD_REQUEST_ERROR",
  "message": "Invalid email foo",
  "errors": […],
  "status": 400,
  "supportUrl": "https://app.loyaltysurf.io/settings#contact_support"
}
```

{% endtab %}

{% tab title="422" %}
If the new participant is detected to be a high-level fraudster, and if anti-fraud settings are configured on the program, the participant will be blocked from joining with a status code of `422`.\
\
View the list of available `fraudRiskLevel` and `fraudReasonCode` options on the [Participant](https://docs.loyaltysurf.io/developer-tools/rest-api/api-objects#participant) Object. `matchedParticipantIds` will contain a list of matching fraudsters, but will be empty if an antifraud blacklist rule gets a match first.

```javascript
{
  "name": "ParticipantBlockedError",
  "code": "PARTICIPANT_BLOCKED_ERROR",
  "message": "Participant sarah.smith@email.com is blocked by antifraud rules.",
  "status": 422,
  "supportUrl": "https://app.loyaltysurf.io/settings#contact_support",
  "fraudRiskLevel": "HIGH",
  "fraudReasonCode": "BLACKLIST_MATCH",
  "matchedParticipantIds": [],
  "email": "sarah.smith@email.com",
  "ipAddress": "203.0.113.10",
  "fingerprint": null,
  "blockedAt": "2025-11-13T06:22:31.001Z"
}
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
**Metadata:** Please see our [API Guidelines ](/developer-tools/rest-api/api-guidelines#metadata)for more information about `metadata.`
{% endhint %}

### Update Participant by ID

<mark style="color:green;">`POST`</mark> `https://api.loyaltysurf.io/v1/campaign/:id/participant/:participantId`

Updates a participant within the program using the ID of the participant.

#### Path Parameters

| Name                                            | Type   | Description               |
| ----------------------------------------------- | ------ | ------------------------- |
| id<mark style="color:red;">\*</mark>            | string | The ID of the program     |
| participantId<mark style="color:red;">\*</mark> | string | The ID of the participant |

#### Request Body

| Name         | Type    | Description                                                                                                                                                                                                                                                                                                                                                                                        |
| ------------ | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| email        | string  | <p>(Optional)<br><br>The new email to assign to this participant.<br><br>If the given email is already assigned to another participant within the program, an error response will be returned.</p>                                                                                                                                                                                                 |
| firstName    | string  | <p>(Optional)<br><br>The first name of the participant.</p>                                                                                                                                                                                                                                                                                                                                        |
| lastName     | string  | <p>(Optional)<br><br>The last name of the participant</p>                                                                                                                                                                                                                                                                                                                                          |
| metadata     | object  | <p>(Optional)<br><br>A shallow Object containing custom values to include in the participant data.<br><br>If any existing metadata exists for the participant, any new values provided will be appended to the existing metadata, any existing values provided will overwrite and replace the existing metadata.\*<br><br>To remove any existing metadata set its value to <code>null</code>. </p> |
| unsubscribed | boolean | <p>(Optional)<br><br>The participant's unsubscribed status. If <code>true</code>, they will not receive any program emails.</p>                                                                                                                                                                                                                                                                    |

#### Response

{% tabs %}
{% tab title="200" %}
Returns the updated participant object.

```json
{
    "id": "f8g9nl",
    "firstName": "Gavin",
    "lastName": "Belson",
    "loyaltyActionCount": 2,
    "monthlyloyaltyActionCount": 2,
    "prevMonthlyLoyaltyActionCount": 0,
    "rank": 10001,
    "monthlyRank": 20001,
    "monthlyRank": -1,
    "email": "gavin@hoolie.com",
    "createdAt": 1552404738928,
    "fraudRiskLevel": "LOW",
    "fraudReasonCode": "UNIQUE_IDENTIY",
    "isWinner": true,
    "loyaltyActionCountPerReward": {
        "crew_xfj7ic": 1
    },
    "monthlyLoyaltyActionCountPerReward": {
        "crew_xfj7ic": 1
    },
    "loyaltyActionSource": "DIRECT",
    "metadata": {
       "company": "Hooli, Inc",
       "companySize": 10000
    },
    "unsubscribed": false,
    "rewards": [
        {
            "id": "prew_9x8v1b",
            "rewardId": "crew_m5xm9l",
            "status": "FULFILLED",
            "unread": true,
            "isAvailable": true,
            "approved": true,
            "isFulfilled": true
        },
        {
            "id": "prew_vsdj34",
            "rewardId": "crew_w01fil",
            "status": "FULFILLED",
            "unread": true,
            "isAvailable": true,
            "approved": true,
            "isFulfilled": true
        },
        {
            "id": "prew_sj3kap",
            "rewardId": "crew_w01fil",
            "status": "FULFILLED",
            "unread": true,
            "isAvailable": true,
            "approved": true,
            "isFulfilled": true
        }
    ]
}
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
**\***&#x50;lease see our [API Guidelines ](/developer-tools/rest-api/api-guidelines#metadata)for more information about `metadata.`
{% endhint %}

### Update Participant by Email

<mark style="color:green;">`POST`</mark> `https://api.loyaltysurf.io/v1/campaign/:id/participant/:participantEmail`

Updates a participant within the program using the email address of the participant.

#### Path Parameters

| Name                                               | Type   | Description           |
| -------------------------------------------------- | ------ | --------------------- |
| id<mark style="color:red;">\*</mark>               | string | The program ID        |
| participantEmail<mark style="color:red;">\*</mark> | string | The participant email |

#### Request Body

| Name         | Type    | Description                                                                                                                                                                                                                                                                                                                                                                                                 |
| ------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| email        | string  | <p>(Optional)<br><br>The new email to assign to the participant.<br><br>If the given email is already assigned to another participant within the program, an error response will be returned. </p>                                                                                                                                                                                                          |
| firstName    | string  | <p>(Optional)<br><br>The first name of the participant</p>                                                                                                                                                                                                                                                                                                                                                  |
| lastName     | string  | <p>(Optional)<br><br>The last name of the participant</p>                                                                                                                                                                                                                                                                                                                                                   |
| metadata     | object  | <p>(Optional)<br><br>A shallow Object containing custom values to include in the participant data.<br><br>If any existing metadata exists for the  participant, any new values provided will be appended to the existing participant metadata, any existing values provided will  overwrite and replace the existing metadata.\*<br><br>To remove existing metadata set its value to <code>null</code>.</p> |
| unsubscribed | boolean | <p>(Optional)<br><br>The participant's unsubscribed status. If <code>true</code>, they will not receive any program emails.</p>                                                                                                                                                                                                                                                                             |

#### Response

{% tabs %}
{% tab title="200" %}
Returns the updated participant object.

```json
{
    "id": "f8g9nl",
    "firstName": "Gavin",
    "lastName": "Belson",
    "loyaltyActionCount": 2,
    "monthlyloyaltyActionCount": 2,
    "prevMonthlyLoyaltyActionCount": 0,
    "rank": 10001,
    "monthlyRank": 20001,
    "monthlyRank": -1,
    "email": "gavin@hoolie.com",
    "createdAt": 1552404738928,
    "fraudRiskLevel": "LOW",
    "fraudReasonCode": "UNIQUE_IDENTIY",
    "isWinner": true,
    "loyaltyActionCountPerReward": {
        "crew_xfj7ic": 1
    },
    "monthlyLoyaltyActionCountPerReward": {
        "crew_xfj7ic": 1
    },
    "loyaltyActionSource": "DIRECT",
    "metadata": {
       "company": "Hooli, Inc",
       "companySize": 10000
    },   
    "unsubscribed": false,
    "rewards": [
        {
            "id": "prew_9x8v1b",
            "rewardId": "crew_m5xm9l",
            "status": "FULFILLED",
            "unread": true,
            "isAvailable": true,
            "approved": true,
            "isFulfilled": true
        },
        {
            "id": "prew_vsdj34",
            "rewardId": "crew_w01fil",
            "status": "FULFILLED",
            "unread": true,
            "isAvailable": true,
            "approved": true,
            "isFulfilled": true
        },
        {
            "id": "prew_sj3kap",
            "rewardId": "crew_w01fil",
            "status": "FULFILLED",
            "unread": true,
            "isAvailable": true,
            "approved": true,
            "isFulfilled": true
        }
    ]
}
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
**\***&#x50;lease see our [API Guidelines ](/developer-tools/rest-api/api-guidelines#metadata)for more information about `metadata.`
{% endhint %}

### Remove Participant by ID

<mark style="color:red;">`DELETE`</mark> `https://api.loyaltysurf.io/v1/campaign/:id/participant/:participantId`

Removes a participant within the program using the ID of the participant.

#### Path Parameters

| Name                                            | Type   | Description               |
| ----------------------------------------------- | ------ | ------------------------- |
| id<mark style="color:red;">\*</mark>            | string | The ID of the program     |
| participantId<mark style="color:red;">\*</mark> | string | The ID of the participant |

#### Response

{% tabs %}
{% tab title="200" %}
Returns a success response.

```json
{
    "success": true
}
```

{% endtab %}
{% endtabs %}

### Remove Participant by Email

<mark style="color:red;">`DELETE`</mark> `https://api.loyaltysurf.io/v1/campaign/:id/participant/:participantEmail`

Removes a participant within the program using the email address of the participant.

#### Path Parameters

| Name                                               | Type   | Description           |
| -------------------------------------------------- | ------ | --------------------- |
| id<mark style="color:red;">\*</mark>               | string | The camprogramaign ID |
| participantEmail<mark style="color:red;">\*</mark> | string | The participant email |

#### Response

{% tabs %}
{% tab title="200 Returns a success response." %}

```json
{
    "success": true
}
```

{% endtab %}
{% endtabs %}

***

## PARTICIPANT REWARDS ↓

### Get Participant Rewards by Participant ID

<mark style="color:blue;">`GET`</mark> `https://api.loyaltysurf.io/v1/campaign/:id/participant/:participantId/rewards`

Retrieves a list of rewards earned by a participant.

#### Path Parameters

| Name                                            | Type   | Description                          |
| ----------------------------------------------- | ------ | ------------------------------------ |
| id<mark style="color:red;">\*</mark>            | string | The ID of the program                |
| participantId<mark style="color:red;">\*</mark> | string | The participant's unique ID or email |

#### Query Parameters

| Name   | Type   | Description                                                                                                                                                                                                                                                                                                          |
| ------ | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| nextId | string | <p>(Optional)<br><br>The ID of the participant reward to start the next result set with. This can be used to skip through the list or to page the list of results. Each response will provide a <code>nextId</code> value if there are more rewards otherwise the <code>nextId</code> will be <code>null</code>.</p> |
| limit  | string | <p>(Optional)<br><br>The number of rewards to return. Must be a value less than or equal to 100, which is currently the maximum allowed per request.</p>                                                                                                                                                             |

#### Response

{% tabs %}
{% tab title="200" %}
In this example we are showing two rewards earned by the participant.\
\
`status` will be `"PENDING"` if the reward has not yet been fulfilled, otherwise it will be `"FULFILLED"`.

`isAvailable` will be `true` if the reward has been approved either manually or automatically (depending on the program settings) and fulfilled, otherwise it will be set to `false`.

```json
{
    "limit": 2,
    "nextId": "prew_v2qtfq",
    "rewards": [
        {
            "id": "prew_rr35mg",
            "rewardId": "crew_c6w1qo",
            "status": "PENDING",
            "unread": true,
            "approved": false,
            "approvedAt": null,
            "fulfilledAt": null,            
            "isAvailable": false,
            "isFulfilled": false
        },
        {
            "id": "prew_oltj0s",
            "rewardId": "crew_c6w1qo",
            "status": "FULFILLED",
            "unread": false,
            "approved": true,  
            "approvedAt": 1659453091744,
            "fulfilledAt": 1659453418901,     
            "isAvailable": true,
            "isFulfilled": true
        }
    ]
}
```

{% endtab %}

{% tab title="400" %}
Error response returned if the `limit` query parameter that is provided exceeds the maximum allowed amount.

```javascript
{
    "name": "BadRequestError",
    "code": "BAD_REQUEST_ERROR",
    "message": "Invalid request. Request params are missing or are invalid",
    "status": 400,
    "supportUrl": "https://app.loyaltysurf.io/settings#contact_support",
    "errors": [
        {
            "location": "query",
            "param": "limit",
            "value": "20",
            "msg": "Limit cannot be more than 10."
        }
    ],
    "level": "error",
    "timestamp": "2019-12-31T22:07:49.957Z"
}
```

{% endtab %}
{% endtabs %}

### Get Participant Rewards by Participant Email

<mark style="color:blue;">`GET`</mark> `https://api.loyaltysurf.io/v1/campaign/:id/participant/:participantEmail/rewards`

Retrieves a list of rewards earned by a participant.

#### Path Parameters

| Name                                               | Type   | Description                          |
| -------------------------------------------------- | ------ | ------------------------------------ |
| id<mark style="color:red;">\*</mark>               | string | The ID of the program                |
| participantEmail<mark style="color:red;">\*</mark> | string | The email address of the participant |

#### Query Parameters

| Name   | Type   | Description                                                                                                                                                                                                                                                                                                          |
| ------ | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| nextId | string | <p>(Optional)<br><br>The ID of the participant reward to start the next result set with. This can be used to skip through the list or to page the list of results. Each response will provide a <code>nextId</code> value if there are more rewards otherwise the <code>nextId</code> will be <code>null</code>.</p> |
| limit  | string | <p>(Optional)<br><br>The number of rewards to return. Must be a value less than or equal to 100, which is currently the maximum allowed per request.</p>                                                                                                                                                             |

#### Response

{% tabs %}
{% tab title="200" %}
In this example we are showing two rewards earned by the participant.\
\
`status` will be `"PENDING"` if the reward has not yet been fulfilled, otherwise it will be `"FULFILLED"`.

`isAvailable` will be `true` if the reward has been approved either manually or automatically (depending on the program settings) and fulfilled, otherwise it will be set to `false`.

```json
{
    "limit": 2,
    "nextId": "prew_v2qtfq",
    "rewards": [
        {
            "id": "prew_rr35mg",
            "rewardId": "crew_c6w1qo",
            "status": "PENDING",
            "unread": true,
            "approved": false,      
            "approvedAt": null,
            "fulfilledAt": null,  
            "isAvailable": false,
            "isFulfilled": false
        },
        {
            "id": "prew_oltj0s",
            "rewardId": "crew_c6w1qo",
            "status": "FULFILLED",
            "unread": false,
            "approved": true,    
            "approvedAt": 1659453091744,
            "fulfilledAt": 1659453418901,
            "isAvailable": true,
            "isFulfilled": true
        }
    ]
}
```

{% endtab %}

{% tab title="400" %}
Error response returned if the `limit` query parameter that is provided exceeds the maximum allowed amount.

```javascript
{
    "name": "BadRequestError",
    "code": "BAD_REQUEST_ERROR",
    "message": "Invalid request. Request params are missing or are invalid",
    "status": 400,
    "supportUrl": "https://app.loyaltysurf.io/settings#contact_support",
    "errors": [
        {
            "location": "query",
            "param": "limit",
            "value": "20",
            "msg": "Limit cannot be more than 10."
        }
    ],
    "level": "error",
    "timestamp": "2019-12-31T22:07:49.957Z"
}
```

{% endtab %}
{% endtabs %}

### Approve Participant Reward

<mark style="color:green;">`POST`</mark> `https://api.loyaltysurf.io/v2/campaign/:id/reward/:rewardId/approve`

Approve a reward that was earned by a participant.\
\
You should only use this endpoint if your reward automation level is set to *Manually approve rewards* (learn more [here](https://support.loyaltysurf.com/article/266-how-to-automate-rewards-fulfillment)). This means [`ParticipantRewards`](https://docs.loyaltysurf.io/integrate/rest-api/api-objects#participantreward) will be generated with `status: "PENDING"`, `approved: false`, and `isFulfilled: false`.&#x20;

Calling this endpoint to approve a reward will cause *New Participant Reward* emails to be sent out and automations/integrations to be triggered. If you are using Webhooks to automate rewards, a new [`PARTICIPANT_REACHED_A_GOAL`](https://docs.loyaltysurf.io/automate-rewards/webhooks/events-reference#participant_reached_a_goal) event will be emitted with `data.reward.approved` as `false`.

#### Path Parameters

| Name                                       | Type   | Description                                 |
| ------------------------------------------ | ------ | ------------------------------------------- |
| id<mark style="color:red;">\*</mark>       | string | The ID of the program                       |
| rewardId<mark style="color:red;">\*</mark> | string | The ID of the participant reward to approve |

#### Request Body

| Name    | Type    | Description                                                                                                                                                                                                                                           |
| ------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| fulfill | boolean | <p>(Optional)<br><br>Set <code>true</code> to mark the reward as fulfilled.</p><p></p><p>Fulfilling a reward does not trigger any emails or automations. It helps you stay organized when managing rewards from your LoyaltySurf admin dashboard.</p> |

#### Response

{% tabs %}
{% tab title="200" %}
Returns a success response.

```json
{
    "success": true
}
```

{% endtab %}

{% tab title="406" %}
Error response returned if a reward has already been approved for a participant.

```javascript
{
    "name": "InvalidRewardState",
    "code": "INVALID_REWARD_STATE",
    "message": "Invalid reward state. Reward has already been approved.",
    "status": 406,
    "supportUrl": "https://app.loyaltysurf.io/settings#contact_support",
    "level": "error",
    "timestamp": "2019-10-13T16:43:05.902Z"
}
```

{% endtab %}
{% endtabs %}

### Fulfill Participant Reward

<mark style="color:green;">`POST`</mark> `https://api.loyatysurf.io/v1/campaign/:id/reward/:rewardId/fulfill`

Fulfill a reward that was earned by a participant (this can only be done if the reward is already approved). When you call this endpoint, the [`ParticipantReward`](https://docs.loyaltysurf.io/integrate/rest-api/api-objects#participantreward) should have the following key-values: `status: "PENDING"`, `approved: true`, and `isFulfilled: false`.&#x20;

Fulfilling a reward does not trigger any emails or automations. It helps you stay organized when managing rewards from your LoyaltySurf admin dashboard.

#### Path Parameters

| Name                                       | Type   | Description                                 |
| ------------------------------------------ | ------ | ------------------------------------------- |
| id<mark style="color:red;">\*</mark>       | string | The ID of the program                       |
| rewardId<mark style="color:red;">\*</mark> | string | The ID of the participant reward to fulfill |

#### Response

{% tabs %}
{% tab title="200" %}
Returns a success response.

```json
{
    "success": true
}
```

{% endtab %}

{% tab title="406" %}
Error response returned if a reward has not been approved or has already been fulfilled.

```javascript
{
    "name": "InvalidRewardState",
    "code": "INVALID_REWARD_STATE",
    "message": "Invalid reward state. Reward has already been fulfilled.",
    "status": 406,
    "supportUrl": "https://app.loyaltysurf.io/settings#contact_support",
    "level": "error",
    "timestamp": "2019-10-13T16:43:05.902Z"
}
```

{% endtab %}
{% endtabs %}

### Remove Participant Reward

<mark style="color:red;">`DELETE`</mark> `https://api.loyaltysurf.io/v1/campaign/:id/reward/:rewardId`

Remove a reward that was earned by a participant.\
\
This only applies if your program was configured with manual reward approval and if the provided participant reward has not been approved.

#### Path Parameters

| Name                                       | Type   | Description                                |
| ------------------------------------------ | ------ | ------------------------------------------ |
| id<mark style="color:red;">\*</mark>       | string | The ID of the program                      |
| rewardId<mark style="color:red;">\*</mark> | string | The ID of the participant reward to remove |

#### Response

{% tabs %}
{% tab title="200" %}
Returns a success response.

```json
{
    "success": true
}
```

{% endtab %}

{% tab title="406" %}
Error response returned if a reward has already been approved and thus cannot be deleted.

```javascript
{
    "name": "InvalidRewardState",
    "code": "INVALID_REWARD_STATE",
    "message": "Invalid reward state. This reward has already been approved and cannot be removed.",
    "status": 406,
    "supportUrl": "https://app.loyaltysurf.io/settings#contact_support",
    "level": "error",
    "timestamp": "2019-10-17T16:43:05.902Z"
}
```

{% endtab %}
{% endtabs %}

***

## ANALYTICS ↓

### Get Campaign Analytics

<mark style="color:blue;">`GET`</mark> `https://api.loyaltysurf.io/v1/campaign/:id/analytics`

Retrieves the analytics for a program.

#### Path Parameters

| Name                                 | Type    | Description                                                                                                                                                                                     |
| ------------------------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id<mark style="color:red;">\*</mark> | string  | The ID of the program to retrieve analytics for.                                                                                                                                                |
| days                                 | integer | <p>(Optional) <br><br>The last number of days to retrieve analytics for. Defaults to <code>365</code> if no value is provided.  Maximum limit is <code>1825</code>.</p>                         |
| startDate                            | integer | <p>(Optional but required if <code>days</code> is not set)<br><br>The start date of the analytics timeframe as a Unix timestamp in milliseconds. Example value: <code>1592359793538</code>.</p> |
| endDate                              | integer | <p>(Optional but required if <code>days</code> is not set)<br><br>The end date of the analytics timeframe as a Unix timestamp in milliseconds. Example value: <code>1747879793538</code>.</p>   |

#### Response

{% tabs %}
{% tab title="200" %}
Returns an `analytics` object for the program.

```json
{
  "analytics": {
    "participants": 20,
    "loyaltyActions": 22,
    "rewardFormSubmissions": 34
  },
  "startDate": 1592359793538,
  "endDate": 1747879793538
}
```

{% endtab %}
{% endtabs %}


# API Guidelines

Follow these standard guidelines when interacting with LoyaltySurf APIs.

## Requests

* All requests should be made using HTTPS.
* JSON objects are recommended for POST requests, but standard parameters are accepted.
* All parameters are required unless otherwise specified.

## Responses

* Data is returned in JSON.
* Any non-`200` HTTP response code can be considered an error.

{% hint style="info" %}
**Tip:** Refer to [Response Codes](/developer-tools/rest-api/api-response-codes) for help in troubleshooting any errors.
{% endhint %}

## Rate Limits

All API requests made to LoyaltySurf (including client and server calls) are appropriately rate-limited to prevent excessive requests. If you exceed those limits, you will start receiving 429 error responses for any API calls that you make. Those 429 responses will have the following format.

```javascript
{
    "name": "RateLimit",
    "code": "RATE_LIMIT",
    "message": "You have reached your minute limit.",
    "status": 429,
    "supportUrl": "https://loyaltysurf.io/settings#contact_support",
    "policyName": "MINUTE",
    "level": "error",
    "timestamp": "2019-12-08T00:05:45.478Z"
}
```

The `message` and `policyName` will indicate which limit you hit (e.g. second, minute, or hour).

### Rate Headers

{% hint style="info" %}
&#x20;**NOTE:** These headers are only included for requests made using an API key.
{% endhint %}

| Header                                            | Description                                                                                                                                                                                                                                                                                                               |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`LoyaltySurf-RateLimit-Second-Limit`**          | The number of API requests that are allowed per second.                                                                                                                                                                                                                                                                   |
| **`LoyaltySurf-RateLimit-Second-Remaining`**      | The number of API requests remaining within the second policy.                                                                                                                                                                                                                                                            |
| **`LoyaltySurf-Retry-After-Second-Milliseconds`** | <p> The window of time that the  <code>LoyaltySurf-RateLimit-Second-Limit</code> and <code>LoyaltySurf-RateLimit-Second-Remaining</code> headers apply to.<br><br>For example, a value of 1000 would be a window of 1 second.</p><p></p><p>This value is only provided if the second policy is hit or exceeded.</p>       |
| **`LoyaltySurf-RateLimit-Minute-Limit`**          | The number of API requests that are allowed per minute.                                                                                                                                                                                                                                                                   |
| **`LoyaltySurf-RateLimit-Minute-Remaining`**      | The number of API requests remaining within the minute policy.                                                                                                                                                                                                                                                            |
| **`LoyaltySurf-Retry-After-Minute-Milliseconds`** | <p> The window of time that the  <code>LoyaltySurf-RateLimit-Minute-Limit</code> and <code>LoyaltySurf-RateLimit-Minute-Remaining</code> headers apply to.<br></p><p>For example, a value of 10000 would be a window of 10 seconds.</p><p></p><p>This value is only provided if the minute policy is hit or exceeded.</p> |
| **`LoyaltySurf-RateLimit-Hour-Limit`**            | The number of API requests that are allowed per hour.                                                                                                                                                                                                                                                                     |
| **`LoyaltySurf-RateLimit-Hour-Remaining`**        | The number of API requests remaining within the hour policy.                                                                                                                                                                                                                                                              |
| **`LoyaltySurf-Retry-After-Hour-Milliseconds`**   | <p>The window of time that the  <code>LoyaltySurf-RateLimit-Hour-Limit</code> and <code>LoyaltySurf-RateLimit-Hour-Remaining</code> headers apply to.<br></p><p>For example, a value of 600000 would be a window of 10 minutes.</p><p></p><p>This value is only provided if the hour policy is hit or exceeded.</p>       |

### Policies

The following are the rate limits for all API requests made using an API key.

| Policy     | Limit                   |
| ---------- | ----------------------- |
| **Second** | 30 requests / 5 seconds |
| **Minute** | 200 requests / minute   |
| **Hour**   | 10,000 requests / hour  |

### Slowdown Rate

For operations which update a resource (`PUT`, `POST`, `DELETE`), if the cumulative rate of requests exceed 60 requests per minute, a slowdown delay will be added to each request thereafter. The delay is equal to the number of exceeded requests multiplied by 100 milliseconds (ms).

**For example:**

* 61st request: 100ms delay
* 63rd request: 300ms delay
* 70th request: 1000ms delay

### Max Connections

In addition to the rate limits and slowdown rate, the number of concurrent connections to the REST API allowed per IP address is limited to three (3).

### Suggestions

If you find that you are still hitting call limits after implementing the below suggestions, please [contact us](https://app.loyaltysurf.io/settings#contact_support) and let us know as many details as possible (what APIs you are using, your use case, and which limits you are hitting).&#x20;

#### 1. Cache data for repeat calls

If your site or app uses data from LoyaltySurf on each page load, that data should be cached and loaded from that cache instead of being requested from the LoyaltySurf APIs each time. If you're making repeated requests to get participant information or program data for a custom implementation, the information from those calls should also be cached when possible.

#### 2. Use Webhooks to get updated data from LoyaltySurf

Webhooks are an excellent way for your application to receive updated information from LoyaltySurf without needing to call LoyaltySurf APIs. More details about using Webhooks can be found [here](/developer-tools/webhooks), with example data [here](/developer-tools/webhooks).

## Metadata

Certain LoyaltySurf objects, such as [`Participants`](/developer-tools/rest-api/api-objects#participant) and [`Rewards`](/developer-tools/rest-api/api-objects#reward) can have a special `metadata`parameter, which is useful for storing any custom information.

Learn more here:

{% content-ref url="/pages/fqjf9M1vI3vxCrXZfDoi" %}
[Metadata](/developer-tools/metadata)
{% endcontent-ref %}


# API Response Codes

Refer to the below response code glossary to help you troubleshoot any errors.

## Glossary

| **Response Code**                | **Messages**                                                                                                                                   | **REST API Explanation(s)**                                                                                                                                                                                                                                                                                                                                                                                                |
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `200 OK`                         | The request was successful!                                                                                                                    | N/A                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `400 Bad Request`                | Request validation failed on an input.                                                                                                         | Check that your inputs are entered correctly.                                                                                                                                                                                                                                                                                                                                                                              |
| `402 Usage Limit`                | Participant quota has been exhausted.                                                                                                          | You've reached a plan limit and will need to upgrade to the next tier.                                                                                                                                                                                                                                                                                                                                                     |
| `403 Not Authorized`             | You are not allowed to perform that action.                                                                                                    | <p>Your API key may be revoked or contain a typo, or you may be trying to interact with another user's program or participant data (which is not allowed).<br><br>Verify that your API key has access permission to the campaign (or if you are a team member, make sure you have an Admin role within the team or that you have API access to the campaign).</p>                                                          |
| `404 Resource Not Found`         | The requested resource does not exist.                                                                                                         | You may be trying to request a resource that does not exist or was deleted.                                                                                                                                                                                                                                                                                                                                                |
| `409 Conflict Duplicate Request` | Conflicting duplicate request.                                                                                                                 | <p>If a request is made but has not finished and that exact same request is made.</p><p></p><p>More details on the specific request will be provided within the returned error.</p>                                                                                                                                                                                                                                        |
| `422 Participant Blocked`        | Participant was detected as a high-risk fraudster and was blocked from joining.                                                                | <p>The person may be a high-risk fraudster, and has been blocked from entering the program. <a href="https://support.loyaltysurf.io/article/419-how-does-loyaltysurfs-anti-fraud-system-work">Learn more about how LoyaltySurf's anti-fraud system works</a>.<br><br>Please check that your program's anti-fraud settings are not set to <em>Strict</em>, or that you do not have the email or IP address blacklisted.</p> |
| `429 Too Many Requests`          | You have reached a rate limit.                                                                                                                 | You have sent too many requests in a given time OR You have reached the usage limit in your current plan.                                                                                                                                                                                                                                                                                                                  |
| `5XX Internal Server Error`      | The LoyaltySurf server is inaccessible or offline -- that's our fault! Check for updates on our [status page](https://status.loyaltysurf.io/). | N/A                                                                                                                                                                                                                                                                                                                                                                                                                        |


# Webhooks

Webhooks send data to your server when important events occur in your LoyaltySurf program. This lets you automatically fulfill any custom reward or update users in your database.

## Example scenarios

Here are a few scenarios in which you would use webhooks:

* If you want to have an internal points system for your users, webhooks let you add credits to users in your database every time a loyalty action happens.
* If you want to send custom rewards to your users based on the specific loyalty action they take, you can use webhooks to automate this.

## Getting started

### Step 1: Add a webhook URL to your program

1. Go to the *Options* step in the *Program Editor*.
2. In the *Set up integrations* sectio&#x6E;*,* click the *Webhooks* card. Then enter your webhook endpoint URL.
3. Publish/save your changes.

<figure><img src="/files/cJdNlJ3riotD7ZaeOg3N" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Tips:**

* You can test your webhook URL to see if it is set up properly and/or to see the different types of data from each webhook event. Simply click the *Test* button right next to the webhook URL input field.
* You can select the specific events to receive within the *advanced webhook settings* section.
* A total of 5 webhooks can be added per program.
  {% endhint %}

## **Retry logic**

If we are unable to deliver a webhook the first time, LoyaltySurf will attempt to redeliver your webhooks for several days with an exponential back off. After several days of failed attempts we will mark the webhook as undeliverable and it will no longer be retried.

LoyaltySurf uses a queue system with persistent storage, so if our webhook servers ever experience downtime or become unavailable, webhook events will be retried once the servers are restored. You can always check our [System Status page](https://loyaltysurf.io/status) for webhook health.

## **Next steps**

View [Examples](/developer-tools/webhooks/examples) of implementing webhooks, or view what the request payloads for webhook events look like:

* [When a participant reaches a reward goal](/developer-tools/webhooks/events-reference#participant_reached_a_goal)
* [When a new participant is added to the program](/developer-tools/webhooks/events-reference#new_participant_added)
* [When the program ends](/developer-tools/webhooks/events-reference#campaign_ended)


# Securing Your Webhooks (optional)

This is an optional step. For security purposes, you can add a webhook secret to limit requests sent to your webhook endpoint to those only coming from LoyaltySurf.

## Adding a secret

1. Go to the *Options* step in the *Program Editor*.
2. In the Webhooks integration, click *Show advanced webhook settings* and enter the secret (it can be any string of text).
3. Publish/save your changes.

<figure><img src="/files/RKShXIPRDuwLpM9reQhm" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Once your program has a webhook secret, a signature`LoyaltySurf-Signature` will be included in the header of all outgoing requests to your webhook endpoint.
{% endhint %}

## Validating payloads

When your secret token has been set, LoyaltySurf uses it to create a hash signature to include in the header of each event notification payload.\
\
The signature hash is passed along with each request in the header as `LoyaltySurf-Signature`. You will need to compute a hash once the payload is received and compare it against the`LoyaltySurf-Signature` value provided by LoyaltySurf within the header. Those steps are outlined below.

{% hint style="info" %}
The`LoyaltySurf-Signature` header contains a timestamp and a signature hash value. The timestamp is prefixed by `ts=`, and the signature value is prefixed by `v=`.
{% endhint %}

### **Step 1: Extract the timestamp and signature from the header**

Split the header using the `,` character as the separator to get a list of elements. Then split each element using the `=` character as the separator to get a key/value pair.\
\
The value for key/prefix `ts` corresponds to the timestamp and the `v` key/prefix corresponds to the signature you will use to compare your generated hash against.

{% hint style="info" %}
NOTE: `ts` is a Unix timestamp in milliseconds
{% endhint %}

### **Step 2: Prepare the signed payload string for comparison**

Achieve this by concatenating:

* The timestamp (as a string). AKA the value of `ts`
* The character `.`
* The actual JSON payload within the request body

### **Step 3: Determine the expected signature**

Compute an *HMAC* with a `SHA256` hash function. Use the endpoint's signing secret token as the key (which you added in the *Options* step in the *Program Editor*), and use the signed payload string from **Step 2** as the message.

### **Step 4: Compare signatures**

Compare the LoyaltySurf provided signature within the header to the expected signature. If they match then compute the difference between a current timestamp and the received timestamp `ts`. Then decide if the difference is within your tolerance.

{% hint style="info" %}
**Tip:** The timestamp comparison is completely optional but it will help to protect against timing attacks.
{% endhint %}

## View an example

[View an example here](/developer-tools/webhooks/examples#example-1-webhooks-with-secret)


# Examples

How to implement Webhooks for your LoyaltySurf program.

## Example 1: Webhooks

Below is a **Node.js + Express** example of what the code for your webhook endpoint could look like:

```javascript
//Your webhooks payload endpoint
app.post("/your/webhook/payload-url", function(req, res) {
  const body = req.body;
  
  try {
    if (body.event === 'PARTICIPANT_SUBMITTED_REWARD_FORM') {
      // Write code here to do something when a participant submits a reward form
      console.log(`${body.data.participant.email} just submitted a reward form: ${body.data.reward.description} - ${body.data.reward.cta}`);
      
    } else if (body.event === 'PARTICIPANT_REACHED_A_GOAL') {
      // Write code here to do something when a participant wins a reward
      console.log(`${body.data.participant.email} just won this reward: ${body.data.reward.description}`);

      // If the reward is approved
      if (body.data && body.data.reward && body.data.reward.approved) {
        // Do something
        
        // Optional: If you set metadata on the CampaignReward object, you can reference it:
        if (body.data.reward.metadata && body.data.reward.metadata["proRewardValue"]) {
            console.log(`${body.data.participant.email} earned an amount of ${body.data.reward.metadata["proRewardValue"]}.`);
        }        
      }
    } else if (body.event === 'NEW_PARTICIPANT_ADDED') {
      // Write code here to do something when a new participant is added    
      console.log(`${body.data.email} just joined via source: ${body.data.loyaltyActionSource}.`)
            
    } else if (body.event === 'CAMPAIGN_ENDED') {
      // Write code here to do something when a program ends
      console.log(`${body.data.name} just ended with ${body.data.loyaltyActionCount} total loyalty actions!`);
            
    }
  
  } catch (err) {
    res.status(400).end();
  }
  res.json({received: true});
});
```

{% hint style="info" %}
**Helpful tips:**

* To see the different sample data from webhook request payloads, see [Events](/developer-tools/webhooks/events-reference)
* If you use [reward metadata](https://docs.loyaltysurf.io/integrations/rest-api/api-guidelines#metadata) in your *New Participant Reward* events, your marketing team can update these values anytime in the future from the Program Editor without getting developers involved.
  {% endhint %}

## Example 2: Webhooks (with secret)

Below is a **Node.js + Express** example (using the [crypto-js](https://github.com/brix/crypto-js) library) of what the code for your webhook endpoint could look like:

```javascript
//Your webhooks payload endpoint
app.post("/your/webhook/payload-url", function(req, res) {
  const body = req.body;
  const signature = req.get("LoyaltySurf-Signature");
  
  try {
    // Validate the signature
    validateSignature(body, signature);
  
    // Do work!.....
    // Write your code in here...  
  
  } catch (err) {
    res.status(400).end();
  }
  res.json({received: true});
});

/**
 * Compares the LoyaltySurf header provided signature against the expected
 * signature.
 *
 * @param {Object} body the request body provided by Surf
 * @param {String} signature the signature hash value provided within the header of the request
 * @returns {Boolean} valid true if the expected matches the given
 * @throws {Exception} thrown if the expected signature value does not match the given
 */
const validateSignature = function(body, signature) {
  // Extract
  let parts = signature.split(",");
  // t value
  let timestamp = parts[0].split("=")[1];
  // v value
  let hash = parts[1].split("=")[1];
  // Generate hash
  let message = (timestamp + "." + JSON.stringify(body));
  let expected = CryptoJS.HmacSHA256(message, "YOUR-SECRET-TOKEN").toString();

  // Validate/Compare
  if(expected === hash) {
    return true;
  } else {
    throw new Error("Invalid Signature");
  }
}
```


# Events Reference

Below are sample request payloads you will receive based on the webhook event types you have selected for your program.

## `PARTICIPANT_SUBMITTED_REWARD_FORM`

**Description:** When a participant submits a reward form from the advocate portal

```json
{
  "event": "PARTICIPANT_SUBMITTED_REWARD_FORM",
  "createdAt": 1558345202613,
  "data": {
    "id": "prfs_def678",
    "participantId": "x9a7uu",
    "participantEmail": "richard@piedpiper.com",
    "rewardId": "crew_xlj123",
    "status": "UNREVIEWED",
    "formData": {
      "linkedinPostUrl": "https://linkedin.com/posts/sarah_s-my-review-of-pied-piper-8195769799870726145-Sr9b"
    },  
    "participant": {
      "id": "x9a7uu",
      "email": "richard@piedpiper.com",
      "firstName": "Richard",
      "lastName": "Hendricks",
      "notes": "",
      "rank": 9,
      "isWinner": true,
      "loyaltyActionCount": 11,
      "monthlyLoyaltyActionCount": 8,
      "prevMonthlyLoyaltyActionCount": 0,
      "createdAt": 1554431962667,
      "loyaltyActionSource": "DIRECT",
      "fraudRiskLevel": "LOW",
      "fraudReasonCode": "UNIQUE_IDENTITY",
      "metadata": {
        "piedPiperUserId": "12a39-8aajd-1dwiq",
        "companyName": "Pied Piper, Inc",
        "teamSize": "1-10"
      },
      "unsubscribed": false,
    },
    "reward": {
      "conversionsRequired": 1,
      "couponCode": "LI_25_GIFT",
      "createdAt": 1542560101404,
      "description": "Make a LinkedIn post mentioning Pied Piper",
      "subdescription": "Post must be less than 1 week old from date of submission",
      "instructions": "<div><p><strong>Helpful tips:</strong></p><ul><li>Talk about how you used to do things before using Pied Piper</li><li>Mention specific ROIs (e.g, time saved, revenue generated)</li></ul></div>",
      "cta": "Get $25",
      "submissionType": "URL",
      "submissionExampleUrl": "https://linkedin.com/posts/sarah_s-my-review-of-pied-piper-8195769799870726145-Sr9b",
      "submissionFormUrl": "https://linkedin.com/shareArticle",
      "submissionFormFields": [
        {
          "key": "linkedinPostUrl",
          "label": "Your LinkedIn Post URL",
          "placeholder": "Enter your LinkedIn Post URL here",
          "type": "text",
          "isRequired": true,
          "isVisible": true
        }
      ],
      "submissionFormButtonText": "Submit",
      "submissionFormMessages": {
        "required": "is required",
        "reCaptchaRequired": "You must pass the reCAPTCHA verification.",
        "success": "Thanks! We have received your response.",
        "error": "There was an error. Please try submitting again.",
        "alreadySubmitted": "You already submitted this form."
      },      
      "imageUrl": "https://res.cloudinary.com/loyaltysurf/image/upload/v1553218876/production/ls8shgq3qlwldljr8tl2.jpg",
      "limit": 1,
      "isUnlimited": true,
      "numberOfWinners": 3,
      "title": "LinkedIn Post Mention",
      "id": "crew_xlj123",
      "metadata": {
        "foo": "bar",
        "amount": "$25",
        "points": 1000
      }
    },
    "campaign": {
      "id": "ct8f71",
      "name": "Pied Piper Advocate Program",
      "currencyISO": "USD",
      "rewards": [
        {
          "id" : "crew_xlj123",        
          "title": "LinkedIn Post Mention",          
          "conversionsRequired": 1,
          "couponCode": "LI_25_GIFT",
          "description": "Make a LinkedIn post mentioning Pied Piper",
          "subdescription": "Post must be less than 1 week old from date of submission",
          "instructions": "<div><p><strong>Helpful tips:</strong></p><ul><li>Talk about how you used to do things before using Pied Piper</li><li>Mention specific ROIs (e.g, time saved, revenue generated)</li></ul></div>",
          "limit": 1,
          "isUnlimited": true,
          "limitDuration": "IN_TOTAL",
          "numberOfWinners": 3,
          "cta": "Get $25",
          "submissionType": "URL",
          "submissionExampleUrl": "https://linkedin.com/posts/sarah_s-my-review-of-pied-piper-8195769799870726145-Sr9b",
          "submissionFormUrl": "https://linkedin.com/shareArticle",
          "submissionFormFields": [
            {
              "key": "linkedinPostUrl",
              "label": "Your LinkedIn Post URL",
              "placeholder": "Enter your LinkedIn Post URL here",
              "type": "text",
              "isRequired": true,
              "isVisible": true
            }
          ],
          "submissionFormButtonText": "Submit",
          "submissionFormMessages": {
            "required": "is required",
            "reCaptchaRequired": "You must pass the reCAPTCHA verification.",
            "success": "Thanks! We have received your response.",
            "error": "There was an error. Please try submitting again.",
            "alreadySubmitted": "You already submitted this form."
          },      
          "imageUrl": "https://res.cloudinary.com/loyaltysurf/image/upload/v1553218876/production/ls8shgq3qlwldljr8tl2.jpg",
          "metadata": {
            "foo": "bar",
            "amount": "$25",
            "points": 1000
          }      
        }
      ]
    }
  }
}
```

***

## `PARTICIPANT_REACHED_A_GOAL`

**Description:** When a participant unlocks a new reward

{% hint style="info" %}

### **Important notes:**

* **If you have manual reward approval enabled for your program, events will be sent twice: (1) when the reward is pending approval and (2) when the reward is approved.** To discern between unapproved/approved rewards, use the `data.reward.approved` property (approved rewards will have `approved` as `true`).
* The `data.reward` object contains combined data from the [`CampaignReward`](https://docs.loyaltysurf.io/integrations/rest-api/api-objects#reward) and [`ParticipantReward`](https://docs.loyaltysurf.io/integrations/rest-api/api-objects#participantreward).
  * `data.reward.rewardId` represents the ID of the `CampaignReward` and will always be the same. You can find this ID from *Program Editor > 1. Rewards* and clicking the reward.
  * `data.reward.id` represents the ID of the `ParticipantReward` that was unlocked for the participant. This will be different for every new reward that the participant earns. You can find this ID by going to your admin dashboard and viewing the participant's rewards.
    {% endhint %}

```json
{
  "event": "PARTICIPANT_REACHED_A_GOAL",
  "createdAt": 1558345202613,
  "data": {
    "participant": {
      "id": "x9a7uu",
      "email": "richard@piedpiper.com",
      "firstName": "Richard",
      "lastName": "Hendricks",
      "notes": "",
      "rank": 9,
      "isWinner": true,
      "loyaltyActionCount": 11,
      "monthlyLoyaltyActionCount": 8,
      "prevMonthlyLoyaltyActionCount": 0,
      "createdAt": 1554431962667,
      "loyaltyActionSource": "DIRECT",
      "fraudRiskLevel": "LOW",
      "fraudReasonCode": "UNIQUE_IDENTITY",      
      "metadata": {
        "piedPiperUserId": "12a39-8aajd-1dwiq",
        "companyName": "Pied Piper, Inc",
        "teamSize": "1-10"
      },
      "unsubscribed": false,
    },
    "reward": {
      "approved": true,
      "conversionsRequired": 1,
      "couponCode": "LI_25_GIFT",
      "createdAt": 1542560101404,
      "approvedAt": 1659474941892,
      "fulfilledAt": null,
      "description": "Make a LinkedIn post mentioning Pied Piper",
      "subdescription": "Post must be less than 1 week old from date of submission",
      "instructions": "<div><p><strong>Helpful tips:</strong></p><ul><li>Talk about how you used to do things before using Pied Piper</li><li>Mention specific ROIs (e.g, time saved, revenue generated)</li></ul></div>",
      "cta": "Get $25",
      "submissionType": "URL",
      "submissionExampleUrl": "https://linkedin.com/posts/sarah_s-my-review-of-pied-piper-8195769799870726145-Sr9b",
      "submissionFormUrl": "https://linkedin.com/shareArticle",
      "submissionFormFields": [
        {
          "key": "linkedinPostUrl",
          "label": "Your LinkedIn Post URL",
          "placeholder": "Enter your LinkedIn Post URL here",
          "type": "text",
          "isRequired": true,
          "isVisible": true
        }
      ],
      "submissionFormButtonText": "Submit",
      "submissionFormMessages": {
        "required": "is required",
        "reCaptchaRequired": "You must pass the reCAPTCHA verification.",
        "success": "Thanks! We have received your response.",
        "error": "There was an error. Please try submitting again.",
        "alreadySubmitted": "You already submitted this form."
      },      
      "imageUrl": "https://res.cloudinary.com/loyaltysurf/image/upload/v1553218876/production/ls8shgq3qlwldljr8tl2.jpg",
      "limit": 1,
      "isUnlimited": true,
      "numberOfWinners": 3,      
      "title": "LinkedIn Post Mention",
      "rewardId": "crew_xlj123",
      "id" : "prew_ccm2ue",
      "participantId": "x9a7uu",
      "metadata": {
        "foo": "bar",
        "amount": "$25",
        "points": 1000
      }
    },
    "campaign": {
      "id": "ct8f71",
      "name": "Pied Piper Advocate Program",
      "currencyISO": "USD",
      "rewards": [
        {
          "id" : "crew_xlj123",        
          "title": "LinkedIn Post Mention",          
          "conversionsRequired": 1,
          "couponCode": "LI_25_GIFT",
          "description": "Make a LinkedIn post mentioning Pied Piper",
          "subdescription": "Post must be less than 1 week old from date of submission",
          "instructions": "<div><p><strong>Helpful tips:</strong></p><ul><li>Talk about how you used to do things before using Pied Piper</li><li>Mention specific ROIs (e.g, time saved, revenue generated)</li></ul></div>",
          "limit": 1,
          "isUnlimited": true,
          "limitDuration": "IN_TOTAL",          
          "numberOfWinners": 3,          
          "cta": "Get $25",
          "submissionType": "URL",
          "submissionExampleUrl": "https://linkedin.com/posts/sarah_s-my-review-of-pied-piper-8195769799870726145-Sr9b",
          "submissionFormUrl": "https://linkedin.com/shareArticle",
          "submissionFormFields": [
            {
              "key": "linkedinPostUrl",
              "label": "Your LinkedIn Post URL",
              "placeholder": "Enter your LinkedIn Post URL here",
              "type": "text",
              "isRequired": true,
              "isVisible": true
            }
          ],
          "submissionFormButtonText": "Submit",
          "submissionFormMessages": {
            "required": "is required",
            "reCaptchaRequired": "You must pass the reCAPTCHA verification.",
            "success": "Thanks! We have received your response.",
            "error": "There was an error. Please try submitting again.",
            "alreadySubmitted": "You already submitted this form."
          },      
          "imageUrl": "https://res.cloudinary.com/loyaltysurf/image/upload/v1553218876/production/ls8shgq3qlwldljr8tl2.jpg",
          "metadata": {
            "foo": "bar",
            "amount": "$25",
            "points": 1000
          }      
        }
      ]
    }    
  }
}
```

***

## `NEW_PARTICIPANT_ADDED`

**Description:** When a new participant is added to the program (via signups from the advocate portal, REST API, and manual adding/importing from the admin dashboard).

<pre class="language-json"><code class="lang-json">{
  "event": "NEW_PARTICIPANT_ADDED",
  "createdAt": 1558345215720,
  "data": {
    "id": "p88y0a",
    "email": "gavin.belson@hooli.com",
    "firstName": "Gavin",
    "lastName": "Belson",
    "notes": "This is obviously our competitor trying out our product!",
    "rank": 762,
    "isWinner": false,
    "loyaltyActionCount": 1,
    "monthlyLoyaltyActionCount": 0,
    "prevMonthlyLoyaltyActionCount": 0,
    "createdAt": 1554479231190,
    "loyaltyActionSource": "DIRECT",
    "fraudRiskLevel": "LOW",
    "fraudReasonCode": "UNIQUE_IDENTITY",    
    "loyaltyActionCountPerReward": {
    },
    "metadata": {
      "piedPiperUserId": "au71p-121x9-88faa",
      "companyName": "Hooli, Inc",
      "teamSize": "10,000+"
    },
    "unsubscribed": false,
    "campaign": {
      "id": "ct8f71",
      "name": "Pied Piper Advocate Program",
      "currencyISO": "USD",
      "rewards": [
        {
          "id" : "crew_xlj123",        
          "title": "LinkedIn Post Mention",          
          "conversionsRequired": 1,
          "couponCode": "LI_25_GIFT",
          "description": "Make a LinkedIn post mentioning Pied Piper",
          "subdescription": "Post must be less than 1 week old from date of submission",
          "instructions": "&#x3C;div>&#x3C;p>&#x3C;strong>Helpful tips:&#x3C;/strong>&#x3C;/p>&#x3C;ul>&#x3C;li>Talk about how you used to do things before using Pied Piper&#x3C;/li>&#x3C;li>Mention specific ROIs (e.g, time saved, revenue generated)&#x3C;/li>&#x3C;/ul>&#x3C;/div>",
          "limit": 1,
          "isUnlimited": true,
          "limitDuration": "IN_TOTAL",
          "numberOfWinners": 3,              
          "cta": "Get $25",
          "submissionType": "URL",
          "submissionExampleUrl": "https://linkedin.com/posts/sarah_s-my-review-of-pied-piper-8195769799870726145-Sr9b",
          "submissionFormUrl": "https://linkedin.com/shareArticle",
          "submissionFormFields": [
            {
              "key": "linkedinPostUrl",
              "label": "Your LinkedIn Post URL",
              "placeholder": "Enter your LinkedIn Post URL here",
              "type": "text",
              "isRequired": true,
              "isVisible": true
            }
          ],
          "submissionFormButtonText": "Submit",
          "submissionFormMessages": {
            "required": "is required",
            "reCaptchaRequired": "You must pass the reCAPTCHA verification.",
            "success": "Thanks! We have received your response.",
            "error": "There was an error. Please try submitting again.",
            "alreadySubmitted": "You already submitted this form."
          },      
          "imageUrl": "https://res.cloudinary.com/loyaltysurf/image/upload/v1553218876/production/ls8shgq3qlwldljr8tl2.jpg",
          "metadata": {
            "foo": "bar",
            "amount": "$25",
            "points": 1000
          }      
        }
      ]
    }    
<strong>  }
</strong>}
</code></pre>

***

## `PARTICIPANT_FRAUD_STATUS_UPDATED`

**Description:** When an existing participant's fraud status changes.

This webhook event is emitted if you manually mark a participant as a fraudster or non-fraudster from the LoyaltySurf admin dashboard. [Learn more here](https://support.loyaltysurf.io/article/419-how-does-loyaltysurfs-anti-fraud-system-work).

Here is an example of a `PARTICIPANT_FRAUD_STATUS_UPDATED` event where you can check the participant's fraud status via `data.participant.fraudRiskLevel` (it will be one of the following options: `"LOW"`, `"MEDIUM"`, or `"HIGH"`). You can also check the fraud reason code via `data.participant.fraudReasonCode` (see the [`Participant`](https://docs.loyaltysurf.io/developer-tools/rest-api/api-objects#participant) object for all fraud reason code options).

<pre class="language-json"><code class="lang-json">{
  "event": "PARTICIPANT_FRAUD_STATUS_UPDATED",
  "createdAt": 1558345215720,
  "data": {
    "participant": {
      "id": "p88y0a",
      "email": "gavin.belson@hooli.com",
      "firstName": "Gavin",
      "lastName": "Belson",
      "notes": "This is obviously our competitor trying out our product!",
      "rank": 762,
      "isWinner": false,
      "loyaltyActionCount": 1,
      "monthlyLoyaltyActionCount": 0,
      "prevMonthlyLoyaltyActionCount": 0,
      "createdAt": 1554479231190,
      "loyaltyActionSource": "DIRECT",
      "fraudRiskLevel": "LOW",
      "fraudReasonCode": "UNIQUE_IDENTITY",    
      "loyaltyActionCountPerReward": {
      },
      "metadata": {
        "piedPiperUserId": "au71p-121x9-88faa",
        "companyName": "Hooli, Inc",
        "teamSize": "10,000+"
      },
      "unsubscribed": false,
    },
    "campaign": {
      "id": "ct8f71",
      "name": "Pied Piper Advocate Program",
      "currencyISO": "USD",
      "rewards": [
        {
          "id" : "crew_xlj123",        
          "title": "LinkedIn Post Mention",          
          "conversionsRequired": 1,
          "couponCode": "LI_25_GIFT",
          "description": "Make a LinkedIn post mentioning Pied Piper",
          "subdescription": "Post must be less than 1 week old from date of submission",
          "instructions": "&#x3C;div>&#x3C;p>&#x3C;strong>Helpful tips:&#x3C;/strong>&#x3C;/p>&#x3C;ul>&#x3C;li>Talk about how you used to do things before using Pied Piper&#x3C;/li>&#x3C;li>Mention specific ROIs (e.g, time saved, revenue generated)&#x3C;/li>&#x3C;/ul>&#x3C;/div>",
          "limit": 1,
          "isUnlimited": true,
          "limitDuration": "IN_TOTAL",
          "numberOfWinners": 3,              
          "cta": "Get $25",
          "submissionType": "URL",
          "submissionExampleUrl": "https://linkedin.com/posts/sarah_s-my-review-of-pied-piper-8195769799870726145-Sr9b",
          "submissionFormUrl": "https://linkedin.com/shareArticle",
          "submissionFormFields": [
            {
              "key": "linkedinPostUrl",
              "label": "Your LinkedIn Post URL",
              "placeholder": "Enter your LinkedIn Post URL here",
              "type": "text",
              "isRequired": true,
              "isVisible": true
            }
          ],
          "submissionFormButtonText": "Submit",
          "submissionFormMessages": {
            "required": "is required",
            "reCaptchaRequired": "You must pass the reCAPTCHA verification.",
            "success": "Thanks! We have received your response.",
            "error": "There was an error. Please try submitting again.",
            "alreadySubmitted": "You already submitted this form."
          },      
          "imageUrl": "https://res.cloudinary.com/loyaltysurf/image/upload/v1553218876/production/ls8shgq3qlwldljr8tl2.jpg",
          "metadata": {
            "foo": "bar",
            "amount": "$25",
            "points": 1000
          }      
        }
      ]
    }    
<strong>  }
</strong>}
</code></pre>

***

## `CAMPAIGN_ENDED`

**Description:** When the program ends.

{% hint style="info" %}
**Please note:** Only the first 1,000 will be returned in the `winners` Array.
{% endhint %}

```json
{
  "event": "CAMPAIGN_ENDED",
  "createdAt": 1558345152138,
  "data": {
    "id": "ct8f71",
    "name": "Pied Piper Advocate Program",
    "participantCount": 5661,
    "startedAt": 1522432573250,
    "endedAt": 1533532422153,
    "status": "COMPLETE",
    "loyaltyActionCount": 1673,
    "winnerCount": 1673,
    "winners": [
      {
        "id": "x9a7uu",
        "email": "richard@piedpiper.com",
        "firstName": "Richard",
        "lastName": "Hendricks",
        "notes": "",
        "rank": 9,
        "isWinner": true,
        "loyaltyActionCount": 11,
        "monthlyLoyaltyActionCount": 8,
        "prevMonthlyLoyaltyActionCount": 0,
        "createdAt": 1554431962667,
        "loyaltyActionSource": "DIRECT",
        "fraudRiskLevel": "LOW",
        "fraudReasonCode": "UNIQUE_IDENTITY",        
        "metadata": {
          "piedPiperUserId": "12a39-8aajd-1dwiq",
          "companyName": "Pied Piper, Inc",
          "teamSize": "1-10"
        },
        "unsubscribed": false,
      }
    ],
    "rewards": [
      {
        "id" : "crew_xlj123",        
        "title": "LinkedIn Post Mention",          
        "conversionsRequired": 1,
        "couponCode": "LI_25_GIFT",
        "description": "Make a LinkedIn post mentioning Pied Piper",
        "subdescription": "Post must be less than 1 week old from date of submission",
        "instructions": "<div><p><strong>Helpful tips:</strong></p><ul><li>Talk about how you used to do things before using Pied Piper</li><li>Mention specific ROIs (e.g, time saved, revenue generated)</li></ul></div>",
        "limit": 1,
        "isUnlimited": true,
        "limitDuration": "IN_TOTAL",
        "numberOfWinners": 3,
        "cta": "Get $25",
        "submissionType": "URL",
        "submissionExampleUrl": "https://linkedin.com/posts/sarah_s-my-review-of-pied-piper-8195769799870726145-Sr9b",
        "submissionFormUrl": "https://linkedin.com/shareArticle",
        "submissionFormFields": [
          {
            "key": "linkedinPostUrl",
            "label": "Your LinkedIn Post URL",
            "placeholder": "Enter your LinkedIn Post URL here",
            "type": "text",
            "isRequired": true,
            "isVisible": true
          }
        ],
        "submissionFormButtonText": "Submit",
        "submissionFormMessages": {
          "required": "is required",
          "reCaptchaRequired": "You must pass the reCAPTCHA verification.",
          "success": "Thanks! We have received your response.",
          "error": "There was an error. Please try submitting again.",
          "alreadySubmitted": "You already submitted this form."
        },      
        "imageUrl": "https://res.cloudinary.com/loyaltysurf/image/upload/v1553218876/production/ls8shgq3qlwldljr8tl2.jpg",
        "metadata": {
          "foo": "bar",
          "amount": "$25",
          "points": 1000
        }      
      }
    ]
  }
}
```


# Metadata

Use metadata to save any custom data to Participants and Rewards to make your advocate program even more dynamic.

Certain LoyaltySurf objects, such as [`Participants`](https://docs.loyaltysurf.io/developer-tools/rest-api/api-objects#participant) and [`Rewards`](https://docs.loyaltysurf.io/developer-tools/rest-api/api-objects#reward) can have a special `metadata` parameter, which is useful for storing any custom information.

## Use Cases

Here are some examples of how you could use `metadata`:

* Issue different reward values to participants based on their different `metadata` properties. [Learn more here](https://support.loyaltysurf.io/article/437-how-to-set-up-dynamic-rewards).
* If you need to save custom data to a participant to display or use later in your own application.
* Attach custom key/value data to rewards in your program to retrieve later via the REST API when automating a reward via Webhooks or Zapier.

***

## **Overview**

### **Participant metadata**

* Can be set via the program editor, admin dashboard, and REST API
* Can be retrieved via REST API and is available via Webhooks
* Can be viewed from your admin dashboard and when you download your participants list

### **Reward metadata**

* Can be set via the program editor
* Can be retrieved via REST API and is available via Webhooks
* Can be used within LoyaltySurf emails

***

## Participant metadata

### Setting participant metadata

There are several different ways to save metadata to a participant.

#### **Program Editor**

From *Program Editor > 2. Design*, you can update the Signup/Login Form with custom fields. When a participant submits a new task from your advocate portal, they will need to submit the custom fields as well, which will be saved as participant metadata.

<figure><img src="https://docs.loyaltysurf.io/~gitbook/image?url=https%3A%2F%2F3285719719-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FTwFF4MDnpq2eL5eyOdtK%252Fuploads%252FrCwGhwlLxnCc1ArFDOMN%252Fimage.png%3Falt%3Dmedia%26token%3D507878ec-2375-4a95-a6bb-cb8235c995da&#x26;width=768&#x26;dpr=4&#x26;quality=100&#x26;sign=ea2005aa&#x26;sv=2" alt=""><figcaption><p>Update the Signup/Login Form in the program editor</p></figcaption></figure>

<figure><img src="https://docs.loyaltysurf.io/~gitbook/image?url=https%3A%2F%2F3285719719-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FTwFF4MDnpq2eL5eyOdtK%252Fuploads%252FKfkqkCewggUpgGR5YzJD%252Fimage.png%3Falt%3Dmedia%26token%3D435adee3-1346-468a-9986-5839a7e6dafa&#x26;width=768&#x26;dpr=4&#x26;quality=100&#x26;sign=afc619bf&#x26;sv=2" alt=""><figcaption><p>When a participant signs up for the first time on your advocate portal, custom fields will be saved as metadata</p></figcaption></figure>

#### **Admin Dashboard**

When you are viewing a participant from the LoyaltySurf admin dashboard, you can add or update their metadata.

<figure><img src="https://docs.loyaltysurf.io/~gitbook/image?url=https%3A%2F%2F3285719719-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FTwFF4MDnpq2eL5eyOdtK%252Fuploads%252FCkUGOXJRqrNzETAOl5gA%252Fimage.png%3Falt%3Dmedia%26token%3D6d7bab21-19be-4869-b629-0ec888ed839a&#x26;width=768&#x26;dpr=4&#x26;quality=100&#x26;sign=66bfc208&#x26;sv=2" alt=""><figcaption><p>Update a participant in the admin dashboard</p></figcaption></figure>

#### **REST API**

You can use these REST API endpoints to add or update a participant's metadata:

**For adding new participants:**

* [`/POST Trigger Loyalty Action by Email`](https://docs.loyaltysurf.io/integrations/rest-api/api-reference#trigger-loyalty-action-by-email)
* [`/POST Add Participant`](https://docs.loyaltysurf.io/integrations/rest-api/api-reference#add-participant)

**For updating existing participants:**

* [`/POST Update Participant by ID`](https://docs.loyaltysurf.io/integrations/rest-api/api-reference#update-participant-by-id)
* [`/POST Update Participant by Email`](https://docs.loyaltysurf.io/integrations/rest-api/api-reference#update-participant-by-email)

### Using participant metadata

#### REST API

You can use these REST API endpoints to retrieve a participant's metadata:

* [`/GET Participant by ID`](https://docs.loyaltysurf.io/developer-tools/rest-api/api-reference#get-participant-by-id)
* [`/GET Participant by Email`](https://docs.loyaltysurf.io/developer-tools/rest-api/api-reference#get-participant-by-email)

#### Webhooks

Participant metadata is returned on all participant payloads in [Webhook events](https://docs.loyaltysurf.io/developer-tools/webhooks/events-reference).

***

## Reward metadata

### Setting reward metadata

There is only one way to update reward metadata, from *Program Editor > 1. Rewards*.

<figure><img src="https://docs.loyaltysurf.io/~gitbook/image?url=https%3A%2F%2F3285719719-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FTwFF4MDnpq2eL5eyOdtK%252Fuploads%252FF68Gn021GyDk7X1QuzxW%252Fimage.png%3Falt%3Dmedia%26token%3Df35eddc9-e060-4c8d-89b9-148adbaba077&#x26;width=768&#x26;dpr=4&#x26;quality=100&#x26;sign=15f0af35&#x26;sv=2" alt=""><figcaption><p>Add/edit reward metadata from the program editor</p></figcaption></figure>

### Using reward metadata <a href="#policies-1" id="policies-1"></a>

You can then reference this reward metadata in different places of the Program Editor for UI purposes. For example, metadata will be available as an option by clicking the "+ Personalize" dropdown in emails.

***

### Tutorial

View the following guide to help you add reward metadata and reference it throughout participant-facing elements of your LoyaltySurf program.

#### Webhooks

Reward metadata is returned on all `campaign` payloads in [Webhook events](https://docs.loyaltysurf.io/developer-tools/webhooks/events-reference). You can reference metadata when automating rewards using webhooks. This is useful so that your marketing team can make changes anytime to reward values in the future without getting developers involved.

<details>

<summary><strong>Guide to implementing reward metadata</strong></summary>

## 1. Add metadata to a reward

* Go to *Campaign Editor > 1. Rewards*.
* Open the reward you want to edit.
* Click "Advanced reward settings" and scroll to the Metadata section.
* Click "Add Metadata", and then enter `rewardForAdvocate` for the key, and `25` for the value.

<figure><img src="/files/TiqvCFnfXpVaKvqpxlQl" alt=""><figcaption></figcaption></figure>

***

## 2. Update campaign emails

* Go to *Campaign Editor > 3. Emails*.
* Open the "New Participant Reward Submission" email.
* In the Email Body section, type in `Once verified, you'll receive an email with instructions on how to redeem your $`
* Click the "+ Personalize" button, and from the dropdown select the reward metadata you added from step 1 above. Your text should now say something like this: `Once verified, you'll receive an email with instructions on how to redeem your ${{campaignReward['7w6ntg']['rewardForAdvocate']}}`
* Preview the changes on the right-side section to make sure everything is rendering properly. You should see your text rendering like this: `Once verified, you'll receive an email with instructions on how to redeem your $25`
* Repeat the above steps for all emails that you want to reference reward metadata in.

<figure><img src="/files/yd66TqcPMge8wPIxdGHV" alt=""><figcaption></figcaption></figure>

***

## 3. Final review and testing

Make sure to thoroughly [test your campaign](https://support.loyaltysurf.io/article/417-how-can-i-test-my-loyalty-program) to ensure that reward metadata displays correctly.

</details>

## Policies <a href="#policies-1" id="policies-1"></a>

The following are the policies when creating or updating metadata.

| Policy                  | Limit            |
| ----------------------- | ---------------- |
| **Metadata Key**        | 40 characters    |
| **Metadata Value**      | 500 characters   |
| **Total Metadata Keys** | 50 keys / object |
| **Key Characters**      | Alphanumeric     |

{% hint style="info" %}
**Note the following:**

* All metadata keys will be converted to camelCase. For example, if you provide a key "My Metadata Key" that key will be converted to `myMetadataKey` .
* **Important:** Do not store any sensitive information (personally identifiable information, such as credit cards and social security numbers) as metadata within LoyaltySurf, as metadata rewards are accessible from the JavaScript SDK.
  {% endhint %}


# Chargebee

Automatically apply Chargebee coupons, credits, or trial extensions as rewards.

{% hint style="info" %}
**Note:** The Chargebee integration is only available to users on the LoyaltySurf Business plan or higher.
{% endhint %}

Even if the Chargebee customer's email address changes, LoyaltySurf will track those changes to ultimately ensure the Chargebee coupon, credit, or trial extension gets applied to the right Chargebee customer.

### How to Set Up

{% hint style="info" %}
You must first select a default currency for your LoyaltySurf campaign in order to use Chargebee.\
\
Your default currency determines whether Chargebee coupons, credits, or trial extensions can be applied to your Chargebee subscriptions. For example, if your default currency is USD, then the coupon, credit, or trial extension you set up can only be redeemed for Chargebee subscriptions using USD.
{% endhint %}

**Step 1**: In *Campaign Editor > 4. Options > Integrations*, open the Chargebee integration card and enter your [Chargebee site](https://www.chargebee.com/docs/1.0/sites-intro.html), [Chargebee API key](https://www.chargebee.com/docs/2.0/api_keys.html), and [Chargebee product catalog version](https://www.chargebee.com/docs/2.0/product-catalog.html) for both live and test mode.

<figure><img src="/files/wINyN2NVrwQ2rt2AU8g5" alt=""><figcaption></figcaption></figure>

**Step 2:** Once connected, press the 'Connect A Reward' button and select your reward.

<figure><img src="/files/g054sazW3XBrwJ7nuE18" alt=""><figcaption></figcaption></figure>

**Step 3:** Click on either coupon, credit, or trial extensio&#x6E;*.* If 'Coupon' is selected, enter the details of the coupon, including the name, type, and discount. You can also click *Show advanced coupon* settings to view more customization settings.

{% hint style="info" %}
**Advanced feature tip: Issue different reward amounts by using dynamic rewards**

Dynamic rewards let you offer different reward values based on specific attributes of the referred friend (such as the pricing plan they signed up for) or referrer (such as their partner status).

For example, you can award $50 in credits to winners when their referral signs up for your base plan or $100 in credits when they sign up for a higher-costing plan.

[Learn more →](https://support.loyaltysurf.io/article/437-how-to-set-up-dynamic-rewards)
{% endhint %}

<figure><img src="/files/WeW1YPTsY1fCyDmqUK45" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Note:** By default, coupons are recommended. However, if you want rewards to be stackable (e.g., $10 off for every loyalty action), you will want to use credits.
{% endhint %}

If 'Credit' is selected, enter the credit description and amount to apply to the Chargebee customer's account every time this reward is unlocked.

<figure><img src="/files/Ymlxd4mjLez13lp7oHX0" alt=""><figcaption></figcaption></figure>

To extend the trial period, select 'Trial Extension', and specify the number of days.

{% hint style="info" %}
Chargebee trial extensions only work for subscriptions labeled <mark style="color:red;">`IN TRIAL`</mark>`.`
{% endhint %}

<figure><img src="/files/TcSsOctFYHBC1zRTcUt6" alt=""><figcaption></figcaption></figure>

**Step 4:** When you're done, click the Save button.<br>

**Step 5 (optional):** To ensure the legitimacy of your campaign and prevent any fraudulent activities, it is advisable to establish Chargebee webhooks. By setting up webhooks, LoyaltySurf can monitor any modifications customers make to their email addresses on Chargebee using the customer's unique Chargebee ID.

<figure><img src="/files/saUGr8s1GanX4nOZTdHT" alt=""><figcaption></figcaption></figure>

**Step 6:** Once you have enabled webhooks, create a new Chargebee webhook and return to the LoyaltySurf Chargebee integration and input the username and password for your Chargebee webhook. For guidance on setting up your webhook, click on this [link](https://www.chargebee.com/docs/2.0/webhook_settings.html).

<figure><img src="/files/2KQbakWPpwfAWnxBtQx5" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
**Important Note:** Only the following event should be selected for your Chargebee webhook:

* Customer Changed

Remember to toggle on "Exclude card information from webhook call".
{% endhint %}

<figure><img src="/files/ylEESsAFuePfZLEnq0Oe" alt=""><figcaption></figcaption></figure>

### Test Mode

Our Chargebee integration comes with a test mode that allows you to test coupons, credits, and trial extensions. When you toggle *Test Mode* on, LoyaltySurf will only apply coupons, credits, or trial extensions to Chargebee subscriptions that exist within your Chargebee account when test mode is toggled on.&#x20;

To enable test mode, toggle the *Test Mode* switch at the bottom-right, then connect a reward(s).

<figure><img src="/files/MRMgBnr71akmOVCAVkex" alt=""><figcaption></figcaption></figure>

Please note that the rewards you connect to while *Test Mode* is enabled are completely separate from those you connect to in live mode.

<figure><img src="/files/90jo3S9qJwfvzzJKNXpF" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
**Important note:** When you go live with your campaign, please make sure to switch back to live mode. Otherwise, rewards will not be issued in live mode while test mode is enabled.
{% endhint %}

### Troubleshooting Tips

If there is an issue with applying Chargebee coupons, credits, or trial extensions, LoyaltySurf will send out a notification email to the campaign owner. The issue will also be stated in the participant's detail page when you view their reward or when you view the participant's activity logs.

Here are some common reasons why there may be failures:

* The customer with the associated LoyaltySurf participant email address does not exist in Chargebee (please make sure to check live or test mode depending on if you have toggled on Test Mode in the LoyaltySurf Chargebee integration)
* If dynamic reward rules are enabled for the Chargebee reward, there may have been no matching rule found.
* If you were expecting a reward to be applied in live mode, double-check that you do not have test mode enabled.
* If your Chargebee customer changes their email address right before the Chargebee reward gets applied, they may not receive it. This is because LoyaltySurf relies on Chargebee sending out a webhook event which notifies LoyaltySurf of the Chargebee customer's new email address, but if there is not at least a few minutes before the reward event, LoyaltySurf will not know about the Chargebee customer's email change.

If there was a failure, you will need to manually issue the Chargebee reward from your [Chargebee dashboard](https://app.chargebee.com/).

#### Other notes:

* If you have manual reward approval enabled for your campaign: Chargebee coupons, credits, and trial extensions will only be issued to the winner(s) after you approve the reward.
* If the loyalty action was triggered recently (or if the reward was approved recently), please allow for a few minutes of server processing before viewing the participant's reward from your LoyaltySurf admin dashboard. During this time, the data displayed for the participant's reward may not be accurate.


# HubSpot

Trigger loyalty actions on HubSpot deal stage changes.

{% hint style="info" %}
**Note:** The Hubspot integration is only available to users on a LoyaltySurf paid plan.
{% endhint %}

### Description

A use-case for this would be if you want to automatically send out gift cards to leads who who complete a demo call with your sales team. This would be triggered after your sales team updates their HubSpot deal stage.

LoyaltySurf will check if the HubSpot deal's associated contacts' email addresses match a LoyaltySurf participant's email address. If a match is found, then a loyalty action will trigger, giving loyalty action credit to the participant and unlocking any rewards, if applicable.

Here's how to set up the HubSpot integration:

### **How to Set Up**

**Step 1**: In *Campaign Editor > 4. Options > Integrations*, click the *Connect to HubSpot* button.

<figure><img src="/files/2lUpPgxcQOMW66aaX2Zm" alt=""><figcaption></figcaption></figure>

**Step 2:** Once connected, toggle the switch to enable the *Loyalty Action Trigger,* then press the 'Connect A Reward' button to link your reward.

<figure><img src="/files/Yr7NhZb0812C2yfjWs2S" alt=""><figcaption></figcaption></figure>

**Step 3:** Select a HubSpot pipeline, then select a deal stage.

<figure><img src="/files/WDQO5GauFPSrAaG3JsdC" alt=""><figcaption></figcaption></figure>

**(Optional) Step 4:** Add a loyalty action trigger hold period by toggling the *Show advanced settings* section.

{% hint style="info" %}
**Note:** The loyalty action trigger hold period is useful for ensuring that deals that fall through do not count as loyalty actions. During this hold period, the loyalty action trigger will be canceled completely if a deal does not retain the stage you selected.
{% endhint %}

### Troubleshooting Tips

* When testing out the HubSpot integration, make sure to view participants' activity logs for details that can help you troubleshoot any issues.
* Events from HubSpot, such as changes in a deal stage, are sent to LoyaltySurf asynchronously and may take up to a minute or longer to process, depending on the system load. As a result, LoyaltySurf can only trigger the corresponding loyalty action once it has received the event. To manage this process, we use a message queue. Therefore, please be patient if you do not see a loyalty action trigger immediately.


# PayPal

Automatically send one-time PayPal payouts as rewards.

{% hint style="info" %}
**Note:** The PayPal integration is only available to users on the LoyaltySurf Business plan or higher. The following countries and currencies are supported [here](https://developer.paypal.com/docs/payouts/standard/reference/country-feature/).
{% endhint %}

### **Description** <a href="#description-1" id="description-1"></a>

When a LoyaltySurf participant unlocks a reward, send them a one-time PayPal payout. The payout will be sent to the LoyaltySurf participant's email address.

### Fee Disclosures <a href="#how-to-set-up-1" id="how-to-set-up-1"></a>

* The following fees are applied on payouts made through PayPal's API:
  * United States: USD 0.25 per U.S. transaction
  * International: 2% of the recipient payment amount, up to a certain amount
* Individual payments cannot exceed USD 20,000.
* No fees are charged to the recipient.

### **How to Set Up** <a href="#how-to-set-up" id="how-to-set-up"></a>

To utilize the PayPal payout feature, you'll need the following (full PayPal payout instructions can be found [here](https://developer.paypal.com/docs/payouts/standard/)) before setting up:&#x20;

1. A PayPal business account (you can [sign up for a PayPal business account here](https://www.paypal.com/bizsignup/))
2. Get [access to PayPal Payouts](https://www.paypal.com/payoutsweb/landing?_ga=1.173127584.2099703533.1638980894)
3. A confirmed [identity](https://www.paypal.com/policy/flow/verifyCip?_ga=1.118076554.2099703533.1638980894), [email](https://www.paypal.com/settings/email/confirm), and [bank account linked to your PayPal business account](https://www.paypal.com/businessexp/money/addbank)
4. Sufficient funds in your PayPal business account (make sure to cover enough for payout totals and fees)
5. When you connect to PayPal within LoyaltySurf, make sure to login with your primary PayPal account holder's credentials. Using a team member's PayPal credentials can result in permission issues when sending out payouts

{% hint style="info" %}
You must first select a default currency for your LoyaltySurf campaign in order to use PayPal.&#x20;
{% endhint %}

**Step 1**: In *Campaign Editor > 4. Options > Integrations*, click the *Connect to PayPal* button

<figure><img src="/files/meSMJ2CzuKNRK6wSHxWX" alt=""><figcaption></figcaption></figure>

**Step 2:** Once connected, press the 'Connect A Reward' button and select your reward.

<figure><img src="/files/Vvd8cvwgnHneuvz3ozhj" alt=""><figcaption></figcaption></figure>

**(Optional) Step 3:** Add a customized email subject and message to the PayPal payout by toggling the *Show advanced payout settings* section.

{% hint style="info" %}
**Advanced feature tip: Issue different reward amounts by using dynamic rewards**

Dynamic rewards let you offer different reward values based on specific attributes of the participant (such as the pricing plan they signed up for).

For example, you can issue $50 payouts for normal users and $100 payouts for VIP users.

[Learn more →](https://support.loyaltysurf.io/article/437-how-to-set-up-dynamic-rewards)
{% endhint %}

<figure><img src="/files/9woSalU4cWRTBCCNJpgH" alt=""><figcaption></figcaption></figure>

Step 4: Then hit Save. Now, anytime this reward is unlocked by a winning participant, a PayPal payout will be sent to the PayPal customer associated with the LoyaltySurf participant email address. If enabled, on their first payout, the participant will receive a confirmation email so they can choose the PayPal email address they want to use.

### Troubleshooting Tips

If there is an issue with PayPal payouts being out to winners, LoyaltySurf will send out a notification email to the campaign owner. The issue will also be stated in the participant's detail page when you view their reward or when you view the participant's activity logs.

Here are some common reasons why there may be failures:

* There may be an issue with your PayPal account. For payouts to work, you must have a verified business PayPal account with access to PayPal payouts and sufficient funds. [View the requirements](https://docs.loyaltysurf.io/integrations/paypal#how-to-set-up).
  * Make sure that the account you connected to PayPal within LoyaltySurf is your primary PayPal account holder. Using a team member's PayPal credentials can result in permission issues when sending out payouts.
* If dynamic reward rules are enabled for the PayPal reward, there may have been no matching rule found.
* If you're not seeing a PayPal confirmation email being sent out (which is sent when a participant first unlocks their first PayPal payout), you must first approve the reward. This only applies if you have manual reward approval enabled for your campaign.

If there was a failure, you will need to manually issue the payout from your [PayPal dashboard](https://paypal.com/myaccount/transfer/homepage/pay).

#### **How to confirm if a payout was sent:**

1. Go to your [PayPal Transactions History](https://www.paypal.com/unifiedtransactions/?filter=0\&query=) page to view all transactions

{% hint style="info" %}
You can disregard the "Mass Payment" items. They are not duplicate payments, but rather records of GrowSurf's usage of the PayPal API to send out payouts via Mass Pay.
{% endhint %}

<figure><img src="/files/iLYQRuHi12gdIk5vUM74" alt=""><figcaption><p>PayPal Transactions History</p></figcaption></figure>

2. Click "Filter", select "Payments sent" for "Transaction type", then click "Apply Filters". You can now browse the list to confirm if payouts were sent out to LoyaltySurf participants.

<figure><img src="/files/xHmbp1sgxFhOjDPol2FL" alt=""><figcaption><p>Filter transactions</p></figcaption></figure>

#### Other notes:

* If the LoyaltySurf participant does not have a PayPal account (or if it is unconfirmed), they will receive an email from PayPal notifying them to sign up for one or to confirm their account.
* If you have manual reward approval enabled for your campaign: PayPal payouts will only be issued to the winner(s) only after you approve the reward.
* If the loyalty action was triggered recently (or if the reward was approved recently), please allow for a few minutes of server processing before viewing the participant's reward from your LoyaltySurf admin dashboard. During this time, the data displayed for the participant's reward may not be accurate.


# Recurly

Automatically apply Recurly coupons, credits, or trial extensions as rewards.

{% hint style="info" %}
**Note:** The Recurly integration is only available to users on the LoyaltySurf Business plan or higher.
{% endhint %}

### How to Set Up

{% hint style="info" %}
You must first select a default currency for your LoyaltySurf campaign in order to use Recurly.\
\
Your default currency determines whether Recurly coupons, credits, or trial extensions can be applied to your Recurly subscriptions. For example, if your default currency is USD, then the coupon, credit, or trial extension you set up can only be redeemed for Recurly subscriptions using USD.
{% endhint %}

**Step 1**: In *Campaign Editor > 3. Options > Integrations*, open the Recurly integration card, and enter your [Recurly API key](https://app.recurly.com/go/developer/api_access) and test API key.

{% hint style="info" %}

* For the "Enter your Recurly API Key" field, please enter an API key from your production Recurly instance
* For the "Enter your Recurly Test API Key" field, you can use the same API key as above, otherwise if you have a separate Recurly instance you use just for development/testing purposes, please enter that one.
  {% endhint %}

<figure><img src="/files/7oRJxBdAYcIwAedP9Hc7" alt=""><figcaption></figcaption></figure>

**Step 2:**  Once connected, press the 'Connect A Reward' button and select your reward.

<figure><img src="/files/qhWYQR6sGzUy1ofVo6MW" alt=""><figcaption></figcaption></figure>

**Step 3:** Click on either coupon, credit, or trial extensio&#x6E;*.* If 'Coupon' is selected, enter the details of the coupon, including the name, type, and discount. You can also click *Show advanced coupon* settings to view more customization settings.

{% hint style="info" %}
**Advanced feature tip: Issue different reward amounts by using dynamic rewards**

Dynamic rewards let you offer different reward values based on specific attributes of the participant (such as the pricing plan they signed up for).

For example, you can issue $50 in credits for normal users and $100 in credits for VIP users.

[Learn more →](https://support.loyaltysurf.io/article/437-how-to-set-up-dynamic-rewards)
{% endhint %}

<figure><img src="/files/1EuJ4cOcpiZBKatTo6us" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Note:** By default, coupons are recommended. However, if you want rewards to be stackable (e.g., $10 off for every loyalty action), you will want to use credits.
{% endhint %}

If 'Credit' is selected, enter the credit description and amount to apply to the Recurly customer's account every time this reward is unlocked.

<figure><img src="/files/tX2eiEI0wejNoUZWionS" alt=""><figcaption></figcaption></figure>

If 'Trial extension' is selected, specify the number of days to extend the trial period.

{% hint style="info" %}
Please note that due to the way that Recurly subscriptions work, the way that LoyaltySurf extends trial periods for existing subscriptions is by creating a new Recurly subscription and applying a [free trial coupon](https://docs.recurly.com/docs/coupons#free-trial-coupons) to it.
{% endhint %}

Then select the Recurly plan to which the free trial coupon should be applied.

<figure><img src="/files/CfKFQ0N8A5vZLWm0D4YB" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
The Recurly free trial coupon generated by LoyaltySurf must be redeemed when the Recurly customer has a new subscription created. It cannot be utilized for existing subscriptions. If a Recurly plan is not chosen for the application of the free trial coupon, the customer will still receive the coupon. However, it can only be redeemed at a later time. For more information about free trial coupons, click [here](https://docs.recurly.com/docs/coupons#free-trial-coupons).
{% endhint %}

**Step 4:** Then hit Save. Now, anytime this reward is unlocked by a winning participant, a Recurly coupon, credit, or trial extension will also be applied to the Recurly subscription associated with the LoyaltySurf participant email address.

**Step 5 (optional):** To ensure the legitimacy of your campaign and prevent any fraudulent activities, it is advisable to establish Recurly webhooks. By setting up webhooks, LoyaltySurf can monitor any modifications customers make to their email addresses on Recurly using the customer's unique Recurly ID.

<figure><img src="/files/oDOAKxb56f59VIqj3tMH" alt=""><figcaption></figcaption></figure>

**Step 6:** Toggle the Recurly webhooks switch to enabled within LoyaltySurf, then go to your Recurly dashboard and create a new Recurly webhook by navigating to Integrations > Webhooks. Click on the configure button and select the New Endpoint option to create a new endpoint. Use the webhook URL displayed in the LoyaltySurf Recurly integration as the endpoint URL. Next, generate a username and password for your endpoint, scroll down to the Notification section, and select `account.updated`. Finally, click the Save Changes button at the bottom of the page. To complete the integration, return to the LoyaltySurf Recurly integration and input the username and password for your Recurly webhook.

{% hint style="warning" %}
**Important Note:** Only the following notification should be selected for your Recurly webhook:

* account.updated
  {% endhint %}

<figure><img src="/files/HRvqYN6AClUZt25MjRlc" alt=""><figcaption></figcaption></figure>

### Test Mode

Our Recurly integration comes with a test mode that allows you to test coupons/credits and trial extensions based on the test API key that you initially provided. This helps you keep development/testing separate from production. When you toggle *Test Mode* on, LoyaltySurf will apply coupons/credits and trial extensions using your test API key.

To enable test mode, toggle the *Test Mode* switch at the bottom-right, then connect a reward.

<figure><img src="/files/t1aEWQEic27dHbMnDkMO" alt=""><figcaption></figcaption></figure>

Please note that the rewards you connect to while *Test Mode* is enabled are completely separate from those you connect to in live mode.

<figure><img src="/files/DHFPqouhZNZW4781lM1n" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
**Important note:** When you go live with your campaign, please make sure to switch back to live mode. Otherwise, rewards will not be issued in live mode while test mode is enabled.
{% endhint %}

### Troubleshooting Tips

If there is an issue with applying Recurly coupons, credits, or trial extensions, LoyaltySurf will send out a notification email to the campaign owner. The issue will also be stated in the participant's detail page when you view their reward or when you view the participant's activity logs.

Here are some common reasons why there may be failures:

* The customer with the associated LoyaltySurf participant email address does not exist in Recurly (please make sure to check live or test mode depending on if you have toggled on Test Mode in the LoyaltySurf Recurly integration)
* If dynamic reward rules are enabled for the Recurly reward, there may have been no matching rule found.
* If you were expecting a reward to be applied in live mode, double-check that you do not have test mode enabled.

If there was a failure, you will need to manually issue the Recurly reward from your [Recurly dashboard](https://app.recurly.com/).

#### Other notes:

* If you have manual reward approval enabled for your campaign: Recurly coupons, credits, and trial extensions will only be issued to the winner(s) after you approve the reward.
* If the loyalty action was triggered recently (or if the reward was approved recently), please allow for a few minutes of server processing before viewing the participant's reward from your LoyaltySurf admin dashboard. During this time, the data displayed for the participant's reward may not be accurate.


# Slack

Get notified in Slack when events happen in your LoyaltySurf campaign.

{% hint style="info" %}
**Note:** The integration for Slack is only available to users on a LoyaltySurf paid plan.
{% endhint %}

### How to connect to Slack <a href="#how-to-connect-to-slack" id="how-to-connect-to-slack"></a>

**Step 1:** In *Campaign Editor > 4. Options > View All Integrations*, click the *Connect to Slack* button

<figure><img src="/files/6jr09KT3clIeR85q3TxQ" alt=""><figcaption></figcaption></figure>

**Step 2:** Approve Slack permissions

<figure><img src="/files/I6rYcBCb8gBB87SzUoml" alt=""><figcaption></figcaption></figure>

**Step 3:** Connect the channel that you want to send LoyaltySurf notifications to

<figure><img src="/files/d1yAHU60t47abh62CkMq" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
**Trying to connect a private Slack channel?**

To select a private Slack channel, both you and the GrowSurf Slack app must already be members of it. Invite the app in Slack first, then refetch.
{% endhint %}

### Notification event types <a href="#notification-event-types" id="notification-event-types"></a>

* You can choose the granularity of the types of notifications that you want to receive within the advanced Slack settings section.
* With *New Participant Reward Submission* alerts, you'll be able to approve or reject submissions directly within Slack.
* With *New Participant Reward* alerts, you'll be able to approve and fulfill rewards directly within Slack.


# Stripe

Automatically apply Stripe coupons, credits, or trial extensions as rewards.

{% hint style="info" %}
**Note:** The Stripe integration is only available to users on a LoyaltySurf paid plan.
{% endhint %}

Even if the Stripe customer's email address changes, LoyaltySurf will track those changes to ultimately ensure the Stripe coupon, credit, or trial extension gets applied to the right Stripe customer.

### **How to Set Up**

{% hint style="info" %}
You must first select a default currency for your LoyaltySurf campaign in order to use Stripe.\
\
Your default currency determines whether Stripe coupons, credits, or trial extensions can be applied to your Stripe customers or subscriptions. For example, if your default currency is USD, then the coupon, credit, or trial extension you set up can only be redeemed for Stripe customers or subscriptions using USD.
{% endhint %}

**Step 1**: In *Campaign Editor > 4. Options > Integrations*, click the *Connect to Stripe* button.

<figure><img src="/files/vMKJrJNikLk76EeZVaHl" alt=""><figcaption></figcaption></figure>

**Step 2:** Once connected, press the 'Connect A Reward' button and select your reward.

<figure><img src="/files/M3te5y04DdiNZr1pUOsM" alt=""><figcaption></figcaption></figure>

**Step 3:** Click on either coupon, credit, or trial extensio&#x6E;*.* If 'Coupon' is selected, enter the details of the coupon, including the name, type, and discount. You can also click *Show advanced coupon* settings to view more customization settings.

{% hint style="info" %}
**Advanced feature tip: Issue different reward amounts by using dynamic rewards**

Dynamic rewards let you offer different reward values based on specific attributes of the participant (such as the pricing plan they signed up for).

For example, you can issue $50 in credits for normal users and $100 in credits for VIP users.

[Learn more →](https://support.loyaltysurf.io/article/437-how-to-set-up-dynamic-rewards)
{% endhint %}

<figure><img src="/files/pNAQwLMcuJ7cN0P7iRj4" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Note:** By default, coupons are recommended. However, if you want rewards to be stackable (e.g., $10 off for every loyalty action, 100% off for one month), you have two options:

1. Select "Coupon" and make sure you apply coupons to Subscriptions instead of Customers.

   <figure><img src="/files/L2jV4uemWAU7s2NE6urR" alt=""><figcaption></figcaption></figure>
2. Alternatively, you can choose to apply a "Credit" (instead of "Coupon").
   {% endhint %}

If 'Credit' is selected, enter the credit description and amount applied to the customer's promotional credits every time this reward is unlocked.

<figure><img src="/files/XSl5cNtaTsMSEdRjEMOz" alt=""><figcaption></figcaption></figure>

If 'Trial extension' is selected, specify the number of days to extend the trial period.&#x20;

<figure><img src="/files/D1JR5HrREMMoHFCpEtQP" alt=""><figcaption></figcaption></figure>

**Step 4:** After clicking Save, a Stripe coupon or credit will be applied to the Stripe customer or subscription linked to the LoyaltySurf participant's email address whenever they unlock a reward. Please note that the trial extension is only applicable to a subscription.

### Test Mode

Our Stripe integration comes with a test mode that allows you to test coupons, credits, and trial extensions. When you toggle *Test Mode* on, LoyaltySurf will only apply coupons, credits, and trial extensions to your Stripe account in test mode.&#x20;

To enable test mode, toggle the *Test Mode* switch at the bottom-right, then connect a reward(s).

{% hint style="info" %}
**Using a Stripe Sandbox account?**

Instead of using test data from your live Stripe account, you can alternatively connect to your Stripe sandbox account. Simply toggle the *Test Mode* switch and you'll see a popup that lets you choose between connecting your sandbox account or just using test data from your live account.
{% endhint %}

<figure><img src="/files/zELceIWwVZP9Rf1Lf3qp" alt=""><figcaption></figcaption></figure>

Please note that the rewards you connect to while *Test Mode* is enabled are completely separate from those you connect to in live mode. For more details on Stripe Testing, [see here](https://stripe.com/docs/testing).

<figure><img src="/files/kILHThFOMDBAKXzReqXb" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
**Important note:** When you go live with your campaign, please make sure to switch back to live mode. Otherwise, rewards will not be issued in live mode while test mode is enabled.
{% endhint %}

### Troubleshooting Tips

If there is an issue with applying Stripe coupons, credits, or trial extensions, LoyaltySurf will send out a notification email to the campaign owner. The issue will also be stated in the participant's detail page when you view their reward or when you view the participant's activity logs.

Here are some common reasons why there may be failures:

* The customer with the associated LoyaltySurf participant email address does not exist in Stripe (please make sure to check live or test mode depending on if you have toggled on Test Mode in the LoyaltySurf Stripe integration)
* If dynamic reward rules are enabled for the Stripe reward, there may have been no matching rule found.
* If you were expecting a reward to be applied in live mode, double-check that you do not have test mode enabled.
* If your Stripe customer changes their email address right before the Stripe reward gets applied, they may not receive it. This is because LoyaltySurf relies on Stripe sending out a webhook event which notifies LoyaltySurf of the Stripe customer's new email address, but if there is not at least a few minutes before the reward event, LoyaltySurf will not know about the Stripe customer's email change.

If there was a failure, you will need to manually issue the Stripe reward from your [Stripe dashboard](https://dashboard.stripe.com/dashboard/).

#### Other notes:

* Only companies based in the [following 135+ countries](https://stripe.com/docs/currencies) can use the Stripe coupons/credits/trial-extension integration.
* If you have manual reward approval enabled for your campaign: Stripe coupons, credits, and trial extensions will only be issued to the winner(s) after you approve the reward.
* If the loyalty action was triggered recently (or if the reward was approved recently), please allow for a few minutes of server processing before viewing the participant's reward from your LoyaltySurf admin dashboard. During this time, the data displayed for the participant's reward may not be accurate.


# Tango Card

Automatically fulfill gift card rewards where winners can pick from top retailers (e.g, Amazon, Starbucks) and/or donate to non-profits.

{% hint style="info" %}
**Note:** The Tango Card integration is only available to users on a LoyaltySurf paid plan, and is only available to companies based in the following countries: USA, Canada, United Kingdom, France, Germany, Italy, Netherlands, Spain, Argentina, Australia, Brazil, India, Singapore, United Arab Emirates.

The default currency you choose for your LoyaltySurf campaign determines which country your recipients can redeem their gift cards in. For example, if your default currency is USD then only USD gift cards can be selected for redemption.
{% endhint %}

## What is Tango Card?

[Tango Card](https://tangocard.com) is a free service that lets you easily reward winners of your loyalty action campaign with their choice of e-gift cards or non-profit donations.

Tango Card is 100% free to use. You only pay for the value of the e-gift cards that you issue to your winners.

**Here are some additional things to note:**

* LoyaltySurf automatically creates a new Tango Card account for you. You do not need to create a separate Tango Card account yourself.
* Your LoyaltySurf Tango Card account is separate from any external Tango Card accounts you already own. You may request to transfer funds from your external accounts to your LoyaltySurf Tango Card account by [contacting Tango Card support](#contact-tango-card-support).
* LoyaltySurf's Tango Card integration supports currencies for the following countries: *USA, Canada, United Kingdom, France, Germany, Italy, Netherlands, Spain, Argentina, Australia, Brazil, India, Singapore, United Arab Emirates*. For other currencies, use [Zapier](https://docs.growsurf.com/automate-rewards/zapier) or [Webhooks](https://docs.growsurf.com/automate-rewards/webhooks) with your external Tango Card account instead.[<br>](https://docs.growsurf.com/automate-rewards/tango-card)

### How Tango Card Looks to Your Winners

Watch [the video](https://www.youtube.com/watch?v=PMrGHNOBuLc) below to see how easy it is for your recipients to receive a *Tango Card Reward Link* via email and then redeem it for their choice of gift card rewards.

{% embed url="<https://www.youtube.com/watch?v=PMrGHNOBuLc>" %}
Your winners will get a Tango Card email with a unique redemption link
{% endembed %}

### **Benefits of Using Tango Card:**

* You control your total spending by funding your account upfront (via ACH/wire, check, or credit card)
* Your winners can choose and combine their choice of e-gift cards from a wide variety of top retailers such as Amazon, and Starbucks, as well as donate to non-profits
* E-gift cards deliver instantly, have a digital trail, and require no inventory
* Tango Card provides customer support to assist in handling any/all issues, available Monday to Friday 7:30 am - 5:00 pm PST

## How to Connect to Tango Card

**Step 1:** In *Campaign Editor > 4. Options > Integrations*, click the *Connect to Tango Card* button.

{% hint style="info" %}
You must first select a default currency for your LoyaltySurf account in order to use Tango Card. Please note that Tango Card is only available in the following currencies: USD, CAD, GBP, EUR, INR, SGD, ARS, AUD, AED, BRL.

Your default currency determines which country your recipients can redeem their gift cards in. For example, if your default currency is USD, then the gift card that you choose can only be redeemed in the United States.
{% endhint %}

<figure><img src="/files/HaLpJSaCyslSz5sSjmid" alt=""><figcaption></figcaption></figure>

**Step 2:** Press the 'Connect A Reward' button and select your reward.

<figure><img src="/files/licNkBIGVD1ydQeVAF0i" alt=""><figcaption></figcaption></figure>

**Step 3:** Select the country for redeeming gift cards, specify the gift card value, and press Save.

{% hint style="info" %}
**Advanced feature tip: Issue different gift card amounts by using dynamic rewards**

Dynamic rewards let you offer different reward values based on specific attributes of the participant (such as the pricing plan they signed up for).

For example, you can issue $50 gift cards for normal users and $100 gift cards for VIP users.&#x20;

[Learn more →](https://support.loyaltysurf.io/article/437-how-to-set-up-dynamic-rewards)
{% endhint %}

<figure><img src="/files/hNTne2NpbeDEpthq7Bfa" alt=""><figcaption></figcaption></figure>

**Step 4:** You will need to fund your Tango Card account balance upfront. Click the *Add Funds* button, choose your preferred funding method, and follow the step-by-step instructions.&#x20;

ACH/wire or check is 100% free. Credit card incurs a 3.5% processing fee.

{% hint style="info" %}
**Note**: If your campaign currency is not USD, CAD, GDP, or EUR, Tango Card requires that you add funds to your account using USD.
{% endhint %}

<figure><img src="/files/pgw93MiwfRFA7CR2ZA5P" alt=""><figcaption></figcaption></figure>

**Step 5:** Verify your account balance by clicking the *Back* button, and your account balance is the *Refresh Balance* icon. Once your account balance is updated, your Tango Card integration is all set!&#x20;

<figure><img src="/files/Pnv3gQpAJbDMjaxGcgnY" alt=""><figcaption></figcaption></figure>

Now, anytime this reward is unlocked by a winning participant, a Tango Card Reward Link will be emailed to them.

{% hint style="danger" %}
**Important notes:**

* If you are adding funds via credit card for the first time, the initial deposit may take up until the end of the next business day to clear (subsequent deposits will process faster in the future).
* If there are insufficient funds in your account balance when covering redemptions, your winners will not receive email links for redeeming gift cards, and you will need to [retry failed redemptions](/integrations/tango-card#retrying-failed-redemptions) at any later time.
  {% endhint %}

**(Optional) Step 6:** To get notified when failed redemptions happen, you can enable Tango Card alert emails by updating your notification preferences on your [settings page](https://app.loyaltysurf.io/settings).

<figure><img src="/files/a9NtxRMKz0E7P8HXUc8f" alt=""><figcaption></figcaption></figure>

## Important Notes

* Only companies based in the following countries can use Tango Card: USA, Canada, United Kingdom, France, Germany, Germany, Italy, Netherlands, Spain, Argentina, Australia, Brazil, India, Singapore, United Arab Emirates.
  * **If you are using a non-USD currency:** Please note that Tango Card uses separate banks for currencies. When you add funds via ACH or wire, please make sure to view the specific instructions within LoyaltySurf to ensure funds are sent to the right bank. If a non-USD payment is sent to Tango Card's USD bank, it will be converted to USD prior to deposit. There may be fees or loss of funds due to this conversion.
    * If your campaign currency is not CAD, GDP, or EUR, Tango Card requires that you add funds to your account using USD. You will also see your primary account balance within GrowSurf as USD, but your participants will still receive gift cards in your campaign's primary currency.
* **Funding fees:** Adding funds via ACH/wire or check is free. Funding via credit card incurs a 3.5% processing fee. (Note: transactions are limited to once a day and $5,000 per transaction.)
* **Funding via credit card:**
  * The initial deposit made by credit card may take up until the end of the next business day for funds to clear.
  * If Tango Card's security team has to investigate a credit card due to red flags, processing may take an additional business day.
  * Once your initial deposit has cleared successfully, subsequent deposits will be processed faster in the future.
* **Insufficient funds:** If insufficient funds are in your account balance when covering redemptions, your winners will not receive email links for redeeming gift cards, and you will need to [retry failed redemptions](/integrations/tango-card#retrying-failed-redemptions).
* **If you have manual reward approval enabled for your campaign**: Tango Card Reward Link emails will only be issued to the winner(s) after you approve the reward.
* **Cancellation policy:** Please make sure you understand [Tango Card's cancellation policy here](https://help.rewardsgenius.com/s/article/TangoCardCancellationPolicy). Please note that Tango Card can NOT cancel direct merchant brands, only unredeemed Reward Links and Prepaid Visas.

## Troubleshooting Tips

If there is an issue with sending out redemption links, LoyaltySurf will send out a notification email to the campaign owner. The issue will also be stated in the participant's detail page when you view their reward or when you view the participant's activity logs.

Here are some reason why there may be failures when trying to send out redemption links:

* There is a lack of funds in your Tango Card account.
* If dynamic reward rules are enabled for the Tango Card reward, there may have been no matching rule found.

### Retrying Failed Redemptions

Once you resolve the issue (such as adding sufficient funds or updating your dynamic rewards configuration), click the 'Retry Redemptions' button (see image below).

<figure><img src="/files/LETj3wpQPCMvYvWXO2DC" alt=""><figcaption></figcaption></figure>

## Contact Tango Card Support

LoyaltySurf automatically creates a Tango Card account on your behalf using your LoyaltySurf email. In the event that you need to contact Tango Card, please reference your Tango Card account details, including your *Account Identifier* (found in the popover window when you click the *Contact Tango Card Support* link in the Tango Card integration card).

#### Email <cs@tangocard.com> or call 1-877-558-2646 if any of the situations below apply:

* You want to change the email address associated with your Tango Card account
* You would like to resend gift cards to winners
* Troubleshooting any issues with recipients redeeming their gift card

#### Email <funding@tangocard.com> or call 1-877-558-2646 if any of the situations below apply:

* If you are experiencing any funding-related issues (credit card, ACH, wire, etc)
* If you have questions or would like updates on the funding status of your account

#### Additional links:

* [Contact Tango Card](https://www.tangocard.com/contact/)
* [Tango Card Customer Support FAQs](https://help.rewardsgenius.com/s/)


# XTRM

Automatically fulfill cash, prepaid cards, and gift card rewards to winners.

{% hint style="info" %}
**Note:** The XTRM integration is only available to users on the Business plan, and is only available to companies based in the following countries: USA, Canada, United Kingdom, France, Germany, Italy, Netherlands, Spain, Argentina, Australia, Brazil, India, Singapore, United Arab Emirates.

The default currency you choose for your LoyaltySurf campaign determines which country your recipients can redeem their gift cards in. For example, if your default currency is USD then only USD gift cards can be selected for redemption.
{% endhint %}

## What is XTRM?

XTRM is a paid service that lets you easily reward winners of your referral campaign with cash, prepaid cards, or gift cards.

XTRM costs $0.25/payout.

**Here are some additional things to note:**

* LoyaltySurf automatically creates a new XTRM account for you. You do not need to create a separate Tango Card account yourself.
* Your LoyaltySurf XTRM account is separate from any external XTRM accounts you already own. You may request to transfer funds from your external accounts to your LoyaltySurf XTRM account by [contacting XTRM support](mailto:support@xtrm.com).
* LoyaltySurf's XTRM integration supports currencies for the following countries: *USA, Canada, United Kingdom, France, Germany, Italy, Netherlands, Spain, Argentina, Australia, Brazil, India, Singapore, United Arab Emirates*. For other currencies, use [Zapier](https://docs.growsurf.com/automate-rewards/zapier) or [Webhooks](https://docs.growsurf.com/automate-rewards/webhooks) with your external XTRM account instead.[<br>](https://docs.growsurf.com/automate-rewards/tango-card)

### How XTRM Looks to Your Winners

Watch [the video](https://www.youtube.com/watch?v=PMrGHNOBuLc) below to see how easy it is for your recipients to receive a *Tango Card Reward Link* via email and then redeem it for their choice of gift card rewards.

{% embed url="<https://www.youtube.com/watch?v=PMrGHNOBuLc>" %}
Your winners will get a Tango Card email with a unique redemption link
{% endembed %}

### **Benefits of Using Tango Card:**

* You control your total spending by funding your account upfront (via ACH/wire, check, or credit card)
* Your winners can choose and combine their choice of e-gift cards from a wide variety of top retailers such as Amazon, and Starbucks, as well as donate to non-profits
* E-gift cards deliver instantly, have a digital trail, and require no inventory
* Tango Card provides customer support to assist in handling any/all issues, available Monday to Friday 7:30 am - 5:00 pm PST

## How to Connect to Tango Card

**Step 1:** In *Campaign Editor > 4. Options > Integrations*, click the *Connect to Tango Card* button.

{% hint style="info" %}
You must first select a default currency for your LoyaltySurf account in order to use Tango Card. Please note that Tango Card is only available in the following currencies: USD, CAD, GBP, EUR, INR, SGD, ARS, AUD, AED, BRL.

Your default currency determines which country your recipients can redeem their gift cards in. For example, if your default currency is USD, then the gift card that you choose can only be redeemed in the United States.
{% endhint %}

<figure><img src="/files/HaLpJSaCyslSz5sSjmid" alt=""><figcaption></figcaption></figure>

**Step 2:** Press the 'Connect A Reward' button and select your reward.

<figure><img src="/files/licNkBIGVD1ydQeVAF0i" alt=""><figcaption></figcaption></figure>

**Step 3:** Select the country for redeeming gift cards, specify the gift card value, and press Save.

{% hint style="info" %}
**Advanced feature tip: Issue different gift card amounts by using dynamic rewards**

Dynamic rewards let you offer different reward values based on specific attributes of the participant (such as the pricing plan they signed up for).

For example, you can issue $50 gift cards for normal users and $100 gift cards for VIP users.&#x20;

[Learn more →](https://support.loyaltysurf.io/article/437-how-to-set-up-dynamic-rewards)
{% endhint %}

<figure><img src="/files/hNTne2NpbeDEpthq7Bfa" alt=""><figcaption></figcaption></figure>

**Step 4:** You will need to fund your Tango Card account balance upfront. Click the *Add Funds* button, choose your preferred funding method, and follow the step-by-step instructions.&#x20;

ACH/wire or check is 100% free. Credit card incurs a 3.5% processing fee.

{% hint style="info" %}
**Note**: If your campaign currency is not USD, CAD, GDP, or EUR, Tango Card requires that you add funds to your account using USD.
{% endhint %}

<figure><img src="/files/pgw93MiwfRFA7CR2ZA5P" alt=""><figcaption></figcaption></figure>

**Step 5:** Verify your account balance by clicking the *Back* button, and your account balance is the *Refresh Balance* icon. Once your account balance is updated, your Tango Card integration is all set!&#x20;

<figure><img src="/files/Pnv3gQpAJbDMjaxGcgnY" alt=""><figcaption></figcaption></figure>

Now, anytime this reward is unlocked by a winning participant, a Tango Card Reward Link will be emailed to them.

{% hint style="danger" %}
**Important notes:**

* If you are adding funds via credit card for the first time, the initial deposit may take up until the end of the next business day to clear (subsequent deposits will process faster in the future).
* If there are insufficient funds in your account balance when covering redemptions, your winners will not receive email links for redeeming gift cards, and you will need to [retry failed redemptions](/integrations/tango-card#retrying-failed-redemptions) at any later time.
  {% endhint %}

**(Optional) Step 6:** To get notified when failed redemptions happen, you can enable Tango Card alert emails by updating your notification preferences on your [settings page](https://app.loyaltysurf.io/settings).

<figure><img src="/files/a9NtxRMKz0E7P8HXUc8f" alt=""><figcaption></figcaption></figure>

## Important Notes

* Only companies based in the following countries can use Tango Card: USA, Canada, United Kingdom, France, Germany, Germany, Italy, Netherlands, Spain, Argentina, Australia, Brazil, India, Singapore, United Arab Emirates.
  * **If you are using a non-USD currency:** Please note that Tango Card uses separate banks for currencies. When you add funds via ACH or wire, please make sure to view the specific instructions within LoyaltySurf to ensure funds are sent to the right bank. If a non-USD payment is sent to Tango Card's USD bank, it will be converted to USD prior to deposit. There may be fees or loss of funds due to this conversion.
    * If your campaign currency is not CAD, GDP, or EUR, Tango Card requires that you add funds to your account using USD. You will also see your primary account balance within GrowSurf as USD, but your participants will still receive gift cards in your campaign's primary currency.
* **Funding fees:** Adding funds via ACH/wire or check is free. Funding via credit card incurs a 3.5% processing fee. (Note: transactions are limited to once a day and $5,000 per transaction.)
* **Funding via credit card:**
  * The initial deposit made by credit card may take up until the end of the next business day for funds to clear.
  * If Tango Card's security team has to investigate a credit card due to red flags, processing may take an additional business day.
  * Once your initial deposit has cleared successfully, subsequent deposits will be processed faster in the future.
* **Insufficient funds:** If insufficient funds are in your account balance when covering redemptions, your winners will not receive email links for redeeming gift cards, and you will need to [retry failed redemptions](/integrations/tango-card#retrying-failed-redemptions).
* **If you have manual reward approval enabled for your campaign**: Tango Card Reward Link emails will only be issued to the winner(s) after you approve the reward.
* **Cancellation policy:** Please make sure you understand [Tango Card's cancellation policy here](https://help.rewardsgenius.com/s/article/TangoCardCancellationPolicy). Please note that Tango Card can NOT cancel direct merchant brands, only unredeemed Reward Links and Prepaid Visas.

## Troubleshooting Tips

If there is an issue with sending out redemption links, LoyaltySurf will send out a notification email to the campaign owner. The issue will also be stated in the participant's detail page when you view their reward or when you view the participant's activity logs.

Here are some reason why there may be failures when trying to send out redemption links:

* There is a lack of funds in your Tango Card account.
* If dynamic reward rules are enabled for the Tango Card reward, there may have been no matching rule found.

### Retrying Failed Redemptions

Once you resolve the issue (such as adding sufficient funds or updating your dynamic rewards configuration), click the 'Retry Redemptions' button (see image below).

<figure><img src="/files/LETj3wpQPCMvYvWXO2DC" alt=""><figcaption></figcaption></figure>

## Contact Tango Card Support

LoyaltySurf automatically creates a Tango Card account on your behalf using your LoyaltySurf email. In the event that you need to contact Tango Card, please reference your Tango Card account details, including your *Account Identifier* (found in the popover window when you click the *Contact Tango Card Support* link in the Tango Card integration card).

#### Email <cs@tangocard.com> or call 1-877-558-2646 if any of the situations below apply:

* You want to change the email address associated with your Tango Card account
* You would like to resend gift cards to winners
* Troubleshooting any issues with recipients redeeming their gift card

#### Email <funding@tangocard.com> or call 1-877-558-2646 if any of the situations below apply:

* If you are experiencing any funding-related issues (credit card, ACH, wire, etc)
* If you have questions or would like updates on the funding status of your account

#### Additional links:

* [Contact Tango Card](https://www.tangocard.com/contact/)
* [Tango Card Customer Support FAQs](https://help.rewardsgenius.com/s/)


# Zapier

Zapier is a code-free tool that lets you connect to 5,000+ apps to automate rewards or sync data.

## Example scenarios

Zapier lets you perform an action when a certain LoyaltySurf event occurs, without having to write any code. Here are a few scenarios in which you would use Zapier:

* **Trigger Loyalty Action:** WHEN you get a new response in Google Forms, THEN trigger a loyalty action.
* **New Participant Reward:** WHEN a participant achieves a loyalty action goal and unlocks a reward, THEN automatically send them a coupon code through *Coupon Carrier*.

## Getting started

<figure><img src="/files/jRCD9sQaIOlzlVdwlqKJ" alt=""><figcaption></figcaption></figure>

1. To begin, access the LoyaltySurf app on Zapier by clicking [here](https://zapier.com/apps/loyaltysurf/integrations).
2. Click the **Connect to 5,000+ Apps** button.
3. Log in to your Zapier account or create one if necessary.&#x20;
4. After logging in, you will be taken to the Zap editor screen, where LoyaltySurf will be visible as the trigger for the Zap you are setting up.

{% hint style="warning" %}
**Note:** Zapier's free plan provides you with 5 total Zaps and 100 free monthly tasks. For more, you will need to upgrade your Zapier plan. Also, if you do not have a Zapier account, you will be prompted to complete a short questionnaire before you can create a Zap.&#x20;
{% endhint %}

## Next steps

View our [Tutorials](/integrations/zapier/tutorials) for examples of how to set up Zaps for common scenarios.

* [Trigger Loyalty Action](https://docs.loyaltysurf.io/integrations/zapier/tutorials#example-1-trigger-loyalty-action)
* [New Participant Reward](https://docs.loyaltysurf.io/integrations/zapier/tutorials#example-2-new-participant-reward)
* [New Participant](https://docs.loyaltysurf.io/integrations/zapier/tutorials#example-3-new-participant)
* [Campaign Ended](https://docs.loyaltysurf.io/integrations/zapier/tutorials#example-4-campaign-ended)


# Tutorials

We'll walk you through creating Zapier Zaps.

## Table of contents

| Scenario                                                                |
| ----------------------------------------------------------------------- |
| [Example 1: Trigger Loyalty Action ](#example-1-trigger-loyalty-action) |
| [Example 2: New Participant Reward](#example-2-new-participant-reward)  |
| [Example 3: New Participant](#example-3-new-participant)                |
| [Example 4: Campaign Ended](#example-4-campaign-ended)                  |

## Example 1: Trigger Loyalty Action

In this example, we'll trigger a loyalty action when there is a new response in Google Forms.

### [Step 1: Get access to LoyaltySurf on Zapier](/integrations/zapier#getting-started)

Once logged into Zapier, click the **Create Zap** button on the sidebar menu.

{% hint style="warning" %}
**Note:**

* Only the LoyaltySurf team owner's campaigns will show up when you connect to Zapier. If you are setting the Zap up as a team member, you will need to connect to Zapier using the team owner's LoyaltySurf account.
* If you used Google to sign up for LoyaltySurf, you'll need to set a password before connecting to Zapier. Go to the [Sign In](https://app.loyaltysurf.io/signin) page and click "Forgot password" to create one.
  {% endhint %}

### Step 2: Set up the Zap trigger

For the **Trigger** step, type *Google Forms* and select **Google Form** from the dropdown menu. Then in the **Event** field, select **New Form Response** from the dropdown menu.

Your screen should now look like this:

<figure><img src="/files/fAa33jeinxkt5Il59rJN" alt=""><figcaption></figcaption></figure>

Press **Continue**, then select **Connect a new account**. In the appearing window, choose an account or sign in to continue to Zapier. Press **Continue** again, pick your form from the dropdown menu under the **Form** field, click **Continue,** and finally, click the **Test trigger** button.<br>

<figure><img src="/files/h66GS7pn6AvOrGLftlkL" alt=""><figcaption></figcaption></figure>

You've now successfully set up the Zap to trigger when there is a new response in Google Forms. Now it's time to create the action for triggering a loyalty action using LoyaltySurf.

### Step 3: Set up the Zap action(s)

For the **Action** step, type *LoyaltySurf* and select **LoyaltySurf** from the dropdown menu. Then in the **Event** field, select **Trigger Loyalty Action** from the dropdown menu.

Your screen should now look like this:

<figure><img src="/files/nCOdh7IoGfckribNFWe3" alt=""><figcaption></figcaption></figure>

Press **Continue**, then select **Connect a new account**. In the appearing window, enter your LoyaltySurf login credentials. Press **Continue**, pick your LoyaltySurf campaign from the dropdown menu under the **Choose** field, then click **Continue**.

Here's what your screen should look like:

<figure><img src="/files/1Epru7rip1STcNGJgadk" alt=""><figcaption></figcaption></figure>

Fill in all the required fields, click **Continue** and then click **Test action**. You should see the expected message: "Successfully awarded loyalty reward."

{% hint style="info" %}
**Loyalty Action trigger not working?**&#x20;

* Double-check that the above information in the screenshot(s) matches what you set up in your Zap.&#x20;
  {% endhint %}

You've now successfully set up the Zap action. Click the **Publish Zap** bottom to finish, then click **Publish & Turn On**. Your Zap is now live and will trigger a loyalty action when there is a new response in Google Forms.

## Example 2: New Participant Reward

In this example, we'll connect LoyaltySurf to Coupon Carrier, letting us send a unique coupon to a participant when they reach a loyalty action goal.

### [Step 1: Click to get access to LoyaltySurf on Zapier](/integrations/zapier#getting-started)

Once logged into Zapier, click the **Create Zap** button on the sidebar menu.

{% hint style="warning" %}
**Note:** Only the LoyaltySurf team owner's campaigns will show up when you connect to Zapier. If you are setting the Zap up as a team member, you will need to connect to Zapier using the team owner's LoyaltySurf account.
{% endhint %}

### Step 2: Set up the Zap trigger

For the **Trigger** step, type *LoyaltySurf* and select **LoyaltySurf** from the dropdown menu. Then in the **Event** field, select **New Participant Reward** from the dropdown menu.

Your screen should now look like this:

<figure><img src="/files/iSpxnHLuz9bHa1OEgJ78" alt=""><figcaption></figcaption></figure>

Press **Continue**, then select **Connect a new account**. In the appearing window, enter your LoyaltySurf login credentials. Press **Continue** again and pick your LoyaltySurf campaign from the dropdown menu under the **Campaign** field.

<figure><img src="/files/gR7ouD5C4iBB2XuyQ0hr" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
**Note:** If you don't see your campaign(s) in the dropdown options, please note that only the campaigns you are an owner of will appear here. If you are setting the Zap up as a team member, you will need to go back to step #1 and connect to Zapier using your team owner's LoyaltySurf account.
{% endhint %}

Click **Continue**, then click the **Test trigger** button.

<figure><img src="/files/HqTCD4Adow5xnZWvCJxr" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
At the "Test your trigger" step, please note that sample data may not accurately reflect your campaign data. Sample data is only used to set up the Zap. When the Zap triggers for a live campaign, real data will be provided in the Zap.
{% endhint %}

You've now successfully set up the Zap to trigger on a new LoyaltySurf participant reward. Now it's time to create the action of sending the winner a coupon code.

### Step 2.5: Set up Zap Filters

Before proceeding, it's important to check if you require a Zap Filter, which acts as a checkpoint for your data flow, halting the process if specific conditions are not met. Answer the following question and follow the instructions if your response is "yes."

**Question 1: Is manual reward approval enabled for your campaign?**

{% hint style="info" %}
If manual reward approval is enabled for your campaign, two Zapier trigger events will occur: (1) when the reward is pending approval, and (2) when the reward is approved.
{% endhint %}

* **Step A:** Set up the Zap trigger, then add the Filter by clicking the **+** button and selecting **Filter** from the **Built-in Tools** section
* **Step B:** Choose *Reward Approved* from the first dropdown&#x20;
* **Step C:** Set the next field to *Exactly matches (Text)*
* **Step D:** In the last field, type `true` or `false`, based on your desired outcome. Rewards that are approved have *Reward Approved* as `true`&#x20;
* **Step E:** Test and continue

### Step 3: Set up the Zap action(s)

For the **Action** step, type *Coupon* and select **Coupon Carrier** from the dropdown menu. Then in the **Event** field, select **Send a Code Email** from the dropdown menu.

Your screen should now look like this:

<figure><img src="/files/3qP7cYjlzm4VgQpzUgaH" alt=""><figcaption></figcaption></figure>

\
Press **Continue**, then sign in. In the pop-up window, enter your Coupon Carrier API key. Press **Continue** again, select **Participant Email** from the drop-down menu under the **Email Address** field, and pick the preferred Coupon Carrier configuration in the **Configuration** field.

<figure><img src="/files/6Dqf8Z0ZKQ0cu2YCVZSl" alt=""><figcaption></figcaption></figure>

Click **Continue**, then click the **Test action** button.

<figure><img src="/files/SrBwycLsTd3PIn3kv0l4" alt=""><figcaption></figcaption></figure>

You've now successfully set up the Zap action. Click the **Publish Zap** bottom to finish, then click **Publish & Turn On**. Your Zap is now live and will send a coupon whenever a LoyaltySurf participant reaches a loyalty action goal and unlocks a reward.

<figure><img src="/files/UNUc9DvAsu6FopS84D4E" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Need multiple actions?**

You can use [Multi-Step Zaps](https://zapier.com/help/premium-features/#multi-step-zaps) to create multiple action steps in your Zap. For example, with the above Zap, you send a coupon via Coupon Carrier. You could chain an additional action, like 'get a notification in Slack', within the same Zap.
{% endhint %}

## Example 3: New Participant

In this example, we'll connect LoyaltySurf to HubSpot. Whenever a new participant is added to your LoyaltySurf campaign, we'll add/update them as a HubSpot contact.

### [Step 1: Get access to LoyaltySurf on Zapier](/integrations/zapier#getting-started)

Once logged into Zapier, click the **Create Zap** button on the sidebar menu.

{% hint style="warning" %}
**Note:** Only the LoyaltySurf team owner's campaigns will show up when you connect to Zapier. If you are setting the Zap up as a team member, you will need to connect to Zapier using the team owner's LoyaltySurf account.
{% endhint %}

### Step 2: Set up the Zap trigger

For the **Trigger** step, type *LoyaltySurf* and select **LoyaltySurf** from the dropdown menu. Then in the **Event** field, select **New Participant** from the dropdown menu.

Your screen should now look like this:

<figure><img src="/files/t5SLBEQR1cT5khIwKtXQ" alt=""><figcaption></figcaption></figure>

Press **Continue**, then select **Connect a new account**. In the appearing window, enter your LoyaltySurf login credentials. Press **Continue** again and pick your LoyaltySurf campaign from the dropdown menu under the **Campaign** field.

<figure><img src="/files/0lM6tDTpePQqK9RDvJBh" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
**Note:** If you don't see your campaign(s) in the dropdown options, please note that only the campaigns you are an owner of will appear here. If you are setting the Zap up as a team member, you will need to go back to step #1 and connect to Zapier using your team owner's LoyaltySurf account.
{% endhint %}

Click **Continue**, then click the **Test trigger** button.

<figure><img src="/files/c71FZWzm6O1z1IhMr4lH" alt=""><figcaption></figcaption></figure>

You've now successfully set up the Zap to trigger on a new LoyaltySurf participant. Now it's time to create the action of adding/updating the new LoyaltySurf participant.

### Step 3: Set up the Zap action(s)

For the **Action** step, type *Hubspot* and select **HubSpot** from the dropdown menu. Then in the **Event** field, select **Create or Update Contact** from the dropdown menu.

Your screen should now look like this:

<figure><img src="/files/bOfPJDWnFGJVNIH85uDq" alt=""><figcaption></figcaption></figure>

Press **Continue**, log in to your HubSpot account, select an account and click **Choose Account** and **Connect App**. Then, click Continue in the Contact Email field and select **Participant Email** from the insert data dropdown menu.

<figure><img src="/files/jPHLq3yVZ5HaU778E5F7" alt=""><figcaption></figcaption></figure>

Then populate any other fields you want to save to the HubSpot contact. Once you've filled in all the properties that you want to save to the HubSpot contact, click **Continue**, then click the blue **Test action** button.

<figure><img src="/files/PO6HxMf7iO7PfXzBIs1t" alt=""><figcaption></figcaption></figure>

You've now successfully set up the Zap action. Click the **Publish Zap** bottom to finish, then click **Publish & Turn On**. Your Zap is now live and will create/update new HubSpot contacts whenever a new LoyaltySurf participant is added.

{% hint style="info" %}
**Need multiple actions?**

[Multi-Step Zaps](https://zapier.com/help/premium-features/#multi-step-zaps) allow you to include multiple actions in one Zap. For instance, a new LoyaltySurf participant is synced to HubSpot in the example provided. However, an additional action, such as receiving a notification in Slack, can be added to the same Zap.
{% endhint %}

## Example 4: Campaign Ended

In this example, the outcome of the LoyaltySurf action campaign will be sent via email to your company's CEO once the campaign concludes.

### [Step 1: Get access to LoyaltySurf on Zapier](/integrations/zapier#getting-started)

Once logged into Zapier, click the **Create Zap** button on the sidebar menu.

{% hint style="warning" %}
**Note:** Only the LoyaltySurf team owner's campaigns will show up when you connect to Zapier. If you are setting the Zap up as a team member, you will need to connect to Zapier using the team owner's LoyaltySurf account.
{% endhint %}

### Step 2: Set up the Zap trigger

For the **Trigger** step, type *LoyaltySurf* and select **LoyaltySurf** from the dropdown menu. Then in the **Event** field, select **Campaign Ended** from the dropdown menu.

Your screen should now look like this:

<figure><img src="/files/DMIr4Q6zkmJzamzaToad" alt=""><figcaption></figcaption></figure>

Press **Continue**, then select **Connect a new account**. In the appearing window, enter your LoyaltySurf login credentials. Press **Continue** again and pick your LoyaltySurf campaign from the dropdown menu under the **Campaign** field.

<figure><img src="/files/ouAbClCgRfTQ4FAH8U39" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
**Note:** If you don't see your campaign(s) in the dropdown options, please note that only the campaigns you are an owner of will appear here. If you are setting the Zap up as a team member, you will need to go back to step #1 and connect to Zapier using your team owner's LoyaltySurf account.
{% endhint %}

Click **Continue**, then click the **Test trigger** button.

<figure><img src="/files/bbHMnatppLzAqzPJLaUy" alt=""><figcaption></figcaption></figure>

You have successfully set up the Zap to activate upon the conclusion of your LoyaltySurf campaign. The next step is to set up the action of sending an email.

### Step 3: Set up the Zap action(s)

For the **Action** step, type *Email by Zapier* and select **Email by Zapier** from the dropdown menu. Then in the **Event** field, select **Send Outbound Email** from the dropdown menu.

Your screen should now look like this:

<figure><img src="/files/OuhE3RE9qwdZ5R8Yr8K0" alt=""><figcaption></figcaption></figure>

Click **Continue** and type in the CEO's email in the **To** field. Then in the **Subject** field, type *Loyalty Action Campaign Results*.

In the **Body** field, add the following custom message with the appropriate `<Count>`s being added by clicking the insert data field and choosing an option from the dropdown menu.

> Hey Wilma,
>
> We just wrapped up our loyalty action campaign. Here are the results:
>
> * `<Campaign Participant Count>` total participants
> * `<Campaign Loyalty Action Count>` total loyalty actions
> * `<Campaign Winner Count>` total winners&#x20;

Here's what your screen should look like:

<figure><img src="/files/XbdI9jGGpZf3f2lRPtKp" alt=""><figcaption></figcaption></figure>

Click **Continue**, then click the **Test action** button.

<figure><img src="/files/lPUROry6Jwilu9P3wzRN" alt=""><figcaption></figcaption></figure>

You've now successfully set up the Zap action. Click the **Publish Zap** bottom to finish, then click **Publish & Turn On**. Your Zap is now live and will send out an email report when your LoyaltySurf campaign ends.

{% hint style="info" %}
**Need multiple actions?**

[Multi-Step Zaps](https://zapier.com/help/premium-features/#multi-step-zaps) allow you to include multiple actions in one Zap. For instance, in the example provided, an email is sent with the results of the LoyaltySurf action campaign to the company's CEO when the campaign ends. An additional action, such as receiving a notification in Slack, can also be added to the same Zap.
{% endhint %}


# Troubleshooting

If you are experiencing issues with your Zapier setup, you can use Zapier's Task History feature to help.

## Zapier Task History

Zapier provides a Task History feature that will allow you to view the data in/out of your Zap, as well as troubleshoot any/all issues. [Learn how you can use Task History here](https://zapier.com/learn/getting-started-guide/task-history/).

Please note that it has been observed that Zapier task history may be delayed up to 20-30 minutes. Keep this in mind when troubleshooting Zap setup.

If you contact LoyaltySurf customer support regarding Zapier issues, you will need to provide us with screenshot(s) and data payloads from the Task History so we can further investigate.

![Zap Task History](/files/-Lrnp8is90KMgk5Hvf8R)

### Sample Data

When setting up your Zap Trigger, at the "Find Data" step, you may see sample data that does not accurately reflect your campaign data. Sample data is only used to set up the Zap. When the Zap triggers for a live campaign, real data will be provided in the Zap.


