Eunoia Docs

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

Eunoia Entities

  • Outlet - Eunoia supports multiple Outlets. HQ owns one or multiple outlets.
  • 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/YOUR_BRAND_APICODE?authorization=YOUR_BRAND_AUTH
  • It is recommended to set this key before you go live otherwise anyone can simply send orders to that brand

API


Getting Outlets

http://<server>/api/1.0/outlets/<hqApiCode>[/<outletApiCode>]

GET Parameters
  • lat: double, latitude of user's current location, optional
  • lng: double, longitude of user's current location, optional
  • app: string, optional, the API code for the app. If available, response will contain an App object
  • includeStore: boolean, defaults to true if not passed in, whether to include list of stores within each Outlet object

If lat and lng is passed in, the outlet returned will contain distance.

Response:
  • success: true
  • outlets: array of Outlet objects
  • app: App object or null
  • headquarter: Headquarter object
Outlet:
  • id: ID
  • name: string
  • description: string
  • sortIndex: integer, can be used for sorting Outlets in ascending order
  • tags: Array of Tags
  • custom: Object of custom properties
  • openingHours: Array of Availabilities
  • openingHoursString: string, a nicely formatted human readable text from the 'openingHours' property
  • imageId: string
  • apiCode: string
  • address: Address object
  • stores: Array of Store object
  • distance: string
Headquarter:
  • name: string
  • imageId: string
  • app: App object or null
  • facebookId: String, facebookId
  • googleWebAppId: String, googleWebAppId
  • enableLoyalty: boolean, enableLoyalty
  • currency: BigDecimal, currency
  • currencySymbol: String, currencySymbol
  • country: Map, [code: countryCode, name: COUNTRY_NAME, fone: COUNTRY_FONE]
  • minPhoneNumber: String, minPhoneNumber
  • maxPhoneNumber: String, maxPhoneNumber
  • lalamoveAccount: lalamoveAccount object
  • deliveryPartners: array of deliveryPartners Object

Getting Closest Outlet from Address

http://<server>/api/1.0/location/closestOutlet/<hq>

GET Parameters
  • lat: double, latitude of user's current location, optional
  • lng: double, longitude of user's current location, optional
Response:
  • success: true
  • outlet: Outlet object

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
  • serverTime: long, Epoch time and date when the api called
  • timeZoneOffset: int, time zone offset of the brand
  • brand: Brand object
Store:

Basic Params

  • id: ID
  • name: string
  • description: string
  • sortString: int
  • address: Address object

Advanced Params

  • id: ID
  • name: string
  • apiCode: string
  • brandCode: 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
  • icolumnStoreId: string
  • email: string
  • phone: string
  • imageId: 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
  • deliverySmsStatuses: Array of Order Statuses, SMS sent to customer if a delivery order reaches these statuses
  • takeAwaySmsStatuses: Array of Order Statuses, SMS sent to customer if a take away order reaches these statuses
  • dineInSmsStatuses: Array of Order Statuses, SMS sent to customer if a dine-in order reaches these statuses
  • closureDates: Array of Closure Date, date/time when reservation is not available
  • deliveryDetails: string
  • customField: string
Address:
  • line1: string
  • line2: string
  • city: string
  • countryCode: string, 2 character country code
  • postalCode: string
  • string: string of the address in one line
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/YOUR_BRAND_APICODE?authorization=YOUR_BRAND_AUTH

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 Store Availability

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

GET Parameters:
  • type: "DELIVERY|TAKE_AWAY|DINE_IN", optional if used for reservations
  • reservation: optional, boolean, type will be DINE_IN if used
  • pax: add if reservation=true, integer, number of people
  • time: long, milliseconds since epoch time, used to indicate the date of ordering, response details will be based on this start date/time
  • lookAheadDays: optional, integer with a default value of 30 if not passed in, the number of days of unavailableDays data the response will include, maximum is 365. For reservations, this is taken as the Advanced Days (beyond which store is unavailable)
  • includeDriverTimeout: optional, boolean, include driver timeout (store settings) on Eta calculation
Response:
  • success: true
  • stores: Array of StoreAvailability, contaning the availability details of stores that can fulfill this request
StoreAvailbility:
  • id: ID of the store
  • name: String, store name
  • available: boolean, whether the store is available. For reservations, this is affected by Cut Off Time and Advanced Days set in the Reservation Settings for the Store
  • nextAvailable: long, milliseconds since epoch time, the next available time
  • eta: long, milliseconds since epoch time, the first time available for selection, this is nextAvailable time plus eta in minutes, not applicable for reservation
  • availbilityTimes: Array of time slots for the next available day, each time slot is a number of the format "hhmm" where hh is in 0 - 23 hour format
  • unavailableDays: Array of day numbers from the current day (based on time in request parameter) when the store is unavailable. This value will be affected by the minimum and maximum order advanced days set for the Store
  • preOrder: boolean, indicate whether pre-ordering is allowed for that store, not applicable for reservation

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
  • postalCode: string, postal code, can be used along with line. If line contains a postal code, then don't submit this value
  • countryCode: string, 2 character string, ISO 3166-2 country code
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
  • postalCode: string, postal code, can be used along with line. If line contains a postal code, then don't submit this value
  • countryCode: string, 2 character string, ISO 3166-2 country code
