# Katana

Source: https://developers.swell.is/app-guides/katana

The Katana app connects Swell to Katana, the manufacturing and inventory software. Paid orders become Katana sales orders, with each item matched to a Katana variant by SKU. When a sales order is delivered in Katana, the app fulfills the Swell order with the carrier and tracking number.

Katana is the source of truth for stock. The app sets Swell stock to Katana's stock at your location every 5 minutes for the items that moved, and for every item once an hour. It checks Katana on a schedule, so changes made in Katana reach Swell within about 5 minutes.

## How it works

| When | What the app does |
| --- | --- |
| An order is paid, or submitted if you choose | Creates a Katana sales order with the customer, addresses, items matched by SKU and the shipping fee. |
| An order is canceled | Deletes its Katana sales order if it isn't packed or delivered yet, unless you turn this off. |
| Every 5 minutes | Copies the status and tracking of sales orders changed in Katana to their Swell orders, and creates a shipment when a sales order is delivered. Sets the Swell stock of items that moved in Katana. |
| Every hour | Starts a stock sync task that sets Swell stock from all Katana stock at your location. |
| You start a task under Katana tasks | Syncs all stock from Katana, sends existing orders to Katana, or creates your Swell products in Katana. |
| You choose Send to Katana on an order | Sends that order to Katana now, for example after you fix a SKU. |

## Before you begin

- A Katana account where you can create API keys, under **Settings > API**.
- A Katana location that ships your Swell orders. Its stock is the stock copied to Swell.
- The same SKUs in Swell and Katana: on the product for products without options, and on each variant for products with options. Products that aren't in Katana yet need a SKU and stock tracking on, so the app can create them there.
- Stock tracking on for the Swell products whose stock should follow Katana. Products with stock tracking off keep their Swell stock.

## Set up

Install Katana from the Swell App Store, and set it up in your test environment before the live one.

**1. Create an API key**

In Katana, go to **Settings > API**, and under **API keys** click **Add new API key**. Copy the key.

**2. Decide where stock starts**

Once the API key and location are saved, Swell stock follows Katana's stock at that location for every product with stock tracking on and a SKU that's in Katana. If Katana doesn't have your stock yet, turn off **Sync stock from Katana automatically** before you save the **Location ID** in the next step, and copy your stock to Katana first, as described under **Creating products in Katana**.

**3. Connect Katana**

In Swell, go to **Apps > Katana > Settings**, enter the **API key** and click **Save settings**. Choose **Actions > Test connection**. The message lists your Katana locations and tax rates with their IDs, such as `101 = Main warehouse`.

Enter the **Location ID** of the location that ships your Swell orders, and optionally a **Tax rate ID**. In the test environment, set **Sales order number prefix** to something like `TEST-`, so test sales orders are easy to spot in Katana. Click **Save settings**, then run **Test connection** again to check the IDs.

**4. Sync stock**

Once Katana has your stock, check that **Sync stock from Katana automatically** is on and choose **Actions > Sync stock from Katana**. Open **Katana tasks** in the dashboard sidebar and open the task. **Stock changes** lists each Swell stock level it changed, **SKUs not in Swell** counts the Katana SKUs it couldn't match, and **SKUs on several Swell items** lists SKUs that need fixing.

**5. Place a test order**

Place and pay for a test order with a product that's in Katana. The order's **Katana** tab shows the sales order number and the status `NOT_SHIPPED`, and the sales order is in Katana. Mark the sales order as delivered in Katana with a tracking number. Within 5 minutes, or right away with **Actions > Get updates from Katana** in the app settings, the order shows `DELIVERED` and the tracking number, and has a new shipment.

Test orders create real sales orders in your Katana account, and delivering them changes Katana's stock. To remove a test sales order before it's packed, cancel the order in Swell.

**6. Go live**

Settings are saved separately for each environment. In the live environment, repeat steps 2 to 4. You can use the same API key.

To send orders placed before you installed the app, open **Katana tasks**, click **Send orders to Katana**, set **Created on or after** and click **Start**. Orders that are fully fulfilled in Swell are skipped. Each sales order commits stock in Katana until it's delivered there, so choose a date that leaves out old orders.

