Skip to main content

Point follower

Sometimes a customer wants to be the point master (that is, to own and calculate their end-user's points in their own system). But they might still want to use Engage's functionality for visualizing and adding points based on non-purchase events like engagements, birthday, reviews or whatever.

In this case, Engage can be configured to be the point follower. Engage and the point master system must now sync points with each other, with the point master being the single source of truth. Point follower, on a functional level, means that Engage stops generating points from purchases.

Engage as point follower

There are two way for Engage to be point follower: balance-only, and all-transaction.

1) Balance only: In this case, Engage receives the current point balances for a contact from the point master system and sets the total in Engage to this value. This is easier to keep in sync, since the master system just sends a total. However, there will be no information about why the balance changed, something that can be useful. This method also doesn't allow member level functionality in Engage.

  • Pros: Easier to use, harder to break

  • Cons: Less detailed information, no member levels

2) All-transaction: In this case, the point master sends information to Engage about what generated the points, allowing the total saved in Engage to be adjusted up or down by some amount. However, there is a risk that the systems might get out of sync or that transactions might be missed. All the data received will be trusted and used in Engage, but we might not be sure that the master system actually sent them.

  • Pros: More detailed information

  • Cons: Risk of getting out of sync or missing transactions

The point follower solution

The current Engage-as-point-follower solution uses a combination of API endpoints and webhooks.

You can see a general introduction to webhooks here.

There are four parts to the solution. Note that part 1 is for balance-only, while part 2 is for all-transaction.

  1. The point master sends balance-only updates via the Engage API

  2. The point master sends all-transaction updates via the Engage API

  3. Engage imports the points log from an external API provided by the point master

  4. Engage exports point adjustments to the point master via a webhook

1) Balance-only points update via the API

The point master needs to regularly send points updates to Engage so that both systems remain in sync. This is done using this Engage API endpoint:

POST /api/v2/point-accounts/balances

The payload has the following form:

    "contactId": "00000000-0000-0000-0000-000000000001",
    "amount": 122,
    "definitionId": 1,
    "timeStamp": "2023-05-16T12:20:03.807Z"
    "contactId": "00000000-0000-0000-0000-000000000002",
    "amount": 63,
    "definitionId": 1,
    "timeStamp": "2023-05-16T12:20:03.807Z"

When the point master calls this endpoint, Engage receives the request and puts it into a queue. A unique transaction ID is also returned. When the job BalanceAccountToAmountJob is run, the queue is processed and the received point balance is then set in Engage for each of the contacts, putting Engage in sync with the point master

If the point master needs to track how the requests are being processed in Engage, it can use the following endpoint along with the transaction ID it received when it posted to /api/v2/point-accounts/balances:

GET /api/v2/point-accounts/balances/status/{id}

The response from this call will be in this form:

  "messages": [
      "message": "string",
      "timeStamp": "2023-05-17T11:03:16.947Z"
  "id": "string",
  "status": "string",
  "timeStamp": "2023-05-17T11:03:16.947Z"

2) All-transaction points update via the API

The points master will send point-generating transactions over the Engage API to keep the points synced. This is the endpoint used.

Adding point transactions

To add point transactions to Engage, use this endpoint:

POST api/v2/point-accounts/transactions

The transaction data is sent in the request body, in this JSON format:

    "contactId": "111111fa6-103b-459b-8d01-b6c000e8e26a",
    "amount": 12,
    "definitionId": 1,
    "timeStamp": "2023-06-01T08:40:51.658Z",
    "source": "Purchase",
    "description": "Gilded gauntlets",
    "validFrom": "2023-06-16T08:40:51.658Z",
    "validTo": "2024-06-16T08:40:51.658Z"

Many transactions can be sent in this array, up to a maximum of 1000.

The points amount (12 in this case) will be added to the point account defined by this contact ID and definition ID. If no point account exists for that contact ID and definition ID, then one will be created and used.

Common values for source are "Purchase", "Adjustment" and "Return". Other values are also available.

Since the points in this example have a validFrom date that's in the future from the purchase date, these points will be pending until then. When that date arrives, they will change to active.

A successful POST to this endpoint gets a HTTP 202 Accepted response. Otherwise you'll get:

  • 400 Too many items, New point system not active

3) Points log via an external API

