Skip to main content
Skip table of contents

Order Processing

About

Simply put an Order is a collection of line items. A line item is a product times quantity. Order processing revolves around figuring available shipping options for the set of line items, pricing and taxes, availability and once the shipping has been chosen and payment made inserting the order into the merchant’s store.

Price discrepancies

It might occur that the product on Katalys’s side was priced differently than the same product in the merchant’s store. This is usually due to legal agreements between Katalys and the merchant. To account for possible differences the integration should ensure line items prices of the inserted order match those coming from Katalys GraphQL API order.lineItems.price.

This can usually be achieved by changing line items on the inserted order. Options vary between the price or applying discounts on individual line items.

Firing order related directives from the UI

Preconditions

  1. You successfully imported a product - Importing Products

Setup a test payment gateway to accept a test credit card

  1. Click Settings - left menu, bottom

  2. Click Payments & Payouts

  3. Click Manual Integration

  4. Input Live API Keys

    1. Reach out to Katalys to get them

Steps

  1. Create a shop

    1. visit Products - left menu

    2. Chose a product in the list, click three dots - right side of the row

    3. Click create Shop

  2. Preview the shop

    1. visit Shops - left menu

    2. click on a shop

    3. click “Preview“ - top right

  3. Performing a purchase

    1. Click on BuyNow and follow through till the end

      1. Test card - repeat “42” until all fields are filled.
        This will results in: 4242 4242 4242 4242 04/24 242

    2. Expect an order to in the Orders list - left menu

    3. Expect directives being fired and recorded in the Store’s Log tab

      1. Settings, Stores, Store, Log

Servicing the update_available_shipping_rates directive

When an order on Katalys is created or updated, Katalys might issue this directive to your integration.

JSON
{
  "directives": [
    {
      "args": {
        "order_id": "91997424-0c62-4525-8043-f00de23cb91c"
      },
      "directive": "update_available_shipping_rates",
      "id": "45a42385-8ebd-45bb-9ac8-c7365aa157ac"
    }
  ]
}

Once your integration has calculated shipping rates for the given order, it should use a mutation to update the order with this new information:

GRAPHQL
mutation UpdateShippingRatesExample($id: ID!, $input: OrderInput!) {
  updateOrder(id: $id, input: $input) {
    id
    shippingRates {
      handle
      amount
      title
    }
  }
}
JSON
{
  "id": "235c9162-80c2-4fd4-9eb8-e398ed130329",
	"input": {
		"shippingRates": [
			{
			  "handle": "economy-international-4.50",
			  "title": "Economy International",
			  "amount": 450
			},
			{
			  "handle": "express-international-15.0",
			  "title": "Express International",
				"amount": 1500
			}
		]
	}
}

Each shipping rate is specified with the following fields:

  • handle is internal to you, the integrator. In the above example, the format is borrowed from Shopify and includes the amount (which makes it work like a cache key, smart!)

  • title is the title that Katalys will display to the buyer during the checkout process (among other places)

  • amount is the decimal amount represented in cents (as an integer). You should assume that the currency here is the same as the one used on the order (but let’s talk about this soon to see if the assumption is sane).

When shipping rates for an order can’t be calculated, Katalys expects the integration to set the shippingRatesError field instead. For example, let’s consider the case where an order can’t be shipped to a given country:

JSON
{
  "id": "235c9162-80c2-4fd4-9eb8-e398ed130329",
	"input": {
    "shippingRatesError": {
	    "code": "no_shipping_rates",
	    "userMessage": "Unfortunately, we're unable to ship to your address.",
	    "details": "(This is optional.)"
    }
	}
}

"no_shipping_rates" is the only recognized error code at the moment of writing. However, your integration is free to set custom error codes for other purposes.

Servicing the update_tax_amounts directive

JSON
{
  "directives": [
    {
      "args": {
        "order_id": "91997424-0c62-4525-8043-f00de23cb91c"
      },
      "directive": "update_tax_amounts",
      "id": "6e1efe64-2f37-40c4-8198-c8b7827dba5d"
    }
  ]
}

As the name suggests, this directive expects your integration to update tax amounts for a given order, according to the amounts calculated by the Merchant’s e-commerce platform.