Response:
  • success: true
  • store: Store object

Get Closest Stores from Address

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

Works similar to the previous one, but returns a list of stores sorted by distance in ascending order from the address.

GET Parameters:
  • line: address string
  • postalCode: string, postal code, can be used along with line. If line contains a postal code, then don't submit this value
  • countryCode: string, 2 character string, ISO 3166-2 country code
  • showEta: boolean, if true each Store object in the response will have an integer eta property
Response:
  • success: true
  • stores: Array of Store object

Getting all Promotions

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

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. 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.

GET Parameters:
  • authToken: optional, if passed in, will return only promotions applicable for this customer
Response:
Promotion:
  • id: ID
  • name: string
  • description: string
  • imageId: string
  • sortIndex: int
  • 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|INFORMATIONAL"
  • 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", "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 stockLimitnumber 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
  • discountId: string, additional information added when promotion is created.
  • pointsToBuy: int
  • storeIndexs: string
  • bogoProducts: ArrayList long, List of base product id
  • stampsToCollect: int, stamps
  • oneForOne: oneForOne
  • outlet: int, outlet id
  • brand: int, brand id
  • headquarter: int, headquarter id
  • displayAsBanner: boolean, promotion is it displayed as banner
  • discountId: int, discount Id
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
  • BUY_ONE_GET_ONE_DISCOUNTED: Buy One product Get One product Discounted

Store, Product and Modifier Override

http://<server>/api/1.0/storeOverride/update?store=<storeId>

This api will allowed the merchant to be able to edit store, modifier, product override setting on a specific store

Post Parameters:
  • store.kitchenPrepTimeOverride: optional, Integer, change kitchen prep time override value to
  • store.bufferTimeOverride: optional, Integer, change buffer time override value to
  • store.transitTimeOverride: optional, Integer, change transit time override value to
  • store.dineIn: optional, Boolean, change the override dine in availability
  • store.takeAway: optional, Boolean, change the override take away availability
  • store.delivery: optional, Boolean, change the override delivery availability
  • store.productsOverride: optional, List of product to override
  • store.productsOverride.id: optional, Integer, product id to change
  • store.productsOverride.available: optional, Boolean, change the product availability
  • store.productsOverride.overrideDuration: optional, Integer, days of override to get reset to available
  • store.modifiersOverride.id: optional, Integer, modifierGroup id to change
  • store.modifiersOverride.available: optional, Boolean, Modifier Group Availability
  • store.modifiersOverride.overrideDuration: optional, Integer, days for the override to be applied
  • store.modifiersOverride.childModifiers: optional, if not passed in , will applied to all modifier child inside the modifier group, if passed in the only child that would be changed would be child inside this childModifiers
  • store.modifiersOverride.childModifiers.id: optional, Integer, modifier id to change
  • store.modifiersOverride.childModifiers.available: optional, Boolean, modifier availability
  • store.modifiersOverride.childModifiers.overrideDuration: optional, Integer, days for the override to be applied

Body Request Example :

{
    "store": {
        "kitchenPrepTimeOverride": 1,
        "bufferTimeOverride": 1,
        "transitTimeOverride": 1,
        "dineIn": true,
        "takeAway": false,
        "delivery": true,
		"overrideDuration": 1
        "productsOverride": [
            {
                "id": 13191,
                "available": false,
                "overrideDuration": 2
            },
            {
                "id": 13009,
                "available": false,
                "overrideDuration": 3
            }
        ],
        "modifiersOverride": [
            {
                "id": 2018,
                "available": false,
                "overrideDuration": 4,
                "childModifiers": [
                    {
                        "id": 10157,
                        "available": false,
						"overrideDuration": 5
                    }
                ]
            }
        ]
    }
}
	

Response:

exactly the same with request param with additional param overrideClearTime

  • success: true
  • overrideClearTime: String, Estimate time the reset time would be

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
  • splitAvailability: boolean
  • time: long
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
  • description: string, brand description
  • defaultImageId: string, brand image id cloudinary
  • enableProductImages: boolean
  • favouritesImageId: boolean
  • currency: string, brand currency e.g SGD
  • currencySymbol: string
  • countryCode: string, brand country code
  • countryName: string, brand country name
  • countryFone: string
  • custom: string
  • facebookId: string
  • googleWebAppId: string
  • enableCredits: string
  • enableDelivery: string
  • enableLoyalty: string, enable rewarding points
  • enableReservation: string
  • minPhoneNumber: string
  • maxPhoneNumber: string
  • gstRegNumber: string
  • lalamoveAccount: string
  • enableOnemap: string
  • minPhoneNumber: string
  • above is optional parameters
  • stores: string
  • securityCode: stores entity
  • spendPoints: stores entity
  • redeemDollars: stores entity
  • deliveryPartners: array of deliveryPartners Object
