Eunoia Docs

This document describes how to call Eunoia APIs and lists all available ones.

Eunoia Entities

  • Brand - Eunoia supports multiple Brands. Every other entity is tied to a Brand.
  • Store - A place that you make an order to.
  • Product - An item that can be sold on its own
  • Category - A Product can belong to multiple Categories. A Category can have multiple child Categories.
  • Tag - A Product can have zero or one or more Tags. A Tag is just a piece of information with an image.
  • Variant - A Variant is some kind of variation of a Product that the customer must choose one. It has a price. Not all Products have Variants.
  • Modifier Group - A Product can have multiple Modifier Groups. Each group has a set of Modifiers. This allows a wide range of choices to be presented to the customer
  • Modifier - Something that modifies the final Product that the customer receives. Can have extra cost.
  • Availability - A day + time range for when something is available

Calling the API

It will be at something like /api/<version>/<service>/<brandCode>

  • GET for reading
  • POST for modifying something
  • Response is always a JSON
  • If success, response will be

    {
    	status: true [, code: <optional unique integer> ],
    	property1: etc,
    	property2: etc
    }
    

  • If failure, it will be

    {
    	status: false,
    	message: "Hopefully some reason why it failed" [, code: <optional unique integer> ]
    }
    

  • All entities will have the property id. It is a long value that is only unique for that entity
  • Images will have the property imageId. The value will be something like "awblbnmbgwpbzpcc8sux" This is an ID to a resource on Cloudinary. It can also be null. The URL for the image will be 'http://res.cloudinary.com/savantdegrees/image/upload/c_<crop-type>,h_<height>,w_<width>/<id>' E.g http://res.cloudinary.com/savantdegrees/image/upload/c_fit,h_400,w_300/awblbnmbgwpbzpcc8sux. There are many ways to customize the image, get different dimensions and weird transformations. See http://cloudinary.com/documentation/image_transformations
  • For customer related APIs, an authToken is required (see Login Customer)
  • Any customer related requests with an invalid authToken will return

    {
    	success: false,
    	code: -666,
    	message: "Some message you can display to the user"
    }
    

    The user should be redirected to the login flow
  • If the API Authentication Key is set at a brand, every API request to that brand must pass in that key. The key can be passed in as a request parameter authorization or a request header Authorization. E.g. http://platform.eunoia.asia/api/1.0/menu/ALT?authorization=jO0fHEBl1C2d0WOGGIJt6amAwI84msle
  • It is recommended to set this key before you go live otherwise anyone can simply send orders to that brand

API


Getting Stores

http://<server>/api/1.0/stores/<brandCode>

GET Parameters
  • lat: double, latitude of user's current location, optional
  • lng: double, longitude of user's current location, optional
  • line: string, human readable address of user's current location, optional

If `(lat and lng)` or `line` is passed in, the stores returned will be sorted in ascending order of their distances to the user's current location.

Response:
  • success: true
  • stores: Array of Stores
Store:
  • id: ID
  • name: string
  • delivery: boolean, whether this store does delivery right now
  • takeAway: boolean, whether this store does take-away (pick-up) right now
  • dineIn: boolean, whether this store does dine-in right now
  • reservation: boolean, whether this store does reservation right now
  • deliveryPreOrder: boolean, whether this store allows pre-orders (order ahead) for delivery
  • takeAwayPreOrder: boolean
  • dineInPreOrder: boolean
  • selfCollect: boolean, whether customers have to self-collect their order (dine-in or take-away) from the counter
  • presetDelivery: boolean, whether this store does delivery at all, 'delivery' however determines whether the store is doing delivery right now
  • presetTakeAway: boolean
  • presetDineIn: boolean
  • presetReservation: boolean
  • address: Address object
  • coord: Coordinates object
  • email: string
  • phone: string
  • table: Array of Table
  • openingHours: Array of Availabilities
  • dineInHours: Array of Availabilities
  • takeAwayHours: Array of Availabilities
  • deliveryHours: Array of Availabilities
  • openingHoursString: string, a nicely formatted human readable text from the 'openingHours' property
  • dineInHoursString: string, a nicely formatted human readable text from the 'dineInHours' property
  • takeAwayHoursString: string, a nicely formatted human readable text from the 'takeAwayHours' property
  • deliveryHoursString: string, a nicely formatted human readable text from the 'deliveryHours' property
  • imageId: string
  • deliveryMaxOrderValue: decimal number or null, apps should not allow a delivery order larger than this value
  • deliveryMinOrderValue: decimal number or null, apps should not allow a delivery order smaller than this value
  • sortIndex: integer, can be used for sorting Stores in ascending order
  • description: string
  • bufferTime: integer, number of minutes this store adds on as buffer to their preparation time
  • kitchenPrepTime: integer, number of minutes on average this store takes to prepare an order in the kitchen
  • transitTime: integer, buffer time given on top of Google Maps transit time for delivery orders
  • reservationSetting: Reservation Setting object or null, lists properties used for reservation
Address:
  • line1: string
  • line2: string
  • city: string
  • countryCode: string, 2 character country code
  • postalCode: string
  • string: string of the address in one lin
Coordinates:
  • lat: double, latitud
  • lng: double, longitud
Table:
  • id: ID
  • number: string, human readable number
  • sortIndex: integer, can be used for sorting Tables in ascending order
Reservation Setting:
  • minPax: integer, minimum pax allowed per reservation
  • maxPax: integer, maximum pax allowed per reservation
  • advanceDays: integer, number of days from current date a reservation can be made in advance
  • guestNote: string, text to be displayed on reservation submission
  • occasionAllowed: boolean, whether occasion field is allowed
  • occasions: Array of string, a list of preset occasions to be used for selection
  • closureDates: Array of Closure Date, date/time when reservation is not available
