HomeGuidesAPI ReferenceChangelog
GuidesAPI ReferenceChangelogLog In

Webhooks support pushing real-time updates from the server to the client as those updates happen. These are useful whenever you need to know exactly when a specific event happens, allowing you to take action on those events immediately via the API.

Revel supports setting up webhooks whenever any of the following actions occur:

  • An order is completed
  • A customer record is created
  • A customer record is updated
  • A rewards card is created
  • A product/ingredient/modifier is out of stock
  • Menu is updated

Webhook Setup

Revel can be supplied with webhook endpoint URLs that will receive a POST request whenever one of the above actions occurs.

  • https://www.examplerewardscompany.com/receive/revel/loyalty_orders/
  • https://www.examplerewardscompany.com/receive/revel/customer/creation/
  • https://www.examplerewardscompany.com/receive/revel/customer/update/
  • https://www.examplerewardscompany.com/receive/revel/rewards_card/creation/
  • https://www.examplerewardscompany.com/receive/revel/item_availability
  • https://www.examplerewardscompany.com/receive/revel/menu_changed

Things to note:

  1. The URL must be SSL-secure (https://).
  2. Revel systems supports Webhooks endpoints either per event type or a single endpoint for all events. We do not support unique endpoints per client. Clients can be distinguished by utilizing Headers within the webhook payload.
  3. You can choose one or more action to send webhook events for. You are not required to support all of the Webhook events.
  4. The webhook endpoint should accept POST requests with a JSON payload and return an appropriate status code upon successful receipt of the payload (200 - OK). Revel Systems will send the following test Webhook payload to the specified Webhook endpoints upon enablement to confirm setup:
{"ping": "pong"}
connection	close
accept-encoding	gzip
x-revel-signature	101d196a9266dcbbb3a7326f3fe40a774c9edd1f
x-revel-event-type	ping
content-type	application/json
content-length	16

Message Signature And Other Headers

After webhook setup, Revel will provide the webhook recipient with a shared secret key necessary for message payload verification. Every message sent from Revel will include several Revel headers, i.e.:

X-Revel-Signature: XIUKGMCYQYNULKYDLQTL
X-Revel-Instance: revelcustomer

X-Revel-Signature represents a hash-based message authentication code that can be verified by comparing the provided and locally calculated signatures upon message arrival.
Also, the Revel instance will be passed in a header named X-Revel-Instance.

A couple of examples of signature calculation:

import hmac
from hashlib import sha1

signature = hmac.new(
    "{the-shared-secret}".encode('utf-8'),
    "{the-request-body-string}".encode('utf-8'),
sha1).hexdigest()
import (
   "crypto/hmac"
   "crypto/sha1"
   "encoding/hex"
)

func calculateWebhookSignature(secretKey string, payload []byte) string {
    h := hmac.New(sha1.New, []byte(secretKey))
    h.Write(payload)
    signature := hex.EncodeToString(h.Sum(nil))
    return signature
}

Webhook Data

The following json samples show what will be sent via webhooks to their receiving URLs.

Order completed

Upon completion of an order, a representation of the completed order will be sent using Revel's OrderAllInOne format, which includes information for the Order, Order Items, Payments, and Order History. The information about the loyalty transaction can be found under orderInfo.gift_reward_data, which is a JSON object sent in string format. The gift_reward_data values in the following sample contain line breaks for readability's sake.

"orderInfo": {
				"gratuity":	0.0,
				"web_order":	false,
				"has_items":	true,
				"registry_data":	null,
				"exchange_discount":	null,
				"gift_reward_data": "{\"id\":15, \"reward_points\":{\"points_by_items\":106,\"points_by_visits\":4,\"points_by_purchases\":28.35},\"payment_type\":0,\"total_points\":126,\"uri\":\"\\/resources\\/RewardsCard\\/15\\/\",\"advancedRewardsInfo\":[{\"rewardCardNumber\":\"J87YUIL9812X\",\"amountOfPurchasesUpdated\":4.5,\"visitsUpdated\":true,\"amountOfVisitsUpdated\":1,\"purchasesUpdated\":true}],\"establishment\":\"\\/enterprise\\/Establishment\\/1\\/\",\"total_purchases\":43.35,\"current_points\":106,\"address\":\"\",\"customer\":\"\",\"error_code\":0,\"updated_by\":\"\\/enterprise\\/User\\/5\\/\",\"created_by\":\"\\/enterprise\\/User\\/1\\/\",\"updated_date\":\"2016-04-13T17:29:15+00:00\",\"resource_uri\":\"\\/resources\\/RewardsCard\\/15\\/\",\"created_date\":\"2016-04-12T22:06:48+00:00\",\"total_visits\":12,\"number\":\"J87YUIL9812X\"}",
				"uuid": "c3d0ad74-1737-42c3-a352-4a45449a67af",
				"created_by": "/enterprise/User/5/",
				"service_fee_untaxed": "0.000000",
				"discount_tax_amount_included":	null,
				"taxable_surcharge":	0.0,
				"taxable_surcharge_excluded":	0.0,
				"sent":	false,
				"exchanged":	null,
				"updated_by": "/enterprise/User/5/",
				"delivery_employee":	null,
				"dining_option":	0,
				"delivery_duration":	null,
				"table_owner":	null,
				"surcharge_excluded":	0.0,
				"discount_amount":	null,
				"number_of_people":	0,
				"notes": "",
				"crc":	43010,
				"bills": [],
				"pos_mode": "Q",
				"is_unpaid":	false,
				"deleted_discounts": "",
				"points_added":	0,
				"bills_info": "",
				"tax_excluded_amount":	0.36,
				"auto_grat_pct":	0.0,
				"is_discounted":	false,
				"notification_email_sent":	false,
				"delivery_distance":	null,
				"gratuity_type":	0,
				"orderhistory": [
						"/resources/OrderHistory/399/"
				],
				"closed":	true,
				"tax_country": "usa",
				"discount_code": "",
				"has_delivery_info":	false,
				"asap":	false,
				"pickup_time":	null,
				"reporting_id":	null,
				"discount_nontaxable_surcharge_included":	0.0,
				"discount":	null,
				"packages": [],
				"final_total":	4.86,
				"package": [],
				"is_invoice":	false,
				"delivery_clock_in":	null,
				"bills_type":	0,
				"discount_tax_amount":	null,
				"rounding_delta":	0.0,
				"tax_rebate":	0.0,
				"table":	null,
				"discount_reason": "",
				"notification_text_sent":	false,
				"customer_birthdate":	null,
				"vehicle":	null,
				"remaining_due":	0.0,
				"applied_taxes": [
						{
								"name": "JSL	City	Tax",
								"rounding_type":	0,
								"uuid": "7c1f2cbe-5376-47d3-b01e-aa86ff2210e3",
								"id":	21,
								"is_prevailing":	true,
								"tax_rate": "8.0000",
								"tax_table":	null,
								"local_tax_id":	31,
								"order": "/resources/Order/417/",
								"dining_options":	null,
								"resource_uri": "/resources/AppliedTaxOrder/21/"
						}
				],
				"prevailing_tax":	8.0,
				"delivery_clock_out":	null,
				"discount_rule_type":	null,
				"service_charge":	0.0,
				"customer":	null,
				"applied_service_fee": [],
				"discount_taxed":	null,
				"has_history":	true,
				"tax":	0.36,
				"bill_number":	0,
				"id":	417,
				"surcharge":	0.0,
				"points_redeemed":	0,
				"call_number":	null,
				"delivery_estimated_distance":	null,
				"bill_parent":	null,
				"establishment": "/enterprise/Establishment/1/",
				"updated_date": "2016-04-13T10:29:19",
				"prevailing_surcharge":	0.0,
				"invoice_date":	null,
				"crv_value":	0.0,
				"created_date": "2016-04-13T10:27:36",
				"call_name": "",
				"printed":	true,
				"subtotal":	4.5,
				"discounted_by":	null,
				"discount_rule_amount":	null,
				"is_readonly":	false,
				"external_sync":	null,
				"created_at": "/resources/PosStation/1/",
				"service_fee_tax": "0.000000",
				"discount_total_amount": "0.000000",
				"crv_taxed":	false,
				"local_id": "417",
				"exchanged_by": [],
				"service_fee_taxed": "0.000000",
				"resource_uri": "/resources/Order/417/"
		},
		"items": [
				{
						"gift_card_number": "",
						"is_cold":	false,
						"commissions": [],
						"price_to_display": "0.000000",
						"exchange_discount":	null,
						"parent_uuid":	null,
						"uuid": "4c8ddb69-11fa-4a78-ae1d-7cc3f1ecc674",
						"created_by": "/enterprise/User/5/",
						"service_fee_untaxed": "0.000000",
						"pure_sales":	4.5,
						"voided_by":	null,
						"sent":	false,
						"exchanged":	null,
						"updated_by": "/enterprise/User/5/",
						"start_time":	null,
						"crv_value":	0.0,
						"product_name_override": "Cheese",
						"event_date":	null,
						"discount_amount":	null,
						"tax_amount":	0.36,
						"split_parts":	1.0,
						"catering_complete":	false,
						"sales_tax_exemption_reason": "",
						"weight":	0.0,
						"sold_by_weight":	false,
						"taxed_flag":	true,
						"is_discounted":	false,
						"course_number":	0,
						"shared":	0,
						"discount_code": "",
						"deleted":	false,
						"discount":	null,
						"tax_rate":	8.0,
						"seat_number":	null,
						"package_uuid":	null,
						"cup_weight":	0.0,
						"package":	null,
						"modifier_cost": "0.0000",
						"initial_price":	4.5,
						"combo_saving_amount": "0.000000",
						"is_layaway":	false,
						"created_date": "2016-04-13T10:28:57",
						"printed":	true,
						"modifier_amount":	0.0,
						"tax_rebate":	0.0,
						"special_request": "",
						"is_donation":	false,
						"discount_reason": "",
						"temp_sort":	1460568456,
						"commission_amount": "0",
						"station": "/resources/PosStation/1/",
						"serial_number": "",
						"catering_delivery_date":	null,
						"discount_taxed":	null,
						"applied_taxes": [
								{
										"tax_amount": "0.3600",
										"name": "JSL	City	Tax",
										"rounding_type":	0,
										"uuid": "f76c27a1-c5f4-480f-963e-d0cf8f074534",
										"actual_tax_rate": "8.0000",
										"tax_rate": "8.0000",
										"tax_table":	null,
										"order_item": "/resources/OrderItem/1630/",
										"local_tax_id":	31,
										"id":	1629,
										"resource_uri": "/resources/AppliedTaxOrderItem/1629/"
								}
						],
						"is_gift":	false,
						"ervc_type":	0,
						"discount_rule_type":	null,
						"cup_qty":	0,
						"modifieritems": [],
						"split_type":	0,
						"applied_service_fee": [],
						"kitchen_completed":	null,
						"date_paid":	null,
						"cost": "0.0000",
						"uom": "",
						"tax_included":	false,
						"wholesale_saving_amount": "0.000000",
						"is_coupon":	false,
						"voided_date":	null,
						"expedited":	null,
						"id":	1630,
						"on_hold":	false,
						"ingredientitems": [],
						"bill_parent":	null,
						"service_provider":	null,
						"split_with_seat":	0,
						"updated_date": "2016-04-13T10:29:16",
						"product": "/resources/Product/5/",
						"void_ref_uuid":	null,
						"combo_used":	null,
						"dining_option":	0,
						"price":	4.5,
						"voided_reason": "",
						"combo_uuid":	null,
						"order_local_id": "417",
						"discounted_by":	null,
						"discount_rule_amount":	null,
						"service_fee_tax": "0.000000",
						"quantity":	1,
						"service_fee_taxed": "0.000000",
						"order": "/resources/Order/417/",
						"resource_uri": "/resources/OrderItem/1630/"
				}
		],
		"shell_combo_items": [],
		"payments": [
				{
						"updated_date": "2016-04-13T10:28:59",
						"executed":	false,
						"last_4_cc_digits": "",
						"processor_accepted":	false,
						"till_owner":	null,
						"id":	355,
						"payment_date": "2016-04-13T10:28:59",
						"uuid": "00f1a58f-065c-434f-a551-735acbc0ccee",
						"gratuity":	0.0,
						"tip": "0.000000",
						"created_by": "/enterprise/User/5/",
						"refund_transaction_id":	null,
						"station": "/resources/PosStation/1/",
						"cc_first_name":	null,
						"online":	false,
						"establishment": "/enterprise/Establishment/1/",
						"transaction_id": "",
						"exchanged":	null,
						"updated_by": "/enterprise/User/5/",
						"transaction_captured":	false,
						"deleted":	null,
						"refunded":	false,
						"transaction_data": "",
						"payer_id":	null,
						"processor_response":	null,
						"first_4_cc_digits":	null,
						"amount_authorized": "0.000000",
						"signature_img_url":	null,
						"change": "0.000000",
						"invoice_transition_date":	null,
						"other_payment_type":	null,
						"receipt_email":	null,
						"bill":	0,
						"rounding_delta":	0.0,
						"card_type":	null,
						"amount": "4.860000",
						"payment_type":	1,
						"created_date": "2016-04-13T10:28:59",
						"cc_last_name":	null,
						"transaction_status":	null,
						"order": "/resources/Order/417/",
						"resource_uri": "/resources/Payment/355/"
				}
		],
		"order_exchange":	null,
		"history": [
				{
						"order_closed_by": "/enterprise/User/5/",
						"opened": "2016-04-13T10:27:36",
						"order_closed_at": "/resources/PosStation/1/",
						"order_opened_by": "/enterprise/User/5/",
						"uuid": "99da53ed-638f-4e6a-bdbf-b82ab4b6a209",
						"id":	399,
						"closed": "2016-04-13T10:29:19",
						"order_opened_at": "/resources/PosStation/1/",
						"order": "/resources/Order/417/",
						"resource_uri": "/resources/OrderHistory/399/"
				}
		]

Customer Creation or Updates

Upon completion of a customer entry being created or a customer's data being updated, the following sample is a json representation of the Customer record that will be sent via webhook.

{
    "accept_checks": false,
    "account_balance": null,
    "account_limit": null,
    "active": true,
    "address": "11 Wall St",
    "addresses":
    [
        {
            "active": true,
            "address_type": null,
            "city": "New York",
            "company_name": null,
            "country": "US",
            "created_date": "2021-12-06T21:39:47.627209",
            "customer": "/resources/Customer/2192/",
            "delivery_instructions": null,
            "email": "[email protected]",
            "id": 2548,
            "name": null,
            "phone_number": "1231231234",
            "primary_billing": false,
            "primary_shipping": true,
            "resource_uri": "/resources/CustomerAddress/2548/",
            "state": "NY",
            "street_1": "11 Wall St",
            "street_2": null,
            "updated_date": "2021-12-28T21:05:13.977077",
            "uuid": "cad0e89b-d834-47ff-8cc7-483fbd0bcebf",
            "zipcode": "10005"
        }
    ],
    "birth_date": null,
    "cc_exp": null,
    "cc_first_name": null,
    "cc_last_4_digits": null,
    "cc_last_name": null,
    "charge_account": false,
    "city": "New York",
    "company_name": null,
    "contract_expiration": null,
    "created_by": "/enterprise/User/2219/",
    "created_date": "2021-12-28T21:05:13.913408",
    "custom__1": "",
    "custom__2": "",
    "custom__3": "",
    "custom__4": "",
    "custom__5": "",
    "custom__6": "",
    "custom__7": "",
    "customer_groups":
    [],
    "customer_xt_uuid": null,
    "deleted": false,
    "discount": null,
    "email": "[email protected]",
    "email_opt_in": null,
    "exp_date": null,
    "expensify_account": null,
    "first_name": "firstName",
    "gender": 0,
    "gift_card_numbers":
    [],
    "id": 2192,
    "image": null,
    "is_visitor": false,
    "last_name": "lastName",
    "lic_number": null,
    "loyalty_number": null,
    "loyalty_ref_id": null,
    "notes": "",
    "ok_to_email": true,
    "past_due": null,
    "phone_number": "1231231234",
    "phone_opt_in": null,
    "picture": null,
    "pin": null,
    "post_opt_in": null,
    "ref_number": "123",
    "resource_uri": "/resources/Customer/2192/",
    "reward_card_numbers":
    [
        "1231231234"
    ],
    "source": null,
    "state": "NY",
    "tax_exempt": false,
    "tax_location": null,
    "third_party_id": null,
    "title": null,
    "total_purchases": 0,
    "total_visits": 0,
    "track_as_company": false,
    "type": 0,
    "updated_by": "/enterprise/User/2219/",
    "updated_date": "2021-12-28T21:05:13.977077",
    "uuid": "58126996-3fc8-4c87-b326-b4762783c863",
    "vehicles":
    [],
    "version_date": "2021-12-28T21:05:13.973265",
    "zipcode": "10005"
}

Rewards Card Creation

Upon creation of a Rewards Card, the following is a sample json body representation will be sent to the webhook URL configured to receive Rewards Card creations.

{
  "active": true,
  "address": null,
  "created_by": "/enterprise/User/3144/",
  "created_date": "2021-12-28T21:08:12.568476",
  "current_points": 0,
  "customer": null,
  "error_code": 0,
  "id": 3134,
  "number": "123321",
  "payment_type": 0,
  "resource_uri": "/resources/RewardsCard/3134/",
  "reward_points": {
    "points_by_items": 0,
    "points_by_purchases": 0,
    "points_by_visits": 0
  },
  "total_points": 0,
  "total_purchases": 0,
  "total_visits": 0,
  "updated_by": "/enterprise/User/3144/",
  "updated_date": "2021-12-28T21:08:12.568595"
}

Item Availability status is changed on POS

Separate message for every item upon any change of the availability status initiated from the POS for products or modifiers, or on any change of the availability status done on the POS for the related products/ modifiers/ ingredients, or for all unavailable products/modifiers when the feature is turned off in the settings of MC, the following sample record that will be sent via webhook.

{
  "barcode": "100001009367",
  "id": 622335,
  "instock": false,
  "type": "product"
}

Additional information is provided in the headers:

x-revel-instance (string) - holds instance name
x-revel-event-type (string) - “inout.stock” for our service
x-revel-establishment-id (int) - holds establishment ID

Field descriptions

  • barcode (string) - populated from POS message
  • id (int) - ID for product/modifier - required
  • instock (bool) - availability status of the product/modifier - required
  • type (string) - product or modifier - required

Menu Changed

Example event

{
  "event":"menu.updated"
}

Rules for Menu.Changed Event Firing

The menu.updated event is triggered whenever a change is made to products, modifiers and/or multi-channel and online custom menus and the “Push changes” button is pressed on the management console.

The event is triggered whenever one of the following changes occur and the “Push changes” button is pressed on the Management console:

  1. Any change is made to a custom menu with “Application type” set to “Mode” and “Mode/Station” set to “Online” or “Multi-Channel”.
    1. If the “Mode/Station” setting is changed from "Kiosk", "Bar", "Menu Board", "Online - Catering" or "SmartDining" to “Online” or “Multi-channel” the event will also trigger.
  2. Changes made to Products. Most of the settings and fields trigger the event.
  3. Changes made to Modifiers. Most of the settings and fields trigger the event.
  4. The event will also trigger on EMS level if any of the above changes occur.

For a full list of menu changed webhook triggers, refer to this page.

Using the API

Authorization

Endpoint uses JWT authorization. Specific application's client_id and secret must be used to obtain the access_token.

Sample request/response for obtaining JWT token:

curl --request POST --url "https://revelup-prod.auth0.com/oauth/token" --header 'content-type:application/json' --data '{"grant_type":"client_credentials", "client_id":"<value>", "client_secret":"<value>", "audience":"https://api-portal-be.prod.revelup.io/"}'
{
    "access_token":"XXXXX.YYYYY.ZZZZZ",
    "expires_in":86400,
    "token_type":"Bearer"
}

Fetch application integrations list

Provides a list of existing integrations under the particular application.

GET https://api-portal-be.revelup.io/external/integrations
Header ParameterTypeDescription
AuthorizationstringRequired. A bearer token i.e. 'Bearer XXXXX.YYYYY.ZZZZZ'
content-typestringRequired. Value application/json
Query ParameterTypeDescription
pageintegerOptional. Page number. Default value is 1, min 1, max 1000000.
pageSizeintegerOptional. Number of records to return per page. Default value is 10, min 1, max 100.

Sample request/response:

curl --request GET --url "https://api-portal-be.revelup.io/external/integrations?page=1&pageSize=10" --header 'Authorization:Bearer XXXXX.YYYYY.ZZZZZ' --header 'content-type:application/json'
{
    "pageSize":10,
    "page":1,
    "totalItems":2,
    "totalPages":1,
    "items":[
        {
            "client_id":"pizza-restaurant",
            "establishments":[2,3,10],
            "full_access":false
        },
        {
            "client_id":"sushi-in",
            "establishments":[1],
            "full_access":false
        }
    ]
}

Fetch application webhook message log

Provides a list of handled webhook messages for existing integrations under the particular application. By default only the failed messages are stored.

GET https://api-portal-be.revelup.io/external/message-log
Header ParameterTypeDescription
AuthorizationstringRequired. A bearer token i.e. 'Bearer XXXXX.YYYYY.ZZZZZ'
content-typestringRequired. Value application/json
Query ParameterTypeDescription
pagestringOptional. A reference to a page.
pageSizeintegerOptional. Number of records to return per page. Default value is 10, min 1, max 100.
statestringOptional. Webhook message state, values : 'invoked', 'failed' or 'retrying'.
instanceNamestringOptional. Instance name.
createdOnStartintegerOptional. Time interval floor value, when message was created in unix epoch time i.e. 1674222412
createdOnEndintegerOptional. Time interval ceiling value, when message was created in unix epoch time i.e. 1674222419

Sample request/response:

curl --request GET --url "https://api-portal-be.revelup.io/external/message-log?page=1&pageSize=10&state=failed&instanceName=sushi&createdOnStart=1674222412&createdOnEnd=1674222419" --header 'Authorization:Bearer XXXXX.YYYYY.ZZZZZ' --header 'content-type:application/json'
{
    "next_page": "48U93U2HR0VU93RNIV9P2UN3IRUEVH2IURBVIERBHNIPVQUBRVIB2IBIUBQIUBP2IQUB29UG30V97347Q3B4V7Q3BV8B34VU3B09UV3BV93",
    "items": [
        {
            "id": "4af806e2-4b8d-45dc-8de0-987efe3226f3",
            "instanceName": "sushi",
            "establishmentId": 1,
            "event": "order.finalized",
            "eventTimestamp": 1674222414,
            "applicationId": "045594e2-48e0-46b6-aa54-065b3ec35cd9",
            "webhookUrl": "https://your.webhook.url",
            "payload": "{\"json\":\"payload\"}",
            "state": "failed",
            "createdOn": 1674222419
        }
    ]
}