While the test environment is connected, its orders also create sales orders in Katana. To stop that, turn off **Enabled** in the test environment.

## Using Katana

### Matching by SKU

The app matches Swell items to Katana variants by SKU: the variant's SKU for products with options, and the product's SKU for products without. Each SKU must be on only one Swell product or variant, because one Katana variant can't feed several Swell stock levels. The check covers your whole catalog, including products with stock tracking off. For a SKU on more than one Swell product or variant:

- Orders with that item aren't sent to Katana.
- Stock syncs and 5-minute checks leave those items unchanged, and list the SKU under **SKUs on several Swell items**.
- **Create products in Katana** doesn't create the product.

### Orders to Katana

When an order is paid, or submitted if **Send orders to Katana when** is set to that, the app creates a Katana sales order at your location with:

- The customer, found in Katana by email or created with the order's addresses. The Katana customer ID is saved on the Swell customer and used for their later orders.
- The billing and shipping addresses, the currency, the order date and the order comments.
- One row per item, with the quantity, price, item discount and the **Tax rate ID**, if set.
- The shipping price as a shipping fee, named after the shipping service.

The sales order number is **Sales order number prefix** followed by the Swell order number, such as `SW-1001`. Physical items and digital items whose product has stock tracking on are sent. Gift cards, subscriptions and digital items without stock tracking are left out, and an order with none of the sent items isn't sent.

If an item has no SKU, a SKU that isn't in Katana, or a SKU on more than one Swell product or variant, nothing is created in Katana, and **Error** on the order's **Katana** tab lists the SKUs. These orders aren't retried. Fix the SKUs, then choose **Actions > Send to Katana** on the order.

If Katana rate-limits the app, has a server error or can't be reached, Swell sends the order again later. Other Katana errors are shown in **Error** and aren't retried. Before creating a sales order, the app looks for one with the Swell order's ID in Katana and links it instead, so an order is never created twice. Changes to a Swell order after it's sent aren't sent to Katana.

### Canceled orders

When a Swell order is canceled, the app deletes its Katana sales order while the sales order is `NOT_SHIPPED` or `PENDING`, and the order's status becomes `DELETED`. A packed or delivered sales order is kept, and **Error** says so. To keep the sales orders of canceled orders, set **When a Swell order is canceled** to **Do nothing**.

### Status, tracking and shipments

Every 5 minutes the app reads the sales orders it created that changed in Katana, and copies each one's status, tracking number and tracking URL to the Swell order's **Katana** tab. A sales order deleted in Katana shows `DELETED`.

When the whole sales order is `DELIVERED`, the app creates a Swell shipment for the physical items still to ship, with the carrier, method and tracking number from the Katana fulfillment. Digital items aren't put in a shipment, so an order with only digital items gets the `DELIVERED` status and no shipment. With **Create Swell shipment when delivered in Katana** off, the status and tracking are copied but the order isn't fulfilled.

### Stock from Katana

With **Sync stock from Katana automatically** on, the app sets the stock of each Swell product or variant whose SKU is in Katana to Katana's stock at your location:

- Every 5 minutes, for the items with stock movements at the location since the previous check.
- Every hour, with a stock sync task that reads all Katana stock at the location. Changes that don't create a stock movement in Katana reach Swell this way.

The level is **In stock minus committed** or **In stock**, as set in **Stock quantity to use**, rounded down to whole units. Negative stock in Katana becomes the same negative level in Swell. Only products with stock tracking on are changed. Each change is a stock adjustment, so the product's stock history shows `Katana stock sync` with the location and the old and new levels, and the product's **Katana** tab shows when Katana last changed its stock.

Until an order is in Katana as a sales order, Katana doesn't count its items, so a stock sync can put back the stock the order took in Swell, for example when the order failed to send.

### Creating products in Katana

To create Swell products in Katana, choose **Actions > Create products in Katana** in the app settings, or click **Create products in Katana** on **Katana tasks**, then **Create**. The task goes through every Swell product with stock tracking on:

