Loyalty API

qiibee Loyalty API Documentation

qiibee uses conventional HTTP response codes to indicate the success or failure of an API request.

In general, the 2xx range indicates success, the 4xx range indicates an error due to bad data or an authentication failure. And the 5xx range indicates an error with qiibee's servers (these are rare).

Base URL

The Base URL for all API requests is https://bwaapi.qiibee.com/api/admin

Authentication:

All API endpoints are authenticated with the X-API-KEY header.

If you do not send the header, or the header is invalid we will return a 401 with an error message Missing x-api-key header or Invalid API Key.

Postman Collection

You can use this postman collection to test all endpoints.

You will need to set the following environment variables:

  • qiibee_loyalty_api_base_url

  • qiibee_loyalty_api_key

  • auth_id

Endpoints:

Users

Create User

POST /users

Only the email field is mandatory.

We recommend you send a unique UUID-v4 auth_id for every new user registration so you can map each user to your internal system. If you do not send this field we will generate a UUID-v4 and return it to you.

Please save the auth_id and use it for all actions on a user's account.

eg.

{
"user": {
"email": "[email protected]",
"auth_id": "e24c962d-c81c-4a01-b0cd-57dd233553f1",
"first_name": "John",
"second_name": "Doe",
"language": "en",
"country_ISO": "usa"
}
}

Responses

  • Created: HTTP 201 with the user object

  • Bad data: HTTP 400 with error message

    • eg. duplicate auth_id

Update User details

PUT /users/:auth_id || PATCH /users/:auth_id

You can update every field besides the auth_id

eg.

{
"user": {
"email": "[email protected]",
"first_name": "John",
"second_name": "Smith",
"language": "it",
"country_ISO": "usa"
}
}

Responses

  • Update: HTTP 200 with the user object

  • Not found: HTTP 404 with error message

Get User Details

GET /users/:auth_id

Responses

  • Success: HTTP 200 with the user object:

    • {
      "user": {
      "email": "[email protected]",
      "auth_id": "e24c962d-c81c-4a01-b0cd-57dd233553f1",
      "first_name": "John",
      "second_name": "Doe",
      "language": "en",
      "country_ISO": "usa"
      }
      }
  • Bad data: HTTP 404 with error message

    • eg. not foun

Get User Balances

GET /users/:auth_id/balances

Will return an array of balances with the token type (erc20 or erc721).

Token types

  • erc20 is a regular token

  • erc721 is an NFT token

eg.

{
"data": [
{
"balance": 100,
"token": {
"address": "0x..924",
"name": "My Token Name",
"type": "erc20",
"metadata": { "key": "value" }
}
},
{
"status": [null, "pending", "approved", "rejected"],
"personalised_data": { "key": "value" },
"token": {
"address": "0x..924",
"name": "My NFT Token Name",
"type": "erc721",
"metadata": { "key": "value" }
}
}
]
}

Responses

  • Success: HTTP 200 with an array of balances

  • Bad data: HTTP 404 with error message

    • eg. not found

Create User Membership

POST /users/:auth_id/memberships

All fields are mandatory.

Each user can have 1 membership per exchange provider. You can override the membership number in specific requests - for example, when exchanging points to miles you can provide a new membership number specifically for that request.

exchange_provider_implementation_name can be one of:

  • etihad

  • miles_and_more

The membership number will be validated. If you want to know how you can validate the numbers yourself please reach out to us and we will provide the algorithms for each exchange provider.

eg.

{
"membership": {
"exchange_provider_implementation_name": "etihad" | "miles_and_more",
"membership_number": "xxxx....xxx"
}
}

Responses

  • Created: HTTP 201 with the user object

  • Not found: HTTP 404

    • user not found

  • Bad data: HTTP 400 with error message

    • invalid format for the membership number

    • invalid exchange provider

Update User Membership

Same as Create User Membership.

Get User Memberships

GET /users/:auth_id/memberships

This will return all the memberships for a user. If no memberships exist for the user this will be an empty array.

eg.

{
"data": [
{
"membership_number": "xxx...xxxx",
"exchange_provider": {
"name": "Miles and More",
"implementation_name": "miles_and_more"
}
},
{
"membership_number": "yyy...yyyy",
"exchange_provider": {
"name": "Etihad",
"implementation_name": "etihad"
}
}
]
}

Get User Membership

GET /users/:auth_id/memberships/:implementation_name

Returns the membership information for a user for a particular exchange provider implementation, if found, 404 and empty object otherwise.

eg.

{
"data": {
"membership_number": "xxx...xxx",
"exchange_provider": {
"implementation_name": "etihad",
"name": "Etihad"
}
}
}

Responses

  • Success: HTTP 200 with membership

  • Not found: HTTP 404 if user or membership not found

Delete User Membership

DELETE /users/:auth_id/memberships/:implementation_name

Delete's the membership information for a user if it exists. Returns 404 if user or membership not found.

eg.

{
"data": {
"membership_number": "xxx...xxx",
"exchange_provider": {
"implementation_name": "etihad",
"name": "Etihad"
}
}
}

Responses

  • Success: HTTP 204

  • Not found: HTTP 404 if user or membership not found

  • Bad request: HTTP 400 if the implementation does not exist

Codes

Use this set of endpoints to manage codes that can be given out to users for points or external rewards like airline FFP miles.

Create Code

POST /codes

Create a new code.

We will give you all your campaign_id values.