App:
  • name: string, name of the app
  • apiCode: string
  • 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
  • multipleCheckout: boolean, indicator for app enable multi store checkout
  • minCartMultipleCheckout: BigDecimal, minimum amount for user to order multi store order
Payment Account:
  • name: string, name of the payment account
  • type: "PAYPAL|STRIPE|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
  • tokenizationEnabled: boolean, whether credit card tokenization is enabled (MPGS, OMISE, ADYEN)
  • enabled3ds: boolean,indicator whether OTP verification is enabled (MPGS)
  • brand: (only for Outlets)Brand object
  • sandbox: boolean, adyen indicator if the account is sandbox or not
  • publishableKey: String, publish key of payment account (OMISE, PayMaya)
Delivery Partner:
  • id: long, delivery partner id
  • name: String, delivery partner name
  • partnerType: Enum, delivery partner enum of (OWN | LALAMOVE | PANDAGO)
  • chargeType: Enum, delivery partner enum of (DYNAMIC | STATIC)
  • status: Enum, delivery partner enum of (DRAFT | ACTIVE | DELETED)
  • initiateTime: long, initiate time
  • isMixnmatch: boolean, mix & match flag true if it available
  • maxDistance: int, max delivery distance
  • ownDelivery: Object OwnDelivery for partnerType equals OWN
  • lalamoveAccount: Object lalamoveAccount for partnerType equals LALAMOVE
  • pandagoAccount: Object pandagoAccount for partnerType equals PANDAGO
Own Delivery
Delivery Charge
  • id: long, delivery charge id
  • name: String, delivery charge name
  • tiers: Array of DeliveryChargeTier object
Delivery charge tier
  • idlong, delivery charge tier id
  • amountBigDecimal, delivery charge tier amount
  • minSubTotalBigDecimal, delivery charge tier minSubTotal
  • maxSubTotalBigDecimal, delivery charge tier maxSubTotal
Delivery polygon
  • id: long, delivery polygon id
  • name: String, delivery polygon name
  • status: Enum, delivery polygon enum of (ACTIVE | DELETED | DRAFT)
  • coordinates: Map, delivery polygon lat long
Lalamove account
  • id: long, lalamove account id
  • accountType: String, account type "sandbox" | "live"
  • accountKey: String, account key lalamove
  • minimumSpent: BigDecimal, minimum spent for lalamove
  • motorMaxBasket: BigDecimal, motor max basket for lalamove
  • passOnDeliveryFee: boolean, pass delivery fee to customer option
  • baseDeliveryLimit: BigDecimal, base delivery limit
  • customerPays: BigDecimal, customer pay
  • maxDeliveryLimit: BigDecimal, max delivery limit
  • passSurcharge: BigDecimal, pass surcharge to customer
  • serviceType: String, service type (MOTORCYCLE | CAR)
  • carService:some lalamove account fields for car serviceobject
Pandago account
  • id: long, Pandago account id
  • status: String, Pandago status
  • accountKey: String, Pandago accountKey
  • accountType: String, sandbox | live
  • maxDistance: BigDecimal, max distance in KM
  • maxFee: BigDecimal, max fee delivery
  • minimumSpent: BigDecimal, minimum cart spent
  • coldbag: boolean, true/false
  • paymentMethod: enum, PAID
Free delivery
  • id: long, free delivery id
  • minimumOrder: BigDecimal, minimum order for free delivery
  • stores: array store object
Tag:
  • id: ID
  • imageId: string
  • name: string
  • type: string, tag type
Category:
  • id: ID
  • imageId: string
  • image2Id: string
  • image3Id: string
  • availabilities: Array of Availabilities, if empty, this Category is available the whole day
  • name: string
  • pluCOde: 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
  • available: boolean, if the product is available
  • custom: customMap Entity: custom value and field that applied for this particular brand or HQ
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
  • disabledModifiers: Array of Modifiers
  • modifiers: Array of Modifiers
  • pluCode: String
  • modifierGroupType: string
  • description: String
  • childGroups: Array of Modifier Groups that belongs to thi a modifier group
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
  • overridePrice: boolean, indicator if the price is overridden or not
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:
Samples
  1. http://platform.eunoia.asia/api/1.0/menu/YOUR_BRAND_APICODE?authorization=YOUR_BRAND_AUTH
  2. http://platform.eunoia.asia/api/1.0/menu/YOUR_BRAND_APICODE/YOUR_STORE_ID?authorization=YOUR_BRAND_AUTH

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