- Each product is created in Katana with its variants. Swell options become Katana variant options, such as `Color: red`, with the Swell price as the sales price and the cost as the purchase price.
- SKUs already in Katana aren't created again. When a product is partly in Katana, only its missing variants are added.
- For each item with Swell stock whose Katana variant has no stock at your location, 0 or less, the app adds a Katana stock adjustment named **Starting stock from Swell**, so Katana's stock equals the Swell stock. With **In stock minus committed**, quantities committed in Katana are added. Variants with stock in Katana are left alone.
- Items without a SKU are skipped, and products with a SKU on another Swell product or variant aren't created.

Errors start with `Product export` and are shown in **Error** on the product's **Katana** tab. You can run it again at any time. It doesn't update names, prices or options of products already in Katana.

Products and stock adjustments are created in the Katana account of the API key, so run it in the environment whose Swell stock is right. To copy Swell stock to Katana before Swell starts following it, keep **Sync stock from Katana automatically** off, run **Create products in Katana**, wait for the task to show **Completed**, then turn the setting on.

### Katana tasks

Long syncs run as tasks under **Katana tasks** in the dashboard sidebar, one page per step. Each task shows its status, the items checked, updated, skipped and failed, when it started and finished, and the last error. Only one task of each kind is active at a time.

- **Sync stock from Katana** sets Swell stock from all Katana stock at the location. The hourly schedule starts one too, and completed hourly tasks are removed after 3 days. The task lists the Swell stock it changed under **Stock changes**, up to 2,000 rows.
- **Send orders to Katana** sends paid orders that aren't in Katana yet, or all orders when they're sent on submit, optionally only those created on or after a date. Canceled orders, fully fulfilled orders and orders with nothing for Katana are skipped. Each sales order commits stock in Katana until it's delivered there, so set a date to leave out old orders. Orders Katana rejects get the error on their **Katana** tab, and the task carries on.
- **Create products in Katana** creates your Swell products in Katana, as described above.

When Katana rate-limits the app or has a server error, the task shows **Waiting to retry** and continues by itself: after 1 minute for rate limits, otherwise after 1, 2, 4 and up to 30 minutes. It fails after 8 retries in a row. Other errors, such as a rejected API key, fail the task right away. To stop a task, open it and choose **Cancel**. To continue a failed or canceled task where it stopped, or retry a waiting task now, choose **Resume**.

### Katana pulls

**Katana pulls** in the dashboard sidebar logs each 5-minute check that changed something in Swell. Each check shows what was checked, **Sales orders** or **Stock**, the Swell orders or stock levels updated, the sales orders or SKUs not in Swell, the failures and the last error. Stock checks also list their **Stock changes**. The **With errors** tab lists the checks with an error.

Checks that change nothing aren't logged, and neither are stock checks whose only finding is SKUs that aren't in Swell, such as materials. Each check reads the changes since the previous completed check started, minus a minute. A check that runs out of time or gets an error from Katana shows **Continues next run**, and the next check carries on from there.

### Actions

The **Actions** menu in the app settings has these actions. Save the settings before you run them.

- **Test connection** checks the API key, lists your Katana locations and tax rates with their IDs, and says if the **Location ID** or **Tax rate ID** isn't in Katana.
- **Get updates from Katana** runs the 5-minute check now and says what it changed.
- **Sync stock from Katana** starts a stock sync task.
- **Create products in Katana** starts a product export task.

On an order, **Actions > Send to Katana** sends the order now. It also sends an order again after its sales order was deleted. Canceled orders aren't sent.

### In the dashboard