Closure Date:
  • date: milliseconds since epoch time, date, full day only if startTime/endTime is null
  • startTime: string, format "HH:mm:ss.ms"
  • entdTime: string, format same as above

Sample: http://platform.eunoia.asia/api/1.0/stores/ALT?authorization=jO0fHEBl1C2d0WOGGIJt6amAwI84msle

Get ETA

http://<server>/api/1.0/eta/<brandCode>

GET Parameters:
  • store: ID of store
  • orderType: "DELIVERY|TAKE_AWAY|DINE_IN"
  • address: string, pass in either this or (postalCode and countryCode)
  • postalCode: pass in (this and countryCode) or address
  • countryCode: see postalCode
  • subTotal: decimal number, defaults to 0 if not passed in
Response:
  • success: true
  • eta: integer, estimated time of arrival in minutes

Get GPS Coordinates from Address

http://<server>/api/1.0/location/coordinates

GET Parameters:
  • line: string, any free-form string containing some kind of address
Response:
  • success: true
  • lat: latitude
  • lng: longitude

Get Address from GPS Coordinates

http://<server>/api/1.0/location/address

GET Parameters:
  • lat: latitude
  • lng: longitude
Response:
  • success: true
  • address: Address object

Get Closest Store from Address

http://<server>/api/1.0/location/closestStore/<brandCode>

GET Parameters:
  • line: address string
Response:
  • success: true
  • store: Store object

Getting all Promotions

http://<server>/api/1.0/promotions/<brandCode>

Promotions are to be displayed only. There are two types of promotions - vouchers and promo codes. Vouchers are automatically given to customers in their account (see Customer vouchers property). Customers can then choose which vouchers to apply into their orders. Promo codes on the other hand are free to be used at any time. They simply have to be entered into the order. Of course, terms and conditions still apply.

Apps should pass in vouchers and/or promo codes selected by the customer to Eunoia with "test" = true, to query whether the promotion(s) can be applied. Eunoia will return the order with discounts if the promotion(s) are valid. This should be presented to the customer before paying.

Note that payments will be not validated by Eunoia. Users usually pay first before the app posts the order to Eunoia. Therefore, apps must restrict the payment options when a promotion that requires only certain payments is applied.

Response:
Promotion:
  • id: ID
  • name: string
  • description: string
  • imageId: string
  • tnc: string, terms and conditions
  • benefitType: "FREE_ITEM|DOLLAR_DISCOUNT_ON_ITEM|DOLLAR_DISCOUNT_ON_CART|PERCENTAGE_DISCOUNT_ON_ITEM|PERCENTAGE_DISCOUNT_ON_CART", see Benefit Types below for more details
  • periodType: "LIMITED_PERIOD|FOREVER"
  • periodFrom: millseconds since epochTime, when this promotion starts, only applicable when periodType == "LIMITED_PERIOD"
  • periodTo: millseconds since epochTime, last day before this promotion ends, only applicable when periodType == "LIMITED_PERIOD"
  • fulfillmentType: "ANY_TIME|CUSTOM", ANY_TIME means this can be redeemed anytime during the promotion period, CUSTOM means can only be redeemed during the fulfillment times
  • fulfillmentTimes: Array of Availabilities, can only be redeemed during these hours, only applicable when fulfillmentType == "CUSTOM"
  • publishType: "VOUCHERS|PROMO_CODE"
  • exclusive: boolean, if true this promotion can only be the only promotion used in an order
  • code: string, the promo code, only appicable when publsihType == "PROMO_CODE"
  • freeType: "PRODUCT|MODIFIER", if PRODUCT the free item will be a specific product, if MODIFIER, it will be a specific modifier, only applicable when benefitType == "FREE_ITEM"
  • freeProduct: ID of Product or null, only applicable when freeType == "PRODUCT"
  • freeModifier: ID of Modifier or null, only applicable when freeType == "MODIFIER"
  • takeAway: boolean, whether this promotion can be used for take away orders
  • dineIn: boolean, whether this promotion can be used for dine in orders
  • delivery: boolean, whether this promotion can be used for delivery orders
  • takeAwayStores: Array of Store IDs, only applicable when takeAway is true, and if empty, means ALL stores are applicable
  • dineInStores: Array of Store IDs, only applicable when dineIn is true, and if empty, means ALL stores are applicable
  • deliveryStores: Array of Store IDs, only applicable when delivery is true, and if empty, means ALL stores are applicable
  • emailDomains: Array of strings, e.g. of a string - "@eunoia.asia", only customers whose emails match any of these domains can apply this promotion
  • paymentTypes: Array of strings, currently only "CASH", "MASTERPASS", "PAYPAL", "STRIPE", "CREDIT_CARD", "PAYLAH" only orders paid with any of these payment methods are applicable, if empty all payment types are applicable
  • dollarDiscount: decimal number, dollars off a product or cart, only applicable when benefitType == "DOLLAR_DISCOUNT_ON_ITEM" || "DOLLARY_DISCOUNT_ON_CART"
  • percentageDiscount: decimal number, x% off off a product or cart, only applicable when benefitType == "PERCENTAGE_DISCOUNT_ON_ITEM" || "PERCENTAGE_DISCOUNT_ON_CART"
  • criteriaProducts: Array of Product IDs, products that will receive dollar or percentage discount, only applicable when benefitType == "DOLLAR_DISCOUNT_ON_ITEM" || "PERCENTAGE_DISCOUNT_ON_ITEM"
  • minAmountSpent: decimal number, minimum amount that must be spent (sub-total) before this promotion can be applied
  • maxDiscountValue: decimal number, maximum amount of discount that will be capped when applying this promotion
  • stockCount: "LIMITED|UNLIMITED", if LIMITED, this promotion can be only be redeemed stockLimit number of times
  • stockLimit: number of times this promotion can be redeemed, only applicable when stockCount == "LIMITED"
  • usageCount: "LIMITED|UNLIMITED", if LIMITED, this promotion can be only be redeemed usageLimit number of times per customer
  • usageLimit: number of times this promotion can be redeemed by a customer, only applicable when usageCount == "LIMITED"
  • redeemed: number of times this promotion has been redeemed by any customers, apps should simply not allow this promotion to be applied when this value is equal (or greater) than stockLimit
  • displayAsBanner: boolean, whether this promotion image can be displayed as promotional banner