Getting the Outlet Menu

http://<server>/api/1.0/menu/hq$<hqApiCode>/<outletApiCode>

GET Parameters
  • app: string, the API code for the app. If available, the Brand object will contain an App object, optional
Response:
  • success: true
  • stores: Array of Stores. Each store contains sortIndex, brand, store, and menu

Posting an Order

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

POST body:
  • cartId: unique string created by BE automatically if this parameter sent with null value when create draft order
  • 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
  • draft: boolean, default false, if true, it stores the json body for future retrieval. This can be useful to simulate cart like behaviour
  • 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)
  • payments: Array of Payment Id used for making payments (for payments using web view inside mobile applications)
  • app: string, API code of the app
  • headquarter: (optional) string, API code of the Headquarter to be sent if app/payment account is from the headquarter instead of brand
  • credits: BigDecimal, credit amount to pay the order
  • emailType: String
  • email: String, customer email
  • recipientName: String
  • recipientName: String
  • orders: order entity
  • deliveryRequest: Delivery
  • deliveryPartner: deliveryPartner Object, for delivery dine type only
  • deliveryAccountKey: String, Delivery account key
  • headquarter: (optional) string, API code of the Headquarter to be sent if app/payment account is from the headquarter instead of brand
  • custom: optional hash of string key-value pairs. Maximum of 255 characters for each key or value. These are custom properties that will be attached to this order

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.

deliveryRequest:

Delivery request will be depends on third party, it should follow third party format request for submit order

format request for lalamove
detailed body, can be found here
  • scheduleAt: string, time "2020-09-01T14:30:00.00Z"
  • serviceType: "MOTORCYCLE", "CAR"
  • stops: waypoint
  • deliveries: Object
  • requesterContact: Object
  • specialRequests: Array
format request for pandago
detailed body, can be found here
  • client_order_id: String, from get estimate fee API
  • sender: map of sender
  • recipient: map of recipient
  • payment_method: enum PAID
  • amount: number, order amount
  • description: String, order description
  • estimatedFee: BigDecimal, from get estimate fee API
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
  • cardType: "MASTERCARD|VISA|AMEX|DINERS|JCB|CHINA_UNION_PAY" or null, card type
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
Response:
  • success: true/false
  • order: Order object
  • message: error message
  • vouchers: (error) Array of VoucherErrors
  • promoCodes: (error) Array of PromoCodeErrors
  • stores: (error) Array of Store unavailable
  • items: (error) Array of Items unavailable
  • cartId: (optional) This is sent whenever draft=true is sent in the request. Send this cartId with all subsequent requests pertaining to the same order (For both TEST orders or otherwise) in order to update the json stored. The cartId can also be used to retrieve the last response recieived making a call to getting a cart

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: "DRAFT|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 epoch time, the time when this order was completed, may be null
  • subTotal: BigDecimal, order subtotal
  • mixnmatch: boolean, is it mix n match order or not
  • rewards: reward object, reward list object
  • storeName: String
  • tableNumber: String
  • tablePlucode: String
  • address: Address object
  • id: ID, ignored when POSTed to entpoint
  • email: String
  • busy: Boolean
  • recipientName: String
  • deliveryData:
  • app: String, ignored when POSTed to entpoint
  • cancelTime: DateTime
  • cancelationNotes: String
  • customField: Object
  • recipientDetails: Object
  • storeMaxed: String
  • storeNextFreeTime: String
  • paymentTypes: String
  • customer: Object
  • brand: Object
  • posOrderNumber: String
  • refNumber: String
  • print: String
Recipient Details:
  • name: String,
  • email: String,
  • phone: String,
Custom Field:
  • name: String,
  • property: String,
  • value: String,
Reward:
  • type: String, name of the app
  • amount: BigDecimal
  • usetime: DateTime
deliveryRequest:
detailed body, can be found here
  • id: string, time "2020-09-01T14:30:00.00Z"
  • serviceType: "MOTORCYCLE", "CAR"
  • statusDisplay: waypoint
  • status: Object
  • fee: Object
  • currency: Array
  • pickup: waypoint
  • pickupCoord: waypoint
  • destination: waypoint
  • destinationCoord: waypoint
  • scheduleTime: waypoint
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
  • additionalData: String, json string custom data that user need to add
  • level(OPTIONAL): BRAND or OUTLET
Samples:

Posting a test order: http://platform.eunoia.asia/api/1.0/order/YOUR_BRAND_APICODE