| Where | What it's for |
| --- | --- |
| Apps > Katana > Settings | The API key, location, tax rate, order and stock settings, and the Enabled switch, with the Actions menu. |
| Katana tasks in the sidebar | Stock syncs, order syncs and product exports with their progress, and the buttons that start them. |
| A task | Its status and counts, the stock changes, the SKUs on several Swell items, the last error, and Cancel or Resume. |
| Katana pulls in the sidebar | The 5-minute checks that changed something in Swell, and the checks with errors. |
| The order list | A Katana column with each order's sales order status. |
| An order's Katana tab | The sales order number and ID, status, Katana customer ID, tracking number and page, when it was last synced, and the last error. |
| An order's Actions menu | Send to Katana. |
| A product's Katana tab | When Katana last changed the product's stock, and the last product export error. |
| A product's stock history | A Katana stock sync adjustment for each change, with the location and the old and new levels. |

## Settings

Settings are in **Apps > Katana > Settings** and are saved separately for each environment.

| Setting | Description | Default |
| --- | --- | --- |
| API key | From Katana > Settings > API. Masked on the settings page. Required. | None |
| Location ID | The Katana location that ships Swell orders and whose stock is copied to Swell. Test connection lists the IDs. Required. | None |
| Tax rate ID | Optional. The Katana tax rate set on every sales order row and on the shipping fee. Test connection lists the IDs. | Katana's default |
| Send orders to Katana when | Order is paid or Order is submitted. | Order is paid |
| Sales order number prefix | Put before the Swell order number to make the Katana sales order number, such as SW-1001. | SW- |
| When a Swell order is canceled | Delete the Katana sales order if it isn't packed or delivered yet, or do nothing. | Delete the Katana sales order (if not shipped yet) |
| Create Swell shipment when delivered in Katana | Fulfills the Swell order with the carrier and tracking number when the whole sales order is delivered. With it off, the status and tracking are still copied. | On |
| Sync stock from Katana automatically | Sets Swell stock from Katana by SKU, every 5 minutes for items that moved and with an hourly stock sync task. Only products with stock tracking on are changed. With it off, Sync stock from Katana doesn't run either. | On |
| Stock quantity to use | In stock minus committed, or In stock. With In stock, a stock sync can put Swell stock back up after a sale until the sales order is delivered in Katana. | In stock minus committed |
| Sync job page size | Katana stock rows or Swell orders read per task step, from 1 to 250. Product exports read up to 100 products per step. | 50 |
| Sales orders last checked | Read-only. When the last completed check of sales orders started. The next check reads changes from a minute before. | None |
| Stock last checked | Read-only. When the last completed check of stock movements started. The next check reads changes from a minute before. | None |
| Enabled | Turns off sending orders and cancellations, the 5-minute checks, the hourly stock sync and the actions, except Test connection, without uninstalling the app. Running tasks fail with a message. | On |

## Limitations

- Items are matched by SKU only. An order with any item that has no SKU, or a SKU that isn't in Katana, isn't sent at all.
- One Katana location ships all Swell orders, and only its stock is copied to Swell.
- Stock goes from Katana to Swell. Swell stock reaches Katana only as the starting stock that **Create products in Katana** sets for items with no stock in Katana.
- Products are created in Katana once. Later changes to names, prices or options aren't sent, and Katana products aren't created in Swell.
- Changes to a Swell order after it's sent, such as its items or address, aren't sent to Katana. Canceling a Swell order doesn't delete a packed or delivered sales order.
- The Swell shipment is created when the whole sales order is delivered. Partial deliveries in Katana aren't mirrored.
- Changes in Katana reach Swell at the next 5-minute check, and stock changes without a stock movement at the next hourly stock sync.
- Digital items with stock tracking go to Katana like physical ones. Mark their sales orders delivered in Katana, even though nothing ships, so Katana deducts their stock.
- Prices are sent as Swell has them, without Swell's tax amounts. Each row and the shipping fee get the **Tax rate ID**, or Katana's default.
- Katana allows 60 API requests a minute. Large tasks take several minutes and wait out rate limits.
- Each check and task step works for about 7 seconds, within the 10-second limit of Swell functions.
- A stock sync task and a 5-minute check that change the same item at the same moment can both apply the difference. The next stock sync corrects it.
- Each environment uses the Katana account of the API key entered in it. Test orders create real sales orders, and test stock follows the Katana location set in the test environment.

## Troubleshooting