Benefit Types
The following are the values of this enum:
  • FREE_ITEM: The benefit of this promotion is a free product or modifier. Apps should remind the user the item is not added to their order if it is not there. Otherwise, the server will simply return an error anyway.
  • DOLLAR_DISCOUNT_ON_ITEM: Dollar discount on a product that is in the criteria list of products
  • DOLLAR_DISCOUNT_ON_CART: Dollar discount on a whole order
  • PERCENTAGE_DISCOUNT_ON_ITEM: Percentage discount on a product that is in the criteria list of products
  • PERCENTAGE_DISCOUNT_ON_CART: Percentage discount on a whole order

Getting the Menu

http://<server>/api/1.0/menu/<brandCode>[/<storeId>]

If storeId is passed in, only the available menu for that particular store is returned.

GET Parameters
  • showAll: boolean, default is false, if true returns all products regardless whether they are available or not
  • app: string, the API code for the app. If available, the Brand object will contain an App object, optional
Response:
Brand:
  • id: ID
  • imageId: string
  • name: string
  • apiCode: string
  • defaultImageId: string, default product image the client should use if any product does not have an image, beware - this can be null also
  • enableProductImages: boolean
  • availabilityTimeIncrement: integer, number of minutes to use for incrementing time in a time picker
App:
  • name: string, name of the app
  • paymentAccounts: Array of Payment Accounts
  • properties: Object containing key/values specific to the app. Each key and value will be string.
  • status: "ACTIVE|DISABLED|DELETED", current status of the app
Payment Account:
  • name: string, name of the payment account
  • type: "PAYPAL|STRIPE|WIRECARD_HPP|PAYLAH", payment type
  • key: string, API key for the payment account. This should be used when requesting for a payment and when payments are posted along with an order
  • clientId: string, only for PayPal, clientId of the account which can be used in a PayPal SDK for making app payments
  • threeDSecure: boolean, only for Wirecard HPP, whether 3D secure is enabled
  • tokenizationEnabled: boolean, only for MPGS, whether credit card tokenization is enabled
Tag:
  • id: ID
  • imageId: string
  • image2Id: string
  • image3Id: string
  • availabilities: Array of Availabilities, if empty, this Category is available the whole day
  • name: string
  • description: string
  • sortIndex: integer, can be used for sorting Categories in ascending order
  • children: Array of child Categories
Category:
  • id: ID
  • imageId: string
  • image2Id: string
  • image3Id: string
  • availabilities: Array of Availabilities, if empty, this Category is available the whole day
  • name: string
  • description: string
  • sortIndex: integer, can be used for sorting Categories in ascending order
  • children: Array of child Categories
Product:
  • id: ID
  • imageId: string
  • image2Id: string
  • image3Id: string
  • name: string
  • description: string
  • sortIndex: integer, can be used for sorting Products in ascending order
  • price: decimal number
  • dineIn: boolean, if Store ID is passed in, whether this Product is available for dine-in right now. If Store ID is not passed in, whether ANY Stores have this available for dine-in
  • delivery: boolean, if Store ID is passed in, whether this Product is available for delivery right now. If Store ID is not passed in, whether ANY Stores have this available for delivery
  • takeAway: boolean, if Store ID is passed in, whether this Product is available for take away right now. If Store ID is not passed in, whether ANY Stores has this available for take-away
  • allDineIn: boolean, only appears when Store ID is not passed in, whether ALL Stores have this Product avaiable for dine-in right now
  • allTakeAway: boolean, only appears when Store ID is not passed in, whether ALL Stores have this Product avaiable for take-away right now
  • allDelivery: boolean, only appears when Store ID is not passed in, whether ALL Stores have this Product avaiable for delivery right now
  • categories: Array of Category ID
  • modifierGroups: Array of Modifier Groups
  • tags: Array of Tag IDs
  • variants: Array of Variants
Modifier Group:
  • id: ID
  • name: string
  • description: string
  • sortIndex: integer, can be used for sorting Modifier Groups in ascending order
  • combo: boolean, whether this group contains a combo of other Products
  • minModifiers: integer, minimum number of Modifiers that must be selected for this group
  • maxModifiers: integer, maximum number of Modifiers that can be selected for this group
  • modifiers: Array of Modifiers
Modifier:
  • id: ID
  • name: string
  • description: string
  • sortIndex: integer, can be used for sorting Modifiers in ascending order
  • price: decimal number
  • minQuantity: minimum number of this Modifier that must be selected
  • maxQuantity: maximum number of this Modifier that can be selected
  • product: ID of a Product if this Modifier belongs in a Modifier Group that is a combo, otherwise will be null
  • preSelected: boolean, whether this Modifier should already be selected for the customer, of course the customer may end up selecting another Modifier
Availability:
  • dayOfWeek: "MONDAY|TUESDAY|etc.."
  • startTime: string, format "HH:mm:ss.ms"
  • endTime: string, format same as above
Banner:
  • id: ID
  • imageId: string, default image and can be used as extra small image if other image types are available
  • product: ID of product this banner is for, or null, apps should go directly to this product page if it is not null
  • sortIndex: integer
  • link: URL string or null
  • name: string
  • startTime: milliseconds since epochTime, time to start showing this banner
  • endTime: milliseconds since epochTime, time to stop showing this banner
  • target: "PRODUCT|LINK|NONE"
  • position: "TOP|BOTTOM" or null
  • description: string
  • type: "GENERAL|ABOUT_BRAND|ONBOARDING" or null
  • imageSmId: string or null, small size image
  • imageMdId: string or null, medium size image
  • imageLgId: string or null, large size image
