---
id: custom-adapter
title: Custom loyalty adapter
hide_title: true
description: "Custom loyalty adapter"
---

import Ingress from "../../../../src/components/ingress/ingress.react";
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

<Ingress title="Custom loyalty adapter">
  A custom loyalty adapter allows you to integrate Walley with your own CRM system
</Ingress>

## Overview

The custom loyalty adapter is an API that you host on your own system. It is called by Walley Checkout when certain events occur. The adapter is used to check whether a customer is a member of your loyalty program, and to create a new membership if the customer chooses to join.

If the customer changes the toggle to apply for membership, a `walleyCheckoutCrmUpdated` JS event will be sent. When this event is received you have to [acquire checkout information](/docs/checkout/getcheckoutinformation) to know the status of the membership.

<img
  src="/img/checkout/loyaltyBooster/swimlane-custom-adapter.png"
  alt="Sequence diagram of the two calls Walley Checkout makes to a custom loyalty adapter"
/>

As shown in the diagram, Walley Checkout calls Get Membership once the customer has identified, and receives the membership details. Once the customer has completed the purchase, it calls Create Membership and receives `201 Created`.

:::preview Early access
This functionality is at an early stage and is not yet available for all merchants. Please contact your Walley representative for more information.

Also note that this is the version 1 of the custom loyalty adapter api, and will be deprecated as soon as version 2 is released later this year. 
:::

## Authentication

All API requests require Basic Authentication and all communication is over HTTPS.

## Get Membership

### Description

Walley calls this endpoint to retrieve the loyalty membership details of a customer based on their email, phone number, and registration number.
It is typically called after a successful identification of the customer in Walley Checkout.

### Example request

```http
GET https://your-adapter.com/api/v1/membership?storeId=123&email=earl.grey@walley.se&mobilePhoneNumber=1234567890&locale=sv-SE HTTP/1.1
Authorization: Basic bXlVc2VybmFtZTpteVBhc3N3b3Jk...
```

#### Request headers

| Header        | Value |
| ------------- | ----- |
| Authorization | Basic |

#### Query parameters

| Parameter          | Type    | Sent  | Description                                                                                                                      |
| ------------------ | ------- | ----- | -------------------------------------------------------------------------------------------------------------------------------- |
| storeId            | integer | Yes   | The store identifier. Can be used to identify where requests came from in your CRM                                               |
| email              | string  | Yes   | The customer’s email address.                                                                                                    |
| mobilePhoneNumber  | string  | Yes   | The customer’s mobile phone number.                                                                                              |
| registrationNumber | string  | Maybe | The customer’s registration number. Only sent if the customer has provided it.                                                   |
| locale             | string  | Yes   | The desired locale used to localize applicationText, membershipName and termsUri [Supported languages](/docs/checkout/languages) |

### Response

#### Success (200 OK)

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "isMember": true,
  "applicationText": "Yes, I would like to become a member in ABC Reward Club and confirm the member terms\n Become a member and gain access to:\n- Points on all purchases\n- Bonus checks\n- Exclusive offers",
  "membershipName": "ABC Reward Club",
  "termsUri": "https://merchant-url.com/terms",
  "membershipDetails": {
    "id": "123456",
    "memberNumber": "987654"
  },
  "requiresRegistrationNumber": false
}
```

| Property                   | Type    | Required | Description                                                                                               |
| -------------------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------- |
| isMember                   | boolean | Yes      | Indicates if the customer is a member of the loyalty program or not                                       |
| applicationText            | string  | No       | The text shown to the customer. [See description](#application-text)                                      |
| membershipName             | string  | Yes      | The name of the loyalty program.                                                                          |
| termsUri                   | string  | Yes      | The URL to the terms and conditions of the loyalty program.                                               |
| membershipDetails          | object  | No       | The membership details of the customer. Only provided if the customer is a member of the loyalty program. |
| requiresRegistrationNumber | boolean | No       | Indicates if the adapter requires the registration number to create the membership.                       |

#### Application text

The `applicationText` property is shown to the user if provided. It can show unique selling points if the user is not a member, or membership benefits if the user already is a member.
It supports simplified markdown, and supported formatting are:

`**bold**` **bold**

`*italic*` *italic*

`- bullet` • bullet

`\n` new line

### Errors and timeouts

If the response is not received within `10 seconds`, the request will be considered timed out.
`1 retry` will be made for server errors and http exceptions after `2 seconds back-off`.

Any non 2xx response or timeout will result in the fallback to not show the membership details to the user.

## Create Membership

### Description

After the customer completes their purchase, Walley calls this endpoint if the customer is not yet a member. The `applyMembership` property indicates whether they chose to apply for membership.  

### Example request

```http
POST https://your-adapter.com/api/v1/membership HTTP/1.1
Authorization: Basic bXlVc2VybmFtZTpteVBhc3N3b3Jk...
Content-Type: application/json

