Omnikyo/Help Center
Reference

Website connection for developers

A developer building a Laravel or plain PHP website uses this to send orders and track campaigns into Omnikyo — the API endpoint, the helper file, the script tag, all field specs and response codes.

বাংলায়: ওয়েবসাইট ডেভেলপার Omnikyo API ব্যবহার করে অর্ডার পাঠায় এবং প্রচারাভিযান ট্র্যাক করে। এই পৃষ্ঠায় API endpoint, helper file, script tag এবং সমস্ত ফিল্ড স্পেসিফিকেশন রয়েছে।

This page has everything a developer needs to connect a website to Omnikyo: the API endpoint, field specifications, response codes, the helper file, the script tag for tracking, and SKU matching rules.

Orders API: POST /api/v1/orders

Send one order to https://omnikyo.com/api/v1/orders. The request must come from your server, not a browser.

Authentication

Pass the secret key in one of these headers:

  • Authorization: Bearer sk_live_…
  • X-Omnikyo-Key: sk_live_…

A browser request (has an Origin header) is refused 400 browser_request with the message "Send orders from your server (PHP), not from browser JavaScript: the secret key would be visible to every visitor. Use the helper file from Omnikyo Settings."

Body

Send JSON with Content-Type: application/json. Maximum 256 KB per request. One order per request.

FieldRequiredTypeLimitsRules
order_numberyestextmax 100Your site's own order id (the idempotency key: sending the same order_number twice returns the first order untouched)
customer.nameyestextmax 200Customer's full name
customer.phoneyestextBangladeshi mobileMust be 01712345678, +8801712345678, 8801712345678, 008801712345678, or 1712345678. Stored as 017…
customer.addressyestextmax 500Street address (couriers need it)
customer.citynotextmax 120City name
customer.emailnotextmax 200Used for Meta event matching if sent
items[]yesarray1–100Each item: sku (required, max 200), quantity or qty (default 1, 1–10,000), price or unit_price (price of one, 0–100,000,000), name (max 300, fallback label)
shipping_feenonumberAccepts numbers, strings with commas/spaces, ৳, or Tk prefix — all cleaned
discountnonumberDiscount amount (subtracted from total)
totalnonumberOrder total. If missing, calculated as items + shipping − discount (never below 0)
payment_methodnotextmax 40Any text. COD: empty, cod, or contains cash. Bkash: contains bkash. Bank: contains bank. Online: anything else
paid_amountnonumberMoney already paid. Capped at total. Online methods default to paid in full; COD defaults to 0
notenotextmax 1,000Saved as the order's internal note after "Website order <number> · "
testnobooleantrue, "true", or 1: dry run (nothing is saved)
trackingadded by helpertextThe _okyo cookie value (URL-encoded JSON) — forwarded by the helper
clientadded by helperobjectip, user_agent, page_url — forwarded by the helper

Responses

Always JSON with Cache-Control: no-store.

HTTPCodeMessageMeaning
201created"Received as #1042."Order created with status New (or Confirmed if paid ≥ total and total > 0)
201held"Received as #1042, on Hold: Omnikyo doesn't have enough stock for it."Order created with status Hold; stock is reserved
200duplicate"Order <number> was already received as <#id>. Nothing changed."Same order_number sent before; the first order is returned, body differences ignored
200test"Test passed: this order would be created for <name> with <n> item(s), total ৳<total>. Nothing was saved. Remove "test" to send real orders."Dry run, all validations passed
400browser_request"Send orders from your server (PHP)…"Request has an Origin header
400invalid_json"The body is not valid JSON…"Body parse failed
401missing_key'Add the header "Authorization: Bearer sk_live_…"…'No key header
401invalid_key"This secret key is not valid. Copy it again from Omnikyo Settings…"Key does not exist or has been replaced
402plan_limitPlan's block reason + "Open Settings → Billing in Omnikyo."Order creation blocked by subscription
405method_not_allowed"Send orders with POST. Setup guide: https://omnikyo.com/docs/connect-your-website"GET or other method
413too_large"The order is too large. Send one order per request."Body > 256 KB
422invalid_orderField-level messages (max 5 issues)Missing/bad fields, first 5 listed
422unknown_sku'No product in Omnikyo has the SKU "ABC"…'A sku does not exist; order is kept in Recent orders for retry; JSON includes skus: [...] array
429rate_limited"Too many orders at once. Wait a moment and send again."Burst limit (60) or minute limit (120) exceeded; includes Retry-After header
500server_error"Omnikyo couldn't save this order right now (<reason>). The helper retries by itself…"Omnikyo error; the helper will retry

Idempotency

