Basic Checkout
In this tutorial, we'll manually create an order, add customer information, shipping details, payment, and completing the order—essentially handling everything ourselves without any automation. This isn't a checkout setup we're expected to build in a real-world scenario, but it serves to introduce some of the core concepts behind the system. In most cases, we'll use a platform adapter to streamline the process. We'll cover how to integrate the Norce adapter in a later section.
Create an order
Here is some product information and cart information we've been provided with, when the customer entered our Checkout.
SKU | Name | Price Excluding VAT | VAT |
---|---|---|---|
T001 | Thing | 10 | 0.25 |
Item ID | Cart ID | SKU |
---|---|---|
cart-item-no-1 | our-first-cart | T001 |
On our order, reference
is used for external IDs, so we'll use Cart ID for order/cart/reference
and Item ID for our first and only item, order/cart/items[0]/reference
. We need to calculate the total price including VAT for our item and we need to sum up all our items totals for our order/cart/total
.
In the response we'll find our order id, both in the body and in the location header.
POST /api/v0/checkout/orders
X-Merchant: thingsandstuff
X-Channel: se
Authorization: Bearer super-secret-and-valid-token
Host: thingsandstuff.api-se.playground.norce.tech/checkout/order
Content-Type: application/json
{
"merchant": "thingsandstuff",
"channel": "se",
"cart": {
"reference": "our-first-cart",
"items": [
{
"reference": "cart-item-no-1",
"sku": "T001",
"name": "Thing",
"quantity": 1,
"total": {
"includingVat": 12.5,
"excludingVat": 10
},
"vatRate": 0.25
}
],
"total": {
"includingVat": 12.5,
"excludingVat": 10
}
}
}
201 Created
location: /api/v0/checkout/orders/oaAaAaAA
Content-Type: application/json
{
"id": "oaAaAaAA"
}
We can now fetch our order and we'll see that the order received a few new fields, including a state with the current status checkout
. The order has also received a total, calculated from cart and shippings, but we don't have any shippings yet.
GET /api/v0/checkout/orders/oaAaAaAA
X-Merchant: thingsandstuff
X-Channel: se
Authorization: Bearer super-secret-and-valid-token
Host: thingsandstuff.api-se.playground.norce.tech/checkout/order
200 OK
Content-Type: application/json
{
"id": "oaAaAaAA",
"merchant": "thingsandstuff",
"channel": "se",
"created": "2024-01-01T01:01:01.0000001Z",
"lastModified": "2024-01-01T01:01:01.0000001Z",
"state": {
"currentStatus": "checkout",
"transitions": [
{
"status": "checkout",
"timeStamp": "2024-01-01T01:01:01.0000001Z",
}
]
},
"cart": {
"reference": "our-first-cart",
"items": [
{
"id": "ciaAaaAAAAAAAaaaAAaAAAAaaAaA",
"reference": "cart-no-1",
"name": "Thing",
"sku": "T001",
"quantity": 1,
"price": {
"includingVat": 12.5,
"excludingVat": 10
},
"vatRate": 0.25
}
],
"total": {
"includingVat": 12.5,
"excludingVat": 10
}
},
"total": {
"includingVat": 12.5,
"excludingVat": 10
}
}
Cart references are unique in Norce Checkout, meaning only one order can exist per platform cart. When a customer enters the checkout, an order is created. If they exit to modify their cart and return later, the existing order will be updated instead. Attempting to create a new order with the same cart reference will result in a conflict, signaling that the previous order should be retrieved and updated.
Customer information
Next we need to get some customer information in order to know where to deliver the item to. Let's assume we got that from a form in our checkout. We can then add that information to the order, by updating the order/customer/shipping
.
PUT /api/v0/checkout/orders/oaAaAaAA/customer/shipping
X-Merchant: thingsandstuff
X-Channel: se
Authorization: Bearer super-secret-and-valid-token
Host: thingsandstuff.api-se.playground.norce.tech/checkout/order
Content-Type: application/json
{
"type": "Person",
"givenName": "Henrikinho",
"familyName": "Undulatsson",
"streetAddress": "Odengatanvägen 12",
"streetAddress2": "Lgh 1203",
"postalCode": "915 20",
"city": "Skellefteå",
"country": "SE",
"phone": "0701740612",
"email": "henrikinho.undulatsson@example.com"
}
200 OK
Delivery
Now we can add a delivery option to the order. Our merchant handles all the delivery themselves and the platform contains information about the delivery option.
Delivery ID | Name | Price Excluding VAT | VAT |
---|---|---|---|
thing-to-home-delivery | Thing to Home Delivery | 6 | 0.25 |
We don't actually have a shipping session to deal with here, so we'll just set the delivery method id as a reference, assuming that will all be handled after the order is completed.
Just as when we created an order, we get the id in our response body as well as in our location header.
POST /api/v0/checkout/orders/oaAaAaAA/shippings
X-Merchant: thingsandstuff
X-Channel: se
Authorization: Bearer super-secret-and-valid-token
Host: thingsandstuff.api-se.playground.norce.tech/checkout/order
Content-Type: application/json
{
"reference": "thing-to-home-delivery",
"name": "Thing to Home Delivery",
"total": {
"includingVat": 7.5,
"excludingVat": 6
},
"vatRate": 0.25
}
201 Created
location: /api/v0/checkout/orders/oaAaAaAA/shippings/saAaaAAAAaaaaAAAAaAAAAAAaaA
Content-Type: application/json
{
"id": "saAaaAAAAaaaaAAAAaAAAAAAaaA"
}
Fetching our order again, we can see that the added shipping price has been included in our order total.
GET /api/v0/checkout/orders/oaAaAaAA
X-Merchant: thingsandstuff
X-Channel: se
Authorization: Bearer super-secret-and-valid-token
Host: thingsandstuff.api-se.playground.norce.tech/checkout/order
200 OK
Content-Type: application/json
{
"id": "oaAaAaAA",
"merchant": "thingsandstuff",
"channel": "se",
"created": "2024-01-01T01:01:01.0000001Z",
"lastModified": "2024-01-01T01:02:01.0000001Z",
"state": {
"currentStatus": "checkout",
"transitions": [
{
"status": "checkout",
"timeStamp": "2024-01-01T01:01:01.0000001Z",
}
]
},
"cart": {
"reference": "our-first-cart",
"items": [
{
"id": "ciaAaaAAAAAAAaaaAAaAAAAaaAaA",
"reference": "cart-no-1",
"name": "Thing",
"sku": "T00001",
"quantity": 1,
"price": {
"includingVat": 12.5,
"excludingVat": 10
},
"vatRate": 0.25
}
],
"total": {
"includingVat": 12.5,
"excludingVat": 10
}
},
"shippings": [
{
"id": "saAaaAAAAaaaaAAAAaAAAAAAaaA",
"state": "intent",
"reference": "thing-to-home-delivery",
"name": "Thing to Home Delivery",
"total": {
"includingVat": 7.5,
"excludingVat": 6
},
"vatRate": 0.25
}
],
"total": {
"includingVat": 20,
"excludingVat": 16
}
}
Payment
Our platform provides the following payment method information:
Payment Method ID | Name |
---|---|
thing-payment | Thing Payment |
Similarly to our delivery method, we don't have a payment session active anywhere, so we'll just use our payment method id as reference. We'll make sure to cover the order total with our amount.
POST /api/v0/checkout/orders/oaAaAaAA/payments
X-Merchant: thingsandstuff
X-Channel: se
Authorization: Bearer super-secret-and-valid-token
Host: thingsandstuff.api-se.playground.norce.tech/checkout/order
Content-Type: application/json
{
"reference": "thing-payment",
"name": "Thing Payment",
"type": "default",
"amount": 20
}
201 Created
location: /api/v0/checkout/orders/oaAaAaAA/payments/paAaaAAAAaaaaAAAAaAAAAAAaaA
Content-Type: application/json
{
"id": "paAaaAAAAaaaaAAAAaAAAAAAaaA"
}
Complete the order
When we say that we complete the order, we're referring to changing the order state to completed
.
The order starts in the checkout
state, where all modifications are allowed. Once the state is changed to processing
, changes that affect the order total or payment amounts are no longer permitted. This state is useful for locking the order before initiating transactions, like payments. If an attempt is made to move the order back to checkout, the adapter that changed it to processing
can block the reversal using hooks. The accepted
state indicates the customer has finalized the order, awaiting payment confirmation, with similar restrictions as processing. Once all payments and shipments are complete, the order transitions to completed
.
To complete an order, simply change order/state/currentStatus
to completed
. The order service will automatically transition through the processing
and accepted
states, validating along the way, before reaching completed
. If the payment amount doesn't cover the total, the order may fail validation, and the state change will be rejected.
PUT /api/v0/checkout/orders/oaAaAaAA/state
X-Merchant: thingsandstuff
X-Channel: se
Authorization: Bearer super-secret-and-valid-token
Host: thingsandstuff.api-se.playground.norce.tech/checkout/order
Content-Type: application/json
{
"currentStatus": "completed"
}
200 OK
Fetching our order for the final time, we can see the transitions as the order moved from checkout
, to processing
, to accepted
before finally ending up as completed
.
GET /api/v0/checkout/orders/oaAaAaAA
X-Merchant: thingsandstuff
X-Channel: se
Authorization: Bearer super-secret-and-valid-token
Host: thingsandstuff.api-se.playground.norce.tech/checkout/order
200 OK
Content-Type: application/json
{
"id": "oaAaAaAA",
"merchant": "thingsandstuff",
"channel": "se",
"created": "2024-01-01T01:01:01.0000001Z",
"lastModified": "2024-01-01T01:04:01.0000001Z",
"state": {
"currentStatus": "completed",
"transitions": [
{
"status": "checkout",
"timeStamp": "2024-01-01T01:01:01.0000001Z",
},
{
"status": "processing",
"timeStamp": "2024-01-01T01:04:01.0000001Z",
},
{
"status": "accepted",
"timeStamp": "2024-01-01T01:04:01.0000001Z",
},
{
"status": "completed",
"timeStamp": "2024-01-01T01:04:01.0000001Z",
}
]
},
"cart": {
"reference": "our-first-cart",
"items": [
{
"id": "ciaAaaAAAAAAAaaaAAaAAAAaaAaA",
"reference": "cart-no-1",
"name": "Thing",
"sku": "T00001",
"quantity": 1,
"price": {
"includingVat": 12.5,
"excludingVat": 10
},
"vatRate": 0.25
}
],
"total": {
"includingVat": 12.5,
"excludingVat": 10
}
},
"shippings": [
{
"id": "saAaaAAAAaaaaAAAAaAAAAAAaaA",
"state": "intent",
"reference": "thing-shipping",
"name": "Thing to Home Delivery",
"total": {
"includingVat": 7.5,
"excludingVat": 6
},
"vatRate": 0.25
}
],
"payments": [
{
"id": "paAaaAAAAaaaaAAAAaAAAAAAaaA",
"name": "Thing Payment",
"currency": "SEK",
"type": "default",
"orderId": "oaAaAaAA",
"amount": 20,
"state": "intent",
"reference": "thing-payment"
}
],
"total": {
"includingVat": 20,
"excludingVat": 16
}
}
We should have updated the shipping and payment states to confirmed
. However, we'll leave this as an exercise for you to complete.
Next Steps
In this tutorial, we manually created and managed an order, adding customer information, delivery, and payment details, and then completing the order. While this approach works for simple cases, real-world scenarios are often more complex.
Next, we'll look at how using an adapter can automate many of these tasks and streamline the order creation and management process.