# POS Integrations

# POS Dev Guides



# Clover Dev Guide

## Introduction

CloverPOS is a well documented API that allows us access by token, which must be provided by the merchant. The process for creating a token is simple and gives the user the ability to restrict our access to only the data we need.

## API Key Creation

Referencing the photos below:

<div class="cl-preview-section" id="bkmrk-click-setup-and-then">- Click setup and then click API Tokens link in left nav.
- Click the green **Create New Token** button.
- Name the token bartrack.
- Set the Read checkbox for the following: Inventory, Merchant, Orders. 
    - Click the green ***Create Token*** button.
- Click the eyeball icon next to the hidden private token. 
    - Copy and save the token for configuration!

</div><p class="callout warning">Two-factor authentication must be enabled by the merchant prior to creation of any token.</p>

[![image-1649259173576.png](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/scaled-1680-/image-1649259173576.png)](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/image-1649259173576.png)

[![image-1649259182043.png](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/scaled-1680-/image-1649259182043.png)](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/image-1649259182043.png)

## End-point usage

You’ll need your token and merchant ID. See: [https://docs.clover.com/reference](https://docs.clover.com/reference)

<div class="cl-preview-section" id="bkmrk-categories---get-all">- Categories - GET all item categories, includes the item ids in those categories.
    
    
    - `{{url}}/v3/merchants/{{mId}}/categories`
    - https://sandbox.dev.clover.com/v3/merchants/2CZXFDSA7MQ71/categories
- Orders - GET all a list of orders for merchant w/filter
    
    
    - `{{url}}/v3/merchants/{{mId}}/orders`
    - https://sandbox.dev.clover.com/v3/merchants/2CZXFDSA7MQ71/orders?filter=modifiedTime&gt;1497991264000&amp;filter=modifiedTime&lt;1497994264000
- Order Line Items - GET all line items from an order.
    
    
    - `{{url}}/v3/merchants/{{mId}}/orders/{{orderId}}/line_items`
    - https://sandbox.dev.clover.com/v3/merchants/2CZXFDSA7MQ71/orders//line\_items

</div>### Postman Collection

[https://www.getpostman.com/collections/0f3b1b40494d5b8501f4](https://www.getpostman.com/collections/0f3b1b40494d5b8501f4)

## Notes and Considerations

<div class="cl-preview-section" id="bkmrk-if-an-order-is-later">- If an order is later modified (next business day), that order would show up in the day modified.
- Uses Unix epoch timestamps.

</div>

# Future Dev Guide

## Introduction

The Windows BarTrack agent queries data from MSSQL server directly with a username and password. See [MSSQL username/password setup](https://stackedit.io/app#providerId=googleDriveWorkspace&folderId=1clzVw2PpsLZlxKgWFHAihMrmAw0vJ77e). **TODO:** link

## MSSQL Query Example:

<div class="cl-preview-section" id="bkmrk-"></div>```SQL
SELECT<br></br>	ItemName as item,<br></br>	DepartmentDescription as category,<br></br>	GroupName as subcategory,<br></br>	SoldDate as sale_timestamp,<br></br>	CAST((GrossPrice/100.00) as decimal(10,2)) as price,<br></br>	Quantity as quantity,<br></br>	ItemName+'|'+DepartmentDescription as sku,<br></br>	Cast((TotalTax/100.00) as decimal(10,2)) as tax,<br></br>	CONVERT(nvarchar(50), sitem.SaleID) as order_identifier,<br></br>	CONVERT(nvarchar(50), sitem.SaleItemID) as location_identifier,<br></br>	Cast(((GrossPrice-ActualPrice)/100) as decimal(10,2)) as adjustment,<br></br>	CASE WHEN VoidReason > 0 THEN REPLACE(VoidReason, VoidReason, 'true') ELSE REPLACE(VoidReason, VoidReason, 'false') END as voids<br></br>FROM<br></br>	dbo.SaleItem as sitem<br></br>	LEFT JOIN dbo.Sale as s ON s.SaleID = sitem.SaleID<br></br>	LEFT JOIN dbo.Department ON sitem.Department = Department.DepartmentName<br></br>	LEFT JOIN dbo.SaleItemDiscount as sid ON sitem.SaleItemID = sid.SaleItemID<br></br>WHERE s.CheckStatus <= 1<br></br>	AND s.IsTrainMode = 0<br></br>	AND sitem.IsModifier = 0<br></br>	AND sitem.SoldDate >= '2021-12-24T05:00:00' AND sitem.SoldDate <= '2021-12-25T04:59:00'<br></br>ORDER BY sitem.ItemName<br></br>
```

### Query Notes

<div class="cl-preview-section" id="bkmrk-item-sold-%40-timestam">- Item sold @ timestamp - SaleItem.SoldDate -or- SaleItem.AddDate
- Item name &amp; SKU - SaleItem.ItemName -or- SaleItem.ReceiptDescription | Department.DepartmentDescription | Department.GroupName
- Quantity - SaleItem.Quantity
- Category - Department.DepartmentDescription -or- Department.GroupName
- Raw Price of Item - SaleItem.Gross Price
- Order ID per item - SaleItem.SaleID
- Adjusted Price - SaleItem.Gross Price minus SaleItem.Actual Price
- Tax paid per item - Where Tax.TaxID GET Tax.TaxPercent multiplied by Gross Price
- Void - SaleItem.VoidDate is not NULL

</div>

# Heartland Dev Guide

## Configuration

```JavaScript
// Config.js<br></br>config.AUTHURL = 'https://hrpos.heartland.us';<br></br>config.GURL = 'https://api.hrpos.heartland.us/';<br></br>config.CATEGORIES_ENDPOINT = '/action/generateReport?format=CSV&report=CATEGORY_SALES';<br></br>config.ITEMS_ENDPOINT = '/action/generateReport?format=CSV&report=PURCHASE_ITEM_REPORT';<br></br>config.AUTH_ENDPOINT = '/index.php/api/user/login';
```

## Authentication

### Request Example

Obtain `mb_jwtoken` with POST request to `https://hrpos.heartland.us/index.php/api/user/login`

```JavaScript
{<br></br>	"email": location.username,<br></br>	"password": location.password<br></br>}
```

### Response Example  


```JSON
{<br></br>	"email": "technology@bartrack.beer",<br></br>	"mb_cache_token": "f19ad3860b06366fa8c40706b5e84b99",<br></br>	"rootState": "root.dashboard.snapshot",<br></br>	"mb_jwtoken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiI0MTQ0NCIsImVtYWlsIjoidGVjaG5vbG9neUBiYXJ0cmFjay5iZWVyIiwiZ3JvdXBJZCI6MiwibG9jYXRpb25JZCI6MTE1NDAsImFjY291bnRJZCI6OTk2MCwiZXhwIjoxNjM5NjE0ODE3fQ.qVWAsN4befntOecquGKq79MPn233Xm6FdfjZ_0zd8DM"<br></br>}
```

Pass the `mb_jwtoken` value as a Cookie to the header of GET request of `https://hrpos.heartland.us/index.php/api/accountuser/languageSettings`

```JSON
{<br></br>	headers: { Cookie: "mb_session = ${mb_jwtoken}" }<br></br>}
```

## SQL Info

<div class="cl-preview-section" id="bkmrk-sql-location_identif">- SQL `location_identifier` is actually employee ID

</div>

# Omnivore Dev Guide

You must have a developer account to access this information.  
You may register for an free account, but there should already be one in-house with access to actual locations.

Register Account  
[https://panel.omnivore.io/register](https://panel.omnivore.io/register)  
  
API Reference  
[https://panel.omnivore.io/docs/api/1.0](https://panel.omnivore.io/docs/api/1.0)

## Error Code Overview

The table below provides an overview of the most common and like error responses codes that Omnivore will throw, however, all valid HTTP response codes are possible. A full list of the HTTP error codes that Omnivore can throw can be found [here](https://panel.omnivore.io/docs/api/1.0/errors#http-status-codes).

<table id="bkmrk-status-cause-400---b" role="table"><thead><tr><th>Status</th><th>Cause</th></tr></thead><tbody><tr><td>400 - Bad Request</td><td>The request was malformed. Check to see if you sent all the required parameters and that all referenced resources exist.</td></tr><tr><td>401 - Unauthorized</td><td>The API key provided was invalid or you were unauthorized to handle the data.</td></tr><tr><td>402 - Payment Required</td><td>Your Account Plan doesn't have access to a resource or action on a resource. Upgrade your Plan to gain access.</td></tr><tr><td>403 - Forbidden</td><td>The resource requested is invalid.</td></tr><tr><td>404 - Not Found</td><td>The resource requested was not found on the server.</td></tr><tr><td>405 - Method Not Allowed</td><td>The request method is not supported for the requested resource.</td></tr><tr><td>500 - Interal Server Error</td><td>Something went wrong on our end. Please contact us if this persists.</td></tr><tr><td>503 - Service Unavailable</td><td>Your request could not be processed, most likely because a location is offline.</td></tr></tbody></table>

- - - - - -

#   


### 500 Error Response - POS Configuration Error

This error is described by Omnivore as, `The POS and/or integration points are not configured correctly` meaning that Omnivore needs to interact with the customer's back office computer to remedy the issue. Until the issue has been resolved there is no data available for us to pull.

**Error Message -**

```
[ Integration "omnivore" ] [ 90 ] Error: 500 - INTERNAL SERVER ERROR
{"errors":[{"description":"POS is not configured for the requested operation.","error":"pos_config_error"}]}
[ Integration "omnivore" ] [ 90 ] Establishment finished with error:
      Error: omnivore establishment "90" doesn't have "tickets" data for specified time period, unable to continue
    at Omnivore.<anonymous> (/home/ubuntu/bartrack-pos/integrations/cli/cli.js:1471:23)
    at Generator.next (<anonymous>)
    at fulfilled (/home/ubuntu/bartrack-pos/integrations/cli/cli.js:1419:58)
    at process._tickCallback (internal/process/next_tick.js:68:7)

```

**Email Sample -**

```
Recipient: Omnivore Support Email <support@omnivore.io>
Subject: 500 Error Response for Location ID #igXkjznT

---

Hello, I hope that this email finds you well. While attempting to pull data from this location we encountered the following error and need assistance remedying the issue so that we may perform our regular business operations. Here are the details of the impacted location, as well as the issue -

Customer Name: Primetime Sports Bar & Grille - Fairfax, VA
Location ID: igXkjznT
POS: POSitouch
Error Code: 500
Error: 'internal_server_error'
Error Description: 'POS is not configured for the request operation'

Please let us know if there is anything that we need to perform on our end to resolve the issue, we are looking forward to hearing from you soon, cheers!

```

#   


### 500 Error Response - Internal Server Error

This error is described by Omnivore as, `An unexpected error occurred` meaning that Omnivore dropped the ball and didn't properly handle whatever error was encountered on their end. Until the issue has been resolved there is no data available for us to pull.

**Error Message -**

```
[ Integration "omnivore" ] [ 81 ] Error: 500 - INTERNAL SERVER ERROR
{"errors":[{"description":"The system threw an unexpected error.","error":"internal_error"}]}
[ Integration "omnivore" ] [ 81 ] Establishment finished with error:
      Error: omnivore establishment "81" doesn't have "tickets" data for specified time period, unable to continue
    at Omnivore.<anonymous> (/home/ubuntu/bartrack-pos/integrations/cli/cli.js:1471:23)
    at Generator.next (<anonymous>)
    at fulfilled (/home/ubuntu/bartrack-pos/integrations/cli/cli.js:1419:58)
    at process._tickCallback (internal/process/next_tick.js:68:7)

```

**Email Sample -**

```
Recipient: Omnivore Support Email <support@omnivore.io>
Subject: 500 Error Response for Location ID #igXkjznT

---

Customer Name: Primetime Sports Bar & Grille - Fairfax, VA
Location ID: igXkjznT
POS: POSitouch
Error Code: 500
Error: 'internal_error'
Error Description: 'The system threw an unexpected error'

```

- - - - - -

#   


### 503 Error Response - Service Unavailable

This error is described by Omnivore as, `An attempt was made to interact with an offline location` meaning that the customer is likely experiencing Internet connectivity issues. Until that issue has been resolved we are unable to pull any data.

The Omnivore [documentation](https://panel.omnivore.io/docs/guides/providing_support/offline_locations#offline-notification) states that if the location has failed to respond for 5 minutes it will be deemed inaccessible. While the location is offline you'll receive HTTP 503 errors for all API calls to it. The most common causes are network disruption at the location or the back of house computer has been restarted.

When this occurs you can log into the Ommivore Control Panel and find the establishment in question from the list of Locations and then assess the current **Status** to determine if it is a brief or sustained issue. If the location is offline then the only solution to this problem is to investigate the status and try again later when they come back online

**Error Message -**

```
[ Integration "omnivore" ] [ 82 ] Error: 503 - SERVICE UNAVAILABLE
{"errors":[{"description":"Location ingXgy5T not available - agent offline","error":"agent_offline"}]}
[ Integration "omnivore" ] [ 82 ] Establishment finished with error:
      Error: omnivore establishment "82" doesn't have "tickets" data for specified time period, unable to continue
    at Omnivore.<anonymous> (/home/ubuntu/bartrack-pos/integrations/cli/cli.js:1471:23)
    at Generator.next (<anonymous>)
    at fulfilled (/home/ubuntu/bartrack-pos/integrations/cli/cli.js:1419:58)
    at process._tickCallback (internal/process/next_tick.js:68:7)

```

# Restaurant Manager Dev Guide

This is a three step process that calls ahead to an end-point with a POST along with site specific cert. It returns a list of signed, time-sensitive urls S3 for each file to upload by the BT Client. Once completed it calls GET on the batch for final processing after the uploads have been confirmed. Note that the file name of the export must match this name, it’s expectations based on the point-of-sale type.

# SmartTab Dev Guide

##### **Integration Type: - Undocumented API**

## Parameters Used

<div class="cl-preview-section" id="bkmrk-venueid%3D1%26_%3D16384686">- venueId=1&amp;\_=1638468699524
    
    
    - **TODO:** - Need to discover what the second param \_ is for.
- timeZone
- timeStart
- timeEnd
- date

</div>## Local Storage Keys

```
token: U2FsdGVkX183RZIJk5oO/AuYZbG6KES7q+E/2DoSSAAcX9l+6pduyb6uhJuTV46l
```

## Request Headers

```
Request-Method: GET<br></br><br></br>Authorization: Basic bWZsb3JlczpGbG9yZXMxNjA=
```

## Tabs Endpoint

I’m not sure yet if the mflores is a private sandbox api, or if that URL will be establishment specific.

##### Example URL:

`https://api-mflores.smarttab.com/api/report/tabReport/?timeStart=05%3A00%3A00&timeEnd=05%3A00%3A00&timeZone=America%2FNew_York&date=2020-10-05&venueId=1&_=1638468699524`

### Response JSON Example:

```JSON
[<br></br>  {<br></br>    "id": "30cc598f-58f9-4a3f-a4b0-381360d521a0",<br></br>    "paymentId": null,<br></br>    "ticketId": "3846f386-36e5-4281-8948-fe47566824d9",<br></br>    "tableId": null,<br></br>    "customerId": null,<br></br>    "dayOrdinalNumber": 1,<br></br>    "subNumber": null,<br></br>    "tabStatus": "OPENED", //FILTER CLOSED ONLY<br></br>    "paymentStatus": null,<br></br>    "amount": null,<br></br>    "tips": null,<br></br>    "balanceDue": 39.18,<br></br>    "total": 39.18,<br></br>    "lastFourSymbols": null,<br></br>    "smartTabFee": null,<br></br>    "tableName": null,<br></br>    "closeTime": null,<br></br>    "dayTimestamp": "2020-10-05 00:00:00",<br></br>    "tabName": "Test",<br></br>    "paymentTender": null,<br></br>    "customTender": null,<br></br>    "creditTender": null,<br></br>    "refundAmount": null,<br></br>    "cardDataInputMethod": null,<br></br>    "paymentSource": null,<br></br>    "kioskMode": false,<br></br>    "ownerId": 173,<br></br>    "tabType": "BAR_TYPE",<br></br>    "ownerName": "Michael Flores",<br></br>    "customerName": "Test",<br></br>    "tender": null,<br></br>    "status": "OPENED",<br></br>    "hasVoids": false,<br></br>    "hasDiscounts": false,<br></br>    "hasComps": false,<br></br>    "voidsNum": null<br></br>  }<br></br>]<br></br><br></br>
```

## Ticket Endpoint

I’m not sure yet if the mflores is a private sandbox api, or if that URL will be establishment specific.

##### Example URL:

`https://api-mflores.smarttab.com/api/tab/ticketView?id=30cc598f-58f9-4a3f-a4b0-381360d521a0&venueId=1&_=1638468699525`

### Response JSON Example

*only showing pieces of data we’re looking for, this response has a huge tree for a single row*

```JSON
{<br></br>    "productId": 894,<br></br>    "itemizedDiscountAmount": 0<br></br>    "isVoided": false,<br></br>    "creationTime": "2020-10-05 21:27:15.459+00"<br></br>    "deleted": false,<br></br>    "created": "2020-10-05 21:27:26+00"<br></br>    "modifiers": [],<br></br>    "name": "EAGLE SHOT",<br></br>    "price": 10,<br></br>    "classId": 2,<br></br>    "multiplier": 1,<br></br>    "adjustedGrossPrice": 9.09,<br></br>    "netPrice": 9.09, 72<br></br>    "quantity": 1,<br></br>    "subClassId": null,<br></br>    "priceWithModsAndMultiplier": 10,<br></br>    "includedTax": 1.07,<br></br>    "excludedTax": 0<br></br>}<br></br>
```

## Categories/Products Sold Endpoint

`https://api-mflores.smarttab.com/api/report/product/?dateStart=2021-01-01&dateEnd=2021-10-31&timeStart=05%3A00%3A00&timeEnd=05%3A00%3A00&timeZone=America%2FNew_York&classId%5B%5D=1&classId%5B%5D=2&classId%5B%5D=3&showSold=1&showNotSelling=0&venueId=1&_=1638566076252`

### Response JSON Example:

```JSON
[<br></br>    {<br></br>	    "type": "BEER",<br></br>	    "classId": 1,<br></br>	    "cost": "3.30",<br></br>	    "quantity": "1",<br></br>	    "productId": 761,<br></br>	    "name": "SUDWERK PILSNER ",<br></br>	    "roleIds": [1],<br></br>	    "employeeIds": [173]<br></br>    },<br></br><br></br>    {<br></br>	    "type": "BEER",   <br></br>	    "classId": 1,<br></br>	    "cost": "4.13",<br></br>	    "quantity": "1",<br></br>	    "productId": 209,<br></br>	    "name": "BUD LIGHT",<br></br>	    "roleIds": [1],<br></br>	    "employeeIds": [173]<br></br>	}<br></br>]<br></br>
```

## References:

[SmartTab Integration Notes (JIRA)](https://bartrack.atlassian.net/browse/BAR-950)

# Square Dev Guide

##### **Integration Type: - [Documented API](https://developer.squareup.com/reference/square)**

## Parameters Used

### Caveats

<div class="cl-preview-section" id="bkmrk-voids-are-not-availa"><div class="cl-preview-section">- Voids are not available on this integration. 
    - Due to the way voids are handled in the API data (not the visual report data), they no longer exist as an item line in the data set. Instead you have to listen to their webhook for monitoring order modifications as the Square API does not support it.

</div></div>### Get Location

**GET**: `https://connect.squareup.com/v2/locations`  
`location` is needed as a parameter in the request for orders.

#### Headers

<div class="cl-preview-section" id="bkmrk-authorization%3A-beare"><div class="cl-preview-section">- `Authorization: Bearer {token}`

</div></div>### Get Catalogs

**GET**: `https://connect.squareup.com/v2/catalog/list?types=category,item,item_variation`  
Catalogs are needed to determine an item’s category.

#### Headers

<div class="cl-preview-section" id="bkmrk-authorization%3A-beare-0">- Authorization: Bearer {token}

</div>#### Parameters

<div class="cl-preview-section" id="bkmrk-cursor-initial-reque"><div class="cl-preview-section">- `cursor`
    - Initial request is without `cursor`. If response includes `cursor` then paginate using response `cursor`.
    - If no `cursor` is returned then it is the last page.

</div></div>### Get Orders

**POST**: `https://connect.squareup.com/v2/orders/search`

#### Headers

<div class="cl-preview-section" id="bkmrk-authorization%3A-beare-1">- Authorization: Bearer {token}

</div>#### Body Parameters

<div class="cl-preview-section" id="bkmrk-location_id-as-per-r">- `location_id` as per response from get location
- `sales_start` format `YYYY-MM-DDTHH:MM:ssZ`
- `sales_end` format `YYYY-MM-DDTHH:MM:ssZ`

</div>#### Body Example

```
{  
	"location_ids": [  
		{location_id}  
	],  
	"query": {  
		"filter": {  
			"date_time_filter": {  
				"closed_at": {  
					"start_at": {sales_start},  
					"end_at": {sales_end}  
				}  
			},  
			"state_filter": {  
				"states": [  
					"COMPLETED"  
				]  
			} 
		},  
		"sort": {  
			"sort_field": "CLOSED_AT",  
			"sort_order": "DESC"  
		}  
	}
}

```

#### Response JSON Example:

```
[
	{  
		"id": "kTmqQ6TTaKVY8KlcbAJEQSyeV",  
		"location_id": "GXFWQJMA4XGBA",  
		"line_items": [  
			{  
				"catalog_object_id": "NPOXBH3AEIFOQUMJGDLELNZC",  
				"quantity": "1",  
				"name": "8- Gingers Revenge fig and vanilla",  
				"variation_name": "Regular",    
				"modifiers": [  
					{  
						"name": "12oz"
					}  
				],  
				"gross_sales_money": {  
					"amount": 600
				},  
				"total_tax_money": {  
					"amount": 45,  
				},  
				"total_discount_money": {  
					"amount": 60,  
				}
			}
		]
	}
]


```

### References:

[Square Integration Notes (JIRA)](https://bartrack.atlassian.net/browse/BAR-1174)

# Touch Bistro Dev Guide

##### **Integration Type: - Undeveloped**

## References:

[Touch Bistro Integration Notes (JIRA)](https://bartrack.atlassian.net/browse/BAR-687)

# GoTab Dev Guide

GoTab API explorer:  
[https://gotab.io/api/graph](https://gotab.io/api/graph)<span style="color: #d1d2d3; font-family: Slack-Lato, Slack-Fractions, appleLogo, sans-serif; font-size: 15px; font-style: normal; font-variant-ligatures: common-ligatures; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #222529; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">   
[https://studio.apollographql.com/sandbox/schema/reference/objects/Item?query=returnType%3ADatetime](https://studio.apollographql.com/sandbox/schema/reference/objects/Item?query=returnType%3ADatetime)  
[https://docs.gotab.io/reference/objects#item](https://docs.gotab.io/reference/objects#item)</span>

List of order statuses:

- PENDING
- SCHEDULED
- SENT
- IN\_TRANSIT
- DELIVERED
- OFFLINE\_DELIVERED
- RECALLED
- VOIDED
- RESET

 All items ordered on a tab for that fiscal day:

```
curl -L -X POST 'https://gotab.io/api//graph' \<br></br>-H 'Authorization: BearerToken' \<br></br>-H 'Content-Type: application/json' \<br></br>--data-raw '{"query":"query($locationUuid: String!) {\n  location(locationUuid: $locationUuid) {\n    tabsList(\n      filter: {\n        fiscalDay: { equalTo: \"2022-08-26\" }\n        status: { equalTo: \"CLOSED\" }\n        ordersPlaced: {greaterThan: 0}\n      }\n    ) {\n      tabUuid\n      href\n      name\n      status\n      numGuests\n      tabMode \n      tax\n      subtotal\n      autograt\n      total\n      opened\n      closed\n      orderType\n      server {\n        userId\n        name\n      }s\n      itemsList(\n        filter: {\n          ordered: {equalTo: true}\n        }\n      ) {\n        fee\n        discount\n        comped\n        voided\n        status\n        name\n        itemId\n        taxRate\n        taxRateDetail\n        sku\n        subtotal\n        subtotalInitial\n        options {\n          name\n          shortName\n          isProduct\n          price\n          quantity\n        }\n        adjustments {\n          itemAdjustmentId\n          quantity\n          unitPrice\n          adjustmentReason\n          adjustmentType\n        }\n        accountingStream {\n            accountingStreamUuid\n            name\n            reportingGroup\n        }\n    }\n    }\n  }\n}","variables":{"locationUuid":"NA2RpxKdptZYnHOA3Z~eIo4E"}}'
```

# SpotOn

Please see "Requesting API Access" here:

[SpotOn Establishment Setup Documentation](https://developers.spoton.com/enterprise/docs/enabling-api-access "https://developers.spoton.com/enterprise/docs/enabling-api-access")

# SpotOn

See official documentation:

[https://wiki.bartrack.beer/books/pos-integrations/page/spoton](https://wiki.bartrack.beer/books/pos-integrations/page/spoton "See Official Documentation")

# New Establishment or Integration

1. New integrations and establishment config will be added to staging first.
2. Integration would be tested in three parts:
    
    
    1. individual establishment.
    2. all establishments of integration type.
    3. finally, all integrations/establishments (full daily automation)
3. These types of failure must be tested:
    
    
    1. establishment has no data.
    2. connection failure.
    3. any type of breakage in one integration, does not cause break in another.

# Configuring New Locations

This outlines the processes necessary to configure a location in the database and begin pulling data

# Toast

## <span style="text-decoration: underline; color: #e67e23;">Gather POS Information</span>

1\. In order to configure customers who utilize **Toast** as their POS provider the Customer Success team needs to have the customer create an account for us with the appropriate reporting privileges. Visit the [Toast Homepage](https://pos.toasttab.com/) in a web browser and proceed to **Login** - input the BarTrack `technology@bartrack.beer` credentials

2\. Locate `Switch Restaurant` on the top left side of the webpage and then click it and find the location you're trying to configure - you can either manually search the list or enter the establishment name into the filter

[![image-1651060456221.54.09 AM.png](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/scaled-1680-/image-1651060456221-54-09-am.png)](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/image-1651060456221-54-09-am.png)

3\. Once the location has been found, make note of the establishment name and copy it exactly as displayed in the Toast dashboard. It is extremely important that this is accurately captured - if there are two lines, separate the content of the bottom and top line with a dash.

- In the screenshot above, we would want to record their location name as, `QBar Darien - 8109 cass avenue` in the database.

4\. The next step is to determine how the customer utilizes their Point of Sale system - particularly as it relates to Categories, and Sub-Categories. Navigate to the [Menus &gt; Item Details](https://www.toasttab.com/restaurants/admin/reports/home#selection-details) page to pull up a breakdown of all the sales data at the establishment - you should select the date range for a busy day of the week such as Friday or Saturday.

[![image-1651061810879.16.48 AM.png](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/scaled-1680-/image-1651061810879-16-48-am.png)](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/image-1651061810879-16-48-am.png)

- Once you've generated data for your specified date, try sorting by **Sales Category** or **Menu** to identify where the draft beer sales are.
- Toast has 3 layers of organizational hierarchy whereas we are only capturing 2 - *Category* and *Sub-Category*. You will need to use your judgment to determine which ones that we want to utilize, in the example above I assign `Menu Group` as the **Category** and `Sales Category` as the **Sub-Category**

<p class="callout danger">The **Category** and **Sub-Category** will be different for every location - you will need to manually investigate this to ensure the data comes in clean for SKU mapping, otherwise we'll have to re-pull the data</p>

5\. The last step in the Toast dashboard is to determine if a customer utilizes modifiers for their Draft Beer products. Once you're done identifying the **Category** and **Sub-Category** usage, click on one the Draft Beer items and it will pull up the *Order Details* - if you scroll down you'll see a list of items on the order and there will be a column labeled `Modifiers`.

[![image-1651062498384.28.15 AM.png](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/scaled-1680-/image-1651062498384-28-15-am.png)](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/image-1651062498384-28-15-am.png)

- If there are things related to the glassware size, we will want to ensure that modifiers are marked as TRUE - otherwise, if modifiers do not appear to be a determining factor in identifying what a SKU represents mark this as FALSE

<p class="callout info">The Onboarding Team should have already identified if the customer utilizes modifiers so you can ask them for that information, otherwise, you can verify this yourself by looking at the data in Toast.</p>

- - - - - -

## <span style="text-decoration: underline; color: #e67e23;">Database Configuration</span>

1\. The next step in the configuration process is updating the **establishments** table of the database to reflect the necessary information for the integration. The primary things that you'll need to know are as follows:

- Establishment ID
- Timezone
- Location Name from Toast Dashboard
- Modifier Usage
- Category / Sub-Category

Once you have collected all of the necessary information you can proceed with executing the SQL query below, this will prompt you to enter several variables which encompass the information you captured above -

```SQL
UPDATE <br></br>    establishments<br></br>SET <br></br>    integration_id = 4, <br></br>    default_pour_cost_pct = 20, <br></br>    pos_hour_integration_done = 5, <br></br>    pos_cloud_based = true, <br></br>    pos_modifiers = ${pos_modifier_flag}$, <br></br>    time_zone = '${timezone}$', <br></br>    pos_properties = '{"header_titles": {"category": "${category}$", "subcategory": "${subcategory}$"}, "location_pos_name": "${establishment_toast_name}$"}'<br></br>WHERE <br></br>    id = ${establishment_id}$;
```

**Example Data for Variables -**

```
Name                     Value          <br></br>------------------------ -------------- <br></br>pos_modifier_flag        true           <br></br>timezone                 US/Eastern    <br></br>category                 Menu           <br></br>subcategory              Sales Category <br></br>establishment_toast_name Test Name      <br></br>establishment_id         1              <br></br>
```

- - - - - -

## <span style="text-decoration: underline; color: #e67e23;">Server Configuration</span>

1\. The final step of the configuration process is to SSH onto the POS server to modify the `settings.json` file and insert a new record for the location you are configuring - this can be found in the `/home/ubuntu/bartrack-pos/integrations/cli` directory on the server.

2\. In the configuration file you will need to locate the section for `toast` and then scroll to the bottom of that list of entries, see the screenshot below for reference -

[![image-1651063505662.png](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/scaled-1680-/image-1651063505662.png)](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/image-1651063505662.png)

3\. Once you have found the section, you will need to insert a record in the chronological position based on the `establishment_id`. In order to minimize error, it is recommended to copy the existing structure and paste it into the necessary position and then modifying the `establishment_id`. Once the changes have been finalized be sure to save your changes.

<p class="callout warning">Make sure you are careful when editing the configuration file - incorrect formatting will result in the inability to pull POS data for any locations on the server. In order to minimize error, it is recommended to copy the existing structure and paste it into the necessary position - modifying the establishment </p>

4\. Now that the establishment has been correctly configured you will be able to pull the POS data for the location, you will need to pull the data from the **Activation Date** onwards - it is recommended to pull at least one day of data to ensure that things are operational and there were no configuration-related issues.

# Omnivore

## <span style="text-decoration: underline;"><span style="color: #e67e23; text-decoration: underline;">Gather POS Information</span></span>

1\. In order to configure customers who utilize **Omnivore** for their POS Integration the Customer Success team needs to have the customer install the Omnivore agent on their back-office machine. Visit the [Omnivore Control Panel Login](https://panel.omnivore.io/login) in a web browser and proceed to **Login** - input the BarTrack `technology@bartrack.beer` credentials

2\. Navigate to the `Locations` tab on the top center of the webpage menu - this will provide you a list of all of the customers that are currently integrated with BarTrack through Omnivore. You may utilize the search box on the top right side of the screen to quickly filter locations. See the attached image below for reference -

[![image-1651065136740.png](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/scaled-1680-/image-1651065136740.png)](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/image-1651065136740.png)

3\. Once you have found the location you're looking to configure, you will want to click on that customer and cross-reference the address displayed here with what we have captured in the database to ensure that we are referencing the correct location. Once you have confirmed that the location is valid, you will need to copy the `Location ID`

[![image-1651065215673.png](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/scaled-1680-/image-1651065215673.png)](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/image-1651065215673.png)

<p class="callout info">While here, it is useful to also reference the **Status** and **Ping Latency** in order to determine if there are any issues. As long as the status indicates they are Online and the ping latency does not have any significant yellow or red periods you are good to proceed.</p>

<p class="callout warning">If you do not see a location in the Omnivore Control Panel or their **Status** is offline - please contact the Customer Success team to coordinate a meeting with the customer</p>

- - - - - -

## <span style="text-decoration: underline; color: #e67e23;">Database Configuration</span>

1\. The next step in the configuration process is updating the **establishments** table of the database to reflect the necessary information for the integration. The primary things that you'll need to know are as follows:

- Establishment ID
- Timezone
- Modifier Usage
- Location Identifier

<p class="callout info">The Onboarding Team should have already identified if the customer utilizes modifiers so you will need to ask them for that information - if they are unsure, set this to FALSE and then reference the POS data that is captured</p>

Once you have collected all of the necessary information you can proceed with executing the SQL query below, this will prompt you to enter several variables which encompass the information you captured above -

```SQL
UPDATE <br></br>    establishments<br></br>SET <br></br>    integration_id = 1, <br></br>    default_pour_cost_pct = 20, <br></br>    pos_hour_integration_done = 5, <br></br>    pos_cloud_based = true, <br></br>    pos_modifiers = ${pos_modifier_flag}$, <br></br>    time_zone = '${timezone}$', <br></br>    pos_properties = '{"processed_locations_ids": ["${location_id}$"]}'<br></br>WHERE <br></br>    id = ${establishment_id}$;
```

**Example Data for Variables -**

```
Name                     Value          <br></br>------------------------ -------------- <br></br>pos_modifier_flag        true           <br></br>timezone                 US/Eastern    <br></br>location_id 			 i6EzBB4T      <br></br>establishment_id         1              
```

- - - - - -

## <span style="text-decoration: underline; color: #e67e23;">Server Configuration</span>

1\. The final step of the configuration process is to SSH onto the POS server to modify the `settings.json` file and insert a new record for the location you are configuring - this can be found in the `/home/ubuntu/bartrack-pos/integrations/cli` directory on the server.

2\. In the configuration file you will need to locate the section for `omnivore` and then scroll to the bottom of that list of entries, see the screenshot below for reference -

[![image-1651065864710.24.20 AM.png](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/scaled-1680-/image-1651065864710-24-20-am.png)](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/image-1651065864710-24-20-am.png)

3\. Once you have found the section, you will need to insert a record in the chronological position based on the `establishment_id`. In order to minimize error, it is recommended to copy the existing structure and paste it into the necessary position and then modifying the `establishment_id`. Once the changes have been finalized be sure to save your changes.

<p class="callout warning">Make sure you are careful when editing the configuration file - incorrect formatting will result in the inability to pull POS data for any locations on the server. In order to minimize error, it is recommended to copy the existing structure and paste it into the necessary position - modifying the establishment </p>

4\. Now that the establishment has been correctly configured you will be able to pull the POS data for the location, you will need to pull the data from the **Activation Date** onwards - it is recommended to pull at least one day of data to ensure that things are operational and there were no configuration-related issues.

# Square

## <span style="text-decoration: underline; color: #e67e23;">Gather POS Information</span>

1\. In order to configure customers who utilize **Square** as their POS provider, the Customer Success team needs to gather an `Access Token` from the customer.

- The Customer Success team typically shares this in the [\#customer-pos-integrations](https://bartrack.slack.com/archives/C01V90HPYAJ) Slack channel or [Customer Onboarding Tracker](https://docs.google.com/spreadsheets/d/1IBeZlgJ_QjTNu7DRPAYuL-pgQR3NyUhv88KPFtXC2es/edit#gid=0) spreadsheet

2\. Once you have obtained an `Access Token` for a customers location, you will need to execute the following command on your Terminal -

```shell
curl https://connect.squareup.com/v2/locations \<br></br>  -H 'Square-Version: 2022-02-16' \<br></br>  -H 'Authorization: Bearer EAAAEP2HXAiYWQuoUlL0igb9C2-3HCaahVOdrfSPS7LnB4dwiyRUCBgyXo-IeMKs' \<br></br>  -H 'Content-Type: application/json'
```

<p class="callout warning">Make sure to replace the bearer token in the provided example with the Access Token that the customer provided</p>

3\. After executing the command the server will return a large JSON object of location(s). You should utilize a [JSON Formatter](https://jsonformatter.org/json-pretty-print) to make this more legible, the output should look similar to the example below -

```JSON
{<br></br>  "locations": [<br></br>    {<br></br>      "id": "4D09GFZF388XW",<br></br>      "name": "Palate Bottle Shop",<br></br>      "address": {<br></br>        "address_line_1": "1007 N. 4th Street",<br></br>        "locality": "Wilmington",<br></br>        "administrative_district_level_1": "NC",<br></br>        "postal_code": "28401",<br></br>        "country": "US"<br></br>      },<br></br>      "timezone": "America/New_York",<br></br>      "capabilities": [<br></br>        "CREDIT_CARD_PROCESSING",<br></br>        "AUTOMATIC_TRANSFERS"<br></br>      ],<br></br>      "status": "ACTIVE",<br></br>      ...<br></br>  ]<br></br>}
```

4\. Once you have formatted the JSON object, you will need to find the location that represents the one you are currently trying to configure - be sure to validate the address as there might be multiple different locations under one account. Once you have identified the location you will need to copy the `id` value.

<p class="callout info">If there are no locations in the JSON object that match the location in the database, reach out to the Onboarding team and have them verify the address and which location that we are supposed to use for our integration</p>

- - - - - -

## <span style="text-decoration: underline; color: #e67e23;">Database Configuration</span>

1\. The next step in the configuration process is updating the **establishments** table of the database to reflect the necessary information for the integration. The primary things that you'll need to know are as follows:

- Establishment ID
- Timezone
- Location ID (Square)
- Modifier Usage

<p class="callout info">The Onboarding Team should have already identified if the customer utilizes modifiers so you will need to ask them for that information - if they are unsure, set this to FALSE and then reference the POS data that is captured</p>

Once you have collected all of the necessary information you can proceed with executing the SQL query below, this will prompt you to enter several variables which encompass the information you captured above -

```SQL
UPDATE <br></br>    establishments<br></br>SET <br></br>    integration_id = 3, <br></br>    default_pour_cost_pct = 20, <br></br>    pos_hour_integration_done = 5, <br></br>    pos_cloud_based = true, <br></br>    pos_modifiers = ${pos_modifier_flag}$, <br></br>    time_zone = '${timezone}$', <br></br>    pos_properties = '{"locations_id": "${location_id}$"}'<br></br>WHERE <br></br>    id = ${establishment_id}$;
```

**Example Data for Variables -**

```
Name                     Value          <br></br>------------------------ -------------- <br></br>pos_modifier_flag        true           <br></br>timezone                 US/Eastern    <br></br>location_id              4D09GFZF388XW             <br></br>establishment_id         1              <br></br>
```

- - - - - -

## <span style="text-decoration: underline; color: #e67e23;">Server Configuration</span>

1\. The final step of the configuration process is to SSH onto the POS server to modify the `settings.json` file and insert a new record for the location you are configuring - this can be found in the `/home/ubuntu/bartrack-pos/integrations/cli` directory on the server.

2\. In the configuration file you will need to locate the section for `square` and then scroll to the bottom of that list of entries, see the screenshot below for reference -

[![image-1651068845454.13.59 AM.png](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/scaled-1680-/image-1651068845454-13-59-am.png)](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/image-1651068845454-13-59-am.png)

3\. Once you have found the section, you will need to insert a record in the chronological position based on the `establishment_id`. In order to minimize error, it is recommended to copy the existing structure and paste it into the necessary position and then modifying the `establishment_id` and `access token` to reflect the location you're configuring. Once the changes have been finalized be sure to save your changes.

<p class="callout warning">Make sure you are careful when editing the configuration file - incorrect formatting will result in the inability to pull POS data for any locations on the server. In order to minimize error, it is recommended to copy the existing structure and paste it into the necessary position - modifying the establishment </p>

4\. Now that the establishment has been correctly configured you will be able to pull the POS data for the location, you will need to pull the data from the **Activation Date** onwards - it is recommended to pull at least one day of data to ensure that things are operational and there were no configuration-related issues.

# UpServe

## <span style="text-decoration: underline;"><span style="color: #e67e23; text-decoration: underline;">Gather POS Information</span></span>

1\. In order to configure customers who utilize **UpServe** as their POS provider the Customer Success team needs to have the customer create a guest account for us using the integration email address. Visit the [UpServe Dashboard](https://reports.breadcrumb.com/login) in a web browser and proceed to login - input the BarTrack `technology@bartrack.beer` credentials

2\. Upon authentication, utilize the search box to identify the location you're attempting to configure. Once you've found the location, make a note of the establishment name.

[![image-1651073590206.33.07 AM.png](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/scaled-1680-/image-1651073590206-33-07-am.png)](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/image-1651073590206-33-07-am.png)

- - - - - -

## <span style="text-decoration: underline; color: #e67e23;">Database Configuration</span>

1\. The next step in the configuration process is updating the **establishments** table of the database to reflect the necessary information for the integration. The primary things that you'll need to know are as follows:

- Establishment ID
- Timezone
- Location Name (UpServe)
- Modifier Usage

<p class="callout info">The Onboarding Team should have already identified if the customer utilizes modifiers so you will need to ask them for that information - if they are unsure, set this to FALSE and then reference the POS data that is captured</p>

Once you have collected all of the necessary information you can proceed with executing the SQL query below, this will prompt you to enter several variables which encompass the information you captured above -

```SQL
UPDATE <br></br>    establishments<br></br>SET <br></br>    integration_id = 5, <br></br>    default_pour_cost_pct = 20, <br></br>    pos_hour_integration_done = 5, <br></br>    pos_cloud_based = true, <br></br>    pos_modifiers = ${pos_modifier_flag}$, <br></br>    time_zone = '${timezone}$', <br></br>    pos_properties = '{"location_pos_name": "${location_name}$"}'<br></br>WHERE <br></br>    id = ${establishment_id}$;
```

**Example Data for Variables -**

```
Name                     Value          <br></br>------------------------ -------------- <br></br>pos_modifier_flag        true           <br></br>timezone                 US/Eastern    <br></br>location_name            Outer Range Brewing Company            <br></br>establishment_id         1              
```

- - - - - -

## <span style="text-decoration: underline; color: #e67e23;">Server Configuration</span>

1\. The final step of the configuration process is to SSH onto the POS server to modify the `settings.json` file and insert a new record for the location you are configuring - this can be found in the `/home/ubuntu/bartrack-pos/integrations/cli` directory on the server.

2\. In the configuration file you will need to locate the section for `upserve` and then scroll to the bottom of that list of entries, see the screenshot below for reference -

[![image-1651073967644.39.24 AM.png](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/scaled-1680-/image-1651073967644-39-24-am.png)](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/image-1651073967644-39-24-am.png)

3\. Once you have found the section, you will need to insert a record in the chronological position based on the `establishment_id`. In order to minimize error, it is recommended to copy the existing structure and paste it into the necessary position and then modifying the `establishment_id` to reflect the location you're configuring. Once the changes have been finalized be sure to save your changes.

<p class="callout warning">Make sure you are careful when editing the configuration file - incorrect formatting will result in the inability to pull POS data for any locations on the server. In order to minimize error, it is recommended to copy the existing structure and paste it into the necessary position - modifying the establishment </p>

4\. Now that the establishment has been correctly configured you will be able to pull the POS data for the location, you will need to pull the data from the **Activation Date** onwards - it is recommended to pull at least one day of data to ensure that things are operational and there were no configuration-related issues.

# Revel

## <span style="text-decoration: underline;"><span style="color: #e67e23; text-decoration: underline;">Gather POS Information</span></span>

1\. In order to configure customers who utilize **Revel** as their POS provider, the Customer Success team needs to gather the custom Revel `Login URL` from the customer and inform us which email address that the customer used to create a guest access account for us

- The Customer Success team typically shares this in the [\#customer-pos-integrations](https://bartrack.slack.com/archives/C01V90HPYAJ) Slack channel or [Customer Onboarding Tracker](https://docs.google.com/spreadsheets/d/1IBeZlgJ_QjTNu7DRPAYuL-pgQR3NyUhv88KPFtXC2es/edit#gid=0) spreadsheet

- - - - - -

## <span style="text-decoration: underline; color: #e67e23;">Database Configuration</span>

1\. The next step in the configuration process is updating the **establishments** table of the database to reflect the necessary information for the integration. The primary things that you'll need to know are as follows:

- Establishment ID
- Timezone
- Login URL (Revel)
- Modifier Usage

<p class="callout info">The Onboarding Team should have already identified if the customer utilizes modifiers so you will need to ask them for that information - if they are unsure, set this to FALSE and then reference the POS data that is captured</p>

Once you have collected all of the necessary information you can proceed with executing the SQL query below, this will prompt you to enter several variables which encompass the information you captured above -

```SQL
UPDATE <br></br>    establishments<br></br>SET <br></br>    integration_id = 2, <br></br>    default_pour_cost_pct = 20, <br></br>    pos_hour_integration_done = 5, <br></br>    pos_cloud_based = true, <br></br>    pos_modifiers = ${pos_modifier_flag}$, <br></br>    time_zone = '${timezone}$', <br></br>    pos_properties = '{"url": "${login_url}$"}'<br></br>WHERE <br></br>    id = ${establishment_id}$;
```

**Example Data for Variables -**

```
Name                     Value          <br></br>------------------------ -------------- <br></br>pos_modifier_flag        true           <br></br>timezone                 US/Eastern    <br></br>login_url                https://solacebrewing.revelup.com             <br></br>establishment_id         1              <br></br>
```

- - - - - -

## <span style="text-decoration: underline; color: #e67e23;">Server Configuration</span>

1\. The final step of the configuration process is to SSH onto the POS server to modify the `settings.json` file and insert a new record for the location you are configuring - this can be found in the `/home/ubuntu/bartrack-pos/integrations/cli` directory on the server.

2\. In the configuration file you will need to locate the section for `revel` and then scroll to the bottom of that list of entries, see the screenshot below for reference -

[![image-1651069630108.27.05 AM.png](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/scaled-1680-/image-1651069630108-27-05-am.png)](https://wiki.bartrack.beer/uploads/images/gallery/2022-04/image-1651069630108-27-05-am.png)

3\. Once you have found the section, you will need to insert a record in the chronological position based on the `establishment_id`. In order to minimize error, it is recommended to copy the existing structure and paste it into the necessary position and then modifying the `establishment_id` and `username/password` to reflect the location you're configuring. Once the changes have been finalized be sure to save your changes.

<p class="callout warning">Make sure you are careful when editing the configuration file - incorrect formatting will result in the inability to pull POS data for any locations on the server. In order to minimize error, it is recommended to copy the existing structure and paste it into the necessary position - modifying the establishment </p>

4\. Now that the establishment has been correctly configured you will be able to pull the POS data for the location, you will need to pull the data from the **Activation Date** onwards - it is recommended to pull at least one day of data to ensure that things are operational and there were no configuration-related issues.