{
    "address": {
        "line1": "689 CHANGI ROAD",
        "line2": "",
        "city": "Singapore",
        "postalCode": "419964",
        "countryCode": "SG",
        "coord": {
            "lat": "1.32077724581127",
            "lng": "103.916185580136"
        },
        "id": 1
    },
    "table": null,
    "fulfillmentTime": 1626579420000,
    "type": "DELIVERY",
    "promoCodes": [],
    "test": true,
    "draft": false,
    "rowId": 1,
    "vouchers": [],
    "deliveryPartner": {
        "id": 7,
        "name": "LALAMOVE",
        "priority": 1,
        "partnerType": "LALAMOVE",
        "chargeType": "DYNAMIC",
        "status": "ACTIVE",
        "initiateTime": null,
        "lalamoveAccount": {
            "id": 13,
            "accountType": "sandbox",
            "accountKey": "lalamove-joesburgerCL",
            "minimumSpent": 1,
            "motorMaxBasket": null,
            "passOnDeliveryFee": true,
            "baseDeliveryLimit": 40,
            "customerPays": 8,
            "maxDeliveryLimit": 5,
            "passSurcharge": true,
            "serviceType": "CAR"
        }
    },
    "items": [
        {
            "specialRequest": "",
            "quantity": 1,
            "product": 13595,
            "modifiers": [
                {
                    "modifierId": 10691,
                    "name": "Shio Ramen",
                    "quantity": 1,
                    "price": 12.8
                },
                {
                    "modifierId": 10694,
                    "name": "Chashu Mayo Don",
                    "quantity": 1,
                    "price": 7
                },
                {
                    "modifierId": 10609,
                    "name": "Joe's Impossible Burger",
                    "quantity": 1,
                    "price": 125
                }
            ],
            "storeName": "",
            "storeId": "",
            "brandName": ""
        }
    ],
    "rewardPoints": 0,
    "phone": "",
    "store": 617,
    "app": "eunoia-webstore",
    "authToken": ""
}
	

Posting an Outlet Order

http://<server>/api/1.0/order/<hqApiCode>$<outletApiCode>/outlet

POST body:
  • type: "DELIVERY|TAKE_AWAY|DINE_IN|TEST"
  • orders: Array of Orders. Each order contains OrderItems, storeId, type, and fulfilment time.
  • payments: Array of Payments
  • authToken: authentication token of current customer (if null or missing, this is a guest order)
  • 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
  • draft: boolean, default false, if true, it stores the json body for future retrieval. This can be useful to simulate cart like behaviour
  • fulfillmentTime: milliseconds since epoch time, time the customer wants to be fulfilled, if null, means NOW
  • customer: Guest object, optional
  • vouchers: Array of Voucher IDs to be applied to this order
  • promoCodes: Array of promo codes to be applied to this order
  • 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.

Response:
  • success: true/false
  • order: Outlet Order object
  • message: error message
  • vouchers: (error) Array of VoucherErrors
  • promoCodes: (error) Array of PromoCodeErrors
  • stores: (error) Array of Store unavailable
  • items: (error) Array of Items unavailable
  • cartId: (optional) This is sent whenever draft=true is sent in the request. Send this cartId with all subsequent requests pertaining to the same order (For both TEST orders or otherwise) in order to update the json stored. The cartId can also be used to retrieve the last response recieived making a call to getting a cart
Outlet Order:
  • id: ID, ignored when POSTed to endpoint
  • number: string, human readable unique number of this order, ignored for TEST
  • orders: Array of Orders
  • total: decimal, absolute final total, ignored when POSTed to endpoint
  • subtotal: decimal, subtotal of all the orders
  • customer: Guest object, optional
  • placeTime: long, milliseconds since epoch time, the time this order was placed
  • fulfillmentTime: long, miliseconds, since epoch, time the customer wants the order to be fulfilled
  • payments: Array of Payments
  • outlet: Contains ID of outlet

Order Statuses

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

  • DRAFT -> PLACED
  • 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):

  • DRAFT (Draft): Order is still being built by the client. This status is usually sent when test=true when posting an order.
  • PLACED (Pending): Order is placed and pending acceptance
  • Accepted (Accepted): Order accepted by merchant
  • QUEUED (Pre-order): Order is queued to be prepared at a future time (for pre-orders, i.e. fulfillmentTime is not null).
  • 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>

Query Params:
  • brandCode: brand's apiCode (Use <hqApiCode>$<outletApiCode> for Outlet Orders)
  • orderNumber: Order number
  • reason: string, reason for the cancellation, optional
Response:
  • success: true
  • order: Order object

Getting a Cart

http://<server>/api/1.0/order/<brandCode>/cart?cartId=<cartId>

Response:

This API will retrieve the json stored with this corresponding cartId. If the order has been already placed then it will return the Order otherwise expect the response from Posting an Order or Posting an Outlet Order based on the json stored being an order or an outlet order.

Delivery fee quotation

This section for delivery fee quotation for each third party that available on Eunoia

Lalamove quotation

http://<server>/api/1.0/lalamove/quotation/<brandCode>

