Oyklane API

Connect your store to a CRM, ERP, accounting software, a warehouse or your own app. Read and update products, stock, orders and customers over REST, and get signed webhooks the moment something happens.

  • REST and JSON
  • Signed webhooks with retries
  • Keys with only the access you choose

Get started

  1. Create a key. In your dashboard, open Settings ▸ API & webhooks and click Create key. Name it after the tool (“Zoho CRM”) and tick only the permissions it needs. API keys are part of the Pro plan.
  2. Copy it once. The key starts with oyk_ and is shown only when it's created — keep it in your tool's settings or a secrets manager, never in a web page.
  3. Make a call. Every request goes to https://api.oyklane.com/api/v1.
Your first request
curl https://api.oyklane.com/api/v1/shop \
  -H "Authorization: Bearer oyk_your_key"

Authentication

Send the key in the Authorization header as Bearer oyk_… (or in X-Oyklane-Key). A key only reaches its own store, and only what its permissions allow — a request outside them gets 403. Revoke a key any time from the same settings page; it stops working immediately.

PermissionAllows
read_productsRead products, categories and collections
write_productsCreate, edit and delete products, categories and collections
read_inventoryRead stock levels
write_inventoryChange stock levels
read_ordersRead orders
write_ordersShip orders (add tracking)
import_ordersImport past orders (no payment, stock or messages)
read_customersRead customers
write_customersCreate and edit customers
read_discountsRead discounts
write_discountsCreate discounts

Requests and pagination