Errors are shown in **Error** on an order's or product's **Katana** tab, on the task under **Katana tasks**, and in **Last error** under **Katana pulls**. The app also logs them. In the Swell dashboard, the logs are under **Developer > Console > Logs**.

### Test connection fails

An error starting with `Katana 401` means Katana didn't accept the API key. Check that you copied the whole key, saved it, and haven't deleted it in Katana. If the message says the **Location ID** or **Tax rate ID** doesn't exist in Katana, enter an ID from the list in the message and save.

### An order isn't sent to Katana

Check that **Enabled** is on, that the **API key** and **Location ID** are saved, and that the order is paid, or submitted, as **Send orders to Katana when** requires. Canceled orders aren't sent. Orders with only gift cards, subscriptions or digital items without stock tracking aren't sent. If sending failed, **Error** on the order's **Katana** tab says why. To send it again, choose **Actions > Send to Katana**.

### "Not found in Katana (by SKU): …"

An item has no SKU, shown as the product name followed by `(no SKU)`, or a SKU that no Katana variant has. Add the SKU in Swell or the variant in Katana, then choose **Actions > Send to Katana** on the order.

### "Same SKU on more than one Swell product or variant: …"

Give each Swell product or variant its own SKU, matching its Katana variant. Then choose **Actions > Send to Katana** on the affected orders, and run **Sync stock from Katana**. Stock syncs and checks list the same SKUs under **SKUs on several Swell items**.

### "Shipping fee not added: …"

The sales order was created, but Katana didn't accept the shipping fee. Add the fee to the sales order in Katana.

### "Order canceled in Swell, but the Katana sales order is … and was not deleted"

The sales order was already packed or delivered when the Swell order was canceled, so the app kept it. Handle the sales order in Katana.

### An order isn't fulfilled after delivery in Katana

The shipment is created when the whole sales order is delivered, at the next 5-minute check, or right away with **Actions > Get updates from Katana**. Check that **Create Swell shipment when delivered in Katana** and **Enabled** are on. Orders with only digital items get no shipment, and items already shipped in Swell aren't shipped again.

### Swell stock doesn't follow Katana

Check that **Sync stock from Katana automatically** and **Enabled** are on, that the product has stock tracking on, and that its SKU, or each variant's SKU for products with options, matches the Katana variant. Only the stock at the **Location ID** location is copied. Changes without a stock movement in Katana arrive with the hourly stock sync, and **Sync stock from Katana** gets them now. On the task, **SKUs not in Swell** and **SKUs on several Swell items** show what wasn't matched.

### Swell stock dropped after setup

Swell stock follows Katana's stock at your location, so items Katana has no stock of drop to 0 or below. The task's **Stock changes** and the product's stock history show the levels before the change. To copy Swell stock to Katana, turn off **Sync stock from Katana automatically**, set the Swell stock again, and run **Create products in Katana**, which sets Katana's stock for items with no stock there. Then turn the setting back on.

### A task is waiting or failed

**Waiting to retry** means Katana rate-limited the app or had an error, and the task continues by itself. A task fails after 8 retries in a row, or right away on other errors, and **Error** says why. A task also fails with `The Katana app is turned off in settings` when **Enabled** is off, and a stock sync with `"Sync stock from Katana automatically" is off in the app settings`. Fix the cause, then open the task and choose **Resume**.

### "The Katana app is turned off. Turn on "Enabled" in the app settings first."

**Enabled** is off, so the actions other than **Test connection** don't run. Turn on **Enabled**, click **Save settings**, and try again.

### A check shows Continues next run

The check ran out of time or got an error from Katana, and the next check continues where it stopped. If **Last error** repeats on every check, for example after the API key was deleted in Katana, fix the cause.

### Katana pulls shows sales orders not in Swell

The check found sales orders created by the app that don't belong to an order in this environment, such as sales orders from the other environment when test and live use the same Katana account.

## Uninstalling

Uninstalling the app stops sending orders and cancellations to Katana, the 5-minute checks and the hourly stock sync, so Swell stock no longer follows Katana. It removes the app's settings, including the API key, and removes **Katana tasks**, **Katana pulls**, the **Katana** tabs and column and **Send to Katana** from your dashboard. Uninstalling applies to the environment you are in, so remove the app from the test and live environments separately.