Query Params:
  • body: String, string of json request on Lalamove getQuotation
  • accountKey: String, lalamove eunoia account key
Response:
  • success: boolean, true/false
  • lalamove response: response from Lalamove getQuotation
  • message: string, error message

Pandago estimate

http://<server>/api/1.0/pandago/estimate/<brandCode>

POST body
  • pandagoRequest: String of json request for estimate fee
  • accountKey: String of eunoia pandago accountKey
  • fulfillmentTime: long, fulfillmentTime for the order
Success Response:
  • success: boolean, true/false
  • pandagoResponse: Map, map of response from estimate fee
Note: if client_order_id available in pandagoResponse please attach it to delivery request when post the order to prevent discrepancy fee issue
Error Response:
  • success: boolean, true/false
  • message: String, message of the error
  • code: String, identity of the error
Pandago estimate's Error codes:
  • PE01: Pandago estimate fee more than max fee on Eunoia's Pandago settings
  • PE02: Estimate order time more than 2 days
  • PE03: Param fulfillmentTime not found
  • PE04: Distance from sender to recipient more than max distance on Eunoia's pandago settings

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
  • optOutMarketingEmails: boolean, optional. To indicate whether customer wants to opt out from receiving marketing emails. If not submitted during registration, default is false. If not submitted during update, existing value is left unchanged.
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

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

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>

App 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
  • app: (optional) string, the app apiCode. If included, the payment account will be used from the app instead of brand/headquarter
  • cartId: (optional) string, the cartId of the order for which the payment is being made. If included, the payment will be verified and the order will be placed automatically
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.

Web Checkout

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

Web checkout using Paylah invloves creating a payment request with the user's registered Paylah mobile number. A request using this API will trigger a payment request push notification on the user's Paylah app with which they can complete/cancel payment. The web interface continues to check transaction status periodically to determine the payment status. 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, optional
  • accountKey: string, api code of Payment Account
  • mobileNumber: string, registered Paylah mobile number, required
  • trackingId: string, (maximum length = 20), generated on the app as a random alpha-numeric string for each payment attempt
  • amount: decimal number, payment amount
  • app: (optional) string, the app apiCode. If included, the payment account will be used from the app instead of brand/headquarter
  • cartId: (optional) string, the cartId of the order for which the payment is being made. If included, the payment will be verified and the order will be placed automatically
Response:
  • success: true

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
  • app: (optional) string, the app apiCode. If included, the payment account will be used from the app instead of brand/headquarter
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
  • app: (optional) string, the app apiCode. If included, the payment account will be used from the app instead of brand/headquarter
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
  • app: (optional) string, the app apiCode. If included, the payment account will be used from the app instead of brand/headquarter
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 KMF_Cloud_UAT1
  • 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>&app=<app>

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: (optional) boolean, whether the user wants to save their card Used together with tokenizationEnabled in Payment Account
  • app: (optional) string, the app apiCode. If included, the payment account will be used from the app instead of brand/headquarter
  • cartId: (optional) string, the cartId of the order for which the payment is being made. If included, the payment will be verified and the order will be placed automatically

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
  • app: (optional) string, the app apiCode. If included, the payment account will be used from the app instead of brand/headquarter
  • cartId: (optional) string, the cartId of the order for which the payment is being made. If included, the payment will be verified and the order will be placed automatically

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

Response:
  • success: true

Uniweb Grabpay Gateway (Developmental)

http://<server>/ipg/uniweb/payment/<transactionId>?brand=<brandCode>&amount=<amount>&authToken=<authToken>&accountKey=<accountKey>&app=<appCode>&cartId=<cartId>

URL Parameters:
  • brandCode: string, brand code, optional
  • amount: decimal number
  • authToken: authentication token of current customer, required if tokenizeCard is true
  • accountKey: string, api code of Payment Account
  • app: (optional) string, the app apiCode. If included, the payment account will be used from the app instead of brand/headquarter
  • cartId: (optional) string, the cartId of the order for which the payment is being made. If included, the payment will be verified and the order will be placed automatically
Response:
  • success: true/false
  • url: URL for the gateway page.

This payment method allows the app to use SMS OTP to make payment on a webpage provided by Grab.

Open the URL received from the above API in a web view within the app. The web page allows the user to enter the phone number, enter the received OTP and complete payment. After the payment confirmation, observe the web view URL for the following changes:

  • If the url contains paymentSuccess - 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 paymentFailure - payment failed or cancelled. Navigate away from the web view and inform the user that payment has failed or was cancelled.

Cybersource Secure Acceptance Hosted Checkout

http://<server>/ipg/sa/payment/<trackingId>?brand=<brandCode>&amount=<amount>&authToken=<authToken>&accountKey=<accountKey>&tokenizeCard=<tokenizeCard>&name=<name>&app=<appCode>&cartId=<cartId>

