Supa is a QR payment solution for restaurants in Poland. It integrates with POS systems of restaurants and allows guests to see their orders, split them, pay for them & leave a review.
Why integrating with us?
Payment at the table is a new way of providing convenient service for the restaurant's guests.
Increase the restaurant turnover
We do our best to make the integration between any POS system and Supa as easy as possible. So we created this guide to make it easier for you.
Contact Supa team via the feedback form on our website: https://supa.pl/ We’ll provide you with a test restaurant for integration development and will stay in contact for any questions you have.
Once you receive a test restaurant from Supa technical team, you will see POS system integration section. You can find required information for integration in the POS restaurant account section:
We are using oAuth2 methods. For every Supa restaurant, a new unique refreshToken is generated. It has an infinite lifetime and may be used to acquire temporary authToken to access the API.
To get an auth token, please use AuthRefresh
A temporary token will be returned, that can be used to make HTTPS requests or create a socket.io connection.
Please note that if your integration for a specific restaurant will be revoked - refreshToken will no longer be able to generate you a fresh authToken.
Socket.io connection should be established between cash register server & Supa servers. Socket.io has client libraries built for all most common programming languages: Java, C++, Kotlin, C#, PHP etc.
https://pos.supa.pl/socket.io
[websocket]
https://pos.supa.pl/socket.io?authToken=eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp...qg08a5iDZvMWDkUYJOAzs
You can request our support team to switch your webhook type to https.
In order to properly operate, Supa has to be in sync with the POS system and have the latest information about the restaurant and its orders. To achieve this, Supa will issue “commands” (either via socket.io or https) with specific for each command arguments.
Response to each command should be in format specified in this API reference, otherwise validation will fail and data will not be synced.
You can also return data in arbitrary format, but that will require a Supa team to create an adapter for your integration - which will require additional time & costs.
Currently, there are 8 commands that a POS system has to implement.
Please refer to the corresponding Commands Section
Supa server has to be informed about a few events happening in your system. Regardless of the selected webhookType, you can always inform Supa either via:
For example:
socketClient.emit('onOrderPrint', {
externalOrderId: 'my-pos-order-id',
externalTableId: 'my-pos-table-id'
}, (qrURL: string | null) => {
if (typeof qrURL === 'string') {
addQRCodeToBill({ text: qrURL })
}
});
Call our https API: https://pos.supa.pl/integrations/third-party/{eventName}
Currently, there are 2 required events that Supa server has to be notified of.
Please refer to the corresponding Events Section
Any webhook call (from Supa to the POS system) can produce an error.
socketClient.on('getOrderById', (params, cb) => {
try {
// ... try to get an order by id
} catch (error) {
cb({
error: {
message: error.message || "Oops, something went wrong",
identifier: error.identifier || "OrderNotFoundException",
payload: params
}
})
}
});
HTTP/1.1 404 Not Found
Content-Type: application/json
{
statusCode: 404
message: "Oops, something went wrong",
identifier: "OrderNotFoundException",
payload: { id: 123 }
}
Please inform the Supa team about possible errors your system could raise so we could properly inform your guests about actions they have to take in order to resolve the issues.
Each error is identified by "identifier" string that error object contains.
Currently, we support the following error identifiers:
Webhooks to your POS system will be issues either through socket.io event or https endpoint.
Each command we issue has a corresponding args, and we expect from you a corresponding result
Each result returned from your POS system will be validated on our side, and we will display success or error for each operation in the Supa admin page.
For socket events:
Your socket.io client should like in this example:
socketClient.on('getSections', (pagination, cb) => {
const { page, limit } = pagination
const sections = [
{
externalId: 'section#1',
name: 'VIP Section 1',
description: 'Section for VIP Guests',
},
];
cb(sections.slice((page-1)*limit, page*limit));
});
For a full code reference for socket.io please take a look at Examples
For HTTPS webhooks we'll send a POST request with a corresponding JSON body. Example:
{
command: 'getSections', // getRestaurantAccount|getSections etc..
args: { page: 1, limit: 15 } // or other arguments specific for other commands
}
Here in REQUEST BODY SCHEMA we're providing the models for the commands we'll issue through the webhooks.
required | object |
required | object |
required | object |
required | object |
required | object |
required | object |
required | object This, in fact, is OPTIONAL. Only required if you want to implement demo orders for your customers |
required | object This command may only be triggered for orders which POS system marked with splitAvailable=true If your system does not support splitAvailable (it's false for all orders), you don't have to implement & support this command. Note that this command will most of the time be followed by getOrderById for both original order (which has to be already split) & and the new order |
required | object |
required | object |
{- "getRestaurantAccount": {
- "args": null,
- "result": { }
}, - "getSections": {
- "args": {
- "page": 0,
- "limit": 0
}, - "result": [
- {
- "externalId": "string",
- "name": "string",
- "description": "string"
}
]
}, - "getTables": {
- "args": {
- "page": 0,
- "limit": 0
}, - "result": [
- {
- "externalId": "string",
- "name": "string",
- "fullName": "string",
- "number": 0,
- "seatingCapacity": 0,
- "description": "string",
- "isActive": true,
- "printOrderQRAvailable": true
}
]
}, - "getWaiters": {
- "args": {
- "page": 0,
- "limit": 0
}, - "result": [
- {
- "externalId": "string",
- "name": "string",
- "phone": "string",
- "requiresPin": true,
- "pinCode": "string"
}
]
}, - "getPaymentTypes": {
- "args": {
- "page": 0,
- "limit": 0
}, - "result": [
- {
- "externalId": "string",
- "name": "string",
- "kind": "unknown",
- "isEnabled": true,
- "isActive": true
}
]
}, - "getOrderById": {
- "args": {
- "orderId": "string"
}, - "result": {
- "sum": 0.1,
- "paidSum": 0.1,
- "guestsCount": 0.1,
- "version": "string",
- "status": "opened",
- "openedAt": "2019-08-24T14:15:22Z",
- "billedAt": "2019-08-24T14:15:22Z",
- "externalId": "string",
- "discount": 0.1,
- "currency": "string",
- "fullSum": 0.1,
- "closedAt": "2019-08-24T14:15:22Z",
- "comment": "string",
- "number": 0.1,
- "guests": [
- {
- "externalId": "string",
- "name": "string",
- "comment": "string",
- "raw": { }
}
], - "items": [
- {
- "externalId": "string",
- "name": "string",
- "price": 0,
- "amount": 0.1,
- "cost": 0,
- "course": 0,
- "modifiers": [
- {
- "externalId": "string",
- "productExternalId": "string",
- "productGroupExternalId": "string",
- "name": "string",
- "amount": 0,
- "sum": 0
}
], - "comment": "string",
- "status": "added",
- "product": {
- "externalId": "string",
- "name": "string",
- "price": 0
}, - "raw": { },
- "guestExternalId": "string"
}
], - "payments": [
- {
- "externalId": "string",
- "taxID": "string",
- "receiptEmail": "string",
- "sum": 0,
- "status": "new",
- "currency": "string",
- "isPrepay": true,
- "isExternal": true,
- "restaurantPaymentType": {
- "externalId": "string"
}, - "raw": { }
}
], - "tables": [
- {
- "externalId": "string"
}
], - "waiters": [
- {
- "externalId": "string"
}
], - "requiresManualClose": true,
- "splitAvailable": true,
- "taxIdFillingAvailable": true,
- "receiptEmailFillingAvailable": true,
- "raw": { }
}
}, - "createOrder": {
- "args": {
- "tableId": 0,
- "guests": [
- {
- "name": "string",
- "items": [
- {
- "productId": 0,
- "guestId": 0,
- "amount": 0.1,
- "course": 0.1,
- "modifiers": [
- {
- "productModifierId": 0,
- "amount": 0
}
]
}
]
}
]
}, - "result": {
- "id": 0.1,
- "externalTableIds": [
- "string"
], - "restaurant": {
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "deletedAt": "2019-08-24T14:15:22Z",
- "waiters": [
- {
- "deletedAt": "2019-08-24T14:15:22Z",
- "id": 0.1,
- "restaurantId": 0.1,
- "restaurant": { },
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "type": "employee",
- "raw": { },
- "externalId": "string",
- "name": "string",
- "phone": "string",
- "requiresPin": true,
- "pinCode": "string"
}
], - "id": 0.1,
- "uuid": "string",
- "name": "string",
- "currency": "string",
- "phoneCode": "string",
- "timezone": "string"
}, - "userUUID": "string",
- "userAddedAt": "2019-08-24T14:15:22Z",
- "tables": [
- {
- "id": 0.1,
- "sortOrder": 0.1,
- "restaurantId": 0.1,
- "orders": [
- { }
], - "restaurantSectionId": 0.1,
- "restaurantSectionName": "string",
- "restaurantSection": {
- "id": 0.1,
- "restaurantId": 0.1,
- "sortOrder": 0.1,
- "raw": { },
- "tables": [
- { }
], - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "deletedAt": "2019-08-24T14:15:22Z",
- "externalId": "string",
- "name": "string",
- "description": "string"
}, - "qrUrl": "string",
- "alias": "string",
- "printOrderQREnabled": true,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "raw": { },
- "externalId": "string",
- "name": "string",
- "fullName": "string",
- "number": 0,
- "seatingCapacity": 0,
- "description": "string",
- "isActive": true,
- "printOrderQRAvailable": true
}
], - "waiters": [
- {
- "id": 0.1,
- "restaurantId": 0.1,
- "restaurant": {
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "deletedAt": "2019-08-24T14:15:22Z",
- "waiters": [
- {
- "deletedAt": "2019-08-24T14:15:22Z",
- "id": 0.1,
- "restaurantId": 0.1,
- "restaurant": { },
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "type": "employee",
- "raw": { },
- "externalId": "string",
- "name": "string",
- "phone": "string",
- "requiresPin": true,
- "pinCode": "string"
}
], - "id": 0.1,
- "uuid": "string",
- "name": "string",
- "currency": "string",
- "phoneCode": "string",
- "timezone": "string"
}, - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "type": "employee",
- "raw": { },
- "externalId": "string",
- "name": "string",
- "phone": "string",
- "requiresPin": true,
- "pinCode": "string"
}
], - "items": [
- {
- "id": 0.1,
- "sortOrder": 0.1,
- "orderId": 0.1,
- "order": { },
- "guestId": 0.1,
- "guest": {
- "id": 0.1,
- "sortOrder": 0.1,
- "userId": 0.1,
- "order": { },
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "deletedAt": "2019-08-24T14:15:22Z",
- "externalId": "string",
- "name": "string",
- "comment": "string",
- "raw": { }
}, - "modifiers": [
- {
- "id": 0.1,
- "orderItemId": 0.1,
- "orderItem": { },
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "amountIndependentOfParentAmount": true,
- "externalId": "string",
- "productExternalId": "string",
- "productGroupExternalId": "string",
- "name": "string",
- "amount": 0,
- "sum": 0,
- "displayAmount": 0.1,
- "discount": 0.1
}
], - "productId": 0.1,
- "product": {
- "id": 0.1,
- "fullName": "string",
- "description": "string",
- "defaultCourse": 0.1,
- "isModifier": true,
- "isActive": true,
- "searchVector": { },
- "measuringUnitName": "string",
- "restaurantId": 0.1,
- "restaurant": {
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "deletedAt": "2019-08-24T14:15:22Z",
- "waiters": [
- {
- "deletedAt": "2019-08-24T14:15:22Z",
- "id": 0.1,
- "restaurantId": 0.1,
- "restaurant": { },
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "type": "employee",
- "raw": { },
- "externalId": "string",
- "name": "string",
- "phone": "string",
- "requiresPin": true,
- "pinCode": "string"
}
], - "id": 0.1,
- "uuid": "string",
- "name": "string",
- "currency": "string",
- "phoneCode": "string",
- "timezone": "string"
}, - "categoryId": 0.1,
- "category": {
- "id": 0.1,
- "restaurantId": 0.1,
- "externalId": "string",
- "name": "string",
- "description": "string",
- "color": "string",
- "restaurant": {
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "deletedAt": "2019-08-24T14:15:22Z",
- "waiters": [
- {
- "deletedAt": null,
- "id": null,
- "restaurantId": null,
- "restaurant": null,
- "createdAt": null,
- "updatedAt": null,
- "type": null,
- "raw": { },
- "externalId": null,
- "name": null,
- "phone": null,
- "requiresPin": null,
- "pinCode": null
}
], - "id": 0.1,
- "uuid": "string",
- "name": "string",
- "currency": "string",
- "phoneCode": "string",
- "timezone": "string"
}, - "parentCategory": { },
- "sortOrder": 0.1,
- "raw": { },
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "deletedAt": "2019-08-24T14:15:22Z"
}, - "modifiers": [
- {
- "id": 0.1,
- "productId": 0.1,
- "restaurantId": 0.1,
- "product": { },
- "type": "simple",
- "modifierProductExternalId": "string",
- "modifierProductName": "string",
- "modifierProductPrice": 0.1,
- "modifierProductGroupExternalId": "string",
- "modifierProductGroupName": "string",
- "modifierGroupMinAmount": 0.1,
- "modifierGroupMaxAmount": 0.1,
- "modifierGroupFreeOfChargeAmount": 0.1,
- "minAmount": 0.1,
- "maxAmount": 0.1,
- "defaultAmount": 0.1,
- "freeOfChargeAmount": 0.1,
- "amountIndependentOfParentAmount": true,
- "sortOrder": 0.1,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "includedSections": [
- {
- "deletedAt": "2019-08-24T14:15:22Z",
- "id": 0.1,
- "restaurantId": 0.1,
- "sortOrder": 0.1,
- "raw": { },
- "tables": [
- {
- "id": null,
- "sortOrder": null,
- "restaurantId": null,
- "orders": [ ],
- "restaurantSectionId": null,
- "restaurantSectionName": null,
- "restaurantSection": null,
- "qrUrl": null,
- "alias": null,
- "printOrderQREnabled": null,
- "createdAt": null,
- "updatedAt": null,
- "raw": { },
- "externalId": null,
- "name": null,
- "fullName": null,
- "number": null,
- "seatingCapacity": null,
- "description": null,
- "isActive": null,
- "printOrderQRAvailable": null
}
], - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "externalId": "string",
- "name": "string",
- "description": "string"
}
], - "raw": { },
- "remainingAmount": 0.1,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "deletedAt": "2019-08-24T14:15:22Z",
- "externalId": "string",
- "name": "string",
- "price": 0
}, - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "deletedAt": "2019-08-24T14:15:22Z",
- "externalId": "string",
- "name": "string",
- "price": 0,
- "amount": 0.1,
- "cost": 0,
- "course": 0,
- "comment": "string",
- "status": "added",
- "raw": { },
- "guestExternalId": "string",
- "discount": 0.1
}
], - "guests": [
- {
- "id": 0.1,
- "sortOrder": 0.1,
- "userId": 0.1,
- "order": { },
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "deletedAt": "2019-08-24T14:15:22Z",
- "externalId": "string",
- "name": "string",
- "comment": "string",
- "raw": { }
}
], - "payments": [
- {
- "id": 0.1,
- "order": { },
- "restaurantPaymentTypeId": 0.1,
- "restaurantPaymentType": {
- "id": 0.1,
- "restaurantId": 0.1,
- "sortOrder": 0.1,
- "raw": { },
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "externalId": "string",
- "name": "string",
- "kind": "unknown",
- "isEnabled": true,
- "isActive": true
}, - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "deletedAt": "2019-08-24T14:15:22Z",
- "externalId": "string",
- "taxID": "string",
- "receiptEmail": "string",
- "sum": 0,
- "status": "new",
- "currency": "string",
- "isPrepay": true,
- "isExternal": true,
- "raw": { },
- "typeId": "string",
- "typeName": "string",
- "typeKind": "unknown"
}
], - "appliedDiscounts": [
- {
- "id": 0.1,
- "order": { },
- "discountTypeId": 0.1,
- "discountType": {
- "id": 0.1,
- "externalId": "string",
- "name": "string",
- "restaurantId": 0.1,
- "restaurant": {
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "deletedAt": "2019-08-24T14:15:22Z",
- "waiters": [
- {
- "deletedAt": "2019-08-24T14:15:22Z",
- "id": 0.1,
- "restaurantId": 0.1,
- "restaurant": { },
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "type": "employee",
- "raw": { },
- "externalId": "string",
- "name": "string",
- "phone": "string",
- "requiresPin": true,
- "pinCode": "string"
}
], - "id": 0.1,
- "uuid": "string",
- "name": "string",
- "currency": "string",
- "phoneCode": "string",
- "timezone": "string"
}, - "isActive": true,
- "isAutomatic": true,
- "canApplyManually": true,
- "canApplyByCardNumber": true,
- "canApplyByDiscountCard": true,
- "canApplySelectively": true,
- "discountByFlexibleSum": true,
- "raw": { },
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}, - "isRounding": true,
- "isSelectivelyApplied": true,
- "discountSum": 0.1,
- "discountSumByOrderItemId": { },
- "raw": { },
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "parentId": 0.1,
- "requiresManualClose": true,
- "splitInfo": {
- "ordersIds": [
- 0.1
], - "fullSum": 0.1,
- "paidSum": 0.1,
- "beforeCurrentOrderSum": 0.1
}, - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "deletedAt": "2019-08-24T14:15:22Z",
- "source": "syrve",
- "restaurantId": 0.1,
- "sum": 0.1,
- "paidSum": 0.1,
- "guestsCount": 0.1,
- "version": "string",
- "status": "opened",
- "openedAt": "2019-08-24T14:15:22Z",
- "billedAt": "2019-08-24T14:15:22Z",
- "externalId": "string",
- "discount": 0.1,
- "currency": "string",
- "fullSum": 0.1,
- "closedAt": "2019-08-24T14:15:22Z",
- "comment": "string",
- "number": 0.1,
- "splitAvailable": true,
- "taxIdFillingAvailable": true,
- "receiptEmailFillingAvailable": true,
- "raw": { },
- "mainWaiterId": 0.1
}
}, - "splitOrder": {
- "args": {
- "splitItems": [
- {
- "itemId": "string",
- "amount": 0.1
}
], - "orderId": "string"
}, - "result": {
- "newOrderId": "string"
}
}, - "billAndLockOrder": {
- "args": {
- "waiterId": "string",
- "waiterPinCode": "string",
- "orderId": "string"
}, - "result": null
}, - "payOrder": {
- "args": {
- "paymentItems": [
- {
- "paymentTypeId": "string",
- "sum": 0.1,
- "taxID": "string",
- "receiptEmail": "string"
}
], - "waiterId": "string",
- "waiterPinCode": "string",
- "orderId": "string"
}, - "result": null
}
}
import { io as SocketIoClient } from 'socket.io-client';
import axios from 'axios';
import dayjs from 'dayjs';
const BASE_URL = 'https://pos.supa.pl'
const REFRESH_TOKEN = 'eyJhbGciOiJIU...CqmpNPDvfPN4mJpiFJp_s';
const getAccessToken = async (refreshToken) => {
const { data } = await axios.post(`${BASE_URL}/auth/refresh?refreshToken=${refreshToken}`);
return data.token;
}
const paginate = (array, { page, limit }) => {
return array.slice((page - 1) * limit, page * limit)
}
const authToken = await getAccessToken(REFRESH_TOKEN);
const socketClient = new SocketIoClient(BASE_URL, {
path: '/socket.io',
query: { authToken },
transports: ['websocket'],
secure: true,
});
socketClient.on('connect', async () => {
console.log('POS connected');
// socketClient.emit('onOrderPrint', { externalOrderId: 'order1', externalTableId: 'table1' }, (response) => console.log(response, ' | onOrderPrint response'));
// socketClient.emit('PING', (response) => console.log(response, ' | PING response'));
await new Promise(resolve => setTimeout(resolve, 1000));
socketClient.emit('onCashRegisterStart');
socketClient.emit('onOrderUpsert', { externalOrderId: 'order#1' });
});
socketClient.on('disconnect', () => {
console.log('POS disconnected');
});
socketClient.on('connect_error', (error) => {
if (socketClient.active) {
// temporary failure, the socket will automatically try to reconnect
} else {
// the connection was denied by the server
// in that case, `socket.connect()` must be manually called in order to reconnect
console.log(error.message);
}
});
socketClient.on('getRestaurantAccount', (cb) => {
console.log('getRestaurantAccount');
const account = {
organisationId: 'orgId2',
organisationName: 'Test Organisation',
cloudId: '#001',
tariff: 'Basic',
};
cb(account);
});
socketClient.on('getSections', (pagination, cb) => {
console.log('getSections', pagination);
const sections = [
{
externalId: 'section#1',
name: 'VIP Section 1',
description: 'Section for VIP Guests',
},
];
cb(paginate(sections, pagination));
});
socketClient.on('getWaiters', (pagination, cb) => {
console.log('getWaiters', pagination);
const waiters = [
{
'externalId': 'waiterExternalId#1',
'name': 'Daniella Waiter',
'phone': '+48835000000',
'requiresPin': false
}
];
cb(paginate(waiters, pagination));
});
socketClient.on('getTables', (pagination, cb) => {
console.log('getTables', pagination);
const tables = [
{
externalId: 'table1#1',
externalSectionId: 'section#1',
name: 'Table 1',
number: 1,
description: 'VIP table',
},
];
cb(paginate(tables, pagination));
});
socketClient.on('getPaymentTypes', (pagination, cb) => {
console.log('getPaymentTypes', pagination);
const paymentTypes = [
{
externalId: 'paymentType#1',
name: 'Supa',
kind: 'card',
},
];
cb(paginate(paymentTypes, pagination));
});
socketClient.on('getOrderById', (params, cb) => {
console.log('getOrderById', params);
const ordersById = {
'order#1': {
status: 'opened',
externalId: 'order#1',
currency: 'PLN',
sum: 12300,
paidSum: 12300,
fullSum: 12500,
guestsCount: 2,
openedAt: dayjs().subtract(2, 'hours').toISOString(),
billedAt: dayjs().subtract(15, 'minutes').toISOString(),
closedAt: null,
guests: [
{
externalId: 'your-guest-id-1',
name: 'Guest 1',
raw: {},
},
{
externalId: 'your-guest-id-2',
name: 'Guest 2',
raw: {},
},
],
items: [
{
externalId: 'jsakjdsakj',
price: 5000,
name: 'Hamburger of 1st guest',
amount: 2,
cost: 10000,
comment: 'extra spicy',
guestExternalId: 'your-guest-id-1',
product: {
externalId: 'product-id#1',
price: 5000,
name: 'Hamburger of 1st guest',
},
modifiers: [
{
externalId: 'modifier#1',
productExternalId: 'modifier-type-id#1',
name: 'Additional Gouda',
amount: 2,
sum: 2000,
}
],
raw: {},
},
{
externalId: 'jsakjdsakjвфіо213',
price: 5300,
name: 'Salad of 2nd guest',
amount: 2.5,
cost: 13250,
guestExternalId: 'your-guest-id-2',
product: {
externalId: 'product-id#2',
price: 5300,
name: 'Salad of 2nd guest',
},
raw: {},
},
],
payments: [
{
externalId: 'payment-id',
sum: 12300,
status: 'processed',
currency: 'PLN',
restaurantPaymentType: { externalId: 'paymentType#1' },
raw: {},
},
],
tables: [{ externalId: 'table1#1' }],
waiters: [{ externalId: 'waiterExternalId#1' }],
raw: {}
}
}
cb(ordersById[params.orderId]);
});
socketClient.on('billAndLockOrder', async (data, cb) => {
console.log('billAndLockOrder', data);
await new Promise(resolve => setTimeout(resolve, 1000));
cb();
});
socketClient.on('payOrder', async (data, cb) => {
console.log('payOrder', data);
await new Promise(resolve => setTimeout(resolve, 1000));
cb();
});
This one should be sent as soon as the order has been created/updated or deleted. This will place a corresponding UpsertEvent in the Supa’s internal processing queue - and it will dispatch a corresponding getOrderById event as soon as possible
externalOrderId required | string |
{- "externalOrderId": "string"
}
Before order bill is printed, you may call this endpoint and receive a link for a QR payment.
externalOrderId | string |
externalTableId | string |
{- "externalOrderId": "string",
- "externalTableId": "string"
}