The Katana values on your orders, customers and products, and the records under **Katana tasks** and **Katana pulls**, are kept and come back if you reinstall. Swell shipments and stock adjustments the app made stay as they are. Sales orders, customers, products and stock adjustments in Katana stay there. The app isn't notified when it's uninstalled, so if you no longer need the API key, delete it in Katana under **Settings > API**.

After a reinstall, enter the settings again. The first check reads Katana changes from the hour before, so run **Sync stock from Katana** to bring stock up to date. Sales orders that changed in Katana before that hour aren't updated in Swell until they change again.

## For developers

| Function | Runs on | What it does |
| --- | --- | --- |
| order-events | order.submitted, order.paid and order.canceled | Sends the order on the event chosen in the settings, and deletes the sales order of a canceled order. |
| katana-poll | Every 5 minutes | Copies sales order changes and the stock of moved items from Katana to Swell, and logs checks that changed something. |
| inventory-sync | Every hour, at 2 minutes past | Starts a stock sync task unless one is active, and removes hourly tasks completed more than 3 days ago. |
| sync-run | sync.created and sync.updated, while the task is pending or running | Runs one step of a task and saves the progress. Saving it starts the next step. |
| sync-retry | The task's retry time, while it's waiting | Sets the task back to pending, so sync-run retries the step. |
| sync-control | The Cancel and Resume actions | Sets the task to canceled, or back to pending. |
| katana-actions | The settings actions, the Katana tasks buttons and Send to Katana | Tests the connection, runs a check, starts a task, or sends one order. |

The app stores its fields under `$app.katana`. Orders have `katana_sales_order_id`, `katana_order_no`, `katana_customer_id`, `katana_status`, `katana_tracking_number`, `katana_tracking_url`, `katana_shipment_id`, `katana_synced_at` and `katana_error`. Accounts have `katana_customer_id`. Products have `katana_stock_synced_at` and `katana_error`.

Tasks are stored in the app collection `apps/katana/syncs`, with `type` (`inventory`, `orders` or `products`), `trigger`, `status`, `date_from`, `page`, `last_id`, `pages`, `checked`, `changed`, `skipped`, `not_found`, `failed`, `adjusted`, `duplicate_skus`, `report`, `report_rows`, `total`, `last_error`, `retries`, `date_retry`, `date_started` and `date_completed`. Checks are stored in `apps/katana/pulls`, with `source` (`sales_orders` or `inventory`), `status`, `changed`, `not_found`, `failed`, `duplicate_skus`, `report`, `report_rows`, `date_cursor`, `date_pass_started`, `page`, `date_completed`, `last_error` and `date_last_error`. To start a task without the dashboard, create a `syncs` record with `type`, and `date_from` for an order sync.

The app calls the Katana API at `https://api.katanamrp.com/v1` with the API key as a Bearer token. Sales orders are created with `ecommerce_order_type` set to `swell`, `ecommerce_store_name` set to the store ID and `ecommerce_order_id` set to the Swell order ID, which the app looks up before creating one. The app polls Katana rather than using Katana webhooks: `GET /sales_orders` with `ecommerce_order_type=swell`, `updated_at_min` and `include_deleted=true`, and `GET /inventory_movements` with `location_id` and `created_at_min`, then `GET /inventory` for the moved variants. Each source has its own checkpoint in the settings, `orders_checked_at` and `stock_checked_at`, written with `$events: false`. The first check looks back 1 hour.

Stock changes are `products:stock` adjustments for the difference. When Katana returns 429 with a `Retry-After` of up to 3 seconds, the app waits once. For Katana 429 and 5xx errors and network errors, `order-events` throws a `SwellError` with `retry: true`, so Swell delivers the event again. Checks and task steps stop starting new work after 7 seconds.

## Support

Swell builds and maintains the Katana app. For help with the app, email support@swell.is. For questions about your Katana account, contact Katana.