URL Parameters:
  • brandCode: string, brand code, optional
  • amount: decimal number
  • authToken: authentication token of current customer, required if tokenizeCard is true
  • accountKey: string, api code of Payment Account
  • tokenizeCard: (optional) boolean, whether the user wants to save their card. Used together with tokenizationEnabled in Payment Account
  • name: (optional) if authToken is not provided but name has to be displayed in the Secure Acceptance Dashboard (EBC)
  • app: (optional) string, the app apiCode. If included, the payment account will be used from the app instead of brand/headquarter
  • cartId: (optional) string, the cartId of the order for which the payment is being made. If included, the payment will be verified and the order will be placed automatically

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 paymentSuccess - 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 paymentFailure - payment failed or cancelled. Navigate away from the web view and inform the user that payment has failed or was cancelled.

Test credit cards can be found here.

Cybersource Secure Acceptance Pay with Token

http://<server>/ipg/sa/payment/<trackingId>?brand=<brandCode>&amount=<amount>&authToken=<authToken>&accountKey=<accountKey>&token=<token>&name=<name>&cartId=<cartId>

POST Parameters:
  • brandCode: string, brand code, optional
  • amount: decimal number
  • authToken: authentication token of current customer, required if tokenizeCard is true
  • accountKey: string, api code of Payment Account
  • token: string, payment token returned by tokenization during previous payment
  • name: (optional) if authToken is not provided but name has to be displayed in the Secure Acceptance Dashboard (EBC)
  • cartId: (optional) string, the cartId of the order for which the payment is being made. If included, the payment will be verified and the order will be placed automatically

This will allow users to directly proceed to the review page on Secure Acceptance Hosted Payment without the need to re-enter the card details. The rest of the functionality is the same as mentioned above.

Omise

Create Charge

This API allows the app to create an Omise Charge with a tokenized card. If successful, the Payment object in response can be used in the payments array when posting the order.

http://<server>/api/1.0/payment/<brandCode>/omiseCreate

POST Parameters:
  • token: string, Omise payment token
  • accountKey: string
  • amount: decimal number
  • authToken: authentication token of current customer, required if tokenizeCard is true
  • tokenizeCard: (optional) boolean, whether the user wants to save their card. Used together with tokenizationEnabled in Payment Account
  • app: string, the app apiCode. If included, the payment account will be used from the app instead of brand/headquarter
  • storeId: String, store id that will attached to omise metadata
  • posOrderNumber: String, posOrderNumber that will attached to omise metadata
  • returnUri: String, return URL for 3DS omise charge
Response:
  • success: true
  • payment: Payment object containing the Omise transaction (Charge) ID

Digital Gift Card

Payments can also be done by redeeming Quikcilver's Digital Gift Card

Get Digital Gift Card Wallet

http://<server>/ipg/qcdgc/wallet?brand=<brand>&accountKey=<accountKey>&authToken=<authToken>

Query Parameters:
  • brand: string, brand or HQ code (hq$<hqCode>)
  • accountKey: string, app key for the payment account
  • authToken: string, user's authToken
  • app: (optional) string, the app apiCode. If included, the payment account will be used from the app instead of brand/headquarter
Response:
  • success: true/false
  • wallet: Wallet object containing the balance and walletNumber
Wallet
  • balance: number, balance available
  • walletNumber: number, walletNumber to be provided for redemptions

Redeem Digital Gift Card

http://<server>/ipg/qcdgc/redeem/<trackingId>?brand=<brand>&accountKey=<accountKey>&authToken=<authToken>&amount=<amount>&billAmount=<billAmount>&remarks=<remarks>

Path Parameters:
  • trackingId: string, random identifier for this transaction
Query Parameters:
  • brand: string, brand or HQ code (hq$<hqCode>)
  • accountKey: string, app key for the payment account
  • authToken: string, user's authToken
  • app: (optional) string, the app apiCode. If included, the payment account will be used from the app instead of brand/headquarter
  • amount: number, amount to be deducted
  • billAmount: number, Total bill amount
  • remarks: string, remarks for the transaction
  • iColumnStoreId: (optional) string, the IColumn Store ID. If included, the IColumn Store name will be sent during redemption as MerchantOutletName else the MerchantOutletName set in the account setting.
Response:
  • success: true/false
  • message: string
  • amount: number, amount deducted
  • balance: number, balance amount in the wallet
  • transactionIdnumber, transaction Identifier from quikcilver for this transaction. Will be needed if the transaction has to be refunded

Paypal

current paypal payment using v2 api docs and smart button from paypal check this for more details : paypal checkout doc

Paypal smart checkout

This API allows to verify payment by id that already created on front end with smart button from paypal, after verify payment it will captured and if success it will give success response. the Payment object in response can be used in the payments array when posting the order.

