← For developers

Developer docs

How to build, test and sell themes and apps for Oyklane stores.

How it works

Oyklane is an e-commerce platform for Indian brands. Sellers run their store from the Oyklane admin and add themes and apps from the Oyklane Store. You build them; Oyklane hosts the listing, takes the seller's payment and pays you your share.

  1. Create a developer account. Sign up with your email. Add your name or company, website and the UPI ID your earnings are paid to.
  2. Create a listing. Choose theme or app, name it, say what it does, set a price (free, or ₹99 and up) and add screenshots.
  3. Build and test. Themes: upload a .zip and click through it on our demo store. Apps: point the listing at your app and install it on your own test store.
  4. Send it for review. We check it works, is honest and asks only for what it needs. If something needs fixing, you get a note.
  5. Listed on the Oyklane Store. Approved listings show on the Oyklane Store, where sellers find them and install them in one click.
  6. Get paid. You keep 80% of every theme sale and of every paid app month, paid to your UPI ID.

Environments

  • Developer account — sign up here. Your listings, uploads, review notes and earnings live in your dashboard.
  • Theme preview — every upload runs on our demo store straight away, on every page with sample products, for you and our reviewers.
  • Test store for apps — make your own store at store.oyklane.com and install your app on it from your listing. Test with your own sample data, not a seller's store.
  • API — https://api.oyklane.com/api/v1. The key your app gets works only for the store that installed it.

Themes

Oyklane themes are Liquid, the same shape as Oyklane's own (Classic, Modern, Atelier, Fresh, Lumière). Your theme draws the home page, the header and footer, and the sections sellers place around pages. The platform draws product, collection, search, cart, checkout, account, order, blog and contact pages in your theme's colours and fonts, so checkout and payments work the same in every store.

