Skip to main content

Integration with a virtual Point of Sale (vPOS)

Snabble is able to use a virtual Point of Sale (vPOS) to integrate into the systems of a retailer. The vPOS acts like a usual Point of Sale system (PoS), but hands the processing of the checkout over to Snabble.

The vPOS is used in the checkout flow on two points: First it is used to determine the price and further restrictions at the beginning. Second, after completing the checkout the information on the checkout is passed back to the vPOS. This allows it to trigger the correct retailer internal processes.

Data Model

Checkouts are represented through the following data structure:

{
"shopId": "1",
"externalShopId": "12",
"loyaltyCard": "...",
"items": [
{
"id": "54ddafde-5207-11e9-b1c7-68f7286a148f",
"sku": "1",
"type": "default",
"name": "Wine",
"amount": 2,
"price" : 119,
"taxRate" : "19",
"totalPrice": 238,
"saleRestriction": "min_age_18",
"scannedCode": "0000000000001"
},
{
"id": "b33a8950-521e-11e9-934a-68f7286a148f",
"sku": "bottle",
"type": "deposit",
"refersTo": "54ddafde-5207-11e9-b1c7-68f7286a148f",
"name": "Deposit",
"amount": "2",
"price": 8,
"taxRate": "19",
"totalPrice": 16
},
{
"id": "aded2a10-521f-11e9-96a0-68f7286a148f",
"type": "discount",
"refersTo": "54ddafde-5207-11e9-b1c7-68f7286a148f",
"name": "Wine promotion",
"amount": "1",
"price": -38,
"taxRate": "19",
"totalPrice": -38
},
{
"id": "5c8c5168-5207-11e9-bf60-68f7286a148f",
"sku": "2",
"type": "default",
"amount": 1,
"weight": 42,
"weightUnit": "g",
"name": "Apple",
"amount": "1",
"price": 199,
"referenceUnit": "kg",
"taxRate": "7",
"totalPrice": 8,
"scannedCode": "0000000000420"
},
{
"id": "64769fc8-5207-11e9-8f9a-68f7286a148f",
"sku": "3",
"type": "default",
"name": "Rolls",
"amount": 1,
"units": 6,
"price": 32,
"taxRate": "7",
"totalPrice": 192,
"scannedCode": "0000000000062"
},
{
"id": "6a347656-5207-11e9-9d96-68f7286a148f",
"sku": "4",
"type": "default",
"name": "Bread",
"amount": 2,
"price": 129,
"priceModifiers": [
{
"name": "Discount 10%",
"price": -10,
}
]
"taxRate": "7",
"totalPrice": 238,
"scannedCode": "0000000001298"
}
],
"taxShares" : [
{ "rate": "19", "net": 182, "share": 34, "total": 216 },
{ "rate": "7", "net": 391, "share": 27, "total": 418 }
],
"netPrice" : 573,
"totalPrice" : 634,
"orderId": "f30b0aa4-5210-11e9-a411-68f7286a148f",
"externalCheckoutId": "1",
"paymentInformation": {
"mandateReference": "..."
},
"state": "completed",
"receiptBuffer": "c25hYmJsZQo=",
"receiptFormat": "pdf"
}
ParameterTypeDefaultDescription
shopIdstringIdentifier of the shop
externalShopIdstringnullExternal identifier of the shop as provided through the Shops API
loyaltyCardstringnullLoyalty card number of the customer
customerCustomerCustomer details
itemsLineItem[]List of the line items
taxSharesTaxShare[]nullList of tax shares
netPriceintnullNet price of the checkout
totalPriceintnullTotal price of the checkout
orderIdstringnullIdentifier of the Snabble order
externalCheckoutIdstringnullIdentifier used by the vPOS to identify the checkout
paymentInformationobjectnullAdditional information provided by the payment system (i.e. transaction id, SEPA mandate)
statestringnullThe state of the checkout (open, completed)
receiptBufferstringnullBase64 encoded receipt
receiptFormatstringFormat of the receiptBuffer (pdf or text)
errors[]ErrornullList of errors

Tax Shares

ParameterTypeDefaultDescription
ratestringTax rate as string encoded decimal
netintNet portion
shareintTax share for this rate
totalintThe total

Line Item

ParameterTypeDefaultDescription
idstringIdentifier of the line item
typestringdefaultType of the line item (default, deposit, giveaway, discount, coupon)
refersTostringnullline item that is related to this one (i.e. if the line item represents a deposit the id of the line item which requires it)
skustringnullSKU of the product
couponIDstringnullid of the coupon
amountintNumber of products / packages
weightint0Weight purchased
weightUnitstringUnit of the weight
referenceUnitstringReference unit for weighable item, Details: Product API: weighable products
unitsint0Number of units in a package in case of bundle or piece product
priceintPrice of the product for single unit, piece, weightUnit, etc
totalPriceintTotal price of the line item
namestringName of the product
taxRatestringTax rate as string encoded decimal
scannedCodestringScanned code
saleRestrictionstringRestrictions that apply to the line item
priceModifiersPriceModifierPrice Modifiers that apply to the line item
errors[]ErrornullList of errors

Price Modifier

ParameterTypeDefaultDescription
namestring""Name of the modifier
priceintThe price modification

Discounts & Modifiers