http://<server>/api/1.0/paypal/smartCheckout/<brandCode>or<hq$hqcode>

POST parameters:
  • paypalOrderId: String, get from smart checkout button response.id from paypal actions.order.authorize()
  • trackingId: String, get from smart checkout button response.purchase_units[0].payments.authorizations[0].id from paypal actions.order.authorize()
  • accountKey: String, this is paymentMethod.key
  • amount: BigDecimal, this is amount total of customer order
  • paidTime: long, this is time that customer did payment (in milliseconds)
Response:
  • success: boolean true or false
  • transactionId: String, payment transactionId
  • trackingId: String, payment trackingId
  • paidTime: long, paid time
Paypal Refund

This API allows to refund authorize or captured payment, but its only works one time. the response will tell customer if their order is fail and payment already refunded (success) or if it fail, it will tell customer to contact admin store (optional)

http://<server>/api/1.0/paypal/refund/<brandCode>or<hq$hqcode>

POST parameters:
  • paypalOrderId: String, get from smart checkout button response.id from paypal actions.order.authorize()
  • trackingId: String, get from smart checkout button response.purchase_units[0].payments.authorizations[0].id from paypal actions.order.authorize()
  • accountKey: String, this is paymentMethod.key
Response:
  • success: boolean true or false
  • transactionId: String, payment transactionId
  • trackingId: String, payment trackingId

Webhooks-V2

Webhooks allow developers to register a URL that will receive HTTP POST requests whenever an event occurs in Eunoia Platform for their brand. For this version of webhoooks, we expect that the receiving endpoint sends a response when they receive the request. If the response is not sent then the webhook will retry as many times as indicated by 'retries'.

Expected response: { "success": true }

This URL can be configured under Brand Settings:

Parameters:

  • event: string, type of the event
  • order: json of Order
  • url: string, webhooksv2 url that set on brand setting
  • retries: int, number of retries when webhooksv2 fail, default = 10
  • cancelOnFail: boolean, true or false for auto cancel while webhooks fail
  • orderId: int, id of order
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.

Version "2.0"

Parameters:

  • event: "ORDER.NEW"
  • order: json of Order
  • cancelOnFail: boolean, true or false

Order Status Changed (ORDER.STATUS_CHANGED)

This event triggers when the status of an order has changed.

Version "2.0"

Parameters:

  • event: "ORDER.STATUS_CHANGED"
  • order: json of Order
  • cancelOnFail: boolean, true or false

Note: if webhooksv2 fail after retries and cancelOnFail param is true it will cancel all new orders

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:
  • success: true/false
  • reservation: Reservation object
  • message: Error message if success is false and the reservation could not be placed
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|ACCEPTED|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
  • customer: Customer object containing basic information

Edit a Reservation

http://<server>/api/1.1/reservation/<brandCode>/update/{reservation number}

POST body:
  • storeId: ID of store that is receiving this reservation
  • reservationDate: String Date, Example: "15 Nov 2021"
  • reservationTime: String Time, Example: "10:00 PM"
  • pax: Integer, total reservation pax
  • occasion: Optional, String
  • specialRequest: String, reservation special request
  • customer: Guest object
  • table: Array of table
Response:
  • success: true/false
  • reservation: Reservation object
  • message: Error message if success is false and the reservation could not be placed

Cancelling a Reservation

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

Query Params:
  • brandCode: brand's apiCode
  • number: Reservation number
Response:
  • success: true
  • reservation: Reservation object
  • message: Error message if success is false and the reservation could not be cancelled

Reservation Statuses

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

Note that reservation could be directly QUEUED if there is no table available

  • PLACED -> ACCEPTED | QUEUED | CANCELLED
  • ACCEPTED -> QUEUED | CANCELLED
  • QUEUED -> SEATED | CANCELLED
  • SEATED -> COMPLETED | CANCELLED
  • COMPLETED -> CANCELLED

Load Available Table for Reservation

http://<server>/api/1.1/reservation/<brandCode>/loadAvailableTables/{reservation number}

POST body:
  • storeId: ID of store that is receiving this reservation
Response:
  • success: true/false
  • table: Array of availabletable

Load Reservation Stores (GET Method)

http://<server>/api/1.1/reservation/<brandCode>/loadReservationStore

Response:
  • success: true/false
  • stores: Array of Store object

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

  • PLACED (Pending): Reservation is placed and pending acceptance
  • ACCEPTED (Accepted): Reservation is accepted
  • QUEUED (Confirmed): Reservation is already has table at it
  • SEATED : Reservation has started and being served
  • COMPLETED: Reservation is completed. This only happens when someone completes the Reservation
  • CANCELLED: Reservation is cancelled for some reason. A Reservation can be cancelled using Cancel Reservationas long as it is within the cancellable limit as set in the Store's Reservation Setting but can be manually cancelled anytime from the Admin Dashboard.

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