{
  "applyMembership": true,
  "storeId": 123,
  "externalStoreId": "ext-5678",
  "address": {
    "firstName": "John",
    "lastName": "Doe",
    "address": "123 Main St",
    "postalCode": "416 70",
    "city": "Gothenburg",
    "countryCode": "SE"
  },
  "email": "john.doe@example.com",
  "mobilePhoneNumber": "+46701234567",
  "registrationNumber": "000000-0000"
}
```

#### Request headers

| Header        | Value            |
| ------------- | ---------------- |
| Authorization | Basic            |
| Content-Type  | application/json |

#### Request body

| Property           | Type    | Sent  | Description                                                                                    |
| ------------------ | ------- | ----- | ---------------------------------------------------------------------------------------------- |
| applyMembership    | boolean | Yes   | Indicates if the customer wants to apply for membership.                                       |
| storeId            | integer | Yes   | The store identifier. Can be used to identify where requests came from in your CRM             |
| externalStoreId    | string  | Maybe | The external store identifier provided when [initializing a checkout.](/docs/checkout/initcheckout) |
| address            | object  | Yes   | The address of the customer.                                                                   |
| email              | string  | Yes   | The customer’s email address.                                                                  |
| mobilePhoneNumber  | string  | Yes   | The customer’s mobile phone number.                                                            |
| registrationNumber | string  | Maybe | The customer’s registration number. Only sent if the customer has provided it.                 |

### Response

#### Success (201 Created)

```http
HTTP/1.1 201 Created
Content-Type: application/json

{
  "id": "123456",
  "memberNumber": "987654"
}
```

| Property     | Type   | Required | Description                                |
| ------------ | ------ | -------- | ------------------------------------------ |
| id           | string | No       | The internal ID to identify the membership |
| memberNumber | string | No       | The member number of the customer.         |

### Errors and timeouts

If the response is not received within `10 seconds`, the request will be considered timed out.
`1 retry` will be made for server errors and http exceptions after `2 seconds back-off`.

Any non 2xx response or timeout will result in the membership not being created.

## Acquiring loyalty membership information

When [acquiring checkout information](/docs/checkout/getcheckoutinformation) after a customer is identified, the `data.customer.loyaltyMembership` object contains information about the outcome of the membership registration.

| Property     | Type   | Returned | Description                                              |
| ------------ | ------ | -------- | -------------------------------------------------------- |
| provider     | string | Yes      | Always `custom` for a custom adapter.                    |
| success      | bool   | Yes      | `false` if the registration of membership failed.        |
| isMember     | string | Maybe    | Indicates membership, possible values are: yes, no, new. |
| id           | string | Maybe    | The internal ID to identify the membership.              |
| memberNumber | string | Maybe    | The member number of the customer.                       |

There will be four possible outcomes:

1. The customer is already a member, so no registration was performed.
2. The customer chose to apply for membership, and a membership was registered successfully.
3. The customer chose not to apply for membership.
4. The customer chose to apply for membership, but the registration failed due to technical reasons.

:::info Important

If the membership failed to register due to technical reasons, create the membership manually so the customer does not lose their points, bonus levels, or similar. To see why the registration failed, check the developer logs in the [Merchant hub](/docs/merchanthub/intro).

:::

<Tabs defaultValue="alreadymember" values={[
    { label: '1. Customer is already a member', value: 'alreadymember' },
    { label: '2. Customer was registered successfully', value: 'success' },
    { label: '3. Customer chose not to apply for membership ', value: 'nothanks' },
    { label: '4. Membership failed to register', value: 'fail' },
]}>

<TabItem value="alreadymember">

```json
{
  "data": {
    "customer": {
      "loyaltyMembership": {
        "provider" : "custom",
        "success": true,
        "isMember":"yes",
        "id": "9b43c86e-227b-4149-b0ee-de7f4846be26",
        "memberNumber": "123456789"
      }
    }
  }
}
```

</TabItem>

<TabItem value="success">

```json
{
  "data": {
    "customer": {
      "loyaltyMembership": {
        "provider" : "custom",
        "success": true,
        "isMember":"new",
        "id": "9b43c86e-227b-4149-b0ee-de7f4846be26",
        "memberNumber": "123456789"
      }
    }
  }
}
```

</TabItem>

<TabItem value="nothanks">

```json
{
  "data": {
    "customer": {
      "loyaltyMembership": {
        "provider" : "custom",
        "success": true,
        "isMember":"no"
      }
    }
  }
}
```

</TabItem>

<TabItem value="fail">

```json
{
  "data": {
    "customer": {
      "loyaltyMembership": {
        "provider" : "custom",
        "success": false
      }
    }
  }
}
```

</TabItem>

</Tabs>