my-theme/
  layout/theme.liquid            required — wraps every page
  templates/index.json           required — the home page's sections
  templates/product.json         optional — sections around the product page
  templates/collection.json, page.json, contact.json   optional, the same way
  sections/*.liquid              each with a {% schema %} for the editor
  snippets/*.liquid
  assets/*.css, *.js, *.svg
  config/settings_schema.json    required — theme settings in the editor
  config/settings_data.json      required — their starting values
  locales/*.json

Layout

<!doctype html>
<html lang="en">
<head>
  <title>{{ page_title }}</title>
  <link rel="stylesheet" href="{{ 'theme.css' | asset_url }}">
</head>
<body>
  {% section 'header' %}
  <main>{{ content_for_layout }}</main>
  {% section 'footer' %}
</body>
</html>

Sections

A section is a Liquid file with a {% schema %} listing its settings (and blocks, for repeatable items). Sellers add, reorder and edit sections in the visual editor; templates/index.json sets which sections the home page starts with.

<section class="rich-text">
  <h2>{{ section.settings.heading }}</h2>
  <p>{{ section.settings.text }}</p>
  <a href="{{ routes.all_products_url }}">Shop all</a>
</section>

{% schema %}
{
  "name": "Rich text",
  "settings": [
    { "type": "text", "id": "heading", "label": "Heading", "default": "Honest products" },
    { "type": "textarea", "id": "text", "label": "Text" },
    { "type": "select", "id": "align", "label": "Alignment", "default": "center",
      "options": [{ "value": "left", "label": "Left" }, { "value": "center", "label": "Centre" }] }
  ]
}
{% endschema %}

Product, collection, page and contact pages

These pages keep the platform's own main section (sys-product, sys-collection, sys-page, sys-contact), and your sections can go around it — add templates/product.json and so on for a starting layout. Cart and checkout can't be changed.

Rules

  • Upload a .zip of the folder: up to 6 MB unzipped, 512 KB a file, 600 files. Text files only: .liquid .json .css .js .svg .txt.
  • Every Liquid and JSON file is checked on upload; problems are listed file by file.
  • Build every link from routes (e.g. {{ routes.cart_url }}), never a fixed path — stores run on their own domains.
  • A paid theme's code is locked in the seller's store; they customise it in the editor.
  • Versions: upload 1.0.1, 1.1.0… and send each for review. Sellers who bought it can install the new version.

Liquid reference

Objects on every page

  • shop — name, handle, currency, support_email, support_phone, logo
  • routes — root_url, all_products_url, collections_url, cart_url, cart_add_url, search_url, account_url, blog_url, contact_url, pages_url…
  • collections (by handle), all_products, best_sellers, blog, linklists (menus)
  • cart, customer (when signed in), page_title
  • settings — your theme settings; inside a section, section.settings and block.settings

Oyklane filters and tags

  • {{ product.price | money }} and money_without_trailing_zeros — prices in the store's currency
  • {{ 'theme.css' | asset_url }} — a file from your assets/ folder
  • image_url, placeholder_svg, color_on (black or white text for a background colour)
  • {% section 'name' %} — places a section in the layout

Standard Liquid tags and filters work as usual (if, for, assign, capture, date, escape, url_encode…).

Apps

An app is your own web app, on your own server. When a store installs it, Oyklane makes an API key for that store with only the permissions your listing asks for, and sends it to your install webhook. Sellers open your app from their Apps page.

What you set on the listing

  • App link (https) — where sellers land when they open your app.
  • Install webhook (https) — install and uninstall events are posted here, signed with your app secret.
  • Permissions — the API scopes your app needs (below). Ask only for what it uses.
  • Storefront script (optional, https) — added to every page of stores that install your app, never checkout or payment pages.
  • Support email and privacy policy — needed for review.

Install webhook

POST <your install webhook>
X-Oyklane-Event: app.installed
X-Oyklane-Signature: <hex HMAC-SHA256 of the body>

{
  "event": "app.installed",
  "store": { "id": "…", "handle": "my-store", "name": "My Store", "url": "https://…" },
  "apiBase": "https://api.oyklane.com/api/v1",
  "apiKey": "oyk_…",          // only the permissions your listing asked for
  "scopes": ["read_products", "read_orders"],
  "at": "2026-10-08T10:00:00.000Z"
}

When it's removed you get app.uninstalled and the key stops working. Keep each store's key safe on your server.

Checking it's really from Oyklane

// Node: check a webhook from Oyklane
import crypto from "crypto";

function fromOyklane(rawBody, signatureHeader, secret) {
  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(String(signatureHeader)));
}

Opening your app

https://yourapp.com/oyklane?store=my-store&ts=1791450000&signature=<hex>
// signature = HMAC-SHA256("store=my-store&ts=1791450000", your app secret)
// Refuse links older than 5 minutes.

Pricing

Free, or a monthly price (₹99 or more) billed with the seller's Oyklane plan. You get 80% of every month that's paid.

API

Send the key as Authorization: Bearer oyk_…. Lists are paginated with ?page= and ?limit= (up to 100), newest first. Up to 240 requests a minute per key. Errors come back as { "error": "…" } with a 4xx status.

curl "https://api.oyklane.com/api/v1/products?page=1&limit=50" \
  -H "Authorization: Bearer oyk_…"

{ "data": [ … ], "page": 1, "limit": 50, "total": 132 }
MethodPathScopeNotes
GET/shop—The store's name, handle and currency
GET/products, /products/:idread_productsFilter with ?q= ?status= ?sku= ?handle=
POST, PATCH, DELETE/productswrite_productsCreate, edit, delete
GET, POST/categories, /collectionsread_products / write_products
GET/inventoryread_inventoryStock per variant
POST/inventory/adjustwrite_inventoryAdd or take away stock
GET/orders, /orders/:idread_orders
POST/orders/:id/fulfillmentswrite_ordersMark shipped with courier and tracking
POST/orders/importimport_ordersPast orders from another platform
GET, POST, PATCH/customersread_customers / write_customers
GET, POST/discountsread_discounts / write_discounts

Scopes

  • read_products — Read products, categories and collections
  • write_products — Create, edit and delete products, categories and collections
  • read_inventory — Read stock levels
  • write_inventory — Change stock levels
  • read_orders — Read orders
  • write_orders — Ship orders (add tracking)
  • import_orders — Import past orders (no payment, stock or messages)
  • read_customers — Read customers
  • write_customers — Create and edit customers
  • read_discounts — Read discounts
  • write_discounts — Create discounts

Review

  • It works on phones and desktops, and every page loads.
  • No tracking or scripts the listing doesn't mention; nothing that asks shoppers for payment details.
  • An honest description and screenshots — no claims you can't back up.
  • For apps: permissions only for what the app does; a support email and a privacy policy.

Questions? partners@oyklane.com