Fields:

  • value - value of points the code is worth

    • The external reward rate will be calculated based on your settings.

    • eg. if 1 point is 10 miles, then a code of 5 points is worth 50 miles.

  • campaign_id - all the IDs for your campaigns will be provided by us

  • length - optional. Length of the code to generate.

    • Minimum: 9

    • Default: 9

  • email - optional. If an email is passed we will also send the user an email with the code generated. You can choose a template or make a new one. Defaults to null

  • language - optional. Language for the email. Defaults to en

  • reference_id - optional. type: string.

    • is used as a duplicate check, so if it's sent it always needs to be unique for every request.

    • For example, you could pass your internal receipt/order ID to make sure that one transaction in your system is never processed twice, even if you happen to send the request twice.

eg.

{
"code": {
"value": "100",
"campaign_id": 1,
"length": 9,
"email": "[email protected]",
"language": "en",
"reference_id": "Order 109348HJ61"
}
}

Responses:

  • Success: HTTP 201 and the code:

    • {
      "data": {
      "code": "719026461",
      "value": "100",
      "campaign_id": 1,
      "reference_id": "Order 109348HJ61"
      }
      }
  • Bad request: HTTP 400

    • eg. Invalid campaign id or Code length too short

  • Conflict: HTTP 409 when reference_id was already used

Rewards

Manage your rewards. Eg. Discount Coupons

Users exchange points for a reward.

Soon you will also be able to send rewards to users dynamically.

Get Reward Details

GET /rewards/:reward

This endpoint will fetch a reward and the associated transaction and user_id if it has already been sent to a user.

Check out the Transactions section of the documentation to see what the loyalty event types are.

eg.

{
"code": "SPECIAL20",
"used": true | false,
"user_id": null | "user_id",
"reward_type": {
"id": 10,
"name": "20 EUR Discount",
"value": "100",
"website": "www.domain.com",
"valid_until": "1659515347",
"locations": [
{
"id": "2039",
"street": "Falkenstrasse",
"city": "Zurich",
"country": "Switzerland",
"zip": "8008",
"geolocation": "Geolocation point"
}
]
},
"transaction": {
"id": "284798327469",
"loyalty_event_type": "points_to_rewards",
"tx_hash": "0x.......293dsf23",
"points_burned": "100",
"token": null | {
"address": "0x..3849hz654",
"name": "My Token Name",
"type": "erc20" | "erc721",
"metadata": {
"key": "value"
}
},
"status": "success",
"reward_id": 3443,
"inserted_at": "1627976023"
}
}

Transactions

The following transaction/loyalty event types exist and you can use the transactions API to perform actions:

  • code_to_points - redeem a code for points

  • code_to_nft - redeem a code for an NFT

  • code_to_external_rewards - redeem a code for external rewards like miles

  • credit_points - credit point's to a user's account

    • eg. reward a user for spends

  • debit_points - debit points from a user's account

    • eg. redeem points for a reward like a coupon

  • points_to_rewards - redeem points for a reward like a discount coupon

  • points_to_external_rewards - redeem points for external rewards like miles

  • nft_personalisation - approve/reject a user's NFT personalisation

    • controlled via the NFTs endpoint

Create Transaction

POST /transactions

Use this endpoint to create any of the transaction types listed above.

Currently supported:

  • credit_points

  • debit_points

Based on the transaction type the body will differ.

Credit/Debit Points

All fields are mandatory.

If you try to debit more points than the user currently has you'll receive a 400.

Body:

  • amount can be an integer or string.

{
"transaction": {
"user_auth_id": "d0d15b76-1928-46bb-9927-8ffbf802455f",
"type": "credit_points" | "debit_points",
"amount": "100",
"token_id": 12
}
}

Exchange Points to Rewards

All fields are mandatory.

If you try to exchange more points than the user currently has you'll receive a 400.

Body:

  • amount can be an integer or string.

{
"transaction": {
"user_auth_id": "d0d15b76-1928-46bb-9927-8ffbf802455f",
"type": "points_to_rewards",
"amount": "100",
"token_id": 12,
"reward_type_id": 2432
}
}

Exchange Points to External Rewards

The following fields are optional:

  • membership_number_override- string - use this field to override the user's saved membership number only for this action

    • It will not overwrite the saved number in the account

  • exchange_rate_override- integer - use this field to specify a different exchange rate from what you've configured.

    • eg. 1 point is 40 airline miles but you want to change it to 80 for a particular user based on their tier.

    • It will not overwite the stored exchange rate

If you do not want to persist membership info for users you can send it with every request but for a better customer experience we encourage you to store it using the memberships API.

If you try to exchange more points than the user currently has you'll receive a 400.

Body:

  • amount can be an integer or string.

{
"transaction": {
"user_auth_id": "d0d15b76-1928-46bb-9927-8ffbf802455f",
"type": "points_to_external_rewards",
"amount": "100",
"token_id": 12,
"exchange_provider_implementation_name": "etihad" | "miles_and_more",
"membership_number_override": "xxx...xxx",
"exchange_rate_override": "10"
}
}

Responses

  • Success: HTTP 202

  • Bad request: HTTP 400

    • Insufficient balance

    • Invalid amount field

    • User/Token does not exist

    • Non existant exchange provider

    • Invalid membership number

NFTs

Manage your NFTs and approve/reject user personalisations like engravings and personal messages.

Approve/Reject NFT personalisation

POST /nfts

Use this endpoint to approve or reject a user's NFT personalisation.

If you reject it, the user will receive an email asking them to change the personalisation. You can pick from existing mail templates or create a new one.

All fields are mandatory.

eg.

{
"userNFT": {
"user_nft_id": "37329",
"status": "approved" | "rejected"
}
}