Variant:
  • id: ID
  • price: decimal number
  • modifierGroups: Array of Modifier Groups
  • name: string
Samples
  1. http://platform.eunoia.asia/api/1.0/menu/ALT?authorization=jO0fHEBl1C2d0WOGGIJt6amAwI84msle
  2. http://platform.eunoia.asia/api/1.0/menu/MLP?authorization=jO0fHEBl1C2d0WOGGIJt6amAwI84msle
  3. http://platform.eunoia.asia/api/1.0/menu/MLP/19?authorization=jO0fHEBl1C2d0WOGGIJt6amAwI84msle

Note that at store 19, only takeaway is available for that product.


Posting an Order

http://<server>/api/1.0/order/<brandCode>

POST body:
  • type: "DELIVERY|TAKE_AWAY|DINE_IN|TEST"
  • items: Array of OrderItems
  • payments: Array of Payments
  • discounts: Array of Discounts
  • store: ID of store that is receiving this order
  • table: ID of table for this order, can be NULL
  • authToken: authentication token of current customer (if null or missing, this is a guest order)
  • address: Address object (only applicable for DELIVERY)
  • specialRequest: string
  • origin: "IOS|ANDROID" or NULL
  • test: boolean, default false, if true, it's as if type == "TEST" but order will behave correctly as the intended type
  • fulfillmentTime: milliseconds since epoch time, time the customer wants to be fulfilled, if null, means NOW
  • customer: Guest object, optional
  • phone: string, optional, if passed in sets the phone number that the merchant can call specifically for that order
  • vouchers: Array of Voucher IDs to be applied to this order
  • promoCodes: Array of promo codes to be applied to this order
  • rewardPoints: integer
  • pax: integer, number of people eating in (only applicable for DINE_IN)
  • masterpassPayment: object, optional to pay using masterpass
  • paymentIds: Array of Payment Ids used for making payments (for payments using web view inside mobile applications)
  • app: string, API code of the app

If type == "TEST" the server will return a response as if this order is successfully placed. Useful for retrieving taxes, applying promotion codes, vouchers and so on.

Apps should not pass in any taxes and/or discounts from promotions. Those will automatically calculated and applied by Eunoia when the order is posted.

See here for more details on applying promotions.

Guest:
  • firstName: optional
  • lastName: optional
  • phone: optional
  • email: optional
OrderItem:
  • id: ID, ignored when POSTed to endpoint
  • product: ID of product
  • productName: string, name of product, ignored when POSTed to endpoint
  • quantity: integer
  • modifiers: Array of ModifierItems
  • total: decimal, ignored when POSTed to endpoint
  • specialRequest: string, instructions provided by user when ordering
  • variant: ID of Variant that is chosen, can be null for Products without Variants
  • variantName: string name of Variant that was chosen, ignored when POSTed to endpoint
  • variantPrice: decimal number, price of variant chosen, if no variant was chosen, this will be null, ignored when POSTed to endpoint
ModifierItem:
  • id: ID, ignored when POSTed to endpoint
  • modifierName: string, ignored when POSTed to endpoint
  • modifierId: ID of Modifier this is referring to
  • quantity: integer
  • modifiers: Array of ModifierItems (only applicable if this modifier is a combo product)
Payment:
  • id: ID, ignored when POSTed to endpoint
  • amount: decimal number
  • type: "CASH|CREDIT_CARD|PAYPAL|CREDITS|PAYLAH"
  • trackingId: string, can be anything, this value will just be stored as information, optional
  • transactionId: string, can be anything, this value will just be stored as information
  • paidTime: long, milliseconds since epoch time
  • status: "PAID|CANCELLED|REFUNDED"
  • accountKey: string, API key of the Payment Account
  • creditCardToken: Credit Card Token object
Address:
  • line1: string
  • line2: string, optional
  • city: string
  • countryCode: 2 character string, ISO 3166-2 country code
  • postalCode: string
Response:

When promotions are applied, success will be false if the any of the vouchers or promo codes applied are not valid. The vouchers property and promoCodes will contain details about why they are invalid.

VoucherError:
  • id: ID of Voucher that is invalid
  • message: string, a human readable string that explains why the voucher is invalid
PromoCodeError:
  • code: string, the promo code that is invalid
  • message: string, a human readable string that explains why the promo code is invalid
Order:
  • id: ID, ignored when POSTed to endpoint
  • type: "DELIVERY|TAKE_AWAY|DINE_IN|TEST"
  • number: string, human readable unique number of this order, ignored for TEST
  • items: Array of OrderItems
  • extraCharges: Array of ExtraCharges
  • payments: Array of Payments
  • discounts: Array of Discounts
  • placeTime: long, milliseconds since epoch time, the time this order was placed
  • status: "PLACED|COMPLETED|CANCELLED|DELETED|READY", see Order Status section
  • total: decimal, absolute final total, ignored when POSTed to endpoint
  • store: ID of store
  • table: ID of table
  • storeObject: Store object
  • tableObject: Table object
  • specialRequest: string
  • etaTime: long, milliseconds since epoch time, time the order will actually be fulfilled
  • fulfillmentTime: long, miliseconds, since epoch, time the customer wants the order to be fulfilled
  • phone: customer's phone number, may be null
  • pax: number of people eating in
  • queueTime: long, milliseconds since epoch time, the time when this order was queued for future preparation, may be null
  • prepareTime: long, milliseconds since epoch time, the time when this order started preparing, may be null
  • readyTime: long, milliseconds since epoch time, the time when this order was marked as ready, may be null
  • completeTime:long, milliseconds since epock time, the time when this order was completed, may be null