For a checkout different promotions might apply. There are three different possibilities to represent promotions: A promotion might change the price and totalPrice of a LineItem. In this case the system has no information and the prices are displayed as given

A promotion might modify the price of the line item. This modification should be represented by a Modifier. For example a price reduction can be respresented by:

    {
"id": "6a347656-5207-11e9-9d96-68f7286a148f",
"sku": "4",
"type": "default",
"name": "Bread",
"amount": 3,
"price": 129,
"modifiers": [
{
"name": "Promotion",
"price": -29,
}
]
"taxRate": "7",
"totalPrice": 300,
"scannedCode": "0000000001298"
}

General discounts (i.e. a cart discount) are represented through line items of type discount. These line items might reference another line item (i.e. the coupon that triggered the discount). For example:

    {
"id": "aded2a10-521f-11e9-96a0-68f7286a148f",
"type": "discount",
"refersTo": "54ddafde-5207-11e9-b1c7-68f7286a148f",
"name": "Cart Promotion 10%",
"amount": "1",
"taxRate": "7",
"price": -38,
"totalPrice": -38
},

Coupons

Coupons are represented as line items of type coupon.

    {
"id": "aded2a10-521f-11e9-96a0-68f7286a148f",
"type": "coupon",
"name": "Coupon",
"amount": "1",
"scannedCode": "1234"
},

Error

In case of an error the checkout may contain a list of errors. Further the the line item may contain a list of error objects to indicate why they cause an error. Such an object consists of type string and an informational message.

{
"items": [
{
"id": "00883a9e-520c-11e9-a629-68f7286a148f",
"errors": [
{
"type": "invalid_line_item",
"message": "Invalid line item"
}
]
}
],
"errors": [
{
"type": "invalid_cart_items",
"message": "Invalid line item"
}
]
}
ParameterTypeDefaultDescription
typestringType of the error
messagestringnullOptional informational error message
Line Item Errors
Error typesDescription
unknown_productProduct could not be identified
sale_stopProduct can't be sold
invalid_line_itemThe line item is semantically invalid
otherOther errors
Cart Errors
Error typesDescription
invalid_cart_itemsSome cart items are invalid
service_unavailableThe service is currently not available
invalid_loyalty_cardThe loyalty card is invalid

Endpoints

Authorization

The Service sends an Authorization header as described in RFC 7235 Section 4.2. The supported authentication schemes are Bearer (see RFC 6750) and Basic (see RFC 7617). Additionally authorization through TLS 1.2 / 1.3 certificates is supported.

Obtain Checkout Information

This endpoint is called if the system needs to complete the information in a checkout. It sends an incomplete checkout and the service should respond with a completed checkout. The checkout misses the prices, the tax rates, the names and the sale restrictions.

The service responds with a completed checkout containing the missing information. Further it might add additional line items that represent promotions (like discounts or additional items) or deposits.

Request

POST / HTTP 1.1
Accept: application/json

{
"shopId": "1",
"loyaltyCard": "...",
"items": [
{
"id": "54ddafde-5207-11e9-b1c7-68f7286a148f",
"sku": "1",
"type": "default",
"amount": 2,
"scannedCode": "0000000000001"
}
]
}

Response

HTTP/1.1 201 Created
Content-Type: application/json

{
"shopId": "1",
"loyaltyCard": "...",
"items": [
{
"id": "54ddafde-5207-11e9-b1c7-68f7286a148f",
"sku": "1",
"type": "default",
"name": "Product",
"amount": 2,
"price" : 119,
"taxRate" : "19",
"totalPrice": 238,
"saleRestriction": "min_age_18",
"scannedCode": "0000000000001"
}
],
"taxShares" : [
{ "rate": "19", "net": 200, "share": 38, "total": 238 }
],
"netPrice" : 200,
"totalPrice" : 238
}
Status Codes
  • 200 OK, 201 Created: The information was completed and the checkout is approved for processing
  • 400 Bad Request: The information could not be completed or the checkout is not approved for processing

Place completed Checkout

After Snabble has processed the checkout it sends a request to the vPOS. This request contains all information on the checkout.

Request

The service sends the information as obtained before and adds the Snabble orderId and information on the payment. Further it sets the completed flag to true.

POST / HTTP 1.1
Accept: application/json

{
"shopId": "1",
"items": [
{
"id": "54ddafde-5207-11e9-b1c7-68f7286a148f",
"sku": "1",
"type": "default",
"name": "Product",
"amount": 2,
"price" : 119,
"taxRate" : "19",
"totalPrice": 238,
"saleRestriction": "min_age_18",
"scannedCode": "0000000000001"
}
],
"taxShares" : [
{ "rate": "19", "net": 200, "share": 38, "total": 238 }
],
"netPrice" : 200,
"totalPrice" : 238,

"orderId": "f30b0aa4-5210-11e9-a411-68f7286a148f",
"paymentInformation": {
"mandateReference": "..."
},
"state": "completed"
}

Response

The endpoints responds with the checkout. Optionally it might send a property externalCheckoutId. These are stored. Further it might provide a receipt through the receiptBuffer property.

HTTP/1.1 201 Created
Content-Type: application/json

{
// all fields as above
"externalCheckoutId": "1",
"receiptBuffer": "c25hYmJsZQo="
}
Status Codes
  • 200 OK, 201 Created: The Checkout was processed by the vPOS