---
title: "Build a Qikink plugin"
space: "Commera"
url: "https://docs.bwh.tech/commera/build-a-plugin/what-you-will-build"
updated: "2026-10-09"
---

In this tutorial, you build `commera_qikink`, a Commera plugin that sends store orders to [Qikink](https://qikink.com). Qikink is an Indian print-on-demand service. You list its products in your store, and when a shopper orders one, Qikink prints the item, packs it and ships it to the shopper. Your store keeps no stock of these items. The app sends each order to Qikink, buys the Qikink lines with a drop-ship Purchase Order, and shows the courier and tracking link when Qikink ships.

The finished plugin is public at [github.com/Rl0007/commera_qikink](https://github.com/Rl0007/commera_qikink). Each step of this tutorial is one commit in that repository, and each step page links to its commit.

## What each step adds

| Step | You add | You see it in |
| --- | --- | --- |
| 1. [Create the app](/commera/build-a-plugin/create-the-app) | A Frappe app with Commera's dashboard build | A **Qikink** row in the `/commera` sidebar |
| 2. [Add settings](/commera/build-a-plugin/add-settings) | A Qikink Settings DocType and its settings tab | **Settings > Installed plugins > Qikink** |
| 3. [Connect to Qikink](/commera/build-a-plugin/connect-to-qikink) | An API client with a shared, cached access token | A Qikink order read from `bench console` |
| 4. [Map products](/commera/build-a-plugin/map-products) | A Qikink SKU on each variant, a product card and a **Set Qikink SKUs** action | The product page in `/commera` |
| 5. [Block unmapped carts](/commera/build-a-plugin/block-unmapped-carts) | A hook that refuses a Qikink product with no SKU | The storefront checkout |
| 6. [Send paid orders](/commera/build-a-plugin/send-paid-orders) | An order event handler that sends each paid order to Qikink once | The order in the Qikink sandbox |
| 7. [Create drop-ship orders](/commera/build-a-plugin/create-drop-ship-orders) | A drop-ship Purchase Order for the Qikink lines | The Purchase Order in ERPNext |
| 8. [Add an order card and actions](/commera/build-a-plugin/order-card-and-actions) | An order card and a **Send to Qikink** action for cash on delivery orders | The order page in `/commera` |
| 9. [Keep status in sync](/commera/build-a-plugin/keep-status-in-sync) | An hourly status sync that records the shipment | The order status and the shopper's tracking link |
| 10. [Handle cancellations](/commera/build-a-plugin/handle-cancellations) | A cancel guard and a **Mark cancelled on Qikink** action | A refused cancel on the storefront and the order page |
| 11. [Add a Qikink orders page](/commera/build-a-plugin/qikink-orders-page) | A dashboard page with a sync action | A **Qikink orders** page in `/commera` |
| 12. [Add a palette command](/commera/build-a-plugin/add-a-palette-command) | A **Sync Qikink orders** command in the search palette | The Cmd+K palette in `/commera` |
| 13. [Test and ship](/commera/build-a-plugin/test-and-ship) | Tests for sending, tokens, the cart refusal and cancellations | `bench run-tests` |

## Requirements

- A bench with Commera and ERPNext installed on a site, and `developer_mode` turned on for that site.
- For step 9: a bwh_shipping release with partner shipments. The plugin records a shipment that Qikink made, with no carrier contract of your own.
- Node.js and Yarn. `bench commera init` runs `yarn install` in your plugin.
- A Qikink account. Get the sandbox keys at [dashboard.qikink.com](https://dashboard.qikink.com) under **Integration > Custom API**. You need the **Client ID** and the **Client Secret**. The Client ID is the same for sandbox and live, but the Client Secret is different.

:::tip[Set your git identity first]

`bench new-app` makes the first commit of your plugin at once, with the git identity of the shell user. Run `git config --global user.name` and `git config --global user.email` before you start.

:::

## How an order flows

A shopper orders a Qikink product in your storefront. Commera asks your plugin if the cart can check out, then tells your plugin when the order is paid. Your plugin sends the order to Qikink and polls Qikink for the status.

```mermaid
sequenceDiagram
    participant Shopper
    participant Commera
    participant Plugin as commera_qikink
    participant Qikink
    Shopper->>Commera: Place Order
    Commera->>Plugin: validate_cart hook
    Plugin-->>Commera: None, or a refusal message
    Commera->>Plugin: order_paid event, in a background job
    Plugin->>Qikink: POST /api/order/create
    Plugin->>Commera: Drop-ship Purchase Order
    Note over Commera,Plugin: Cash on delivery orders go with Send to Qikink
    loop Every hour
        Plugin->>Qikink: GET /api/order
        Plugin->>Commera: record_shipment with the AWB
    end
    Commera-->>Shopper: Courier and tracking link
```

## Next steps

- [Step 1: Create the app](/commera/build-a-plugin/create-the-app)
- [Overview](/commera/build-a-plugin/overview): what a Commera plugin can change
- [Events](/commera/plugin-reference/events): the order events your plugin can listen to