ExtraCharge:
  • id: ID, ignored when POSTed to entpoint
  • percentage: decimal, can be NULL, for "20%", this value will be = 20
  • type: "GST|SERVICE_CHARGE|DELIVERY_CHARGE|OTHERS"
  • comment: string
  • amount: decimal, absolute amount in dollars of this extra charge
  • name: name as specified by the admin if applicable
  • string: human friendly value to show to customers
  • tax: boolean, where this charge is a tax, apps may need to treat the display of taxes differently, also taxes should be displayed last
  • inclusive: boolean
Discount:
  • id: ID, ignored when POSTed to endpoint
  • percentage: same idea from ExtraCharge's percentage
  • amount: same
  • reason: string, why this discount is given
  • promotion: ID of the promotion used for creating this discount, ignored when POSTed to endpoint
  • voucher: ID of the voucher used for creating this discount, ignored when POSTed to endpoint
Samples:

Posting a test order: http://platform.eunoia.asia/api/1.0/order/ALT?authorization=jO0fHEBl1C2d0WOGGIJt6amAwI84msle

{
	"type": "TEST",
	"items": [
		{
			"product": 31,
			"quantity": 1,
			"modifiers": [
				{
					"modifierId": 610,
					"quantity": 1
				},
				{
					"modifierId": 606,
					"quantity": 3
				}
			]
		},
		{
			"product": 4,
			"quantity": 1,
			"modifiers": [
				{
					"modifierId": 261,
					"quantity": 1
				},
				{
					"modifierId": 265,
					"quantity": 1
				},
				{
					"modifierId": 266,
					"quantity": 2
				}
			]
		},
		{
			"product": 273,
			"quantity": 1,
			"variant": 6
		}
	],
	"discounts": [
		{
			"amount": 2.99,
			"reason": "$2.99 off for using this cool app"
		}
	],
	"payments": [
		{
			"amount": 49.01,
			"type": "PAYPAL",
			"transactionId": "PAYPAL-123456",
			"status": "PAID",
			"paidTime": 1457273565769
		}
	],
	"store": 1
}    
	

Reading all Orders

http://<server>/api/1.0/orders/<brandCode>

GET Parameters:
  • store: ID of Store, if missing Orders from all Stores are returned
  • pageSize: maximum number of records to return per page, if missing = 20
  • pageNumber: 0-based index of page to return, if missing = 0
  • sortOrder: "ASC|DESC", if missing = "ASC"
  • sortProperty: "placeTime", for now, if missing = "placeTime"
  • status: "PLACED|COMPLETED|CANCELLED", if missing, all orders will be returned
  • placeTimeFrom: long, epoch time in millisecond, inclusive
  • placeTimeTo: long, epoch time in millisecond, exclusive
  • authToken: if passed in, will only return orders for this customer
  • number: string, order number
Response:
  • success: true
  • orders: Array of Order
  • pager: Pager object
Pager:
  • count: integer, total number of records that match the query
  • pageSize: integer, size (number of records) per page
  • pageNumber: 0-based index of page

Order Statuses

When an order is submitted, its status is PLACED. The state transitions are as follows:

  • PLACED -> QUEUED | PREPARATION | CANCELLED
  • QUEUED -> PREPARATION | CANCELLED
  • PREPARATION -> READY | CANCELLED
  • READY -> COMPLETED | CANCELLED
  • COMPLETED -> CANCELLED

The following are descriptions for each status (values in brackets are what is displayed to back-end users):

  • PLACED (Pending): Order is placed and pending acceptance
  • QUEUED (Pre-order): Order is queued to be prepared at a future time (for pre-orders, i.e. fulfillmentTime is not null). This happens when the order is accepted
  • PREPARATION (Preparing): Order is being prepared in the kitchen. This happens when the order is accepted (for ASAP orders), or when the order is close to fulfilment time (for pre-orders) i.e fulfilment time - delivery time - kitchen prep time
  • READY (Ready / In-Transit): Order is ready for serving or delivery. This happens automatically based on the kitchen preparation time set by the store administrator
  • COMPLETED: Order is completed. This only happens when someone completes the order
  • CANCELLED: Order is cancelled for some reason. An order can be cancelled at any time.

Accepting an Order

http://<server>/api/1.0/order/<brandCode>/accept/<orderNumber>

Response:
  • success: true
  • order: Order object

Completing an Order

http://<server>/api/1.0/order/<brandCode>/complete/<orderNumber>

Response:
  • success: true
  • order: Order object

Cancelling an Order

http://<server>/api/1.0/order/<brandCode>/cancel/<orderNumber>

Response:
  • success: true
  • order: Order object

Querying whether a Customer is Registered

http://<server>/api/1.0/customer/registered/<brandCode>

POST Parameters:
  • email
Response:
  • success: true
  • registered: boolean

Register a Customer

http://<server>/api/1.0/customer/register/<brandCode>

Don't pass in the parameter if not available.

POST Parameters:
  • firstName
  • lastName
  • email
  • password
  • gender: "MALE|FEMALE"
  • origin: "ANDROID|IOS"
  • dateOfBirth: long value, epoch time in milliseconds
  • phone
  • facebookId
  • googlePlusId
  • lineId: LINE mid
  • accessToken: Required when facebookId, googlePlusId or lineId is passed in
  • refreshToken: lineId refresh token
  • addressName: name of address, free-form value e.g. "Home", "Office"
  • addressLine1
  • addressLine2
  • addressCity
  • addressCountryCode: 2-character string ISO 3166-2
  • addressPostalCode
  • deviceToken: device token for push notifications
  • deviceType: "ANDROID|IOS"
  • app: string, API code of the app, required if deviceToken is available
  • nationalityCode: 2-character string ISO 3166-2 country code
