Overview
Introduction
Your integration is going to be linked with an Organization, and that Organization has a list of Locations. Each location can have more than one brand (Sushi, Poke, Burgers, ...). And each brand has a catalog with a different set of products.
When you create a new Order, it has to be linked to a specific brand (brand ids are unique, the same brand in different locations has a different id). Then we will route the order to the right location under the right brand name.
Please contact with our support team at hola@last.app to receive a token.
Authentication
For both the Rest API and the webhooks we use the same authentication method. We will share with you a secret token, and in all the requests it has to be included as a header.
Header
Authorization: Bearer \${token}
Rest API
GET Location List
[
{
"id": "f2779a96-578f-4649-89f6-a0972183efea",
"name": "Pl Catalunya",
"address": "Plaça de Catalunya, 08002 Barcelona",
"email": "notifications@restBarcelona.com",
"postalCode": "08002",
"phoneNumber": "666666666",
"latitude": 41.441969,
"longitude": 2.203933,
"region": "Barcelona",
"city": "Barcelona",
"externalId": "2345",
"defaultPosCatalogId": "f2779a96-578f-4649-89f6-a0972183efea",
"brands": [
{
"id": "23cdda27-2f82-46e4-a366-deecd5d420d0",
"name": "My Sushi Brand",
"catalogs": {
"default": "03406b61-0dfc-40a9-a07b-408960d8cc1c",
"glovo": "3c085f01-140f-47dc-80d9-5225bb67774d",
"deliveroo": "9a408ddc-8438-4549-95e6-5cee67a2d648",
"uber": "13a2c877-3856-4dcc-b071-645a26de938e",
"shop": "3c085f01-140f-47dc-80d9-5225bb67774d"
}
},
{
"id": "f2779a96-578f-4649-89f6-a0972183efea",
"name": "My Poke Brand",
"catalogs": {
"default": "03406b61-0dfc-40a9-a07b-408960d8cc1c",
"glovo": "3c085f01-140f-47dc-80d9-5225bb67774d",
"deliveroo": "9a408ddc-8438-4549-95e6-5cee67a2d648",
"uber": "13a2c877-3856-4dcc-b071-645a26de938e",
"shop": "3c085f01-140f-47dc-80d9-5225bb67774d"
}
}
],
"postalCodes": [
{
"postalCode": "08002",
"comments": ""
},
{
"postalCode": "08013",
"comments": ""
}
],
"preparationMinutes": 15,
"polygons": [
[
{ "lat": 41.13361190470618, "lng": 1.2731949865977343 },
{ "lat": 41.14027007942357, "lng": 1.2880436957041796 },
{ "lat": 41.14123966013921, "lng": 1.3035790503184375 },
{ "lat": 41.13238362388618, "lng": 1.3143937170664843 },
{ "lat": 41.124172945711976, "lng": 1.2845246374766406 }
],
[
{ "lat": 41.13361190470618, "lng": 1.2731949865977343 },
{ "lat": 41.14027007942357, "lng": 1.2880436957041796 },
{ "lat": 41.14123966013921, "lng": 1.3035790503184375 },
{ "lat": 41.13238362388618, "lng": 1.3143937170664843 },
{ "lat": 41.124172945711976, "lng": 1.2845246374766406 }
]
],
"shopAreas": [
{
"id": "a830f995-0234-446f-ac42-c3e2492881bb",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"name": "Sicilia",
"deliveryFee": 1200,
"deliveryExtraMinutes": 11,
"minimumBasket": 1000,
"polygon": [
{ "lat": 41.411206735924424, "lng": 2.170459031494123 },
{ "lat": 41.39781609535299, "lng": 2.1618759626464668 },
{ "lat": 41.39408167471969, "lng": 2.1728622907714668 },
{ "lat": 41.40039143284847, "lng": 2.191058396728498 },
{ "lat": 41.41107799290444, "lng": 2.190886735351545 }
],
"enabled": false,
"estimatedDeliveryMinutes": 26
},
{
"id": "4123e3a2-2b2b-4c28-a733-50e87735b352",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"name": "maracaibo",
"deliveryFee": 190,
"deliveryExtraMinutes": 30,
"minimumBasket": 1000,
"polygon": [
{ "lat": 41.44968945529636, "lng": 2.1989548200683418 },
{ "lat": 41.441582953121106, "lng": 2.1914017194824043 },
{ "lat": 41.431287522523725, "lng": 2.2140610212402168 },
{ "lat": 41.44261240636137, "lng": 2.2152626508788886 }
],
"enabled": false,
"estimatedDeliveryMinutes": 45
},
{
"id": "8fd4a673-ef0c-4730-9e00-95e2c31b7982",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"name": null,
"deliveryFee": 0,
"deliveryExtraMinutes": null,
"minimumBasket": null,
"polygon": [
{ "lat": 41.39196569037639, "lng": 2.1377135546310333 },
{ "lat": 41.38882630455909, "lng": 2.1463767238319598 },
{ "lat": 41.38410500329319, "lng": 2.1495199068802373 },
{ "lat": 41.38307532428261, "lng": 2.150013351287412 },
{ "lat": 41.37685162391421, "lng": 2.146658155003527 },
{ "lat": 41.37404910631808, "lng": 2.1377883369850625 },
{ "lat": 41.37480752561103, "lng": 2.1328979464657216 },
{ "lat": 41.37646762430614, "lng": 2.1288658628311463 },
{ "lat": 41.38069737451375, "lng": 2.1261875712639 },
{ "lat": 41.38357578862208, "lng": 2.125515120724928 },
{ "lat": 41.38885148878816, "lng": 2.128108690495516 }
],
"enabled": true,
"estimatedDeliveryMinutes": 15
},
{
"id": "da32a7e9-a541-40f7-9626-f9e53d59661f",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"name": null,
"deliveryFee": 0,
"deliveryExtraMinutes": null,
"minimumBasket": null,
"polygon": [
{ "lat": 41.380224370506724, "lng": 2.194976676493545 },
{ "lat": 41.34775919146317, "lng": 2.1757673426458446 },
{ "lat": 41.33641777131268, "lng": 2.130792061884126 },
{ "lat": 41.35549084543963, "lng": 2.089936654169282 },
{ "lat": 41.38331719623883, "lng": 2.074830452997407 },
{ "lat": 41.396324507960216, "lng": 2.082726876337251 },
{ "lat": 41.411389130337874, "lng": 2.092683236200532 },
{ "lat": 41.425034405220025, "lng": 2.1369718714544383 },
{ "lat": 41.41422140427475, "lng": 2.176453988153657 }
],
"enabled": true,
"estimatedDeliveryMinutes": 15
},
{
"id": "e359f624-2d2d-4691-a304-065fbc0c7bc6",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"name": null,
"deliveryFee": 0,
"deliveryExtraMinutes": null,
"minimumBasket": null,
"polygon": [
{ "lat": 41.41011215450934, "lng": 2.136979783830233 },
{ "lat": 41.40173217584032, "lng": 2.162002071890834 },
{ "lat": 41.383048038305674, "lng": 2.17191815877956 },
{ "lat": 41.362030226927445, "lng": 2.160765392134474 },
{ "lat": 41.355954211595176, "lng": 2.135193069825325 },
{ "lat": 41.36536498320847, "lng": 2.111060385131056 },
{ "lat": 41.38198763769528, "lng": 2.1013472561008895 },
{ "lat": 41.39975954721055, "lng": 2.112853868690081 },
{ "lat": 41.40774235345601, "lng": 2.131570259111344 }
],
"enabled": true,
"estimatedDeliveryMinutes": 15
},
{
"id": "e5f9db87-9b79-433f-b38e-85c47313bc21",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"name": null,
"deliveryFee": 0,
"deliveryExtraMinutes": null,
"minimumBasket": null,
"polygon": [
{ "lat": 41.41775997724526, "lng": 2.137298453837295 },
{ "lat": 41.409520740821016, "lng": 2.16613756516542 },
{ "lat": 41.40874825882698, "lng": 2.169914115458389 },
{ "lat": 41.38093279015199, "lng": 2.1829603801068265 },
{ "lat": 41.35387856255594, "lng": 2.1668242106732327 },
{ "lat": 41.34563122807394, "lng": 2.132835258036514 },
{ "lat": 41.35903261605653, "lng": 2.1009062419232327 },
{ "lat": 41.38170560278213, "lng": 2.0882033000287015 },
{ "lat": 41.40643075773568, "lng": 2.1036528239544827 }
],
"enabled": true,
"estimatedDeliveryMinutes": 15
}
],
"workingTimes": {
"default": {
"thursday": [
{
"id": "6939ef89-9179-4ab8-97ff-d394999b5370",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"day": "thursday",
"start": "08:00",
"end": "00:00"
}
],
"monday": [
{
"id": "6c2d8783-b299-4a44-9a9b-fae4f0b92874",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"day": "monday",
"start": "08:00",
"end": "00:00"
}
],
"wednesday": [
{
"id": "991070eb-9561-460f-ad61-177affdc1b7b",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"day": "wednesday",
"start": "08:00",
"end": "00:00"
}
],
"tuesday": [
{
"id": "aa1f3526-209c-4471-8a0c-090a10c0c975",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"day": "tuesday",
"start": "08:00",
"end": "00:00"
}
],
"friday": [
{
"id": "df2c5ea5-ac9b-49a1-aff2-507cec1f528c",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"day": "friday",
"start": "08:00",
"end": "00:00"
}
]
},
"f2779a96-578f-4649-89f6-a0972183efea": {
"friday": [
{
"id": "01e85701-1f9e-424c-a925-24749145cfd9",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"day": "friday",
"start": "08:00",
"end": "20:00",
"locationVirtualBrandId": "f2779a96-578f-4649-89f6-a0972183efea"
}
],
"saturday": [
{
"id": "9ebbec16-c4de-4ff0-9c95-400414f51d60",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"day": "saturday",
"start": "08:00",
"end": "20:00",
"locationVirtualBrandId": "f2779a96-578f-4649-89f6-a0972183efea"
}
],
"monday": [
{
"id": "b609a2d5-c528-42ac-bd19-4b29ba85aa59",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"day": "monday",
"start": "08:00",
"end": "20:00",
"locationVirtualBrandId": "f2779a96-578f-4649-89f6-a0972183efea"
}
],
"wednesday": [
{
"id": "c4ac6828-afc5-4777-864b-8df55c7af067",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"day": "wednesday",
"start": "08:00",
"end": "20:00",
"locationVirtualBrandId": "f2779a96-578f-4649-89f6-a0972183efea"
}
],
"thursday": [
{
"id": "d8def688-b17f-48ed-a680-0fe8acc9cf7e",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"day": "thursday",
"start": "08:00",
"end": "20:00",
"locationVirtualBrandId": "f2779a96-578f-4649-89f6-a0972183efea"
}
],
"tuesday": [
{
"id": "ebd13e06-dbea-40d3-b66c-05ccec1465dc",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"day": "tuesday",
"start": "08:00",
"end": "20:00",
"locationVirtualBrandId": "f2779a96-578f-4649-89f6-a0972183efea"
}
]
}
}
},
{
"id": "6df10f06-b232-4e8c-8599-d202d50f18d0",
"name": "Prado",
"address": "Calle del Prado, 2, 28014 Madrid",
"email": "notifications@restMadrid.com",
"postalCode": "28014",
"phoneNumber": "666666666",
"latitude": 41.441969,
"longitude": 2.203933,
"region": "Madrid",
"city": "Madrid",
"externalId": "1234",
"defaultPosCatalogId": "f2779a96-578f-4649-89f6-a0972183efea",
"brands": [
{
"id": "58ec0ff0-99ce-4ebe-b315-dd9458331209",
"name": "My Sushi Brand",
"catalogs": {
"default": "03406b61-0dfc-40a9-a07b-408960d8cc1c",
"glovo": "3c085f01-140f-47dc-80d9-5225bb67774d",
"deliveroo": "9a408ddc-8438-4549-95e6-5cee67a2d648",
"uber": "13a2c877-3856-4dcc-b071-645a26de938e",
"shop": "3c085f01-140f-47dc-80d9-5225bb67774d"
}
}
],
"postalCodes": [
{
"postalCode": "28001",
"comments": ""
},
{
"postalCode": "28005",
"comments": ""
}
],
"preparationMinutes": 20,
"polygons": [
[
{ "lat": 41.13361190470618, "lng": 1.2731949865977343 },
{ "lat": 41.14027007942357, "lng": 1.2880436957041796 },
{ "lat": 41.14123966013921, "lng": 1.3035790503184375 },
{ "lat": 41.13238362388618, "lng": 1.3143937170664843 },
{ "lat": 41.124172945711976, "lng": 1.2845246374766406 }
],
[
{ "lat": 41.13361190470618, "lng": 1.2731949865977343 },
{ "lat": 41.14027007942357, "lng": 1.2880436957041796 },
{ "lat": 41.14123966013921, "lng": 1.3035790503184375 },
{ "lat": 41.13238362388618, "lng": 1.3143937170664843 },
{ "lat": 41.124172945711976, "lng": 1.2845246374766406 }
]
],
"shopAreas": [
{
"id": "a830f995-0234-446f-ac42-c3e2492881ba",
"locationId": "f2779a96-578f-4649-89f6-a0972183efef",
"name": "Testing Shop",
"deliveryFee": 1200,
"deliveryExtraMinutes": 11,
"minimumBasket": 1000,
"polygon": [
{ "lat": 41.411206735924424, "lng": 2.170459031494123 },
{ "lat": 41.39781609535299, "lng": 2.1618759626464668 },
{ "lat": 41.39408167471969, "lng": 2.1728622907714668 },
{ "lat": 41.40039143284847, "lng": 2.191058396728498 },
{ "lat": 41.41107799290444, "lng": 2.190886735351545 }
],
"enabled": false,
"estimatedDeliveryMinutes": 26
}
],
"workingTimes": {
"default": {
"thursday": [
{
"id": "6939ef89-9179-4ab8-97ff-d394999b5370",
"locationId": "6df10f06-b232-4e8c-8599-d202d50f18d0",
"day": "thursday",
"start": "08:00",
"end": "00:00"
}
],
"monday": [
{
"id": "6c2d8783-b299-4a44-9a9b-fae4f0b92874",
"locationId": "6df10f06-b232-4e8c-8599-d202d50f18d0",
"day": "monday",
"start": "08:00",
"end": "00:00"
}
],
"wednesday": [
{
"id": "991070eb-9561-460f-ad61-177affdc1b7b",
"locationId": "6df10f06-b232-4e8c-8599-d202d50f18d0",
"day": "wednesday",
"start": "08:00",
"end": "00:00"
}
],
"tuesday": [
{
"id": "aa1f3526-209c-4471-8a0c-090a10c0c975",
"locationId": "6df10f06-b232-4e8c-8599-d202d50f18d0",
"day": "tuesday",
"start": "08:00",
"end": "00:00"
}
],
"friday": [
{
"id": "df2c5ea5-ac9b-49a1-aff2-507cec1f528c",
"locationId": "6df10f06-b232-4e8c-8599-d202d50f18d0",
"day": "friday",
"start": "08:00",
"end": "00:00"
}
]
},
"58ec0ff0-99ce-4ebe-b315-dd9458331209": {
"friday": [
{
"id": "01e85701-1f9e-424c-a925-24749145cfd9",
"locationId": "6df10f06-b232-4e8c-8599-d202d50f18d0",
"day": "friday",
"start": "08:00",
"end": "20:00",
"locationVirtualBrandId": "58ec0ff0-99ce-4ebe-b315-dd9458331209"
}
],
"saturday": [
{
"id": "9ebbec16-c4de-4ff0-9c95-400414f51d60",
"locationId": "6df10f06-b232-4e8c-8599-d202d50f18d0",
"day": "saturday",
"start": "08:00",
"end": "20:00",
"locationVirtualBrandId": "58ec0ff0-99ce-4ebe-b315-dd9458331209"
}
]
}
}
}
]
HTTP Request
GET https://api.last.app/v1/locations
Location
Field name | Description |
---|---|
id (String) | Unique identifier for the location |
externalId (String) | Unique identifier for the location in your system |
name (String) | Name of the location |
address (String) | Address of the location |
email (String) | Email of the location |
phoneNumber (String) | Contact phone number |
latitude (Float) | Latitude of the location |
longitude (Float) | Longitude of the location |
region (String) | Region of the location |
city (String) | City of the location |
defaultPosCatalogId (String) | Default POS catalog unique identifier |
brands (Array) | List of location brands |
postalCodes (Array) | List of postalCodes delimiting the delivery area |
preparationMinutes (Integer) | Default preparationMinutes for this location |
polygons (Array) | Array of polygons of the areas of service (DEPRECATED: Find polygons inside shopAreas!) |
shopAreas (Array) | Array of areas of service, their cost and ETA |
workingTimes (Array) | Array of location (default) and brands schedules |
Brand
Field name | Description |
---|---|
id (String) | Unique identifier for the location brand |
name (String) | Brand name |
catalogs (Object) | Object containing catalog ids used by the brand |
GET Location Floorplans
[
{
"id": "d482a7b0-377e-4a56-8c43-7d847738f044",
"name": "Main",
"tables": [
{
"id": "03d96ebb-b36c-43b1-874a-24eecec1abc2",
"name": "A1",
"seats": 2
},
{
"id": "398bcf26-141f-42c5-80a2-391270d7f92a",
"name": "B2",
"seats": 2
},
{
"id": "11b005ee-d7e3-4aea-b545-9d1d659b0396",
"name": "Barra",
"seats": 4
}
]
},
{
"id": "75b87c37-6ca2-4815-9e07-3f05b0185a66",
"name": "Outside",
"tables": [
{
"id": "cb38cb1c-9052-4637-a499-50d4fd8fc86c",
"name": "T2",
"seats": 2
}
]
}
]
HTTP Request
GET https://api.last.app/v1/locations/:locationId/floorplans
Floorplan
Field name | Description |
---|---|
id (String) | Unique identifier for the floorplan |
name (String) | Name of the floorplan |
tables (Array) | List of tables on this floorplan |
Table
Field name | Description |
---|---|
id (String) | Unique identifier for the table |
name (String) | Name of the table |
seats (Integer) | Default number of seats for this table |
GET Location Catalog
{
"name": "Weekend catalog",
"modifierGroups": [
{
"allowRepeat": false,
"id": "c033799d-0448-4166-8f21-a3f86c115849",
"min": 1,
"max": 1,
"name": "Point",
"modifiers": [
{
"name": "Rare",
"id": "120ae8bc-05e2-4e17-8dc4-4d33ae76e023",
"organizationModifierId": "c064032c-885a-4e61-9bee-293ee030aa76",
"priceImpact": 0,
"externalId": "1234"
},
{
"name": "Medium",
"id": "8ddc4e32-195d-49cd-9b0e-96e3dc0945b5",
"organizationModifierId": "b671220a-fe3a-4dff-8aef-c2a228a57e56",
"priceImpact": 0
},
{
"name": "Well done",
"id": "12881d29-efa5-4522-a3b0-0f790b1d1e93",
"organizationModifierId": "77a42a6f-3af3-495a-8767-2fe0816d792c",
"priceImpact": 0
}
]
}
],
"categories": [
{
"name": "Example category",
"id": "d8486f43-04c6-4d94-b683-654e053957f0",
"products": [
{
"name": "Burger",
"type": "PRODUCT",
"price": 750,
"vatPercentage": 10,
"allergens": ["EGG", "GLUTEN"],
"specifications": ["glutenfree", "hot", "vegan"],
"id": "1a2cfa61-0d75-43d1-a839-3b5ba5c3bf10",
"externalId": "3567",
"description": "A nice burger",
"imageUrl": "https://res.cloudinary.com/lastpos/image/upload/someImageId",
"modifierGroups": ["c033799d-0448-4166-8f21-a3f86c115849"],
"organizationProductId": "e98f45e0-d614-4a44-9ab1-616489fc38f1"
}
]
},
{
"name": "Combos",
"id": "combos-category-id",
"products": [
{
"name": "Menu",
"type": "COMBO",
"price": 1000,
"vatPercentage": 10,
"id": "7452516e-5884-4495-b953-7997cb0d3039",
"categories": [
{
"id": "a289a696-f39a-434d-af3e-421b35ed3cb6",
"name": "First",
"max": 1,
"products": [
{
"id": "a21192ec-5e7e-414c-8c86-df9110238ad1",
"name": "Edamame",
"priceImpact": 150,
"modifierGroups": []
}
]
}
],
"organizationComboId": "e4a4ace0-fda5-45e7-9b77-f03d4161019c",
"imageUrl": "https://res.cloudinary.com/lastpos/image/upload/comboImage",
"description": "Explanation of the combo"
}
]
}
]
}
HTTP Request
GET https://api.last.app/v1/location/${locationId}/catalog/${catalogId}
Query params
Field name | Description |
---|---|
showDisabled (Boolean) | Send as 'true' to show disabled items also |
Modifier Group
Field name | Description |
---|---|
id (String) | Identifier of the modifier group in Last |
name (String) | Name of the group |
min (Integer) | Minimum number of modifiers to be selected |
max (Integer) | Maximum number of modifiers to be selected |
allowRepeat (boolean) | If enabled a modifier can be selected multiple times |
modifiers (Array) | Array containing the modifiers |
Product
Field name | Description |
---|---|
id (String) | Unique identifier of the product in Last |
name (String) | Name of the product |
type (String) | PRODUCT |
description (String) | Description of the product |
imageUrl (String) | Image url of the product |
price (Integer) | Price per unit of the product (without modifiers included) |
vatPercentage (Integer) | Percentage of VAT |
modifierGroups (Array) | Array containing the modifiers of the product |
allergens (Array) | Array containing the allergens of the product |
specifications (Array) | Array containing the specifications of the product. All possible values: ["vegetarian", "vegan", "glutenfree", "mild", "medium", "hot"] |
organizationProductId (String) | Unique identifier of the parent product in the organization |
externalId (String) | Identifier of the product in the external system |
Combo
Field name | Description |
---|---|
id (String) | Unique identifier of the product in Last |
name (String) | Name of the product |
type (String) | COMBO |
description (String) | Description of the product |
imageUrl (String) | Image url of the product |
price (Integer) | Price per unit of the product (without modifiers included) |
vatPercentage (Integer) | Percentage of VAT |
categories (Array) | Array containing the categories of the combo |
organizationComboId (String) | Unique identifier of the parent combo in the organization |
ComboCategory
Field name | Description |
---|---|
id (String) | Unique identifier of the category in Last |
name (String) | Name of the category |
max (Integer) | Maximum number of products to select |
products (Array) | Array containing the products of the category (only of type PRODUCT) |
ComboProduct
Field name | Description |
---|---|
id (String) | Unique identifier of the combo in Last |
name (String) | Name of the product |
priceImpact (Integer) | Price to be added to the combo total price |
modifiers (Array) | Array containing the modifiers of the product |
Modifier
Field name | Description |
---|---|
id (String) | Unique identifier of the modifier in Last |
name (String) | Name of the modifier |
priceImpact (Integer) | Price per unit of the modifier |
externalId (String) | Identifier of the modifier in the external system |
organizationModifierId (String) | Unique identifier of the modifier in the organization |
Category
Field name | Description |
---|---|
id (String) | Unique identifier of the category in Last |
name (String) | Name of the category |
products (Array) | Array containing the products and combos of the category |
GET Tab List
Allows to list tabs given a set of parameters.
{
"tabs": [
{
"id": "bbcfabf5-d660-4c21-9751-4e8f197439e2",
"name": null,
"creationTime": "2020-07-31T15:48:22.000Z",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"source": "Shop",
"allergyInfo": null,
"customerNote": null,
"kitchenNote": null,
"tableName": null,
"closeTime": "2020-08-06T15:32:04.000Z",
"cancelTime": "2020-08-06T15:32:04.000Z",
"locationBrandId": "23cdda27-2f82-46e4-a366-deecd5d420d0",
"customerId": "998a26bd-04a0-11ea-8884-0242ac110002",
"code": "S002",
"pickupType": "takeAway",
"schedulingTime": "2020-08-02T22:30:00.000Z",
"activationTime": "2020-08-06T15:32:04.000Z",
"tabTables": [],
"products": [
{
"id": "f3cf29da-b5c9-408f-b6e9-ba14732b0bc8",
"catalogProductId": "7d2b8e27-e0bf-4732-8044-223943b7fd05",
"organizationProductId": "3cbeaeca-49f6-4dda-be87-5f7cb96d12db",
"organizationComboId": null,
"externalId": "0534073e-3eec-4ecc-83a4-ab446a30ca2a",
"name": "Burger",
"price": 1400,
"quantity": 1,
"course": "Main",
"comments": null,
"fullPrice": 1400,
"pointsExpense": 100,
"finalPrice": 1400,
"type": "PRODUCT",
"promotionId": null,
"modifiers": [
{
"id": "348ca8b3-28cd-4adf-a5ce-951f0158d704",
"name": "Cheese",
"priceImpact": 0,
"quantity": 1,
"catalogModifierId": "65254ec3-3ec8-4279-a5b9-118dd4391832"
}
],
"comboProducts": []
}
],
"seats": 1,
"language": "ES",
"bills": [
{
"id": "866ed6ee-f325-434b-9c8a-e5d0fc07b53f",
"number": 859,
"rectifiedBillNumber": 934,
"creationTime": "2020-07-31T15:48:23.000Z",
"finalizingTime": "2020-07-31T15:48:23.000Z",
"company": {
"name": "LastPOS",
"taxId": "1234",
"address": "Maracaibo 8, Nave 2, 08041, Barcelona"
},
"customerCompanyName": "Acme Inc.",
"customerCompanyTaxId": "B12345678",
"total": 1400,
"tax": 127,
"taxableBase": 1273,
"discountTotal": 0,
"deliveryFee": 0,
"minimumBasketSurcharge": 0,
"terraceSurcharge": 0,
"terraceSurchargePercentage": 0,
"preferredPaymentMethod": "card",
"payments": [],
"products": [
{
"id": "7a740ff2-d326-42ea-a239-c9b9125d3fc3",
"catalogProductId": "7d2b8e27-e0bf-4732-8044-223943b7fd05",
"tabProductId": "f3cf29da-b5c9-408f-b6e9-ba14732b0bc8",
"name": "Burger",
"price": 1400,
"originalPrice": 1400,
"quantity": 1,
"modifiers": [
{
"id": "be75642e-7f74-42e8-bd3d-de575caa1847",
"name": "Cheese",
"priceImpact": 0,
"quantity": 1,
"catalogModifierId": "54393d6e-5780-45da-a96f-8de45eac10cc"
}
],
"comboProducts": []
}
]
}
],
"customerInfo": {
"name": "Bruce",
"surname": "Wayne",
"phoneNumber": "+34666666666",
"email": "batman@wayneindustries.com"
},
"delivery": {
"address": "Gran Via de les Corts Catalanes, 620",
"details": "First door to the left",
"latitude": 41.3876734,
"longitude": 2.1647098,
"statuses": [
{
"creationTime": "2020-08-03T09:10:11.000Z",
"status": "KITCHEN"
},
{
"creationTime": "2020-08-05T14:06:09.000Z",
"status": "CLOSED"
}
],
"courier": {
"id": "be75642e-7f74-42e8-bd3d-de575caa1847",
"name": "Jose"
},
"cutlery": false
}
}
],
"page": 0,
"lastPage": 0
}
HTTP Request
GET https://api.last.app/v1/tabs
Query parameters
Field name | Description |
---|---|
locationId (String) | Only retrieve tabs from this location |
startDate* (DateTime) | Retrieve tabs with activation time after startDate (in ISO 8601) |
endDate* (DateTime) | Retrieve tabs with activation time after endDate (in ISO 8601) |
withDeletedBills (Boolean) | Include each tab deleted bills |
page (Integer) | This request is paginated, you can select the page with this parameter |
tableId (String) | Only retrieve tabs from a specific table |
tableName (String) | Only retrieve tabs from tables with a specific name |
open (Boolean) | Only retrieve tabs which are open/closed |
customerId (String) | Only retrieve tabs from a specific customer |
GET Tab by ID
Allows to retrieve a specific tab by its ID.
{
"id": "bbcfabf5-d660-4c21-9751-4e8f197439e2",
"name": null,
"creationTime": "2020-07-31T15:48:22.000Z",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"source": "Shop",
"allergyInfo": null,
"customerNote": null,
"kitchenNote": null,
"tableName": null,
"closeTime": "2020-08-06T15:32:04.000Z",
"locationBrandId": "23cdda27-2f82-46e4-a366-deecd5d420d0",
"customerId": "998a26bd-04a0-11ea-8884-0242ac110002",
"code": "S002",
"pickupType": "takeAway",
"schedulingTime": "2020-08-02T22:30:00.000Z",
"activationTime": "2020-08-06T15:32:04.000Z",
"tabTables": [],
"products": [
{
"id": "f3cf29da-b5c9-408f-b6e9-ba14732b0bc8",
"catalogProductId": "7d2b8e27-e0bf-4732-8044-223943b7fd05",
"organizationProductId": "3cbeaeca-49f6-4dda-be87-5f7cb96d12db",
"organizationComboId": null,
"externalId": "0534073e-3eec-4ecc-83a4-ab446a30ca2a",
"name": "Burger",
"price": 1400,
"quantity": 1,
"course": "Main",
"comments": null,
"fullPrice": 1400,
"finalPrice": 1400,
"type": "PRODUCT",
"promotionId": null,
"modifiers": [
{
"id": "348ca8b3-28cd-4adf-a5ce-951f0158d704",
"name": "Cheese",
"priceImpact": 0,
"quantity": 1,
"catalogModifierId": "65254ec3-3ec8-4279-a5b9-118dd4391832"
}
],
"comboProducts": []
}
],
"seats": 1,
"language": "ES",
"waiters": [
{
"name": "Elon"
}
],
"bills": [
{
"id": "866ed6ee-f325-434b-9c8a-e5d0fc07b53f",
"number": 859,
"creationTime": "2020-07-31T15:48:23.000Z",
"finalizingTime": "2020-07-31T15:48:23.000Z",
"company": {
"name": "LastPOS",
"taxId": "1234",
"address": "Maracaibo 8, Nave 2, 08041, Barcelona"
},
"total": 1400,
"tax": 127,
"taxableBase": 1273,
"discountTotal": 0,
"deliveryFee": 0,
"minimumBasketSurcharge": 0,
"terraceSurcharge": 0,
"terraceSurchargePercentage": 0,
"preferredPaymentMethod": "card",
"payments": [],
"products": [
{
"id": "7a740ff2-d326-42ea-a239-c9b9125d3fc3",
"catalogProductId": "7d2b8e27-e0bf-4732-8044-223943b7fd05",
"tabProductId": "f3cf29da-b5c9-408f-b6e9-ba14732b0bc8",
"name": "Burger",
"price": 1400,
"originalPrice": 1400,
"quantity": 1,
"modifiers": [
{
"id": "be75642e-7f74-42e8-bd3d-de575caa1847",
"name": "Cheese",
"priceImpact": 0,
"quantity": 1,
"catalogModifierId": "54393d6e-5780-45da-a96f-8de45eac10cc"
}
],
"comboProducts": []
}
]
}
],
"customerInfo": {
"name": "Bruce",
"surname": "Wayne",
"phoneNumber": "+34666666666",
"email": "batman@wayneindustries.com"
},
"delivery": {
"address": "Gran Via de les Corts Catalanes, 620",
"details": "First door to the left",
"latitude": 41.3876734,
"longitude": 2.1647098,
"statuses": [
{
"creationTime": "2020-08-03T09:10:11.000Z",
"status": "KITCHEN"
},
{
"creationTime": "2020-08-05T14:06:09.000Z",
"status": "CLOSED"
}
],
"courier": {
"id": "be75642e-7f74-42e8-bd3d-de575caa1847",
"name": "Jose"
},
"cutlery": false
}
}
HTTP Request
GET https://api.last.app/v1/tabs/${tabId}
POST Add Bill to Tab
Allows to create a bill with all the pending products & fees pending to be paid.
HTTP Request
POST https://api.last.app/v1/tabs/${tabId}/bill
Field name | Description |
---|---|
discount (Object) | Optional discount object |
Response
{
"id": "7036ecd9-7464-4023-b7f2-f293209455bf",
"tabId": "690d47b2-82ef-421b-88b9-686cc7bb606d",
"creationTime": "2021-11-22T11:05:47.704Z",
"number": 1379,
"payments": [],
"type": "products",
"title": "Products",
"products": [
{
"tabProductId": "be928187-e2d1-4115-a87c-be5b8fbc1f25",
"id": "ec1deb57-aebe-46f6-994f-396d9b38e7c4",
"name": "Arroz Natural",
"quantity": 1,
"price": 280,
"originalPrice": 280,
"discountType": null,
"discountAmount": null,
"discountConcept": null,
"promotionId": null,
"modifiers": [],
"comboProducts": [],
"comments": null
},
{
"tabProductId": "3dff1236-ad7f-4f38-a825-4d606c96f718",
"id": "eb0944d5-84af-4883-87d2-576bedaa838b",
"name": "Vegetal Vegetal",
"quantity": 1,
"price": 690,
"originalPrice": 690,
"discountType": null,
"discountAmount": null,
"discountConcept": null,
"promotionId": null,
"modifiers": [],
"comboProducts": [],
"comments": null
}
],
"total": 1067,
"tax": 97,
"taxPercentage": 10,
"taxableBase": 970,
"taxLabel": "IVA",
"discountPreTax": 0,
"subTotal": 970,
"originalTotal": 970,
"discountTotal": 0,
"deliveryFee": 0,
"minimumBasketSurcharge": 0,
"terraceSurcharge": 97,
"terraceSurchargePercentage": 10,
"company": {},
"diners": 2,
"customerCompany": null,
"allergyInfo": null,
"customerNote": null,
"kitchenNote": null,
"tableName": "A1",
"source": "Restaurant",
"virtualBrandId": "23cdda27-2f82-46e4-a366-deecd5d420d0",
"code": "R004",
"note": null,
"pickupType": null,
"schedulingTime": null,
"activationTime": "2021-11-22T11:05:31.000Z",
"locationBrandId": "23cdda27-2f82-46e4-a366-deecd5d420d0"
POST Bill Payment
Adds a payment to an existing bill from an open tab. It is possible for a bill to have multiple partial payments. Once all the tab bills are paid fully, the tab will be closed automatically. If the sum of all the payments is greater than the bill total, the difference will be considered as tip for that bill.
{
"amount": 2500,
"tip": 10,
"method": "card",
"externalId": "1111-8888-5555-4444-7777"
}
HTTP Request
POST https://api.last.app/v1/bills/${billId}/payment
Response
{
"id": "1111111-2222-3333-4444-555555555",
"closed": true
}
Response
Field name | Description |
---|---|
id (String) | Unique identifier of the payment in Last |
closed (Boolean) | Whether the tab was automatically closed after submitting the payment |
Tab Payment object
Field name | Description |
---|---|
amount (Integer) | Amount of the payment |
tip (Integer) | Amount of the payment paid as tip |
method (String) | Method used for the payment |
externalId (String) | Optional unique identifier of the payment |
DELETE Bill Payment
Deletes a payment from an existing bill.
HTTP Request
DELETE https://api.last.app/v1/bills/${billId}/payments/${paymentId}
POST Create Order
{
"brandId": "f2779a96-578f-4649-89f6-a0972183efea",
"products": [
{
"type": "PRODUCT",
"id": "86eda7fe-e59f-4ca3-89a8-3a179ee8e0f2",
"name": "Burger",
"quantity": 2,
"price": 1000,
"modifiers": [
{
"priceImpact": 300,
"id": "63ac4b67-c39b-42bb-8d44-36e57e586152",
"name": "Extra meat",
"quantity": 2
},
{
"priceImpact": 0,
"id": "cf7805aa-4fb9-4a97-b975-924b48898a97",
"name": "Water (33 cl)",
"quantity": 1
}
]
},
{
"type": "PRODUCT",
"externalId": "07fc40ab-0e6b-4cb7-ac6b-3442c7c77ade",
"name": "Ice cream",
"quantity": 1,
"price": 480,
"modifiers": [
{
"quantity": 1,
"name": "Vanilla flavour",
"priceImpact": 0,
"id": "614338bc-b017-4cc4-9528-375a5d42d0ea"
},
{
"priceImpact": 0,
"id": "e127cc65-5281-4433-8389-1ed8286f7074",
"name": "Small size",
"quantity": 1
}
]
},
{
"type": "COMBO",
"name": "Combo",
"price": 480,
"id": "348951a7-dea5-409e-a365-21f51045da67",
"quantity": 1,
"products": [
{
"id": "4b5dd754-e4b2-478c-9bf7-df1f476d0763",
"quantity": 1,
"name": "Combo option",
"priceImpact": 0
}
]
}
],
"id": "ba115841-275e-4cf3-a07b-755fae8299b5",
"notes": "I am allergic to tomato",
"code": "B1234567",
"operationalCode": "B123",
"pickupTime": "2019-09-10T13:17:00.000Z",
"preferredPaymentMethod": "cash",
"customer": {
"name": "Bruce",
"surname": "Wayne",
"phoneNumber": "+34666666666",
"email": "hello@test.com"
},
"company": {
"name": "Monsters, Inc",
"address": "Gran Via de les Corts Catalanes, 620",
"taxId": "B66249567"
},
"schedulingTime": "2019-09-10T13:17:00.000Z",
"delivery": {
"address": "Gran Via de les Corts Catalanes, 620",
"details": "First door to the left",
"latitude": 41.3876734,
"longitude": 2.1647098,
"fee": 190
},
"payments": [
{
"method": "card",
"paidAmount": 7000
}
]
}
HTTP Request
POST https://api.last.app/v1/orders
Order
Field name | Description |
---|---|
brandId (String) | Unique identifier for a location brand. |
externalId (String) | Identifier of the order on your system |
code (String) | Code shown to the user in your system |
operationalCode (String) | Operational code you want us to show on the ticket. Max 4 chars. |
pickupTime (DateTime) | Estimated pickupTime time in ISO 8601 |
customer (Object) | Object containing name, phone number(with prefix) |
delivery (Object) | Object details of the delivery. If it is present, the order is considered as a delivery. Otherwise the order is a take away. |
products (Array) | Array containing the products |
tableId (String) | Id of the table to link with this order. Ignored in case of delivery |
discount (Object) | Optional discount object |
schedulingTime (DateTime) | Time selected by the user as the scheduled time in ISO 8601 |
payments (Array) | Optional payment object containing method and paid amount. |
company (Object) | Optional company details for invoicing. |
notes (String) | Optional order notes or comments. |
preferredPaymentMethod (String) | Optional In case of not having any payments, you can set the preferred payment method of the customer for delivery orders |
withoutBills (Boolean) | Optional Flag to not generate a bill for this order yet |
Product
Field name | Description |
---|---|
id (String) | Unique identifier of the product in Last |
name (String) | Name of the product |
quantity (Integer) | Quantity of the product |
course (String) | Course of the product |
price (Integer) | Price per unit of the product (without modifiers included). Represented as an integer in the smallest denomination of the currency |
comments (String) | comments of the product |
type (String) | Type of the product. Must be PRODUCT or COMBO. |
modifiers (Array) | Array containing the modifiers of the product. Only if product type is PRODUCT. |
products (Array) | Array containing the combo products of the combo. Only if product type is COMBO. |
discount (Object) | Optional discount object |
Modifier
Field name | Description |
---|---|
id (String) | Unique identifier of the modifier in Last |
quantity (Integer) | Quantity of the modifier |
name (String) | Name of the modifier |
priceImpact (Integer) | Price per unit of the modifier. Represented as an integer in the smallest denomination of the currency |
Delivery
Field name | Description |
---|---|
address (String) | Delivery address of the order |
details (String) | Details of the delivery, such as floor, stairs, etc |
latitude (Float) | Latitude |
longitude (Float) | Longitude |
fee (Integer) | Delivery fee in cents |
comments (String) | Delivery related comments |
external (Boolean) | Optional flag to mark order as external |
cutlery (Boolean) | Optional flag to ask for cutlery |
Payment
Field name | Description |
---|---|
method (String) | Payment method of the order. |
amount (Integer) | Amount that's already paid. If it's more than the total we consider there is a tip. |
Company
Field name | Description |
---|---|
name (String) | Company name. |
address (String) | Company address. |
taxId (String) | Company tax ID. |
Discount
Field name | Description |
---|---|
promotionId (String) | Unique identifier of the promotion. |
type (String) | Type of the promotion. 'percentage' or 'currency' |
amount (Integer) | Amount to be discounted by the promotion, can be a percentage or currency amount depending on the type |
concept (String) | Description of the discount |
Response
{ "id": "67f0c646-47da-4684-b70e-1d369e6a566e", "code": "D001" }
Response
Field name | Description |
---|---|
id (String) | Unique identifier of the order in Last |
code (String) | Short code assigned to the order |
POST Add Products to Tab
{
"products": [
{
"type": "PRODUCT",
"id": "86eda7fe-e59f-4ca3-89a8-3a179ee8e0f2",
"name": "Burger",
"quantity": 2,
"course": "Starters",
"price": 1000,
"modifiers": [
{
"priceImpact": 300,
"id": "63ac4b67-c39b-42bb-8d44-36e57e586152",
"name": "Extra meat",
"quantity": 2
},
{
"priceImpact": 0,
"id": "cf7805aa-4fb9-4a97-b975-924b48898a97",
"name": "Water (33 cl)",
"quantity": 1
}
]
},
{
"type": "PRODUCT",
"externalId": "07fc40ab-0e6b-4cb7-ac6b-3442c7c77ade",
"name": "Ice cream",
"course": "Desserts",
"quantity": 1,
"price": 480,
"modifiers": [
{
"quantity": 1,
"name": "Vanilla flavour",
"priceImpact": 0,
"id": "614338bc-b017-4cc4-9528-375a5d42d0ea"
},
{
"priceImpact": 0,
"id": "e127cc65-5281-4433-8389-1ed8286f7074",
"name": "Small size",
"quantity": 1
}
]
},
{
"type": "COMBO",
"name": "Combo",
"price": 480,
"course": "Main",
"id": "348951a7-dea5-409e-a365-21f51045da67",
"quantity": 1,
"products": [
{
"id": "4b5dd754-e4b2-478c-9bf7-df1f476d0763",
"quantity": 1,
"name": "Combo option",
"priceImpact": 0
}
]
}
]
}
HTTP Request
POST https://api.last.app/v1/tabs/:tabId/add-products
Product
Field name | Description |
---|---|
id (String) | Unique identifier of the product in Last |
name (String) | Name of the product |
quantity (Integer) | Quantity of the product |
course (String) | Course of the product |
price (Integer) | Price per unit of the product (without modifiers included). Represented as a positive integer in the smallest denomination of the currency |
comments (String) | comments of the product |
modifiers (Array) | Array containing the modifiers of the product |
discount (Object) | Optional discount object |
Modifier
Field name | Description |
---|---|
id (String) | Unique identifier of the modifier in Last |
quantity (Integer) | Quantity of the modifier |
name (String) | Name of the modifier |
priceImpact (Integer) | Price per unit of the modifier. Represented as an integer in the smallest denomination of the currency |
POST Order Cancellation
{
"cancelReason": "User cancelled manually"
}
HTTP Request
POST https://api.last.app/v1/orders/${orderId}/cancel
Order cancellation object
Field name | Description |
---|---|
cancelReason (String) | String detailing the reason for the cancellation |
GET Order Status
{
"status": "KITCHEN"
}
HTTP Request
GET https://api.last.app/v1/orders/${orderId}/status
Order status object
Field name | Description |
---|---|
status (String) | Status of the order. One of: [CREATED, KITCHEN, READY_TO_PICKUP, ON_DELIVERY, DELIVERED, CLOSED, CANCELLED] |
POST Order Status
{
"newStatus": "READY_TO_PICKUP"
}
HTTP Request
POST https://api.last.app/v1/orders/${orderId}/status
Order status object
Field name | Description |
---|---|
newStatus (String) | New status of the order. One of: [KITCHEN, READY_TO_PICKUP, ON_DELIVERY, DELIVERED, CLOSED] |
GET Promotion List
{
"promotions": [
{
"id": "28afe959-6204-4169-b5ba-fc90f15aad43",
"organizationId": "90724ad8-334b-40d8-a07b-45d4b5e563d4",
"name": "El tenedor",
"description": "el tenedor",
"pointsExpense": null,
"discountType": "percentage",
"discountAmount": 10,
"allowRepeat": true,
"accumulated": true,
"categories": ["d8486f43-04c6-4d94-b683-654e053957f0"]
},
{
"id": "39bfaca0-9920-4224-9762-0cbc8d61dbcf",
"name": "2x1",
"description": "2x1",
"pointsExpense": null,
"discountType": "2x1",
"discountAmount": null,
"allowRepeat": true,
"accumulated": false,
"code": "GETTWO",
"products": [
"00828e09-6f83-4f0e-8ea7-1dca77f465ba",
"02379925-554e-41cf-9bb8-c5d8cc84759b"
]
},
{
"id": "d1e90fb6-c3af-4317-84aa-05215920b6b0",
"organizationId": "90724ad8-334b-40d8-a07b-45d4b5e563d4",
"name": "Point products",
"description": "Get one of this products for 10 points",
"pointsExpense": 10,
"discountType": "products",
"discountAmount": null,
"allowRepeat": false,
"accumulated": false,
"products": [
"63b42746-e800-43d6-a853-d09a4a69d162",
"6e964602-d42a-4848-b987-311772c522aa",
"78723506-2c6f-43fe-9232-6c588fa9c42d"
]
}
]
}
HTTP Request
GET https://api.last.app/v1/promotions
Query parameter | Description |
---|---|
offset (Integer) | Optional. The number of promotions to skip. |
limit (Integer) | Optional. The maximum number of promotions to be returned. |
GET Promotion
{
"id": "28afe959-6204-4169-b5ba-fc90f15aad43",
"organizationId": "90724ad8-334b-40d8-a07b-45d4b5e563d4",
"name": "El tenedor",
"description": "el tenedor",
"pointsExpense": null,
"discountType": "percentage",
"discountAmount": 10,
"allowRepeat": true,
"accumulated": true,
"categories": ["d8486f43-04c6-4d94-b683-654e053957f0"],
"products": ["18be645c-84e5-4172-8b51-3bd619362aa3"],
"customerIds": ["57b5ba5c-996d-412a-a5ab-283e8e347f91"],
"weekdays": ["monday"],
"locations": ["f2779a96-578f-4649-89f6-a0972183efea"]
}
HTTP Request
GET https://api.last.app/v1/promotions/${promotionId}
Promotion
Field name | Description |
---|---|
id (String) | Unique identifier of the promotion in Last |
organizationId (String) | Unique identifier of the organization where the promotion applies |
name (String) | Name of the promotion |
description (String) | Description of the promotion |
pointsExpense (Integer) | Amount of points that are needed and will be consumed when the promotion is used |
discountType (String) | Type of the promotion. One of products, 2x1, percentage, currency |
discountAmount (Integer) | Amount to be discounted by the promotion, can be a percentage or currency amount depending on the type |
enabled (Boolean) | Current status of the promotion |
allowRepeat (Boolean) | If enabled this promotion can be applied multiple times in the same order |
accumulated (Boolean) | If enabled this promotion can be applied alongside other promotions |
availableInShop (Boolean) | Promotion can be used in Last Shop |
code (String) | Code that can be used by the customer in the shop to apply the promotion |
maxRedemptions (Integer) | Maximum number of usages of this promotion |
minExpense (Integer) | Minimum expense amount to use this promotion |
startTime (DateTime) | Start time of the promotion if it's not permanent |
endTime (DateTime) | End time of the promotion if it's not permanent |
oncePerPerson (Boolean) | If enabled this promotion can be only used once per person |
internalDescription (Boolean) | Internal description of the promotion |
showPopup (Boolean) | If enabled this promotion will show a popup when applied on LastShop |
deleted (Boolean) | Permanent status of the promotion |
availableInPos (Boolean) | Promotion can be used in Last POS |
availableInAdmin (Boolean) | Promotion can be seen in Last Admin |
pickupType (String) | Kind of orders where this promotion can be applied |
freeDelivery (Boolean) | If enabled this promotion specifies delivery of the order is free |
products (Array) | Array containing the products of the promotion where the promotion applies |
categories (Array) | Array containing the categories where the promotion applies |
POST Create/Update Promotion
{
"accumulated": true,
"allowRepeat": false,
"availableInShop": true,
"availableInPos": true,
"availableInAdmin": true,
"code": "KONAMICODE",
"description": "el tenedor desc",
"discountAmount": 1000,
"discountType": "currency",
"enabled": true,
"endTime": "2021-02-03T23:00:00.000Z",
"id": "28afe959-6204-4169-b5ba-fc90f15aad43",
"locations": ["f2779a96-578f-4649-89f6-a0972183efea"],
"maxRedemptions": 3,
"minExpense": 1290,
"name": "El tenedor",
"organizationId": "90724ad8-334b-40d8-a07b-45d4b5e563d4",
"pointsExpense": 10,
"products": ["07ec300a-31cb-42c6-9519-0bd25191d74d"],
"startTime": "2021-01-14T23:00:00.000Z",
"weekdays": ["monday"],
"customerIds": ["0ae6e3fb-c340-4b26-80ed-3bbe49f54db7"]
}
HTTP Request
POST https://api.last.app/v1/promotions/create-or-update
Promotion
Field name | Description |
---|---|
id (String) | Optional. Unique identifier for a promotion. If it is not provided the promo will be created instead of updated. |
locations (Array) | Optional. Location IDs where the promotion will take effect. |
maxRedemptions (Integer) | Optional. The amount after which the promotion will expire. |
minExpense (Integer) | Optional. Minimum expense in cents for which the promotion will take effect |
products (Array) | Optional. One of products array or categories array. Product IDs in which the promotion will take effect. This IDs are the organizationProductId or the organizationComboId of the catalog products. |
categories (Array) | Optional. One of products array or categories array. Category IDs in which the promotion will take effect. |
weekdays (Array) | Optional. Weekdays when the promotion will take effect |
code (String) | Optional. Code to get the promotion applied |
startTime (DateTime) | Optional. Promotion availability starting time in ISO 8601 |
endTime (Datetime) | Optional. Promotion availability ending time in ISO 8601 |
pointsExpense (Integer) | Amount of points that are needed and will be consumed when the promotion is used |
accumulated (Boolean) | If enabled the promotion could be accumulated with others |
allowRepeat (Boolean) | If enabled this promotion can be applied multiple times in the same order |
availableInShop (Boolean) | If enabled this promotion can be applied in LastShop |
availableInPos (Boolean) | If enabled this promotion can be applied in LastPOS |
availableInAdmin (Boolean) | If enabled this promotion will be shown in LastAdmin |
name (String) | Name of the promotion |
description (String) | Description of the promotion |
discountType (String) | Type of the promotion. One of: ['percentage', 'currency'] |
discountAmount (Integer) | Amount to be discounted by the promotion, can be a percentage or currency amount in cents depending on the type |
enabled (Boolean) | Availability of the promotion |
customerIds (Array) | Array of customer identifiers which will be eligible to use the promotion |
GET Customer
Response
{
"name": "Bruce",
"surname": "Wayne",
"phoneNumber": "+34666666666",
"creationTime": "2020-07-31T15:48:22.000Z",
"email": "hello@test.com",
"source": "Shop",
"marketingCommunication": true,
"internalNote": "General purpose field",
"hasUser": true,
"points": 30,
"addresses": [
{
"address": "Gran Via de les Corts Catalanes, 620",
"details": "First door to the left",
"postalCode": "08007",
"latitude": 41.3876734,
"longitude": 2.1647098
}
]
}
HTTP Request
GET https://api.last.app/v1/customers/${customerId}
Query parameter | Description |
---|---|
customerId (String) | Unique identifier of the customer in Last |
GET Customer list
Response
{
"customers": [
{ /* customer object */ },
{ /* customer object */ },
...
],
"page": 0,
"lastPage": 0
}
HTTP Request
GET https://api.last.app/v1/customers
Query parameter | Description |
---|---|
page (Integer) | Result page to show |
phoneNumber (String) | Full phone number with country code |
updateTime (String) | Return customers created / updated after this time (in ISO 8601) p.e: 2024-08-10 |
* This request is paginated in groups of 100
POST Create Customer
HTTP Request
POST https://api.last.app/v1/customers
Customer Object
Field name | Description |
---|---|
name (String) | Name of the customer |
surname (String) | Surname of the customer |
creationTime (String) | Creation time (in ISO 8601). |
phoneNumber (String) | Full phone number with country code |
internalNote (String) | Internal note |
source (String) | Source of the customer |
email (String) |
Request
{
"name": "Bruce",
"surname": "Wayne",
"phoneNumber": "+34666666666",
"internalNote": "This is a note",
"email": "hello@test.com",
"source": "MyWebsite",
"marketingCommunication": true
}
Response
{
"id": "4b292bf3-97e8-4f02-bb6e-d8c4247ab4c5",
"name": "Bruce",
"surname": "Wayne",
"phoneNumber": "+34666666666",
"internalNote": "This is a note",
"email": "hello@test.com",
"source": "MyWebsite",
"marketingCommunication": true
}
POST Update Customer
There's no need to include all fields, just those that have changed.
HTTP Request
POST https://api.last.app/v1/customers/${customerId}
Query parameter | Description |
---|---|
customerId (String) | Unique identifier of the customer in Last |
Request
{
"name": "Matt"
}
Response
{
"id": "4b292bf3-97e8-4f02-bb6e-d8c4247ab4c5",
"name": "Matt",
"surname": "Wayne",
"phoneNumber": "+34666666666",
"internalNote": "This is a note",
"email": "hello@test.com",
"points": 36,
"marketingCommunication": true
}
PUT Add Points to Customer
HTTP Request
PUT https://api.last.app/v1/customers/${customerId}/add-points
Request
{
"addedPoints": 10
}
POST Create reservation
HTTP Request
POST https://api.last.app/v1/reservations
Reservation
Field name | Description |
---|---|
name (String) | Name of the diner. |
locationId (String) | Location which receives the reservation. |
diners (Integer) | Number of the diners of the reservation. |
phoneNumber (String) | Full phone number with country code |
source (String) | Name of the integrated platform sending the reservation. |
dateTime (DateTime) | Date and time of the reservation in ISO 8601. |
surname (String) | OPTIONAL Surname of the diner. |
customerComments (String) | OPTIONAL Message of the reservation to be showed to the restaurant. |
externalId (String) | OPTIONAL ID of the reservation on the integrated platform. |
Request
{
"name": "Juanito",
"surname": "Jones",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"externalId": null,
"phoneNumber": "+34666111444",
"diners": 2,
"customerComments": null,
"source": "ReservationPlatform",
"dateTime": "2024-02-05T14:00:00.000Z"
}
PUT Update reservation
HTTP Request
PUT https://api.last.app/v1/reservations/${reservationId}
Request
{
"name": "Juanito",
"surname": "Jones",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"externalId": null,
"phoneNumber": "+34666111444",
"diners": 2,
"customerComments": null,
"source": "ReservationPlatform",
"dateTime": "2024-02-05T14:00:00.000Z"
}
DELETE Cancel reservation
HTTP Request
DELETE https://api.last.app/v1/reservations/${reservationId}
Webhooks
Whenever there is a content change in our side that may be relevant for an integration we trigger webhook updates.
The request will be made via POST
to your chosen webhook enpoint, which on success should return an empty response with status 200
.
The update will come in json
format in the body of the request, wrapped in an event
object, with a corresponding payload (data
) with the relevant resource or information.
Field name | Description |
---|---|
id (String) | Unique identifier of the event |
type (String) | Type of event |
created (DateTime) | The time the event was created at (ISO-8601 UTC) |
data (Object) | The data associated with the particular event |
Customer
{
"id": "33f9dc36-5e99-4044-8e2e-9b22c403c5f7",
"type": "customer:created",
"created": "2020-10-06T18:32:04.000Z",
"data": {
"id": "072c8bc3-4601-47d1-8a11-26935d57222f",
"name": "Bruce",
"surname": "Wayne",
"phoneNumber": "+34666666666",
"email": "hello@test.com",
"source": "Shop",
"marketingCommunication": true,
"hasUser": true,
"addresses": [
{
"address": "Gran Via de les Corts Catalanes, 620",
"details": "First door to the left",
"postalCode": "08007",
"latitude": 41.3876734,
"longitude": 2.1647098
}
]
}
}
Types
customer:created
customer:updated
Points
{
"id": "33f9dc36-5e99-4044-8e2e-9b22c403c5f7",
"type": "customer_points:updated",
"created": "2020-10-06T18:32:04.000Z",
"data": {
"customerId": "072c8bc3-4601-47d1-8a11-26935d57222f",
"tabId": "1b0e7a24-ad88-4825-93e4-18dc7865db07",
"amount": 200,
"totalEarned": 200
}
}
Types
customer_points:updated
Promotions
We'll sent this webhook when a promotion is created, updated or deleted.
{
"id": "28afe959-6204-4169-b5ba-fc90f15aad43",
"organizationId": "90724ad8-334b-40d8-a07b-45d4b5e563d4",
"name": "El tenedor",
"description": "el tenedor",
"pointsExpense": null,
"discountType": "percentage",
"discountAmount": 10,
"enabled": true,
"allowRepeat": true,
"accumulated": true,
"availableInShop": true,
"code": "10TENEDOR",
"maxRedemptions": null,
"minExpense": 200,
"startTime": null,
"endTime": null,
"oncePerPerson": true,
"internalDescription": "",
"showPopup": true,
"availableInPos": false,
"availableInAdmin": true,
"freeDelivery": false,
"categories": ["d8486f43-04c6-4d94-b683-654e053957f0"],
"products": ["18be645c-84e5-4172-8b51-3bd619362aa3"],
"customerIds": ["57b5ba5c-996d-412a-a5ab-283e8e347f91"],
"deleted": false
}
Types
promotion:created
promotion:updated
promotion:deleted
Tab
{
"id": "bbcfabf5-d660-4c21-9751-4e8f197439e2",
"name": null,
"creationTime": "2020-07-31T15:48:22.000Z",
"locationId": "f2779a96-578f-4649-89f6-a0972183efea",
"source": "Shop",
"allergyInfo": null,
"customerNote": null,
"kitchenNote": null,
"tableName": null,
"closeTime": "2020-08-06T15:32:04.000Z",
"locationBrandId": "23cdda27-2f82-46e4-a366-deecd5d420d0",
"customerId": "998a26bd-04a0-11ea-8884-0242ac110002",
"code": "S002",
"pickupType": "takeAway",
"schedulingTime": "2020-08-02T22:30:00.000Z",
"activationTime": "2020-08-06T15:32:04.000Z",
"tabTables": [],
"products": [
{
"id": "f3cf29da-b5c9-408f-b6e9-ba14732b0bc8",
"catalogProductId": "7d2b8e27-e0bf-4732-8044-223943b7fd05",
"organizationProductId": "3cbeaeca-49f6-4dda-be87-5f7cb96d12db",
"organizationComboId": null,
"externalId": "0534073e-3eec-4ecc-83a4-ab446a30ca2a",
"name": "Burger",
"price": 1400,
"quantity": 1,
"course": "Main",
"comments": null,
"fullPrice": 1400,
"finalPrice": 1400,
"type": "PRODUCT",
"promotionId": null,
"modifiers": [
{
"id": "348ca8b3-28cd-4adf-a5ce-951f0158d704",
"name": "Cheese",
"priceImpact": 0,
"quantity": 1,
"catalogModifierId": "65254ec3-3ec8-4279-a5b9-118dd4391832"
}
],
"comboProducts": []
}
],
"seats": 1,
"language": "ES",
"bills": [
{
"id": "866ed6ee-f325-434b-9c8a-e5d0fc07b53f",
"number": 859,
"rectifiedBillNumber": 934,
"creationTime": "2020-07-31T15:48:23.000Z",
"finalizingTime": "2020-07-31T15:48:23.000Z",
"company": {
"name": "LastPOS",
"taxId": "1234",
"address": "Maracaibo 8, Nave 2, 08041, Barcelona"
},
"total": 1400,
"tax": 127,
"taxableBase": 1273,
"discountTotal": 0,
"deliveryFee": 0,
"minimumBasketSurcharge": 0,
"terraceSurcharge": 0,
"terraceSurchargePercentage": 0,
"preferredPaymentMethod": "card",
"payments": [],
"products": [
{
"id": "7a740ff2-d326-42ea-a239-c9b9125d3fc3",
"catalogProductId": "7d2b8e27-e0bf-4732-8044-223943b7fd05",
"tabProductId": "f3cf29da-b5c9-408f-b6e9-ba14732b0bc8",
"name": "Burger",
"price": 1400,
"quantity": 1,
"modifiers": [
{
"id": "be75642e-7f74-42e8-bd3d-de575caa1847",
"name": "Cheese",
"priceImpact": 0,
"quantity": 1,
"catalogModifierId": "54393d6e-5780-45da-a96f-8de45eac10cc"
}
],
"comboProducts": []
}
]
}
],
"delivery": {
"address": "Gran Via de les Corts Catalanes, 620",
"details": "First door to the left",
"latitude": 41.3876734,
"longitude": 2.1647098,
"statuses": [
{
"creationTime": "2020-08-03T09:10:11.000Z",
"status": "KITCHEN"
},
{
"creationTime": "2020-08-05T14:06:09.000Z",
"status": "CLOSED"
}
],
"courier": {
"id": "be75642e-7f74-42e8-bd3d-de575caa1847",
"name": "Jose"
},
"cutlery": false
}
}
Types
tab:created
tab:closed
tab:cancelled
Tab Status
Field name | Description |
---|---|
tabId (string) | Id of the tab |
externalId (string) | Id of the tab in the system that created it |
status (String) | Status of the order. One of: [CREATED, KITCHEN, READY_TO_PICKUP, ON_DELIVERY, DELIVERED, CLOSED] |
{
"id": "33f9dc36-5e99-4044-8e2e-9b22c403c5f7",
"type": "tab:delivery-status-updated",
"created": "2020-10-06T18:32:04.000Z",
"data": {
"tabId": "1f153b1f-e0ba-4cae-a2f0-ce96496b7cac",
"externalId": "some-id",
"status": "READY_TO_PICKUP"
}
}
Types
tab:delivery-status-updated
Catalog
Field name | Description |
---|---|
catalogIds (Array) | Array containing the ids of the updated catalogs. |
locationId (String) | Optional. If present, indicates that the catalog updates only affects that location. |
{
"id": "33f9dc36-5e99-4044-8e2e-9b22c403c5f7",
"type": "catalog:updated",
"created": "2020-10-06T18:32:04.000Z",
"data": {
"catalogIds": [
"ccb436b2-039e-47b3-bf59-3269e56f3567",
"2f8fb8b8-b961-402e-8c59-81afb4ef8b9a"
],
"locationId": "bdd59445-db01-438b-bdd5-f9f21c9e489b"
}
}
Types
catalog:updated
Shipment
{
"id": "33f9dc36-5e99-4044-8e2e-9b22c403c5f7",
"type": "shipment:sent",
"created": "2020-10-06T18:32:04.000Z",
"data": {
"shipmentId": "2f8fb8b8-b961-402e-8c59-81afb4ef8b9a",
"pickupTime": "2020-10-06T18:32:04.000Z",
"pickup": {
"address": "Gran Via de les Corts Catalanes, 620",
"contact": {
"phone": "+34666111222",
"firstname": "MacDonalds Gran Via"
}
},
"dropoffs": [
{
"address": "Calle rey agapito, 17",
"addressDetails": "Piso 3r1a",
"latitude": 41.3876734,
"longitude": 2.1647098,
"code": "R067",
"tabId": "324e07ed-d557-47bc-8ccd-0f1d3fe0fb67",
"source": "Restaurant",
"schedulingTime": "2020-10-06T19:32:04.000Z",
"comment": "Porfavor, picar al timbre al llegar",
"contact": {
"firstname": "Juan",
"phone": "+34666777888",
"email": "test@test.com",
"phoneNumberCode": "833 16 243"
},
"preferredPaymentMethod": "cash"
}
]
}
}
Field name | Description |
---|---|
shipmentId (String) | Unique identifier of the shipment |
pickupTime (DateTime) | Estimated pickupTime time in ISO 8601. |
pickup (Object) | Contains pickup details. |
dropoffs (Array) | Array of delivery points. |
Pickup
Field name | Description |
---|---|
address (String) | Address of the location. |
contact (Object) | Contains pickup contact details. |
Dropoff
Field name | Description |
---|---|
address (String) | Delivery address. |
addressDetails (String) | Delivery address details. |
code (Array) | Delivery order code. |
tabId (String) | Delivery order tab id. |
source (String) | Delivery order source. |
comments (String) | Delivery order comments and instructions. |
contact (Object) | Contains delivery contact info. |
preferredPaymentMethod (String) | Preferred payment method. |
Types
shipment:sent
shipment:cancelled
Kitchen Order
Field name | Description |
---|---|
id (String) | Unique identifier of the kitchen order. |
locationId (String) | Identifier of the location owner of kitchen order. |
creationTime (String) | Creation time (in ISO 8601). |
versions (Array) | List of kitchen order versions with the products. |
tabId (String) | Tab id associated to the Kitchen order. |
allergyInfo (String) | Optional allergy information of the diner. |
code (String) | Order code. |
pickupTime (String) | Order Pickup time (in ISO 8601). |
waiterName (String) | Optional name of the waiter. |
note (String) | Optional order note. |
printerId (String) | Identifier of the printer for this kitchen order. |
{
"id": "5ea5aefd-23b1-45ec-8250-6504817fc351",
"type": "kitchen-order:created",
"creationTime": "2023-02-13T08:45:08.310Z",
"locationId": "f109347c-3cf4-40c4-8a7d-e8d095192667",
"versions": [
{
"id": "2618114d-4fa0-41d2-8d3a-df794937e0ef",
"sentTime": "2023-02-13T08:45:08.310Z",
"products": [
{
"id": "6fd9af6b-6ed3-4aee-a067-1127da4d186a",
"name": "Test Product 2",
"comments": "",
"quantity": 1,
"modifiers": [
{
"id": "e93ad05e-f4fb-494b-a6dd-7d2d0fbb50b0",
"name": "Spicy Mayo",
"quantity": 1
}
]
},
{
"id": "bc73d17b-ed9e-4814-9d67-b3fbf07cf569",
"name": "Gofre premium",
"comments": "",
"quantity": 1,
"modifiers": [
{
"id": "76abb12f-8c3d-4958-9659-78de71375089",
"name": "Topping plátano canario",
"quantity": 1
},
{
"id": "2293f6f8-846b-43e0-b7f3-11928a91621e",
"name": "Topping salmón flambeado",
"quantity": 1
}
]
}
]
}
],
"tabId": "f109347c-3cf4-40c4-8a7d-e8d095192661",
"allergyInfo": null,
"code": "S032",
"pickupTime": "2023-02-13T09:35:08.122Z",
"waiterName": null,
"note": null,
"printerId": "f109347c-3cf4-40c4-8a7d-e8d095192259",
}
Types
kitchen-order:created
kitchen-order:updated
Kitchen Note
We'll sent this webhook when a waiter ask for a course of some kitchen orders.
Field name | Description |
---|---|
course (String) | Course to be asked to serve (p.e: starters). |
locationId (String) | Identifier of location owner of kitchen orders. |
kitchenOrderIds (Array) | List of kitchenOrder IDs. |
{
"type": "kitchen_note:created",
"course": "desserts",
"locationId": "f109347c-3cf4-40c4-8a7d-e8d095192667",
"kitchenOrderIds": [
"2618114d-4fa0-41d2-8d3a-df794937e0ef",
"6fd9af6b-6ed3-4aee-a067-1127da4d186a",
"e93ad05e-f4fb-494b-a6dd-7d2d0fbb50b0"
]
}
Types
kitchen_note:created
Floorplan
Field name | Description |
---|---|
id (String) | Unique identifier of the floorplan. |
name (String) | Name of the floorplan. |
tables (Array) | List of tables of the floorplan products. |
{
"id": "d482a7b0-377e-4a56-8c43-7d847738f044",
"type": "floorplan:updated",
"name": "Main",
"tables": [
{
"id": "03d96ebb-b36c-43b1-874a-24eecec1abc2",
"name": "A1",
"seats": 2
},
{
"id": "398bcf26-141f-42c5-80a2-391270d7f92a",
"name": "B2",
"seats": 2
},
{
"id": "11b005ee-d7e3-4aea-b545-9d1d659b0396",
"name": "Barra",
"seats": 4
}
]
},
{
"id": "75b87c37-6ca2-4815-9e07-3f05b0185a66",
"name": "Outside",
"tables": [
{
"id": "cb38cb1c-9052-4637-a499-50d4fd8fc86c",
"name": "T2",
"seats": 2
}
]
}
Types
floorplan:updated
floorplan:deleted
Reservations
Field name | Description |
---|---|
id (String) | Unique identifier of the floorplan. |
name (String) | Name of the floorplan. |
tables (Array) | List of tables of the floorplan products. |
{
"id": "54e9f57d-1aea-418e-b2d2-70a89f997143",
"type": "reservation:created",
"created": "2024-02-05T10:25:39.581Z",
"data": {
"id": "32c477b5-b5c1-460a-9c57-c2440796d6e5",
"externalId": null,
"name": "Juanito",
"surname": "Jones",
"phoneNumber": "+34666111444",
"diners": 2,
"customerComments": null,
"source": "ReservationPlatform",
"dateTime": "2024-02-05T14:00:00.000Z",
"cancelled": false,
"locationId": "f2779a96-578f-4649-89f6-a0972183efea"
}
}
Types
reservation:created
reservation:updated
reservation:deleted
FAQ
How can I get a testing account and a testing auth token?
At the moment, you'll need to send an email to our support team at hola@last.app.
We're currently working on adding the possibility to obtain testing credentials directly through API.
Once I have finished the integration with a testing account, how can I obtain the restaurants production token?
The restaurant manager should send an email to our support team at hola@last.app asking for the token. If you are a third party, you can also ask for the token, only if you have the permission from the restaurant.
How can I get the ID of each location?
You can get all the locations related info making a request to GET Location List.
Which is the difference between Location and brand?
In our system, a Location is a Restaurant, in simple words. Each location maybe want to appear with different brands in their online sales channels. For example, a location named as Rick Restaurant can have multiple brands appearing at JustEat and UberEats, for example Rick Chickens, Rick Pizza, and Rick Sushi.
Which catalogs is my location using currently?
In the response from GET Location List you will find a list of brands for each location, and each of this brands contains at the same time a list of catalogs.
How can I add a webhook URL or suscribe to a webhook event?
At the moment, you'll need to send an email to our support team at hola@last.app.
We're currently working on adding the possibility to handle webhook management directly through API.
It is posible to update products pricing or catalogs through API?
This is not possible at the moment, currently you need to access Last.app admin panel to do this.
How many tokens I need for all my integrated restaurants?
You'll need one token for each Organization that you are managing. In our system, an Organization is a set of locations from the same franchise. For example, if you are managing three restaurants from the same franchise, you only need one token.
Which is the difference between tab, order, and bill?
In fact, there is no differente between a tab and an order. For internal requirements, we name a restaurant customer request as tab, but for the API, we preferred to name it as order, as it is more industry standard.
A bill is an invoice, and it belongs to a tab. It contains payments and invoice details.
I have an API question, who can I ask about it?
You can send an email to integrations@last.app, where we will be pleased to help you as mush as we can.