There are two fields to update:

  • Mandatory: the totalTax field on Order should contain the total tax amount for the order, calculated based on the line items and the totalShipping amount (where applicable). This field is mandatory because it precludes the calculation of the order grand total. If the tax amount is zero (e.g. due to tax exemption) a value of 0 must be specified. A value of null signals that the tax still hasn’t been calculated, in which case the integration must indicate a failure in the response (see Forming a response below).

  • Optional: the tax field on each LineItem should contain the tax amount for that specific line item. This field is for evidence only and does not directly affect the total tax amount on the order (totalTax should to be independently set as described in the previous step)

GRAPHQL
mutation UpdateTaxAmountsExample($id: ID!, $input: OrderInput!) {
  updateOrder(id: $id, input: $input) {
    totalTax
    lineItems {
      tax
    }
  }
}
JSON
{
  "id": "235c9162-80c2-4fd4-9eb8-e398ed130329",
  "input": {
    "totalTax": 250,
    "lineItems": [
      {
        "id": "4af7128c-7f22-4efb-9f85-25bbc23d82e2",
        "tax": 150
      }
    ]
  }
}

💰 totalTax and tax, like other money amounts, must be represented in cents. For example, the amount 12.99 is represented as the integer value 1299.

🧾 usProductTaxCode - For products that are either exempt from sales tax in some US jurisdictions or are taxed at reduced rates, a Product might have a tax code stored in the usProductTaxCode field. The codes are specified by TaxJar. The product can be accessed through a LineItem, using product and variant fields.

Servicing the update_availability directive

JSON
{
  "directives": [
    {
      "args": {
        "order_id": "91997424-0c62-4525-8043-f00de23cb91c"
      },
      "directive": "update_availability",
      "id": "ee4d346f-de86-4285-934c-a9f1b9c5c0ed"
    }
  ]
}

During checkout, there comes a time when the system must check inventory levels to determine if enough items are in stock to satisfy the order.

Katalys will issue this directive to the integration, which in turn should update each line item to signal its availability (or lack thereof).

The checkout process will only be allowed to continue if all line items are available.

GRAPHQL
mutation UpdateAvailabilityExample($id: ID!, $input: OrderInput!) {
  updateOrder(id: $id, input: $input) {
    id
    lineItems {
      id
      available
    }
  }
}
JSON
{
  "id": "235c9162-80c2-4fd4-9eb8-e398ed130329",
  "input": {
    "lineItems": [
      {
        "id": "711d0515-0dca-445d-b2a2-1478547763f9",
        "available": false
      },
      {
        "id": "fe46588f-57ea-4b5b-9970-25687b59286b",
        "available": false
      }
    ]
  }
}

💼 An integration should consult the merchant’s inventory levels. It should also check whether a product is allowed to still be sold when stock reaches zero (in which case the line item should be marked as available).

Servicing the complete_order directive

This directive is sent when an Katalys order’s paymentStatus changes to paid.

To service this directive the integration must update the Katalys order’s fulfilmentStatus to "FULFILLED" and set the externalId value to the order id used by the eCommerce stack. Example: gid://shopify/Order/5113822838965 - Shopify order id

GRAPHQL
mutation CompleteOrder($id: ID!, $input: OrderInput!) {
  updateOrder(id: $id, input: $input) {
    id
    fulfillmentStatus
  }
}
JSON
{
  "id": "235c9162-80c2-4fd4-9eb8-e398ed130329",
  "input": {
		"fulfillmentStatus": "FULFILLED"
		"externalId": "gid://shopify/Order/5113822838965"
	}
}

This is the time when your integration should insert an order into the Merchant’s store.

🧠 Note that Katalys could issue this directive more than once for the same order, so it must be serviced in an idempotent way – i.e., running it multiple times with the same order ID only results in a single order in the Merchant’s store.

Your integration might want to store additional metadata on the order through the Katalys GraphQL API. Read more about the externalData field.

Forming a response

Once your integration is done servicing the directives and updating the order, it should form a response to the initial POST request that issued the directives. The response should have a 200 status if everything went OK and the directives could be successfully performed. In every other case the response should be non-200. We can decide on the format of the response, but for now this we recommend this (a list of objects, one for each received directive):

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.