Response:
  • success: true
  • authToken: string
  • code: integer
Code Values:
  • -100: Email already exists
  • -101: Email already exists and account is connected to Facebook
  • -102: Email already exists and account is connected to Google Plus
  • -106: Email already exists and account is connected to LINE

Update a Customer

http://<server>/api/1.0/customer/update/<brandCode>

Don't pass in the parameter if not updating.

Additional POST Parameters:
  • authToken: authentication token of the user
  • addressId: ID of address to update, if not passed in when address data is passed in the system will create a new address for the customer
  • currentPin: string, current 6 digit PIN, required when updating 6 digit PIN
  • pin: string, new 6 digit PIN, required when updating 6 digit PIN
  • currentPassword: string, the current password, required only if a new password is sent

The rest are the same as Register a Customer.

Delete a Customer Address

http://<server>/api/1.0/customer/deleteAddress/<brandCode>

POST Parameters:
  • authToken: string
  • id: ID of Address to delete
Response:
  • success: true

Get Customer Details

http://<server>/api/1.0/customer/details/<brandCode>

GET Parameters:
  • authToken: string
Response:
  • success: true
  • customer: Customer Object
Customer:
  • id: ID
  • firstName
  • lastName
  • email
  • phone
  • googlePlusId
  • facebookId
  • gender "MALE|FEMALE" or null
  • dateOfBirth: milliseconds since epoch time, or null
  • addresses: List of Addresses
  • rewards: Rewards object
  • credits: decimal, number of credits the customer has left, should only be used for display
  • countryCode: 2-character string country code
  • vouchers: Array of Vouchers this customer has in their account, this can be applied on an Order
  • hasPin: boolean, whether the customer account has a pin
  • creditCardTokens: Array of tokenized Credit Cards this customer has in their account
Voucher:
  • id: ID
  • promotion: Promotion object
  • used: integer, number of times this voucher has been used, only applicable for vouchers that can be used multiple times per customer
Rewards:
  • totalRewardPoints
  • expiryDate: miliseconds since epoch time, when the reward points will expire
  • earnPointAmount
  • earnPoint
  • redeemPointAmount
  • redeemPoint
  • description
  • earnExclusionCategories: List of Categories
  • redeemExclusionCategories: List of Categories
Credit Card Token:
  • id: ID
  • created: milliseconds since epoch time, when this token was created
  • maskedAccountNumber: string, masked account number of tokenized credit card that can be displayed on the app
  • cardType: "MASTERCARD|VISA|AMEX|DINERS|JCB|CHINA_UNION_PAY" or null, card type

Login Customer

http://<server>/api/1.0/customer/login/<brandCode>

POST Parameters:
  • email
  • password
  • facebookId
  • googlePlusId
  • lineId: LINE mid
  • accessToken: Facebook or Google Plus or LINE access token
  • refreshToken: LINE refresh token
  • deviceToken: device token for push notifications
  • deviceType: "ANDROID|IOS"
  • app: string, API code of the app, required if deviceToken is available

(email and password) OR (facebookId and accessToken) OR (googlePlusId and accessToken) OR (lineId and accessToken) is required

Response:
  • success: true,
  • authToken: string
Code Values:
  • -106: Incorrect password

Logout Customer

http://<server>/api/1.0/customer/logout/<brandCode>

POST Parameters:
  • accessToken: Facebook or Google Plus access token
  • authToken: string
  • deviceToken: device push token so as to disable push notifications to this device
Response:
  • success: true

Request for Customer Password Change

http://<server>/api/1.0/customer/forgotPassword/<brandCode>

POST Parameters:
  • email: customer email address
Response:
  • success: true
Code values (if success: false)
  • -103: Email not found

Change Customer Password (after Request)

http://<server>/api/1.0/customer/changePassword/<brandCode>

POST Parameters:
  • email: customer email address
  • pin: pin number that was sent to their email account
  • password: new password
Response:
  • success: true
Code values (if success: false)
  • -103: Email not found
  • -104: Pin is incorrect
  • -105: Code has expired

Create PIN

http://<server>/api/1.0/customer/createPin/<brandCode>

POST parameters:
  • authToken: string
  • pin: string, 6 digit PIN used to authenticate Masterpass transactions
Response:
  • success: true

Get Favourite Product List for Customer

http://<server>/api/1.0/customer/favourites

GET Parameters:
  • authToken: string
  • productData: boolean, if true returns product details in 'favourites' property of the response
Response:
Favourite
  • product: ID of product
  • variant: ID of variant
  • time: milliseconds since epoch time, time this product was favourited
  • data: Product object, only sent when productData parameter is true
  • modifiers: array of Modifier objects
Modifier:
  • modifier: ID of modifier
  • quantity: integer

Add a Favourite Product for Customer

http://<server>/api/1.0/customer/favourite

POST Parameters:
  • authToken: string
  • product: ID of product
  • variant: optional, ID of variant
  • modifiers: optional, array of Modifier objects. Eg: modifiers[0].modifier=123&modifiers[0].quantity=1
Response:
  • success: true

Remove a Favourite Product for Customer

http://<server>/api/1.0/customer/unfavourite

POST Parameters:
  • authToken: string
  • product: ID of product
  • variant: optional, ID of variant
  • modifiers: optional, array of Modifier objects. Eg: modifiers[0].modifier=123&modifiers[0].quantity=1
Response:
  • success: true

Delete a Credit Card Token for Customer

http://<server>/api/1.0/customer/deleteCardToken

POST Parameters:
Response:
  • success: true

Wirecard Hosted Payment Page

http://<server>/ipg/wirecard-hpp/mobilePayment/<uniquePaymentId>?headquarter=<headquarter>&brand=<brandCode>&amount=<paymentAmount>&authToken=<authToken>&token=<creditCardToken>&voidAfterPayment=<voidAfterPayment>&orderJson.target=<target>&orderJson.json=<json>&accountKey=<accountKey>

