A loyalty program within the Entur systems is an extension to a product.
Thus, a loyalty program will always have a unique product attached.
The product may give fare reductions, but this is managed elsewhere in the Entur systems.
In these cases, this document will use the term "discount rights", as in "the customer has discount
rights from the XX product"
Loyalty programs are divided into three main types:
All types have a first date of validity and an expiration date (even if it may be null).
This is an overview of the data structure:
Time-limited loyalty programs
An example of a time-limited loyalty program is "a customer card". For this type of loyalty program
Entur supports registering any discounts the contract has been used to garner. It is not possible to
register points-transactions or coupons on contracts for a time-limited loyalty program.
Coupon-limited loyalty programs
An example of a coupons-limited loyalty program is "a 10-coupon daily reduction", where a customer
is allowed 10 separate days of discount rights. In this case, the coupons-limited loyalty program
is configured to create a contract for a time-limited loyalty program for a given period (here, 24h)
from first purchase. On contracts for this type of loyalty program, neither points-transactions or
discounts may be registered. However, if configured, usage will be registered on the created
Points-limited loyalty programs
This type of loyalty program is currently used for gift cards. Contracts for a Points-limited
loyalty program can contain a list of points-transactions. The type of the points is specified
on the initial deposit, and can not be mixed. It is not possible to register discounts or coupons on
a contract for a points-based loyalty program.
Loyalty program versions
Loyalty programs are versioned by date. For each version, these fields can be changed:
Product version. If a new product version is available in the products db, you can create a new
loyalty program version to match.
Version start and end times. A Loyalty Program is valid if there exists a version with startDate
before now and endDate after now. If multiple versions have overlapping time periods, the one
with the highest versionNumber is considered the CURRENT version.
If the startDate is in the future, it is considered to be in DRAFT status. Creating new versions
will overwrite the current DRAFT version.
If the endDate is in the past, the version is considered DEPRECATED and no new contracts can be
created for this version. If all versions are DEPRECATED, no new contracts can be created and no
existing contracts will be accessible.
DRAFT means it is possible to save the loyalty program for further edits or another publish date, but it is not possible to create contracts on the program.
CURRENT mean it is possible to create contracts.
DEPRECATED means that it is no longer possible to create contracts
Descriptions. If the descriptions are not altered when a new version is created, they are copied
to the new version.
For COUPONS based loyalty programs, you can adjust the couponConfig by making a new version.
Call to create a new version:
"description": "Reis Kundekort gir deg 20% rabatt på alle kjøp"
A loyalty program may define a usageValidityPeriod, governing how long any attached contracts are valid.
To avoid ambiguity, only Day and Time units are allowed.
A Contract is the connection from one or more customers to a Loyalty Program. A Contract can be
considered an instance of a loyalty program. So, for instance, if the loyalty program is points-based
and relates to the fictional product ENT:PointsBasedProduct:GiftCard, each Contract can be considered
a single gift card. Another example, if we have the product ENT:EntitlementProduct:levelA1 (personnel
ticket, silver) and there exists a loyalty program with this product, each Contract can be considered
an entitlement for one specific employee or family member.
There are some limitations imposed on the types of thing you can register on a Contract based on the
type of the loyalty program it belongs to. Read more about this above.
In particular, only POINTS-based Contracts may have transactions, only TIMED Contracts may have OrderLineEvents
and only COUPONS-based Contracts may have child Contracts - each representing a used coupon.
Contracts may have Consumers. A Consumer is a Customer, identified by customerNumber and organisationId.
The endpoint also accepts customerRef which may be useful for identifying external customers down
stream in the sales process. Consumers have two flags:
isContractHolder: Whether this consumer is the current contract holder.
Only one contract holder can exist for a given contract.
Contract holders must be from the same organisation that owns the Contract.
It is not possible to add Consumers with isContractHolder=false unless there exists a Consumer
isBlocked: If a Consumer is marked as blocked, it will not show up as a valid contract for this
customer when searching. At the same time, since there exists a Consumer for that customer, they
can not create a new Consumer. This effectively blocks this customer from using this contract.
A Contract may be created with a set of policies. Policies are values that need to be supplied with
correct value to add a consumer to the Contract. For instance, if a Contract is created with a policy
that requires any consumers to be called "Anders", only customers supplying this information will
be able to consume the contract.
Decide when the Loyalty program should be available. Typically, Loyalty programs have long lives.
Decide how long a contract should be available as default. It may be several years, for instance for
Decide if other organisations should be allowed to connect their customers to your contracts. This
will make it easier to adapt your loyalty program for new users, but will not drive customers to
your sales channels. Only your customers can own a contract, regardless of what you decide here.
Decide on the text you want to use to represent this loyalty program to your customers.
In the example above, the first contract is open to all, not connected to any consumers and only
accessible by uuid. The second is already connected to one consumer (as contract holder), and has
a policy that only allows a customer who supplies a specific email when attempt to consume. This
second contract can also be found via its externalRef or its consumer. The external reference is
propagated through the sales channels when used.
How to connect a profile to a contract
A profile can be connected to a Contract in two ways:
It can be the contract owner. This must be a profile from the same organisation that owns the loyalty program and contract.
It can be a contract consumer. This can be a profile from any organisation.
Common for both types of connections is that they must conform to the policy that has been set up for the Contract when the connection is performed.
Also, a major difference here is that a contract only can have one owner. If the owner is removed
from the contract, it will no longer be accessible.
The organisation of the profile you are connecting
The customer number of the profile.
A customer reference. This field is not required but can be provided. If present, it will be echoed in the responses.
Whether you are trying to register a profile as the Contract Holder. Only one such is possible.
An object containing values for validating your claim to this contract. Depending on the contract, it may have a set of values you need to match to be able to consume it. The keys must match the keys used when creating the contract. Note, the contents of these fields are stored and compared as hashed values, so they may contain gdpr data without issues.
For instance, if the contract requires a specific email, it is sent here.
To get the uuid for this url, you may want to look up via the search endpoint.
How to connect a profile to a personnel ticket right
Personnel tickets are treated slightly different than other contracts. All contracts for personnel ticket
loyalty programs are created by the personnel ticket system. They simultaneously create a customer
profile and connect it as owner of the contract. All of this happens with the organisation ID 29
(the Norwegian Public Rail Administration) and therefore by default inaccessible for all partners.
It is somewhat simpler and will make sure customers are connected correctly in both the new and old
personnel ticket regimes. It will look up the customer based on customerNumber, and connect it to
the corresponding contracts.
Using contracts for entitlement products in the sales process
To use entitlement products in the sales flow, the customer must exist in Entur customers and it
must be connected to one or more entitlement products through loyalty program contracts (see the
previous two sections).
Using entitlement products based on contracts is done as part of the sales flow:
In this graph, the actors are:
Channel -> The distribution channel or backend-for-frontend for the sales agent
Example: Currently logged in customer is Anders Jensen. He has customerNumber 1234567. His customer
profile is connected to his personnel ticket (personnel ticket reference "ABCD-DEFG-GH12") and his
daughters' (Josefine, reference "1234-ABCF-3456")
Employees hav at least two entitlements. One for private journeys and one for work travel. These
have the same externalRef.
Family members and pensioners have just one personnel ticket entitlement - for private travel.
The Contract Owner for the personnel ticket entitlements are owned (isContractHolder=true) by a
customer profile administrated by the personnel ticket system. This means that the
ownerCustomerNumber typically will not refer to the current customer.
Client side rendering
At this point, the sales client must present the relevant choices to the end user and offer an option
to choose which ticket rights to use, if any. For each, this is also where it is connected to the
userType - ADULT, CHILD, etc. - for each traveller. This list should be filtered based on traveldate
and the validity dates of the contracts.
In our example, we could choose to present this as a list of choices:
Anders, Adult, private
Anders, Adult, corporate
Josefine, Child, private
Also, this is the place to determine if any of the travellers get senior citizens rebate.
Using the entitlements to get discounted offers
Once the end user has selected who is travelling, you can query offers with the entitlement products.
In the example, the end user has chosen two private travels, one for himself and one for his daughter.
Since the offers service has no concept about a customer we need to pass the entitlements for the
correct travellers to get the correct prices. Internally, the entitlement product we send in has a
connection to a SalesDiscountRight which is applied to the prices before returning from offers.
When passed an entitlement product, offers will locate valid SalesDiscountRights and apply them.
Which SalesDiscountRights were applied can be read directly from the returned offer in the section
called FareProductConfiguration. Any calculated discounts can be found at jpath
We recommend the savings are shown to the end user:
Oslo S - Bergen, Vy
Personnel ticket discount (*)
Here, the (*) may show some text about this kind of discount being reported to the Tax Authorities.
Accepting the offer and payment
Once the offer above is accepted, the procedure for creating the order requires some small changes
when using entitlements.
To begin, we need to know if the current logged in user is allowed to use those entitlements. To do
this, we need to have that person as creator of the Order:
... other order-values ...,
Then, the offer is converted to an order. Here, we need to include who is travelling (so names on
personnel tickets can be correct). Also, which contracts and entitlement product were actually
chosen for the different travellers. This is done when calling reserve-offers with an appropriate
Note about the example: Each traveller gets their own offerConfiguration. For each element we
specify who the traveller is through the customer object (with customer number from the entitlement),
and which contract and entitlement product were used.
This is then used internally to check if the creator is allowed to use the entitlements they are
presenting. Note that these credentials and the activation time are checked a second time when
activating the ticket.
NOTE: An entitlement must be valid for the customer on the date of travel when creating the order
and, for period tickets, both when attempting to activate the ticket and on the expiry date.