Requests and responses are JSON. Lists return the newest first, 50 at a time: pass ?page=2&limit=100 (100 at most). Every list answers with { data, page, limit, total }. To sync only what changed, pass updated_since with the time of your last sync (ISO 8601, e.g. 2026-10-01T00:00:00+05:30). Amounts are in rupees (or the store's currency), not paise.

Paid orders changed since your last sync
curl "https://api.oyklane.com/api/v1/orders?payment_status=paid&updated_since=2026-10-01T00:00:00%2B05:30&limit=100" \
  -H "Authorization: Bearer oyk_your_key"

Endpoints

MethodPathPermissionWhat it does
GET/shopany keyYour store: name, handle, currency, time zone, domain.
GET/productsread_productsProducts, newest first. Filters: status, q (title or SKU), sku, handle, external_id, updated_since.
GET/products/{id}read_productsOne product with its variants and images.
POST/productswrite_productsCreate a product. category by name (made if new), images copied into your Files, externalId to import safely.
PATCH/products/{id}write_productsChange a product — send only the fields that change.
DELETE/products/{id}write_productsDelete a product.
GET/categoriesread_productsCategories. Filters: name, external_id.
POST/categorieswrite_productsCreate a category (name, image, externalId) — or get the one with that name.
GET/collectionsread_productsCollections with their product ids. Filter: external_id.
POST/collectionswrite_productsCreate a collection with productIds or productExternalIds.
GET/inventoryread_inventoryStock for every variant (variant_id, sku, quantity).
POST/inventory/adjustwrite_inventoryAdd to or set a variant's stock, with a reason.
GET/ordersread_ordersOrders, newest first. Filters: payment_status, fulfillment_status, created_since, external_id, updated_since.
GET/orders/{id}read_ordersOne order with line items, address and totals.
POST/orders/{id}/fulfillmentswrite_ordersShip items: courier, tracking number and link; the shopper is emailed.
POST/orders/importimport_ordersRecord a past order from another platform, with its date and number. No payment, stock change, messages or fees.
GET/customersread_customersCustomers, newest first. Filters: email, phone, external_id, updated_since.
GET/customers/{id}read_customersOne customer.
POST/customerswrite_customersCreate a customer — or fill in the one with that externalId, email or phone.
PATCH/customers/{id}write_customersChange a customer.
GET/discountsread_discountsDiscounts. Filters: code, external_id.
POST/discountswrite_discountsCreate a discount code — or get the one with that code or externalId.
Ship an order and email the tracking link
curl -X POST https://api.oyklane.com/api/v1/orders/ORDER_ID/fulfillments \
  -H "Authorization: Bearer oyk_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "courier": "Delhivery", "tracking_number": "1234567890", "notify_customer": true }'
Set a variant's stock from your warehouse
curl -X POST https://api.oyklane.com/api/v1/inventory/adjust \
  -H "Authorization: Bearer oyk_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "variant_id": "VARIANT_ID", "mode": "set", "quantity": 42, "reason": "received" }'

Example: an order

GET /orders/{id}
{
  "data": {
    "id": "cm8x2k…",
    "number": 1043,
    "email": "ananya@example.com",
    "phone": "+919876543210",
    "currency": "INR",
    "subtotal": 2199,
    "shipping": 100,
    "tax": 0,
    "total": 2299,
    "payment_method": "razorpay",
    "payment_status": "paid",
    "fulfillment_status": "unfulfilled",
    "gstin": null,
    "customer": { "id": "cm8w9q…", "name": "Ananya Sharma", "email": "ananya@example.com" },
    "shipping_address": { "name": "Ananya Sharma", "address1": "12 MG Road", "city": "Bengaluru", "province": "Karnataka", "zip": "560001", "country": "India" },
    "line_items": [
      { "id": "cm8x2m…", "product_id": "cm7…", "variant_id": "cm7…", "title": "Pure Linen Shirt — M", "quantity": 1, "price": 2199, "total": 2199 }
    ]
  }
}

Webhooks

Instead of asking every few minutes, let Oyklane tell you. In Settings ▸ API & webhooks, add an endpoint (an https:// URL of your server or your CRM's webhook URL) and pick its events. Oyklane sends a POST with the JSON body (the same shape as the API) within seconds.

EventWhen
order.createdA new order was placed
order.paidAn order was paid
order.fulfilledItems were shipped
order.deliveredAn order was delivered
order.cancelledAn order was cancelled
order.refundedAn order was refunded (fully or partly)
product.createdA product was created
product.updatedA product was changed
product.deletedA product was deleted
customer.createdA new customer was added

Answer with any 2xx within 10 seconds. Anything else is retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 6 hours. Every delivery is listed in your settings with its response, and you can send one again or send a test.

Verifying a webhook

Each request carries these headers. Check the signature before trusting the body, and ignore anything older than five minutes.

x-oyklane-eventThe event, e.g. order.paid
x-oyklane-deliveryA unique id — use it to ignore a repeat
x-oyklane-timestampUnix seconds when it was sent
x-oyklane-signaturesha256= + HMAC-SHA256 of {timestamp}.{raw body} with your endpoint's secret (whsec_…)
Node.js (Express)
import crypto from "node:crypto";

// Express: keep the raw body — the signature is over the exact bytes.
app.post("/oyklane-webhook", express.raw({ type: "application/json" }), (req, res) => {
  const ts = req.get("x-oyklane-timestamp");
  const sig = req.get("x-oyklane-signature"); // "sha256=…"
  const expected = "sha256=" + crypto
    .createHmac("sha256", process.env.OYKLANE_WEBHOOK_SECRET) // whsec_…
    .update(`${ts}.${req.body}`)
    .digest("hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
  if (!fresh || !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
    return res.sendStatus(401);
  }
  const event = req.get("x-oyklane-event"); // e.g. "order.paid"
  const payload = JSON.parse(req.body);
  // …send it to your CRM, then answer quickly:
  res.sendStatus(200);
});

Connect a CRM

The same four steps work for Zoho CRM, HubSpot, Salesforce, LeadSquared, Freshsales — or Zapier and Make if you'd rather not write code.

  1. Create a key with read_orders and read_customers (add write_orders if your CRM or warehouse should add tracking).
  2. Add a webhook for customer.created, order.paid and order.fulfilled. Point it at your server — or at the “catch hook” URL Zapier or Make gives you.
  3. Map the fields. Customer → contact (name, email, phone); order → deal or sale (number, total, status, line items). Use the customer's id as the external id so repeats update instead of duplicating.
  4. Backfill once. Page through /customers and /orders to bring in history; after that, webhooks keep the CRM up to date. A nightly call with updated_since catches anything a busy CRM missed.

Move a store to Oyklane

Bring a whole store across — from Shopify or anywhere — with one key that has write_products, write_customers, write_discounts and import_orders. Send each record's id from the old store as externalId (e.g. shopify:8123): it's unique in your store, so running the import again finds what it already made ("created": false) instead of duplicating it.

  1. Categories — POST /categories with a name. Or skip them and send category by name on each product.
  2. Products — image URLs are copied into your Files, so nothing depends on the old store. Variants are named by their option values, e.g. M / Red.
  3. Collections — link products with productExternalIds.
  4. Customers — matched by externalId, email, then phone; a match is only filled in, never overwritten.
  5. Discounts — imported codes stay off product pages unless you send showOnStore: true.
  6. Past orders — POST /orders/import keeps the date and number. Nothing a new order sets off happens: no payment, stock change, emails, WhatsApp, webhooks or Oyklane fees.
Import a past order
curl -X POST https://api.oyklane.com/api/v1/orders/import \
  -H "Authorization: Bearer oyk_…" -H "Content-Type: application/json" \
  -d '{"externalId":"shopify:5012","number":1042,"createdAt":"2026-03-02T10:15:00+05:30",
       "email":"asha@example.com","paymentMethod":"prepaid","paymentStatus":"paid",
       "fulfillmentStatus":"fulfilled","shipping":49,"total":548,
       "customer":{"name":"Asha Rao","phone":"+919876543210"},
       "shippingAddress":{"name":"Asha Rao","address1":"12 MG Road","city":"Bengaluru","province":"Karnataka","zip":"560001","country":"India"},
       "lineItems":[{"title":"Lakadong Turmeric 250g","sku":"TUR-250","quantity":2,"price":249.5,"productExternalId":"shopify:771"}],
       "courier":"Delhivery","trackingNumber":"1234567890"}'

AI agents (MCP)

The same API is available as a Model Context Protocol server at https://api.oyklane.com/api/mcp, so AI assistants can look up orders, products and stock with your key — with the same permissions and limits.

Errors and limits

StatusMeaning
400Something in the request isn't valid — the error field says what.
401No key, or the key was revoked.
403The key doesn't have the permission this needs.
404Not found in this store.
429More than 240 requests a minute with this key — wait a moment and retry.

Questions about the API? Ask the Help assistant in your dashboard. Building a theme or an app for other stores? See the integrations guide.