URL Parameters:
  • uniquePaymentId: string (maximum length = 40), generated on the app as a random alpha-numeric string for each payment attempt
  • brandCode: string, brand code, optional
  • headquarter: string, HQ code, optional
  • paymentAmount: decimal number
  • authToken: authentication token of current customer, required if tokenized card needs to be saved to a customer account
  • token: string, id of the customer's credit card token to be used for this payment, optional
  • voidAfterPayment: boolean, if the payment needs to be voided on completion. This can be used to create and save new cards by paying a $1 amount and then voiding the payment once the credit card token is created, optional
  • accountKey: string, api code of Payment Account. If token is being used, use a payment account where 3D secure is not enabled.
  • orderJson.target: "OUTLET|STORE", target for the order, optonal
  • orderJson.json: string, json containing the order which will eventually be posted after completing payment, optonal

This payment method allows the mobile app to:

  • Use the hosted payment page to make a payment for a transaction.
  • Save a tokenized credit card for each customer by placing a $1 transaction and immediately voiding the payment. These tokens can be used within the app to make subsequent payments.

Open the URL (Hosted Payment Page method) in a web view within the app. The web page allows the user to enter credit card information securely inside the web page and complete payment. Each payment creates a credit card token for the customer which is updated as stored as part of the customer details. Observe the web view URL for the following changes:

  • If the url contains mobileSuccess - payment was successful. Navigate away from the web view and either post the order with an array of payments containing the unique payment id as the trackingId or refresh the customer details to get the new list of credit card tokens.
  • If the url contains mobileFail - payment failed. Navigate away from the web view and inform the user that payment has failed.
Testing:
  • VISA: 4005550000000001, Expiry Date: 2018, CVV: 602
  • MASTERCARD: 5453010000064154, Expiry Date: 2018, CVV: 123
  • Failed transactions can be simulated with the following payment amounts: $4.43, $5.54, $6.64, $8.86, $9.96, $11.07

DBS/POSB Bin Codes

http://<server>/api/1.0/wirecard-hpp/binCodes/<brandCode>

Response:
  • success: true
  • binCodes: Array of DBS/POSB Bin Codes
Bin Code:
  • prefix: string, first 6 digits for credit cards of this type
  • cardType: "MASTERCARD|VISA|AMEX|DINERS|JCB|CHINA_UNION_PAY", card type
  • description: string, usually the card name. Eg: Visa Platinum or Gold

DBS Paylah

Paylah is a mobile wallet allowing customers to make funds transfer and online payments via a mobile number.

App Checkout

http://<server>/api/1.0/paylah/appCheckout/<brandCode>

Checkout using Paylah can be either regular or express checkout. For regular checkout, open the Paylah app from the current app using the URL schemes as part of the response to process payment. A payment can be either successful or cancelled by the user on the Paylah app, in either case, the current is re-opened by the Paylah app using the return URL scheme. Upon return, query the transaction status to decide order processing. For express checkout, the payment status is returned in the API response. If the payment is successful, post the order with an array of payments containing the unique payment id as the trackingId.

POST Parameters:
  • authToken: string
  • accountKey: string, api code of Payment Account
  • mobileNumber: string, registered Paylah mobile number, required only if expressCheckout=true
  • returnUrl: string, return URL scheme of the mobile app. The Paylah app will use this to open your app upon completion
  • trackingId: string, (maximum length = 20), generated on the app as a random alpha-numeric string for each payment attempt
  • amount: decimal number, payment amount
  • expressCheckout: boolean, whether this transaction uses express checkout
Response:
  • success: true
  • androidAppUrl: string, open the Paylah Android app using deep linking with this URL scheme. This field is not used for express checkout.
  • iosAppUrl: string, open the Paylah iOS app using app linking with this URL scheme. This field is not used for express checkout.

Setup Express Checkout

http://<server>/api/1.0/paylah/setupExpressCheckout/<brandCode>

POST Parameters:
  • authToken: string
  • accountKey: string
  • mobileNumber: string, registered Paylah mobile number
  • returnUrl: string, return URL scheme of the mobile app. The Paylah app will use this to open your app upon completion
Response:
  • success: true
  • androidAppUrl: string, open the Paylah Android app using deep linking with this URL scheme
  • iosAppUrl: string, open the Paylah iOS app using app linking with this URL scheme

Express Checkout Status

http://<server>/api/1.0/paylah/expressCheckoutStatus/<brandCode>

POST Parameters:
  • authToken: string
  • accountKey: string
  • mobileNumber: string, registered Paylah mobile number
Response:
  • success: true
  • expressCheckoutEnabled: boolean

Transaction Inquiry

http://<server>/api/1.0/paylah/transactionInquiry/<brandCode>

POST Parameters:
  • authToken: string, optional
  • accountKey: string, api code of Payment Account
  • trackingId: optional, unique payment ID used to initiate this transaction
Response:
  • success: true
  • payment: Payment object

Testing

Testing Paylah requires the following application installations:

  • Install ZeroTier One app from the Google Play Store or the Apple App Store
  • Install the Sandbox Paylah app for Android or iOS. Installing the Sandbox Paylah app on a mobile device will overwrite any production Paylah app already installed, so preferrably use this on a test device to avoid conflicts.

Contact a Eunoia administrator to setup a ZeroTier One connection to the Paylah payment server. Follow the steps below to setup a test account on the Paylah app:

  • Select Environment UAT BAU Sandbox
  • Click on either New Installation or Activate Device ID
  • Click login and enter a mobile number (90000053 or 90000054)
  • Enter user ID (P0000053P or P0000054P) and password (any 6 digits)
  • Enter OTP (any 6 digits)
  • Enter Paylah password (qwerty)