Sending the same order_number twice returns the first order unchanged (same order_number = idempotency key). Idempotency key format: connect:<order_number> per business.

Rate limits

Per secret key: burst 60, 120 per minute. The helper retries up to 3 times with delays.

The Omnikyo helper file (PHP)

Settings generates a PHP helper file with your secret key built in. Use it instead of calling the API directly.

How it works

  • Detects the framework: if Laravel's app() exists and supports terminating(), it queues the request to send after the page returns to the customer. Plain PHP sends immediately.
  • Adds two fields: tracking (the visitor's _okyo cookie) and client (IP, user agent, referrer).
  • Retries up to 3 attempts with 2 s and 4 s delays between them.
  • Logs problems to storage/logs/laravel.log (Laravel) or PHP's error log.
  • Never throws; never slows the checkout.

Laravel setup

  1. Create app/Support/Omnikyo.php with the code from Settings.
  2. Add OMNIKYO_KEY=sk_live_… to .env. The helper reads from: config('services.omnikyo.key'), env(), getenv(), or reads .env itself if config is cached.
  3. Call after saving the order:
\App\Support\Omnikyo::sendOrder([
    'order_number' => $order->id,
    'customer' => [
        'name' => $order->customer_name,
        'phone' => $order->phone,
        'address' => $order->address,
        'city' => $order->city,
    ],
    'items' => [...],
    'shipping_fee' => 100,
    'discount' => 0,
    'total' => 750,
    'payment_method' => 'cod',
]);

Plain PHP setup

  1. Create omnikyo.php with the code from Settings. The file contains your secret key, so keep it private.
  2. At the top of your checkout file: require_once __DIR__ . '/omnikyo.php';
  3. Call the same way: Omnikyo::sendOrder([...]);

Helper logs: php -r 'error_log("message");' or check php_errors.log / error.log.

The connect.js script tag

Add one line to the main layout before </head>:

<script async src="https://omnikyo.com/connect.js?key=pk_live_…"></script>

What it does

  1. Records where the visitor came from in a first-party cookie _okyo (30 days, SameSite=Lax, Secure on HTTPS, host-only so it does not follow if the domain changes). Stores UTM parameters (utm_source, utm_medium, utm_campaign, utm_term, utm_content), fbclid, landing URL (500 chars), referrer (300), _fbp, _fbc cookies, timestamp. The last campaign touch rule: a visit with any UTM tag or click id replaces what is stored; a plain visit keeps it; an outside referral fills it only if nothing campaign-like is stored yet. Updates _fbp (90 days) if missing.
  2. Runs your Meta pixel (if configured in Omnikyo Settings) with the same event id sent to Omnikyo's server, so Meta deduplicates. If the page already has another Meta pixel (fbq), connect.js does nothing and logs to console: "Omnikyo: this page already has a Meta pixel, so Omnikyo is not sending Meta events. Remove the old pixel code to let Omnikyo send them (with server-side matching). Order tracking still works."
  3. Lets the developer track actions via Omnikyo.track() (see below).

Omnikyo.track(...) for developers

Send custom events from the page:

Omnikyo.track("AddToCart", { sku: "TSH-RED-M", price: 650, quantity: 1 });
Omnikyo.track("ViewContent", { sku: "TSH-RED-M", price: 650, name: "T-Shirt Red M" });
Omnikyo.track("InitiateCheckout", { value: 2500 });

Fields:

  • sku → sent as content_ids:[sku] with content_type: product
  • price × quantity → value (in BDT)
  • name → content_name (200 chars)
  • currency (defaults to BDT when a value is present)
  • value → sent as-is

Events are batched and sent to /api/connect/events after 1.5 s, on page hide, or when 20 are queued. Maximum 20 events per request. Content type is text/plain.

Omnikyo.attribution()

Return the _okyo cookie value (URL-encoded) for checkouts that cannot forward cookies (e.g. iframe, different host). Pass it as tracking in the order API.

const tracking = Omnikyo.attribution();
// Send to your server, include in the order API call

Caching

The script is cached at the edge for 5 minutes (Cache-Control: max-age=300), so a pixel change reaches visitors within ~5 minutes. An invalid key returns an empty harmless script after 60 s cache.

Domains

Only requests from the saved domains are processed. A request from a different domain is silently rejected (domain_not_allowed).

How website orders are matched to products (SKU)

Every item must have a SKU that matches a product in Omnikyo exactly, case-insensitive.

Rules

  • No guessing: if the SKU does not exist, the whole order is refused 422 unknown_sku.
  • Case-insensitive: TSH-RED-M matches tsh-red-m.
  • Variants: use the variant's own SKU, not the parent product's SKU.
  • Parent products: not buyable; only variant SKUs are matched.
  • Duplicates: if two products share a SKU, the oldest (lowest id) wins.
  • Even test: true checks SKUs; an unknown SKU fails the test.
  • The order is not saved, kept in Recent orders so it can be retried once the SKU is added.

Connect your website with your developer

Copy a plain message and send it to whoever built your site:

Please connect our website to Omnikyo (it sends each new order and the ad tracking to Omnikyo). It takes about 10 minutes:

  1. In the main layout (resources/views/layouts/app.blade.php), just before </head>:
<script async src="https://omnikyo.com/connect.js?key=pk_live_…"></script>

Remove the old Meta pixel code from the page: this tag runs the pixel now.

  1. In .env:
OMNIKYO_KEY=sk_live_…
  1. Create app/Support/Omnikyo.php with the file from the guide, unchanged.

  2. Right after checkout saves a new order, call \App\Support\Omnikyo::sendOrder([...]) with the order's fields. Each item's SKU must be the same as the product's SKU in Omnikyo.

  3. Place one test order on the website. It shows up in Omnikyo under Settings › Sales channels › Your website › Recent orders.

Full guide: https://omnikyo.com/docs/connect-your-website

Connect your website with an AI coding assistant

Use this prompt in Cursor, Claude, ChatGPT or Copilot (while it has your website's code open):

Connect this Laravel website to Omnikyo, so every new order is sent to Omnikyo along with where the customer came from (Facebook ads, links). Do exactly these four steps and nothing else.

  1. Script tag. In the main layout every page uses (usually resources/views/layouts/app.blade.php, or the shared header partial), add this line just before </head>:
<script async src="https://omnikyo.com/connect.js?key=pk_live_…"></script>

If that layout already contains Meta Pixel code (a <script> with fbq('init', …) and its <noscript> image), remove it: the Omnikyo script now runs the Meta pixel. Leave any other analytics as they are.

  1. Secret key. Add this line to the .env file (and to .env.example with an empty value). Do not put the key anywhere else and never in JavaScript:
OMNIKYO_KEY=sk_live_…
  1. Helper file. Create app/Support/Omnikyo.php with exactly this content, unchanged:

[Helper PHP code here]

  1. Send each new order. Find the code that saves a new order when a customer checks out (the checkout or order controller's store/place-order method; follow the route of the checkout form). Right after the order and its items are saved, and only for new orders, call \App\Support\Omnikyo::sendOrder() with the order's real fields:
$items = [];
foreach ($order->items as $item) {
    $items[] = [
        'sku'      => $item->sku,
        'quantity' => $item->quantity,
        'price'    => $item->price,
    ];
}

\App\Support\Omnikyo::sendOrder([
    'order_number'   => $order->id,
    'customer'       => [
        'name'    => $order->customer_name,
        'phone'   => $order->phone,
        'address' => $order->address,
        'city'    => $order->city,
    ],
    'items'          => $items,
    'shipping_fee'   => $order->shipping_charge,
    'discount'       => $order->discount,
    'total'          => $order->total,
    'payment_method' => $order->payment_method,
]);

Map every field from this site's own models and columns (they will be named differently). Rules:

  • order_number: the order's unique id or number on this site.
  • sku: the product's (or variant's) SKU. It must be the same SKU the product has in Omnikyo. If products here have no SKU field, stop and tell me instead of inventing one.
  • price is the price of ONE item; total is what the customer pays including delivery.
  • payment_method: the site's own value is fine ('cod', 'bkash', 'nagad', 'card' …). If a payment was already made online, also pass 'paid_amount'.
  • Call it from the web request that places the order (not from a queued job), so the visitor's tracking cookie is sent along.
  • Don't wrap it in try/catch and don't wait for it; it never throws and sends after the response.
  • Change nothing else in the checkout.

Then tell me: which layout file you edited, which controller and method you changed, and how you mapped each field.

To check it works: place one test order on the site, then open Omnikyo → Settings → Sales channels › Your website › Recent orders. Problems are listed there and in storage/logs/laravel.log. Full guide: https://omnikyo.com/docs/connect-your-website

Limits of the prompt: it focuses on Laravel. For plain PHP sites or sites on other frameworks, send the API documentation and the helper code separately.

Other ways people ask this

  • POST /api/v1/orders documentation
  • omnikyo api key authentication
  • how to send orders to omnikyo
  • omnikyo php sdk
  • helper file retries
  • script tag caching
  • sku matching rules
  • Omnikyo API php helper
  • laravel এ omnikyo connect
  • website থেকে order api
  • api documentation skus
  • helper file code

Checked against the product on 2026-10-02.