When Engage is acting as point follower, it does not hold the points log (points history) for a contact. The point master owns all that information. Engage, however, can fetch the points log using an external API supplied by the point master, and then display it on the contact card.

The API call will look something like this:


The value "contactId" here is the ID of the contact in question.


This URL is hosted by the point master on their end.

This URL needs to be entered into the Engage backend. Your Voyado team will do this.

The point master needs to ensure the response from the endpoint has this form:

    "transactionDate": "2023-05-08T12:06:58Z",
    "amount": 1900,
    "description": "Purchase of tshirt"
    "transactionDate": "2023-05-08T12:02:55Z",
    "amount": 1500,
    "description": "Purchase of jeans"

Or, if the contact in question has no points yet, the response should be an empty array:


4) Points adjustment via a webhook

If a points adjustment is made in Engage, either manually in the UI or by an automation, and Engage is acting as point follower, that adjustment is not made right away. Instead it is sent as a request to the point master system. This is done using a webhook, provided by the point master, and configured in Engage.

Once the point master has received the update, the points change will only be visible in Engage when the point master performs its next sync (see step 1 for how that works).


Points adjustments made in Engage when it is acting as point follower might not have an immediate effect. We need to wait for the next sync from the point master.

The data sent over the webhook has the following form:

  "eventType": "loyalty.addPoints",
  "id": "70b84f00-d212-47c0-a56d-feaab6294333",
  "payload": "FtaW9DkGDs8yZGxkHU5Urh5B3fYpdjJylVwlCMUj1YlqcJ+9VVxO5dIhawwF2mbDJIkP1B9IVTM9+he86ZFBcIzGLr3K9nhH1hXuc0527Pkruan5TGsanjj4Kf2+7ZueY2FG6Vu5+nEuecxsDBgREyHOynieMBKRlBn3b1AVq7vw9D3dMdE6PpDGKFVAqrxrfP8jmmnPCn7orP4qAIxq6X67D8Jya4bs6ixJvZ66HPUwkmg0cEKiAhtgUlZko9XXMMPJUvHssQuIe6zhfx2r/bH9zwfbKPCNuTQ9q74iSc2CoA9akwCgk/f+PqnYspSznEnBvbwBUYlNoq39MOjjAtoMOoZD8+Jb3SGV9UxL8rHroSlOEttp1c7mX61UFIFCdo/OluCc54ycrjIx9Jgmww==",
  "tenant": "pointfollower"

The payload part is encrypted. The encryption key used must be entered into the Engage back-end, and also communicated separately to the point master system so that they can perform the decryption with the same key. Once decrypted, the form of the payload will depend on whether the points adjustment was done via an automation, or manually in the Engage UI.

Points adjustment through an automation

In this case, the decrypted payload will look like this:

  "ContactId": "1dfe06cd-a1be-4423-8ed4-afd900d998aa",  
  "Amount": 40,
  "Description": "Points awarded",
  "Source": "Automation",
  "PointDefinitionId": 1,
  "Reason": "Voyado",
  "ProcessId": "d6342090-7410-4c00-aa4b-dbd394dac7e6",
  "WorkflowId": "44931e65-e188-46c4-92bd-50e4818fece2",
  "WorkflowName": ""

ProcessId, WorkflowId and WorkflowName refer to the automation.

Points adjustment made manually in Engage

In this case, the decrypted payload will look like this:

  "ContactId": "1dfe06cd-a1be-4423-8ed4-afd900d998aa",  
  "Amount": 40,
  "Description": "Give points from Engage",
  "Source": "Manual",
  "PointDefinitionId": 1,
  "UserId": "c23f28cb-d62d-42cf-9d11-b919198409ea",  
  "UserName": "Jimmy User",  

The UserId and UserName here refer to the user who made the change in Engage.

The point master system can now read the points adjustment and apply it.

Viewing points in Engage

As mentioned, when Engage is point follower, adjustments are not applied directly, but instead sent to the point master using the webhook, and from there back to Engage via the API when the next sync happens.


It's important that the webhook from the point master is configured in Engage before the customer starts using it, or else points updates from automations and so on will be missed.

In the Engage UI, the user can view the points added and sent out:


1) Balance-only: In this case, the Engage UI will only act as an Iframe for showing point transactions after collecting them though the point master's API.

2) All-transaction: The standard solution for showing point transactions on the contact card will work.