The test Paylah mobile numbers 90000053 or 90000054 can be used in the APIs to pay using the Sandbox Paylah app.

MPGS Hosted Checkout

http://<server>/ipg/mpgs/mobilePayment/<uniquePaymentId>?brand=<brandCode>&amount=<paymentAmount>&authToken=<authToken>&accountKey=<accountKey>&tokenizeCard=<tokenizeCard>

URL Parameters:
  • uniquePaymentId: string (maximum length = 40), generated on the app as a random alpha-numeric string for each payment attempt
  • brandCode: string, brand code, optional
  • paymentAmount: decimal number
  • authToken: authentication token of current customer, required if tokenizeCard is true
  • accountKey: string, api code of Payment Account
  • tokenizeCard: boolean, whether the user wants to save their card, optional. Used together with tokenizationEnabled in Payment Account

This payment method allows the mobile app to:

  • Use the hosted checkout page to make a payment for a transaction.
  • Save a tokenized credit card for each customer as part of payment for the first transaction. These tokens can be used within the app to make subsequent payments.

Open the URL (Hosted Checkout method) in a web view within the app. The web page allows the user to enter credit card information securely inside the web page and complete payment. If tokenizeCard is used, the payment creates a credit card token for the customer which is updated as stored as part of the customer details. Observe the web view URL for the following changes:

  • If the url contains mobileResumeSuccess - payment was successful. Navigate away from the web view and either post the order with an array of payments containing the unique payment id as the trackingId or refresh the customer details to get the new list of credit card tokens.
  • If the url contains mobileResumeFail - payment failed. Navigate away from the web view and inform the user that payment has failed.
  • If the url contains mobileResumeCancel - payment was cancelled by user. Navigate away from the web view and inform the user that payment was cancelled.

Test credit cards can be found here.

MPGS Pay with Token

http://<server>/api/1.0/mpgs-dcc/pay/<brandCode>

POST Parameters:
  • authToken: string
  • token: string, id of the customer's credit card token to be used for this payment
  • accountKey: string
  • trackingId: string (maximum length = 40), generated on the app as a random alpha-numeric string for each payment attempt
  • amount: decimal number

This API allows the app to make a fast payment with saved credit card details.

Response:
  • success: true

Webhooks

Webhooks allow developers to register a URL that will receive HTTP POST requests whenever an event occurs in Eunoia Platform for their brand.

This URL can be configured under Brand Settings: Each event will pass in at least 3 POST parameters:

  • version: string, a API version of the event. E.g. "1.0", "1.1" or "2.0"
  • event: string, type of the event
  • brand: string, API code of the brand. Can be useful in case the same URL is being used for multiple brands
More parameters will be passed in depending on the "version" and "event" parameter.

New Order (ORDER.NEW)

This event triggers when a new order is created. Apps will have to query "Reading all Orders" call to retrieve the order details.

Version "1.0"

Parameters:

  • number: string, order number
  • event: "ORDER.NEW"

Order Status Changed (ORDER.STATUS_CHANGED)

This event triggers when the status of an order has changed. Apps will have to query "Reading all Orders" call to retrieve the order details. Refer here for details of the different order statuses.

Version "1.0"

Parameters:

  • number: string, order number
  • event: "ORDER.STATUS_CHANGED"

Testing Push Notifications

http://<server>/api/1.0/test/<brandCode>/push

POST Parameters:
  • message: string
  • deviceType: "ANDROID|IOS"
  • title: string
  • deviceId: string

Configuration to enable this to work is under Brand > Edit under the Brands menu.

The following fields have to be entered for GCM push notifications to work:
  • Android Push Key
The following fields have to be entered for APN push notifications to work:
  • Upload iOS Push Key File (.p12)
  • iOS Push Key Password
  • iOS Push Server Destination

Posting a Reservation

http://<server>/api/1.0/reservation/<brandCode>

POST body:
  • store: ID of store that is receiving this reservation
  • authToken: authentication token of current customer (if null or missing, this is a guest reservation)
  • specialRequest: string, optional
  • occasion: string, optional, indicate occasion for reservation
  • fromTime: milliseconds since epoch time, time the customer wants to be seated
  • customer: Guest object, optional
  • phone: string, optional, if passed in sets the phone number that the merchant can call specifically for that reservation
  • pax: integer, number of people eating in
  • app: string, API code of the app
  • test: boolean, default false, if true, works as though reservation is placed and provides a DRAFT reservation
Response:
Reservation:
  • id: ID, ignored when POSTed to endpoint
  • number: string, human readable unique number of this reservation, ignored for test
  • placeTime: long, milliseconds since epoch time, the time this reservation was placed
  • fromTime: long, milliseconds since epoch time, fulfillment time for this reservation
  • toTime: long, milliseconds since epoch time, estimated end time for this reservation
  • orders: Array of Order linked to this reservation
  • store: ID of store
  • status: "DRAFT|PLACED|QUEUED|SEATED|COMPLETED", current status of this reservation
  • phone: string or null, customer's phone number
  • pax: integer, number of people eating in
  • specialRequest: string or null
  • occasion: string or null

Error Codes:

This is a complete list of all values of code property of the response JSON. The message property of the response JSON can be used to display the failure to the user. However, apps should use code value to perform custom logic instead of the message property because it might change in the future.

  • -100: Attempting to register with an email and password for an account that already exists
  • -101: Attempting to register with a Facebook ID for an account that already exists
  • -102: Attempting to register with a Google+ ID for an account that already exists
  • -103: Email not found
  • -104: Incorrect PIN code
  • -105: PIN code has expired
  • -106: Password is incorrect
  • -107: Password missing
  • -108: Account is blocked
  • -109: Verification failed
  • -110: Account not found
  • -666: Customer auth token not found