Download OpenAPI specification:Download
This document is a technical description of the Loyalty API for Storebox. The Storebox Loyalty API is the programming interface for the Storebox Loyalty Bank.
Storebox Loyalty Bank is an API that provides merchants the opportunity to dynamically track their customers purchase history patterns and award points or coupons based on business rules and for users of the loyalty program to utilize these points and coupons.
The Storebox Loyalty Bank includes services for linking customers to the bank and any existing loyalty programs that may exist for future reference, so that the Storebox Loyalty Bank can be used with an existing loyalty card.
Merchants can use the API to integrate purchases in the physical store or at their webshop to the Storebox Loyalty Bank and thereby have a central and simple identification process based on the customers’ payment card (PAN).
The intended audience for this documentation is technicians developing system integration to Storebox.
The Storebox Loyalty API is organized around REST. The API is designed to have predictable, resource-oriented URLs and to use HTTP response codes to indicate API errors. We use built-in HTTP features, like HTTP authentication and HTTP verbs. JSON is the data interchange format and will be returned in responses from the API, including errors.
Users are a central part the loyalty API. They are the entity to be identified based on provided tokens and will often have coupons, points and/or cards associated.
Concepts:
Member id | A user can have one or more member ids with an associated type, for identification purposes. A member id is provided upon user creation and must be unique. | Member type | To each of the member id there can be connected member type. Member type can later be used to filter users when assigning points. |
User linkage | Users can linked either one-directional or bi-directional. The linkage can be used at lookup time to identify whether a member is part of a company, family, etc. |
Creates a new user, associates it with the given member ids and links it with the given linkedMemberIds
required | Array of objects (member-id-set) |
Array of objects (member-id-set) |
{- "memberIds": [
- {
- "memberId": "aa987654321",
- "memberType": "employee|loyaltymember"
}
], - "linkedMemberIds": [
- {
- "memberId": "aa987654321",
- "memberType": "employee|loyaltymember"
}
]
}
{- "userId": "string"
}
Lookup a user based on a provided member Id. This endpoint will return all relevant information on the user like memberIds, points (if enabled), coupons (if enabled) and linked users (if enabled).
memberId required | string Example: e75ca15c8ae1401c943ff15df437f1d8 Member id that should be looked up |
{- "provider": "storebox",
- "memberIds": [
- {
- "memberId": "aa987654321",
- "memberType": "employee|loyaltymember"
}
], - "card": {
- "cardId": "gse3wM53gjeEls59dGzWK31RCqLVL2vt",
- "cardtype": 16,
- "verified": true,
- "metadata": {
- "property1": "string",
- "property2": "string"
}
}, - "linkedMemberIds": [
- {
- "memberId": "aa987654321",
- "memberType": "employee|loyaltymember"
}
], - "coupons": [
- {
- "couponId": "WYgJ41dzZMTvFywjUPFFbf3ylzMVm83G",
- "couponName": "30% off pepperoni pizza",
- "startDate": "2022-05-14T15:22:11Z",
- "expiryDate": "2022-05-14T15:22:11Z",
- "campaignCode": "campaign-502",
- "campaignName": "Summer special",
- "useCount": 1,
- "value": 7,
- "metadata": {
- "property1": "string",
- "property2": "string"
}
}
]
}
Deletes the user on the specified memberId. Deleting a user will delete all cards, coupons, points, etc. associated with the user. This operation cannot be undone.
memberId required | string Example: e75ca15c8ae1401c943ff15df437f1d8 Member id that should be looked up |
{- "timestamp": 1549880850241,
- "status": "40X",
- "error": "Http status text",
- "message": "Cause of the error"
}
Add/remove member ids and add/remove linked users
memberId required | string Example: e75ca15c8ae1401c943ff15df437f1d8 Member id that should be looked up |
Array of objects (member-id-set) | |
Array of objects (member-id-set) | |
Array of objects (member-id-set) | |
Array of objects (member-id-set) |
{- "addMemberIds": [
- {
- "memberId": "aa987654321",
- "memberType": "employee|loyaltymember"
}
], - "removeMemberIds": [
- {
- "memberId": "aa987654321",
- "memberType": "employee|loyaltymember"
}
], - "addLinkedMemberIds": [
- {
- "memberId": "aa987654321",
- "memberType": "employee|loyaltymember"
}
], - "removeLinkedMemberIds": [
- {
- "memberId": "aa987654321",
- "memberType": "employee|loyaltymember"
}
]
}
{- "timestamp": 1549880850241,
- "status": "40X",
- "error": "Http status text",
- "message": "Cause of the error"
}
Lookup a user based on token. This endpoint keeps the footprint small and will only return the most basic user and card information.
token required | string Token referencing the users card |
{- "provider": "storebox",
- "memberIds": [
- {
- "memberId": "aa987654321",
- "memberType": "employee|loyaltymember"
}
], - "prefersNoPrintedReceipts": true,
- "card": {
- "cardId": "gse3wM53gjeEls59dGzWK31RCqLVL2vt",
- "cardtype": 16,
- "verified": true
}
}
Lookup a user based on a provided token. This endpoint will return all relevant information on the user like memberIds, points (if enabled), coupons (if enabled) and linked users (if enabled).
token required | string Token referencing the users card |
{- "provider": "storebox",
- "memberIds": [
- {
- "memberId": "aa987654321",
- "memberType": "employee|loyaltymember"
}
], - "card": {
- "cardId": "gse3wM53gjeEls59dGzWK31RCqLVL2vt",
- "cardtype": 16,
- "verified": true,
- "metadata": {
- "property1": "string",
- "property2": "string"
}
}, - "linkedMemberIds": [
- {
- "memberId": "aa987654321",
- "memberType": "employee|loyaltymember"
}
], - "coupons": [
- {
- "couponId": "WYgJ41dzZMTvFywjUPFFbf3ylzMVm83G",
- "couponName": "30% off pepperoni pizza",
- "startDate": "2022-05-14T15:22:11Z",
- "expiryDate": "2022-05-14T15:22:11Z",
- "campaignCode": "campaign-502",
- "campaignName": "Summer special",
- "useCount": 1,
- "value": 7
}
]
}
Like the get user endpoint this endpoint returns the user found, based on the provided token. In addition, this endpoint will also return all directly linked members complete with coupons, points etc.
token required | string Token referencing the users card |
{- "memberIds": [
- {
- "memberId": "aa987654321",
- "memberType": "employee|loyaltymember"
}
], - "coupons": [
- {
- "couponId": "WYgJ41dzZMTvFywjUPFFbf3ylzMVm83G",
- "couponName": "30% off pepperoni pizza",
- "startDate": "2022-05-14T15:22:11Z",
- "expiryDate": "2022-05-14T15:22:11Z",
- "campaignCode": "campaign-502",
- "campaignName": "Summer special",
- "useCount": 1,
- "value": 7
}
], - "linkedMember": [
- {
- "provider": "storebox",
- "memberIds": [
- {
- "memberId": "aa987654321",
- "memberType": "employee|loyaltymember"
}
], - "card": {
- "cardId": "gse3wM53gjeEls59dGzWK31RCqLVL2vt",
- "cardtype": 16,
- "verified": true,
- "metadata": {
- "property1": "string",
- "property2": "string"
}
}, - "linkedMemberIds": [
- {
- "memberId": "aa987654321",
- "memberType": "employee|loyaltymember"
}
], - "coupons": [
- {
- "couponId": "WYgJ41dzZMTvFywjUPFFbf3ylzMVm83G",
- "couponName": "30% off pepperoni pizza",
- "startDate": "2022-05-14T15:22:11Z",
- "expiryDate": "2022-05-14T15:22:11Z",
- "campaignCode": "campaign-502",
- "campaignName": "Summer special",
- "useCount": 1,
- "value": 7
}
]
}
]
}
Like the get user endpoint this endpoint returns the user found, based on the provided member id. In addition, this endpoint will also return all directly linked members complete with coupons, points etc.
memberId required | string Example: e75ca15c8ae1401c943ff15df437f1d8 Member id that should be looked up |
{- "memberIds": [
- {
- "memberId": "aa987654321",
- "memberType": "employee|loyaltymember"
}
], - "coupons": [
- {
- "couponId": "WYgJ41dzZMTvFywjUPFFbf3ylzMVm83G",
- "couponName": "30% off pepperoni pizza",
- "startDate": "2022-05-14T15:22:11Z",
- "expiryDate": "2022-05-14T15:22:11Z",
- "campaignCode": "campaign-502",
- "campaignName": "Summer special",
- "useCount": 1,
- "value": 7
}
], - "linkedMember": [
- {
- "provider": "storebox",
- "memberIds": [
- {
- "memberId": "aa987654321",
- "memberType": "employee|loyaltymember"
}
], - "card": {
- "cardId": "gse3wM53gjeEls59dGzWK31RCqLVL2vt",
- "cardtype": 16,
- "verified": true,
- "metadata": {
- "property1": "string",
- "property2": "string"
}
}, - "linkedMemberIds": [
- {
- "memberId": "aa987654321",
- "memberType": "employee|loyaltymember"
}
], - "coupons": [
- {
- "couponId": "WYgJ41dzZMTvFywjUPFFbf3ylzMVm83G",
- "couponName": "30% off pepperoni pizza",
- "startDate": "2022-05-14T15:22:11Z",
- "expiryDate": "2022-05-14T15:22:11Z",
- "campaignCode": "campaign-502",
- "campaignName": "Summer special",
- "useCount": 1,
- "value": 7
}
]
}
]
}
Cards are another central part of the loyalty API.
When users have registered their card number, Storebox will collect and maintian token values from multiple sources in order to identify users realtime based on their paymentcard. This usually requires collaboration with the terminal which provides the token sent to Storebox.
Note that Storebox stores cards in a PCI-DSS compliant environment and never exposes a users raw card number. All endpoints containing card information returns only a masked version of the card number.
Concepts:
Truncated/Masked card number |
A masked card number consists of the first 6 and last 4 digits of the card number. The middle digits have been replaced by a character, we use X. Example: 4571000000000000 -> 457100XXXXXX0000 |
Token | A token is a one-way reference to a card number. Tokens are usually looked up in PSP systems via a payment terminal, which in turn can be used to obtain a user from the loyalty API. |
Card types |
When cards are entered in Storebox, we identify the type of the card based on the IIN. The identified type resolves to a cardType: 1 - Dankort/VISA Dankort 2 - eDankort 3 - VISA/VISA Electron 4 - Mastercard 5 - Reserved 6 - JCB 7 - Maestro 8 - Diners Club 9 - American Express 10 - Reserved 11 - Forbrugsforeningen 16 - BankAxept |
Card frame |
To support users in registering their payment card information, Storebox delivers a PCI-DSS certified webpage. The page can be embedded in an IFrame on any page and is highly customizable. |
For online card registration via web or a smartphone app, a Storebox provided PCI-DSS compliant webpage must be used to comply with international card issuer standards. This webpage can be integrated with an existing webpage using an iframe or a mobile app by using a webview.
The flow can be seen in the following Figure:
Upon completed card registration Storebox can send a notification.
To have Strong Customer Authentication (SCA) like 3D Secure activated contact Storebox.
If SCA is enabled, a declineurl must also be provided, when loading the cardframe. The SCA flow will start automatically after the card submit and will redirect the user through the relevant verification flow.
Only if the SCA flow is successfull will the card be added to Storebox and the user will be redirected to the accept URL. If the flow for some reason is unsuccessfull the user will be redirected to the decline URL.
Server-side you generate the cardframe URL with all parameters (salt must never fall in the hands of client) and provide it to the client.
A quick demo can be had via https://developer.storebox.com/frame/index.html
Example data:
Hash generation: md5(id + accepturl + declineurl + callbackurl + cssurl + languageurl + salt)
md5 -s yourcustomeridhttps://developer.storebox.com/frame/accepted.htmlhttps://developer.storebox.com/frame/declined.htmlhttps://storebox.comhttps://developer.storebox.com/frame/assets/card.css?v=5https://developer.storebox.com/frame/assets/lang.json?v=64H8r63CSEYvbdJarNpF7
Final URL with proper URL encoded parameters, provider and hash that is provided to client: https://test-loyalty.storebox.com/v2/cards/url?id=yourcustomerid1&accepturl=https%3A%2F%2Fdeveloper.storebox.com%2Fframe%2Faccepted.html&declineurl=https%3A%2F%2Fdeveloper.storebox.com%2Fframe%2Fdeclined.html&callbackurl=https%3A%2F%2Fstorebox.com&cssurl=https%3A%2F%2Fdeveloper.storebox.com%2Fframe%2Fassets%2Fcard.css%3Fv%3D5&languageurl=https%3A%2F%2Fdeveloper.storebox.com%2Fframe%2Fassets%2Flang.json%3Fv%3D6&provider=yourproviderid&hash=1045d4756af23a321429ae55766bd15d
Result in browser
The card frame is styled via the CSS specified in the cssurl
parameter in the initial call.
The stylesheet is cached and is only downloaded if the URL changes. For this reason a version parameter can be used in the cssurl
, for example https://.../style.css?v=1
. Please refrain from using a constantly changing parameter, like a timestamp.
This is the Card Frame HTML structure that can be styled:
<form class="">
<div class="field field-input">
<div class="field-label">Kortnummer</div>
<input type="tel" value="" placeholder="Kortnummer" name="CardNumber" id="CardNumber" autocomplete="off" required="" class="">
<span class="field-validation-error">Ugyldigt kortnummer</span>
</div>
<div class="field field-input">
<div class="field-label">Udløbsmåned</div>
<input type="tel" value="" placeholder="Indtast udløbsmåned" name="ExpMonth" id="ExpMonth" autocomplete="off" required="" maxlength="2" class="">
<span class="field-validation-valid"></span>
</div>
<div class="field field-input">
<div class="field-label">Udløbsår</div>
<input type="tel" value="" placeholder="Indtast udløbsår" name="ExpYear" id="ExpYear" autocomplete="off" required="" maxlength="2" class="">
<span class="field-validation-valid"></span>
</div>
<div class="field field-btn">
<input type="submit" value="Gem kort" class="button" id="submit" name="add" disabled="disabled">
</div>
</form>
<div class="generalError">
</div>
<div class="maxCards">
</div>
A JSON file specified in languageurl
configures the text displayed in the card input. The file contains a translation label and value like in the following example. The language file must be provided in UTF-8.
{
"expMonth": {
"errorInvalid": "Skal være mellem 1 og 12",
"label": "Udløbsmåned",
"placeholder": "Indtast udløbsmåned"
},
"expYear":{
"label": "Udløbsår",
"placeholder": "Indtast udløbsår",
"errorExpired":"Kortet er udløbet"
},
"error":{
"generalError":"Der skete en fejl. Prøv venligst igen",
"maxCards":"Du kan ikke tilføje flere kort"
},
"btn":{
"save":"Gem kort"
},
"card":{
"errorInvalid":"Ugyldigt kortnummer",
"unsupportedType":"Denne korttype kan ikke bruges",
"unsupportedBinRange":"Dette kortnummer kan ikke bruges",
"label":"Kortnummer",
"placeholder":"Indtast kortnummer",
"duplicate":"Kortet er allerede registreret"
}
}
The text values are cached and are only downloaded if the URL changes. For this reason a version parameter should be used in the languageurl
, for example https://.../en.json?v=1
. Please refrain from using a constantly changing parameter, like a timestamp.
When a card has been fully processed a callback (GET) will happen if the callbackUrl parameter was defined on initial cardframe request.
A call to list cards is only guaranteed to include a newly created card after the notification has been sent.
Under some circumstances a notification may be sent more than once.
The notification will be sent as a server to server GET
request and is documented under 'Callbacks' below.
The callback does not act upon the responses sent from the callbackurl endpoint. I.e. a redirect will not be followed.
id required | string Member id of the user that should have the card appended |
provider required | string The card provider (container/owner) in Storebox systems |
accepturl required | string The URL where the page is redirected after successful card submit |
declineurl | string Required if Strong Customer Authentication (like 3DS) is enabled. The URL where the page is redirected after unsuccessful Strong Customer Authentication. |
callbackurl | string The URL that receives a callback once a submitted card is ready for use. Must be accessible from Storebox servers. |
cssurl required | string Absolute URL for the CSS file for input styling. Must be accessible from Storebox servers. |
languageurl | string Public URL for the translation JSON file. Must be accessible from Storebox servers. |
type | string Enum: "card" "accountno" What type of frame should be displayed. Default is the card frame Possible values
|
hash required | string MD5 hash of the value of the parameters plus a salt, md5(id + accepturl + declineurl + callbackurl + cssurl + languageurl + salt). |
Returns a list of cards registered to the user
memberId required | string Example: e75ca15c8ae1401c943ff15df437f1d8 Member id that should be looked up |
[- {
- "id": "czueiww7683oiytdq7to9me0ie1askf8",
- "name": "Kostkort",
- "cardNumber": "457100XXXXXX0000",
- "cardTypeId": 1,
- "accountNo": "12345678901",
- "accountNoTypeId": 16,
- "expiryMonth": 4,
- "expiryYear": 22,
- "verified": true,
- "metadata": {
- "property1": "string",
- "property2": "string"
}, - "created": "2018-12-10"
}
]
If existing cards are stored in Storebox, which have not yet been verified by 3DS, this endpoint can be used to start the 3DS flow.
The card owner must complete the authentication, so this endpoint will redirect and start the 3DS flow. The endpoint integration must therefore be from a browser or webview like the card frame.
After a successful completion the card will be marked as verified.
provider required | string The card provider (container/owner) in Storebox systems. |
externalCardId required | string Id of the card to verify. The card id was delivered in the callback on card creation. |
accepturl required | string The URL where the page is redirected after successful card verification. This happens in the frontend so app handlers can be used. |
declineurl required | string The URL where the page is redirected if the verification was unsuccessful. This happens in the frontend so app handlers can be used. |
hash required | string MD5 hash of the value of the parameters plus a salt, md5(provider + externalCardId + accepturl + declineurl + salt). |
Update the name of the card. Emojis are not supported.
cardId required | string Example: e75ca15c8ae1401c943ff15df437f1d8 ExternalCardId of the card. |
name required | string <= 64 characters The name of the card. Emojis are not supported. |
object Optional metadata describing the card, this could be whether the card has been externally verified or blacklisted. Note that all metadata are overridden if the property is set, so it has to be a full set of metadata. |
{- "name": "Kostkort",
- "metadata": {
- "property1": "string",
- "property2": "string"
}
}
{- "timestamp": 1549880850241,
- "status": "40X",
- "error": "Http status text",
- "message": "Cause of the error"
}
A pending card, is a card that is temporarily stored in Storebox' PCI environment. It cannot be looked up via cardlink functionality. The card is entered via i.e. a terminal integration or via an external PCI environment.
The pending state, allows the enduser to enter any information needed and accept terms before the card is enrolled.
Once the enduser creation is completed the card can be activated by the activation code.
The supported way of entering a pending card is currently:
A pending card is deleted after 30 days if it has not been activated.
Enroll the pending card and enable it to be lookup up
activationCode required | string Id of the pendingcard to be activated |
memberId | string Id of the member that should have the pending card associated |
{- "memberId": "e75ca15c8ae1401c943ff15df437f1d8"
}
A coupon (or voucher) is a "ticket or small printed piece of paper that entitles the holder to a discount, or that may be exchanged for goods or services."
The typical coupon operations are: assign -> authorize -> capture/cancel. Cancel removes the authorize state from a coupon so its use is unlocked and it may be authorized/captured again. Multi-use coupons can be authorized while they have usages left to authorize. An authorized coupon/usage will wait for capture/cancel for 3 hours, after which the authorize will be automatically cancelled and the coupon/usage is available again.
The get user endpoint, returns both points and coupons of a user. This section contains more specialized coupon endpoints.
Authorized coupons are not returned in lookups.
Campaign name and code are used to define a context.
Returns all user coupons, that are not in authorized state
token required | string Token referencing the users card |
{- "couponId": "WYgJ41dzZMTvFywjUPFFbf3ylzMVm83G",
- "couponName": "30% off pepperoni pizza",
- "startDate": "2022-05-14T15:22:11Z",
- "expiryDate": "2022-05-14T15:22:11Z",
- "campaignCode": "campaign-502",
- "campaignName": "Summer special",
- "useCount": 1,
- "value": 7,
- "metadata": {
- "property1": "string",
- "property2": "string"
}
}
Assigns a coupon as defined in the request to the member referenced by the token.
token required | string Token referencing the users card |
couponName required | string Human readable name of the coupon | ||||||
startDate | string <date-time> (iso-8601) Date-time notation as defined by RFC 3339, section 5.6, for example, 2022-05-14T15:22:11Z | ||||||
expiryDate required | string <date-time> (iso-8601) Date-time notation as defined by RFC 3339, section 5.6, for example, 2022-05-14T15:22:11Z | ||||||
campaignCode | string Campaigncode can be used to identify the campaign | ||||||
campaignName required | string Name of the campaign the coupon is associated with | ||||||
useCount | integer <int32> (coupon-useCount) Default: -1 Indicator showing how many uses the coupon has left
| ||||||
value | integer <int32> Default 0 |
{- "couponName": "30% off pepperoni pizza",
- "startDate": "2022-05-14T15:22:11Z",
- "expiryDate": "2022-05-14T15:22:11Z",
- "campaignCode": "campaign-502",
- "campaignName": "Summer special",
- "useCount": 1,
- "value": 7
}
{- "couponId": "WYgJ41dzZMTvFywjUPFFbf3ylzMVm83G"
}
Assign multiple coupons as defined in the request to multiple users. Each user in the list will be given coupons based on the contents of the couponTemplates in the request.
Please note that the term couponTemplates in this context is literal and refers only to the request data as templates for issuing coupons for that specific request. It is not a reference to the Coupon Template concept and endpoints and no template is persisted in any way. Use the 'create coupon template' method in case a persisted template is desired, from which coupons can be assigned at any time.
Array of objects |
{- "couponTemplates": [
- {
- "coupon": {
- "couponName": "30% off pepperoni pizza",
- "startDate": "2022-05-14T15:22:11Z",
- "expiryDate": "2022-05-14T15:22:11Z",
- "campaignCode": "campaign-502",
- "campaignName": "Summer special",
- "useCount": 1,
- "value": 7
}, - "memberIds": [
- "string"
]
}
]
}
{- "generatedCoupons": [
- {
- "coupon": {
- "couponName": "30% off pepperoni pizza",
- "startDate": "2022-05-14T15:22:11Z",
- "expiryDate": "2022-05-14T15:22:11Z",
- "campaignCode": "campaign-502",
- "campaignName": "Summer special",
- "useCount": 1,
- "value": 7
}, - "status": [
- {
- "memberId": "string",
- "couponId": "string"
}
]
}
], - "memberIdsNotFound": [
- "string"
]
}
Endpoint for capturing or cancelling multiple coupons in a single request.
capture | Array of strings eventIds to be captured |
cancel | Array of strings eventIds to be cancelled |
{- "capture": [
- "string"
], - "cancel": [
- "string"
]
}
{- "captureStatus": [
- {
- "eventId": "string",
- "code": 0,
- "reason": "string"
}
], - "cancelStatus": [
- {
- "eventId": "string",
- "code": 0,
- "reason": "string"
}
]
}
Coupon Templates are predefined coupon templates with no user association.
When a Coupon Template has been created a coupon based on the template can be assigned to users in different ways:
When registering progress to a user on a template, the system stores the progress over time. When the point goal is reached, a coupon based on the template is assigned to the user and the counter is automatically reset. Any overflow of points will count towards next coupon.
Creates a new template. Once a template is created, progress for individual users can be registered towards its progress goal, it can be assigned on signup or it can be used to directly assign coupons to users.
templateName required | string Human readable name of the template, for example "Coffee discount template" | ||||||
couponName required | string Human readable name of the coupon when assigned, for example "Here's half off on your next coffee!" | ||||||
startDate | string <date-time> Date-time notation as defined by RFC 3339, section 5.6, for example, 2022-05-14T15:22:11Z Absolute start date and time of coupons assigned from template. Any coupon assigned earlier than a templates startDate and will get startDate now(). | ||||||
expiryDate required | string <date-time> Date-time notation as defined by RFC 3339, section 5.6, for example, 2024-05-14T15:22:11Z Absolute expiry date of coupons assigned from template. Use voucherExpiry for setting a relative expiry date on assigned coupons. | ||||||
campaignName required | string Human readable name of the campaign | ||||||
campaignCode required | string A unique code identifying the campaign. | ||||||
progressGoal required | integer <int32> How many points are needed to trigger a coupon creation. | ||||||
value | integer <int32> Default: 0 Metadata. A value that can be used to indicate e.g. discount level or a coupons value. | ||||||
useCount | integer <int32> (coupon-useCount) Default: -1 Indicator showing how many uses the coupon has left
| ||||||
assignOnSignup | boolean Default: false If true, new users will be assigned a coupon based on the template, when they sign up | ||||||
voucherExpiry | string Assigned coupons will be created with an expiryDate relative to date-time of issuing. Must follow the regular expression pattern: ^([DWM])(\d*)$ Available time units: D(ays), W(eeks), M(onths). Examples:
| ||||||
object |
{- "templateName": "Coffee discount template",
- "couponName": "Here's half off on your next coffee!",
- "startDate": "2022-05-14T15:22:11Z",
- "expiryDate": "2024-05-14T15:22:11Z",
- "campaignName": "Discount on your 10th. cup of coffee",
- "campaignCode": "campaign-502",
- "progressGoal": 10,
- "value": 50,
- "useCount": 1,
- "assignOnSignup": false,
- "voucherExpiry": "W2",
- "metadata": {
- "property1": "string",
- "property2": "string"
}
}
{- "couponTemplateId": "ptsnaxm5q5bazf9y1b1ek42a3isxosuj"
}
{- "count": 1,
- "templates": [
- {
- "templateId": "ptsnaxm5q5bazf9y1b1ek42a3isxosuj",
- "templateName": "Coffee discount template",
- "couponName": "Here's half off on your next coffee!",
- "startDate": "2022-05-14T15:22:11Z",
- "expiryDate": "2024-05-14T15:22:11Z",
- "campaignName": "Discount on your 10th. cup of coffee",
- "campaignCode": "campaign-502",
- "progressGoal": 10,
- "value": 50,
- "useCount": 1,
- "assignOnSignup": false,
- "voucherExpiry": "W2",
- "metadata": {
- "property1": "string",
- "property2": "string"
}
}
]
}
Update an existing Coupon Template
couponTemplateId required | string Example: ptsnaxm5q5bazf9y1b1ek42a3isxosuj Id of the Coupon Template |
templateName required | string Human readable name of the template, for example "Coffee discount template" | ||||||
couponName required | string Human readable name of the coupon when assigned, for example "Here's half off on your next coffee!" | ||||||
startDate | string <date-time> Date-time notation as defined by RFC 3339, section 5.6, for example, 2022-05-14T15:22:11Z Absolute start date and time of coupons assigned from template. Any coupon assigned earlier than a templates startDate and will get startDate now(). | ||||||
expiryDate required | string <date-time> Date-time notation as defined by RFC 3339, section 5.6, for example, 2024-05-14T15:22:11Z Absolute expiry date of coupons assigned from template. Use voucherExpiry for setting a relative expiry date on assigned coupons. | ||||||
campaignName required | string Human readable name of the campaign | ||||||
campaignCode required | string A unique code identifying the campaign. | ||||||
progressGoal required | integer <int32> How many points are needed to trigger a coupon creation. | ||||||
value | integer <int32> Default: 0 Metadata. A value that can be used to indicate e.g. discount level or a coupons value. | ||||||
useCount | integer <int32> (coupon-useCount) Default: -1 Indicator showing how many uses the coupon has left
| ||||||
assignOnSignup | boolean Default: false If true, new users will be assigned a coupon based on the template, when they sign up | ||||||
voucherExpiry | string Assigned coupons will be created with an expiryDate relative to date-time of issuing. Must follow the regular expression pattern: ^([DWM])(\d*)$ Available time units: D(ays), W(eeks), M(onths). Examples:
|
{- "templateName": "Coffee discount template",
- "couponName": "Here's half off on your next coffee!",
- "startDate": "2022-05-14T15:22:11Z",
- "expiryDate": "2024-05-14T15:22:11Z",
- "campaignName": "Discount on your 10th. cup of coffee",
- "campaignCode": "campaign-502",
- "progressGoal": 10,
- "value": 50,
- "useCount": 1,
- "assignOnSignup": false,
- "voucherExpiry": "W2"
}
{- "timestamp": 1549880850241,
- "status": "40X",
- "error": "Http status text",
- "message": "Cause of the error"
}
Delete a Coupon Template
couponTemplateId required | string Example: ptsnaxm5q5bazf9y1b1ek42a3isxosuj Id of the Coupon Template |
{- "timestamp": 1549880850241,
- "status": "40X",
- "error": "Http status text",
- "message": "Cause of the error"
}
Get a specific Coupon Template
couponTemplateId required | string Example: ptsnaxm5q5bazf9y1b1ek42a3isxosuj Id of the Coupon Template |
{- "templateId": "ptsnaxm5q5bazf9y1b1ek42a3isxosuj",
- "templateName": "Coffee discount template",
- "couponName": "Here's half off on your next coffee!",
- "startDate": "2022-05-14T15:22:11Z",
- "expiryDate": "2024-05-14T15:22:11Z",
- "campaignName": "Discount on your 10th. cup of coffee",
- "campaignCode": "campaign-502",
- "progressGoal": 10,
- "value": 50,
- "useCount": 1,
- "assignOnSignup": false,
- "voucherExpiry": "W2",
- "metadata": {
- "property1": "string",
- "property2": "string"
}
}
Using templateId to reference a coupon template and register user progress towards a coupon. Once the progressGoal is reached a coupon is automatically assigned to the user. Progress counts up by the registered progress. Progress and issuing of coupons is cyclic. If the registered progress exceeds progressGoal then any leftover progress goes towards next coupon.
Example: progressGoal is 5. Current progress is 4. Registering progress of 3 will assign a coupon and the progress is now 2.
couponTemplateId required | string Example: ptsnaxm5q5bazf9y1b1ek42a3isxosuj Id of the Coupon Template |
memberId required | string |
progress required | integer <int32> |
{- "memberId": "aa987654321",
- "progress": 5
}
{- "timestamp": 1549880850241,
- "status": "40X",
- "error": "Http status text",
- "message": "Cause of the error"
}
Using campaignCode to reference a coupon template and register user progress towards a coupon. Once the progressGoal is reached a coupon is automatically assigned to the user. Progress counts up by the registered progress. Progress and issuing of coupons is cyclic. If the registered progress exceeds progressGoal then any leftover progress goes towards next coupon.
Example: progressGoal is 5. Current progress is 4. Registering progress of 3 will assign a coupon and the progress is now 2.
campaignCode required | string Example: campaign-502 campaignCode of the Coupon Template |
memberId required | string |
progress required | integer <int32> |
{- "memberId": "aa987654321",
- "progress": 5
}
{- "timestamp": 1549880850241,
- "status": "40X",
- "error": "Http status text",
- "message": "Cause of the error"
}
Get all progress information on a specific member.
memberId required | string Example: e75ca15c8ae1401c943ff15df437f1d8 Member id that should be looked up |
[- {
- "templateId": "ptsnaxm5q5bazf9y1b1ek42a3isxosuj",
- "campaignCode": "campaign-502",
- "campaignName": "Discount on your 10th. cup of coffee",
- "progress": 5,
- "progressGoal": 10
}
]
Assign a single coupon based on a Coupon Template to a single user
couponTemplateId required | string Example: ptsnaxm5q5bazf9y1b1ek42a3isxosuj Id of the Coupon Template |
memberId required | string Example: e75ca15c8ae1401c943ff15df437f1d8 Member id that should be looked up |
{- "couponId": "WYgJ41dzZMTvFywjUPFFbf3ylzMVm83G",
- "couponName": "30% off pepperoni pizza",
- "startDate": "2022-05-14T15:22:11Z",
- "expiryDate": "2022-05-14T15:22:11Z",
- "campaignCode": "campaign-502",
- "campaignName": "Summer special",
- "useCount": 1,
- "value": 7
}
Set extra information as name/value pairs on a template. The name/value pairs are returned in coupons created be the referenced template. If a metatdata name already exists, it is overriden with the new value.
couponTemplateId required | string Example: ptsnaxm5q5bazf9y1b1ek42a3isxosuj Id of the Coupon Template |
Array of objects List of metadata name/value pairs to be added | |
removeMetadata | Array of strings List of metadata name/value pairs to be deleted |
{- "addMetadata": [
- {
- "name": "coupon-reference",
- "value": "xatyhgdsadta-1"
}
], - "removeMetadata": [
- "context-reference"
]
}
{- "timestamp": 1549880850241,
- "status": "40X",
- "error": "Http status text",
- "message": "Cause of the error"
}
Creates a new assignment filter for the coupon template. When assigning a coupon based on a template, the filter is used to ensure that the users metadata qualifies for the coupon. Currently only 'country' is supported.
couponTemplateId required | string Example: ptsnaxm5q5bazf9y1b1ek42a3isxosuj Id of the Coupon Template |
filterType required | string Type of the filter. Supported values: "country" |
filterValues required | Array of strings List of filter values |
{- "filterType": "country",
- "filterValues": [
- "uk"
]
}
{- "filterType": "country",
- "filterValues": [
- "uk"
], - "filterId": "ptsnaxm5q5bazf9y1b1ek42a3isxosuj"
}
Get all filters for the template
couponTemplateId required | string Example: ptsnaxm5q5bazf9y1b1ek42a3isxosuj Id of the Coupon Template |
[- {
- "filterType": "country",
- "filterValues": [
- "uk"
], - "filterId": "ptsnaxm5q5bazf9y1b1ek42a3isxosuj"
}
]
Delete all filters for the template
couponTemplateId required | string Example: ptsnaxm5q5bazf9y1b1ek42a3isxosuj Id of the Coupon Template |
{- "timestamp": 1549880850241,
- "status": "40X",
- "error": "Http status text",
- "message": "Cause of the error"
}
couponTemplateId required | string Example: ptsnaxm5q5bazf9y1b1ek42a3isxosuj Id of the Coupon Template |
filterId required | string Example: ptsnaxm5q5bazf9y1b1ek42a3isxosuj Id of the Coupon Template Filter |
filterType required | string Type of the filter. Supported values: "country" |
filterValues required | Array of strings List of filter values |
{- "filterType": "country",
- "filterValues": [
- "uk"
]
}
{- "filterType": "country",
- "filterValues": [
- "uk"
], - "filterId": "ptsnaxm5q5bazf9y1b1ek42a3isxosuj"
}
Delete specific filters to the template
couponTemplateId required | string Example: ptsnaxm5q5bazf9y1b1ek42a3isxosuj Id of the Coupon Template |
filterId required | string Example: ptsnaxm5q5bazf9y1b1ek42a3isxosuj Id of the Coupon Template Filter |
{- "timestamp": 1549880850241,
- "status": "40X",
- "error": "Http status text",
- "message": "Cause of the error"
}
A point bank is a named collection of points.
Concepts:
Expiry period |
Every point bank has an expiry period of the points inserted to it. It can be days, weeks, months or years. The expiry of points is calculated based on the time the points where inserted.
For this to work we track what points are used when, and will always select the oldest points in a burn operation. |
Grace period |
A grace period is the time beyond the expiry period that the points are active. Ex. inserting points in a point bank today with 1 year expiry + grace period = MONTH will make the points expire in 1 year + running month. Grace period can be set to; instant (no grace period), month, quarter |
Get the available points from the default point bank. The points available equals to: sum in point bank - authorized points.
memberId required | string Example: e75ca15c8ae1401c943ff15df437f1d8 Member id that should be looked up |
{- "pointBank": "pointBankName",
- "availablePoints": 50
}
Insert points to the named point bank. If no point bank name is given the points will be inserted on the default point bank.
memberId required | string Example: e75ca15c8ae1401c943ff15df437f1d8 Member id that should be looked up |
pointBank | string name of the point bank being accessed |
points | integer how many points are available |
{- "pointBank": "pointBankName",
- "points": 50
}
{- "pointBank": "pointBankName",
- "availablePoints": 50
}
Burns authorized points and subtract them from the bank. The oldest points will be burned first.
eventId required | string Example: nxb3wMhjIjeElyNMQGzW431RCqLVL2vt Transaction specific id used to confirm an operation |
{- "pointBank": "pointBankName",
- "availablePoints": 50
}
Cancel authorized points and unlocks them to be used.
eventId required | string Example: nxb3wMhjIjeElyNMQGzW431RCqLVL2vt Transaction specific id used to confirm an operation |
{- "pointBank": "pointBankName",
- "availablePoints": 50
}
List user point bank details including expiry information
memberId required | string Example: e75ca15c8ae1401c943ff15df437f1d8 Member id that should be looked up |
includeExpired | boolean Flag indicating whether expired points should be included in returned results |
includeFullyBurned | boolean Flag indicating whether fully burned points should be included in returned results |
page | integer <int32> Pagenumber to return. The page index is zero-based. Defaults to 0 (zero) |
size | integer <int32> Elements returned per page. Defaults to 100. |
sort | string^(created|earnedPoints|spentPoints),(asc|desc... Sort of the returned content. Defaults to 'sort=expiringPointBankId,desc'. Sort can have any of the values: created, earnedPoints or spentPoints. In addition to defining the field to sort in, the sort direction is also defined in this field by either asc or desc Example: '...&sort=created,desc&...' |
{- "content": [
- {
- "pointBank": "pointBankName",
- "earnedPoints": 50,
- "burnedPoints": 20,
- "earnedDate": "2022-05-14T15:22:11Z",
- "expiryDate": "2022-05-14T15:22:11Z",
- "expired": false,
- "inGracePeriod": false
}
], - "totalElements": 1000,
- "totalPages": 10,
- "first": true,
- "last": false,
- "numberOfElements": 100,
- "page": 0
}
Enroll card at a Payment Service Provider (PSP) for online purchases. After card enrollment a ticketId is returned from the PSP to be used for recurring payments at the PSP. 3D Secure verification must be done directly with the PSP upon the first transaction.
Enroll card at a PSP and get a ticketId to use for recurring payments at the PSP. Upon succesfull enrollment the ticketId will also be saved as metadata on the card.
cardId required | string Example: e75ca15c8ae1401c943ff15df437f1d8 ExternalCardId of the card. |
{- "ticketId": "8RzQao5HANxljjo4iswIjKcsepU="
}
When certain events happen within the loyalty platform, a notification can be dispatched.
In order to setup notications, Storebox must receive an URL per notification type with static authentication headers. Storebox will not append information of the event type to the URL.
Example of valid URL sets:
Storebox monitors the response code returned, but will not handle the response body.
Note: None of the endpoints, in the "Notifications" section, exists in the loyalty API, but are endpoints the integrator must implement and expose. The suggested URL's, are only examples, and you, as an integrator, are free to define your own.
Notification that will be send when a coupon is created.
Note: You do not have to use "/coupon-create-notification" in the path, when implementing the receiving endpoint.
memberId required | string member id of the user that has been assigned a coupon |
provider required | string The card provider (container/owner) in Storebox systems that the user belongs to |
required | object (user-coupons) |
{- "memberId": "ptsnaxm5q5bazf9y1b1ek42a3isxosuj",
- "provider": "storebox",
- "coupon": {
- "couponId": "WYgJ41dzZMTvFywjUPFFbf3ylzMVm83G",
- "couponName": "30% off pepperoni pizza",
- "startDate": "2022-05-14T15:22:11Z",
- "expiryDate": "2022-05-14T15:22:11Z",
- "campaignCode": "campaign-502",
- "campaignName": "Summer special",
- "useCount": 1,
- "value": 7
}
}
Notification that will be send when a coupon is deleted.
Note: You do not have to use "/coupon-delete-notification" in the path, when implementing the receiving endpoint.
memberId required | string member id of the user that has been assigned a coupon |
provider required | string The card provider (container/owner) in Storebox systems that the user belongs to |
campaignCode required | string Campaigncode can be used to identify the campaign |
couponId required | string The unique coupon identification |
{- "memberId": "ptsnaxm5q5bazf9y1b1ek42a3isxosuj",
- "provider": "storebox",
- "campaignCode": "campaign-502",
- "couponId": "WYgJ41dzZMTvFywjUPFFbf3ylzMVm83G"
}
Notification that will be send when a coupon is expired.
Note: You do not have to use "/coupon-expire-notification" in the path, when implementing the receiving endpoint.
memberId required | string member id of the user that has been assigned a coupon |
provider required | string The card provider (container/owner) in Storebox systems that the user belongs to |
campaignCode required | string Campaigncode can be used to identify the campaign |
couponId required | string The unique coupon identification |
{- "memberId": "ptsnaxm5q5bazf9y1b1ek42a3isxosuj",
- "provider": "storebox",
- "campaignCode": "campaign-502",
- "couponId": "WYgJ41dzZMTvFywjUPFFbf3ylzMVm83G"
}
Notification that will be send when a coupon is captured/redeemed.
Note: You do not have to use "/coupon-capture-notification" in the path, when implementing the receiving endpoint.
memberId required | string member id of the user that has been assigned a coupon |
provider required | string The card provider (container/owner) in Storebox systems that the user belongs to |
campaignCode required | string Campaigncode can be used to identify the campaign |
couponId required | string The unique coupon identification |
itemNumber | string Product number of the product that triggered the redeem. Special conditions are required to receive this information |
itemNumberType | string Type of the item number |
storeId | string Id of the store that redeemed the coupon. Special conditions are required to receive this information |
storeIdType | string Type of store id |
{- "memberId": "ptsnaxm5q5bazf9y1b1ek42a3isxosuj",
- "provider": "storebox",
- "campaignCode": "campaign-502",
- "couponId": "WYgJ41dzZMTvFywjUPFFbf3ylzMVm83G",
- "itemNumber": "09843098234",
- "itemNumberType": "EAN",
- "storeId": "00032321",
- "storeIdType": "GLN"
}
Notification that will be send when a user received points on a Coupon Template.
Note: You do not have to use "/coupontemplate-progress-added-notification" in the path, when implementing the receiving endpoint.
memberId required | string member id of the user that has been assigned a coupon |
provider required | string The card provider (container/owner) in Storebox systems that the user belongs to |
campaignCode required | string Campaigncode can be used to identify the campaign |
{- "memberId": "ptsnaxm5q5bazf9y1b1ek42a3isxosuj",
- "provider": "storebox",
- "campaignCode": "campaign-502"
}
Notification that will be send when a user is created.
Note: You do not have to use "/user-create-notification" in the path, when implementing the receiving endpoint, but you must have memberId at the end of the path.
memberId required | string Example: e75ca15c8ae1401c943ff15df437f1d8 Member id that should be looked up |
Notification that will be send when a user is deleted.
Note: You do not have to use "/user-delete-notification" in the path, when implementing the receiving endpoint, but you must have memberId at the end of the path.
memberId required | string Example: e75ca15c8ae1401c943ff15df437f1d8 Member id that should be looked up |
A notification will be sent to your endpoint when an end user earns points.
Note: It is not necessary to include "/point-bank-exp-earn-notification" in the path when setting up the receiving endpoint.
provider | string The card provider (container/owner) in Storebox systems. |
memberId | string member id of the user |
pointBank | string name of the point bank being accessed |
availablePoints | integer how many points are available after the operation |
pointChange | integer how many points added (in earn notifications) or subtracted (in burn/expire notifications) |
operation | string To support a single integration endpoint, the type of operation is added to the requestbody. Supported values are: 'EARN_POINTS', 'BURN_POINTS' and 'EXPIRE_POINTS'. It is still possible to have notifications sent to separate endpoints, and ignore this value |
{- "provider": "storebox",
- "memberId": "ptsnaxm5q5bazf9y1b1ek42a3isxosuj",
- "pointBank": "pointBankName",
- "availablePoints": 50,
- "pointChange": 25,
- "operation": "see supported values"
}
A notification will be sent to your endpoint when an end user uses (burns) points
Note: It is not necessary to include "/point-bank-exp-burn-notification" in the path when setting up the receiving endpoint.
provider | string The card provider (container/owner) in Storebox systems. |
memberId | string member id of the user |
pointBank | string name of the point bank being accessed |
availablePoints | integer how many points are available after the operation |
pointChange | integer how many points added (in earn notifications) or subtracted (in burn/expire notifications) |
operation | string To support a single integration endpoint, the type of operation is added to the requestbody. Supported values are: 'EARN_POINTS', 'BURN_POINTS' and 'EXPIRE_POINTS'. It is still possible to have notifications sent to separate endpoints, and ignore this value |
{- "provider": "storebox",
- "memberId": "ptsnaxm5q5bazf9y1b1ek42a3isxosuj",
- "pointBank": "pointBankName",
- "availablePoints": 50,
- "pointChange": 25,
- "operation": "see supported values"
}
A notification will be sent to your endpoint when an end user points expire.
Note: It is not necessary to include "/point-bank-exp-expired-notification" in the path when setting up the receiving endpoint.
provider | string The card provider (container/owner) in Storebox systems. |
memberId | string member id of the user |
pointBank | string name of the point bank being accessed |
availablePoints | integer how many points are available after the operation |
pointChange | integer how many points added (in earn notifications) or subtracted (in burn/expire notifications) |
operation | string To support a single integration endpoint, the type of operation is added to the requestbody. Supported values are: 'EARN_POINTS', 'BURN_POINTS' and 'EXPIRE_POINTS'. It is still possible to have notifications sent to separate endpoints, and ignore this value |
{- "provider": "storebox",
- "memberId": "ptsnaxm5q5bazf9y1b1ek42a3isxosuj",
- "pointBank": "pointBankName",
- "availablePoints": 50,
- "pointChange": 25,
- "operation": "see supported values"
}
A notification will be sent before the points expire. The timing of the notification is configurable by Storebox.
Note: It is not necessary to include "/point-bank-exp-future-expire-notification" in the path when setting up the receiving endpoint.
provider | string The card provider (container/owner) in Storebox systems. |
memberId | string member id of the user |
pointBank | string name of the point bank being accessed |
pointChange | integer how many points are about to expire |
expiryDate | string <date-time> The expiration date of the point change event. |
operation | string To support a single integration endpoint, the type of operation is added to the requestbody. Supported values are: 'NOTIFY_POINT_EXPIRY'. |
{- "provider": "storebox",
- "memberId": "ptsnaxm5q5bazf9y1b1ek42a3isxosuj",
- "pointBank": "pointBankName",
- "pointChange": 25,
- "expiryDate": "2024-05-01T00:00:00.000+00:00",
- "operation": "NOTIFY_POINT_EXPIRY"
}
When a registered card is close to expiry, a notification can be triggered. The timing of the notification is configurable by Storebox.
Note: You do not have to use "/card-expiry-notification" in the path, when implementing the receiving endpoint.
provider | string The card provider (container/owner) in Storebox systems. |
memberId | string member id of the user the card is registered to |
cardId | string external card id of the expiring card |
maskedCardNumber | string Masked card number of the expiring card |
cardTypeId | integer card type of the expiring card |
expiryMonth | integer expiry month of the expiring card |
expiryYear | integer expiry year of the expiring card |
{- "provider": "storebox",
- "memberId": "ptsnaxm5q5bazf9y1b1ek42a3isxosuj",
- "cardId": "e75ca15c8ae1401c943ff15df437f1d8",
- "maskedCardNumber": "501932XXXXXX0325",
- "cardTypeId": "1 (Dankort/VISA Dankort)",
- "expiryMonth": 8,
- "expiryYear": 24
}