Supporting Upsells

This guides follows on from the merchant guide: Post-checkout upsells with Submarine

The core theme functionality of Upsells described in the overview for merchants is built in to SubmarineCheckout.js, the standard Javascript library that’s added to the checkout of any store leveraging Submarine.

The list of products to be displayed is driven by Shopify’s native Product Recommendations API, based on the list of products inside the newly-completed order, and the styling of the widget is driven purely by the existing checkout styles (as a result, any changes to the default theming of your checkout — button colours, for example — will be reflected inside the upsell widget.

To customise the behaviour or display of the upsell widget for your store, you’ll need to fork the base SubmarineCheckout.js library from Github, modify the Upsell module within, and build and deploy your modified version to your theme. Instructions on how to do this are contained within the SubmarineCheckout.js README.

Upsells API

The Upsells API forms part of Submarine’s Storefront API. It exposes one endpoint to process an upsell.

Create upsell
The current implementation of Upsells assumes that the addition of an upsold item to an order does not affect the shipping cost of the order. In this case, a single call to the API is all that is needed:

POST /api/v1/customers/:customer_id/orders/:order_id/upsells

with the following payload:

{
  "data": {
    "type": "upsell",
    "attributes": {
      "notify_customer": false,
      "quantity": "2",
      "variant_id": "12345678"
    }
  }
}

An example response might look like:

{
  "data": {
    "id": "0e874b10-4411-4b49-9ac5-1bd16ff3f179",
    "type": "upsell",
    "attributes": {
      "charge": {
        "amount": 10.0,
        "currency": "AUD",
        "id": "1cc8082c-f2ba-4a54-976a-d6486ad7805d",
        "presentment_amount": 6.96,
        "presentment_currency": "USD"
      }
      "notify_customer": false,
      "order_id": "4136101904454",
      "quantity": 2,
      "variant_id": "18390473867334"
    }
  }
}

An example response with charge error might look like:

{
  "data": {
    "id": "0e874b10-4411-4b49-9ac5-1bd16ff3f179",
    "type": "upsell",
    "attributes": {
      "charge": {
        "amount": 10.0,
        "currency": "AUD",
        "id": "1cc8082c-f2ba-4a54-976a-d6486ad7805d",
        "presentment_amount": 6.96,
        "presentment_currency": "USD"
      }
      "notify_customer": false,
      "order_id": "4136101904454",
      "quantity": 2,
      "variant_id": "18390473867334"
    }
  },
	"errors": [
    {
      "detail": "Insufficient funds.",
      "source": { "pointer": "" },
      "status": "400",
		  "title": "Charge Error"
    }
  ]
}

An example response with an order-editing error might look like:

{
  "data": {
    "id": "07c29c6d-685c-4c3a-beac-8e20a1a3ce50",
    "type": "upsell",
    "attributes": {
      "charge": null,
      "notify_customer": false,
      "order_id": 4593008771175,
      "quantity": 1,
      "variant_id": 39709151395943
    }
  },
  "errors": [
    {
      "detail": "The variant does not exist in the shop.",
      "source": { "pointer": "/data/variant_id" },
      "status": "422",
      "title": "Unprocessable Entity"
    }
  ]
}