Kayroo Connect

Build an integration for a Kayroo store

Everything an external developer needs to read a store's data and react to its events

Last updated: September 2026

1. What is Kayroo Connect?

Kayroo is an e-commerce platform (similar in shape to Shopify) that lets merchants in Algeria run an online store — products, orders, delivery, checkout — without writing any code. "Kayroo Connect" is the name for the platform's public integration layer: a REST API and a webhook system that let an external application talk to one merchant's store from the outside.

This is the same trust model as a Shopify "app" or a WooCommerce plugin that runs on its own server: your application lives entirely on your own infrastructure, in your own repository. It never receives a copy of Kayroo's source code, never gets database credentials, and never gets SSH or admin-panel access. Every interaction goes through the two channels described on this page:

  • A token-authenticated REST API — you request data (products, orders, store info, customer segments, abandoned checkouts) over plain HTTPS.
  • Outbound webhooks — Kayroo pushes a small HTTP notification to your server whenever something happens (a new order, a product change, a new lead, a new review), so you don't have to keep polling.
If a feature you're building ever seems to need direct database access, a Kayroo employee login, or a copy of the Kayroo codebase — it doesn't. That would mean the API is missing something. Ask the store owner to relay the request to the Kayroo team so the API can be extended instead.

2. How the connection works, end to end

There is no app store, no OAuth "install" click, and no developer account to create with Kayroo today. Instead, the store owner (the merchant) is the one who grants your application access, directly from their own admin panel. The flow looks like this:

  1. The merchant opens their Kayroo admin panel, goes to Settings → API Tokens, and creates a new token for your integration — giving it a name and choosing exactly which permissions ("scopes") it should have.
  2. The merchant copies that token and sends it to you (or pastes it directly into your app's setup screen, if that's how your product is designed).
  3. Your application stores that token securely and sends it as a Bearer token on every API request it makes to that merchant's store.
  4. Optionally, the merchant also goes to Settings → Webhooks in their admin panel, pastes in the URL of your server, and picks which events they want you notified about. From then on, Kayroo pushes those events to your URL automatically.
A token is scoped to exactly one store. If your product serves many merchants, each merchant repeats this same setup once and gives you their own token — you do not reuse one merchant's token for another merchant's data.

3. Quick start

Once you have a token from a merchant, every request works the same way: an HTTPS GET request with the token in the Authorization header, addressed to that merchant's store domain, under /api/v1.

bash
curl "https://example-store.kayroo.app/api/v1/store" \
  -H "Authorization: Bearer kt_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
  -H "Accept: application/json"

A successful response looks like this:

json
{
  "data": {
    "id": "9f2c1a...",
    "name": "Example Store",
    "subdomain": "example-store",
    "custom_domain": null,
    "currency": "DZD",
    "language": "fr",
    "delivery_fee": 400,
    "api_version": "v1"
  }
}
Kayroo works out which store a request belongs to purely from the token — so in practice a request to any Kayroo host (the merchant's own kayroo.app subdomain, a merchant's custom domain, or a shared api. host) resolves to the correct store. Using the merchant's own subdomain, as in the example above, is the simplest and clearest choice.

4. Authentication

Every request must include the token as a Bearer token in the Authorization header:

text
Authorization: Bearer kt_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXX

Tokens can optionally have an expiry date, set by the merchant when they create it. Once expired, revoked, or deleted, the token stops working immediately on every future request — there is no grace period.

Missing, malformed, expired, or revoked tokens all get the same response:

json
HTTP/1.1 401 Unauthorized
{ "error": "Invalid or expired token." }

5. Scopes (permissions)

A token is only ever as powerful as the scopes the merchant checked when creating it. Each API endpoint requires exactly one scope — request only what your integration genuinely needs; a merchant is far more likely to trust and approve an integration that doesn't ask for everything.

Scope Grants access to
store.read Basic store information (name, currency, language, delivery fee)
products.read Product catalog, including variants and stock
orders.read Orders and their line items, totals, and delivery destination
customers.read Customer segment counts and abandoned checkouts

If a token is used to call an endpoint it wasn't granted the scope for, the API responds with:

json
HTTP/1.1 403 Forbidden
{
  "error": "insufficient_scope",
  "message": "This token is not authorized for the \"products.read\" scope.",
  "required_ability": "products.read"
}

6. API reference

All endpoints are read-only (GET) and live under /api/v1. All responses are JSON. All monetary amounts are numbers in Algerian Dinar (DZD), with no currency conversion.

GET /api/v1/store — scope: store.read

Basic information about the store: name, subdomain, custom domain (if any), currency, storefront language, and flat delivery fee.

bash
curl "https://example-store.kayroo.app/api/v1/store" \
  -H "Authorization: Bearer kt_live_XXXX"
GET /api/v1/products — scope: products.read

A paginated list of the store's products. Query parameters (all optional):

Param Meaning
visible_only=1 Only products the storefront currently shows
featured=1 Only featured products
search=term Match against product name or SKU
per_page=25 Items per page (default 25, maximum 100)
json
{
  "data": [
    {
      "id": 41,
      "name": "Classic Leather Wallet",
      "slug": "classic-leather-wallet",
      "sku": "WAL-041",
      "description": "Full-grain leather, hand-stitched.",
      "price": 3500,
      "compare_price": 4200,
      "current_price": 3500,
      "on_sale": false,
      "currency": "DZD",
      "stock": 18,
      "in_stock": true,
      "is_visible": true,
      "is_featured": true,
      "category": "Accessories",
      "image_url": "https://example-store.kayroo.app/storage/products/41.jpg",
      "variants": [
        { "id": 101, "options": { "Color": "Brown" }, "price": null, "stock": 10 },
        { "id": 102, "options": { "Color": "Black" }, "price": null, "stock": 8 }
      ],
      "created_at": "2026-02-11T09:12:00+00:00",
      "updated_at": "2026-05-03T14:40:00+00:00"
    }
  ],
  "links": { "first": "...", "last": "...", "prev": null, "next": "..." },
  "meta": { "current_page": 1, "last_page": 4, "per_page": 25, "total": 87 }
}

GET /api/v1/products/{id} returns the same shape for a single product (a plain object under "data"), or a 404 JSON body if the ID doesn't exist on that store.

GET /api/v1/orders — scope: orders.read

A paginated list of orders. Query parameters (all optional):

Param Meaning
status=confirmed One of: pending, confirmed, delivered, cancelled
since=2026-06-01 Only orders created on or after this date
per_page=25 Items per page (default 25, maximum 100)
json
{
  "data": [
    {
      "id": 1032,
      "status": "confirmed",
      "customer": {
        "name": "Amine K.",
        "phone": "0555xxxxxx",
        "email": null,
        "address": "Cité 100 logements, Bt 4"
      },
      "items": [
        { "product_id": 41, "variant_id": 101, "name": "Classic Leather Wallet", "qty": 2, "line_total": 7000 }
      ],
      "subtotal": 7000,
      "discount_amount": 0,
      "coupon_code": null,
      "delivery_price": 400,
      "total": 7400,
      "currency": "DZD",
      "wilaya": "Alger",
      "commune": "Bab Ezzouar",
      "tracking_number": "YAL-88213",
      "landing_page_id": null,
      "created_at": "2026-06-30T10:02:00+00:00",
      "updated_at": "2026-07-01T08:15:00+00:00"
    }
  ],
  "links": { "...": "..." },
  "meta": { "...": "..." }
}
Order responses never include the customer's IP address, user agent, internal fraud/risk status, admin notes, or the public confirmation-link token — those stay internal to Kayroo.
GET /api/v1/customers/segments — scope: customers.read

Aggregate counts of customers grouped into behavioural segments — new, repeat, champions (frequent + high value), and at-risk (used to buy, haven't lately). Optional query parameter: lookback_days (default 90, range 7–365).

json
{
  "data": {
    "new": 128,
    "repeat": 54,
    "champions": 12,
    "at_risk": 31
  },
  "meta": { "lookback_days": 90 }
}
GET /api/v1/abandoned-checkouts — scope: customers.read

A paginated list of checkouts customers started but didn't finish — useful for cart-recovery outreach. Query parameters (all optional):

Param Meaning
days=30 Only checkouts started in the last N days (default 30, max 365)
include_recovered=1 Include ones that later turned into an order (excluded by default)
json
{
  "data": [
    {
      "id": 77,
      "customer_name": "Yasmine B.",
      "customer_phone": "0661xxxxxx",
      "customer_email": null,
      "cart": { "items": [ { "product_id": 41, "qty": 1 } ] },
      "recovered": false,
      "created_at": "2026-07-02T19:40:00+00:00"
    }
  ]
}

8. Rate limits

Each token is limited to 120 requests per minute by default. If you exceed it, you'll get an HTTP 429 response — back off and retry after a short delay. Build in retry-with-backoff logic rather than hammering the API in a tight loop; this also protects your integration from being mistaken for abusive traffic.

9. Errors

Errors are always plain JSON with an "error" key, and sometimes a human-readable "message". The status codes you'll encounter:

Status Meaning Typical cause
401 Unauthenticated Missing, invalid, expired, or revoked token
403 insufficient_scope Token doesn't have the scope the endpoint requires
404 not_found The record ID doesn't exist on this store
422 Validation error A query parameter had an invalid value
429 Too many requests Rate limit exceeded — slow down and retry

10. Webhooks

Instead of constantly polling the API to check "did anything change?", you can ask Kayroo to notify your server the moment something happens. The merchant registers your endpoint URL from Settings → Webhooks in their admin panel and chooses which of the following events to send you:

Event Fires when…
order.created A new order is placed (from checkout or created manually by the merchant)
order.updated An order's status changes (e.g. pending → confirmed → delivered)
order.cancelled An order is cancelled
product.created A new product is added to the catalog
product.updated A product is edited (price, stock, details, …)
product.deleted A product is removed from the catalog
lead.created A visitor submits the store's contact form
review.created A verified buyer submits a product review

Every webhook is an HTTP POST to the URL the merchant registered, with this JSON body shape:

json
{
  "event": "order.created",
  "data": {
    "id": 1032,
    "status": "pending",
    "total": 7400,
    "customer_name": "Amine K.",
    "customer_phone": "0555xxxxxx",
    "created_at": "2026-06-30T10:02:00+00:00"
  },
  "timestamp": "2026-06-30T10:02:01+00:00"
}
Webhook payloads are intentionally thin — just enough to identify what happened. When you receive one, call the matching REST API endpoint (e.g. GET /orders/{id}) if you need the full, current record.

The request also carries two headers you can rely on:

Header Purpose
X-Webhook-Event The event name, same as the "event" field in the body (e.g. order.created)
X-Webhook-Signature An HMAC-SHA256 signature of the raw request body — see verification below

11. Verifying a webhook is genuinely from Kayroo

Before trusting any webhook payload, verify its signature. Every webhook subscription has its own secret, generated by Kayroo when the merchant registers your endpoint and shown to them once, for them to pass on to you securely. To verify a request:

  1. Take the exact raw bytes of the request body (do not re-serialize or reformat the JSON).
  2. Compute HMAC-SHA256 of those bytes using the shared secret as the key.
  3. Compare the result, as a lowercase hex string, to the X-Webhook-Signature header, using a constant-time comparison.
  4. If they don't match, reject the request (respond 401 and discard it) — the payload did not come from Kayroo, or was altered in transit.

Example verification in PHP:

php
$rawBody   = file_get_contents('php://input');
$expected  = hash_hmac('sha256', $rawBody, $sharedSecret);
$received  = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';

if (! hash_equals($expected, $received)) {
    http_response_code(401);
    exit;
}

// Signature verified — safe to process $rawBody now.

Example verification in Node.js:

javascript
const crypto = require('crypto');

function isValidSignature(rawBody, signatureHeader, sharedSecret) {
  const expected = crypto
    .createHmac('sha256', sharedSecret)
    .update(rawBody)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signatureHeader || '')
  );
}
Respond to the webhook request quickly (within a few seconds) with a 2xx status once you've accepted it — do your slow processing afterwards, asynchronously. If your endpoint fails to respond successfully 10 times in a row, Kayroo automatically disables that webhook subscription and the merchant will need to re-enable it.

12. Security & data handling expectations

  • Request only the scopes you actually need. Don't ask a merchant to grant every permission "just in case" — it makes your integration look untrustworthy and most merchants will refuse.
  • Store tokens and webhook secrets encrypted at rest, never in plain text logs, and never expose them in client-side code.
  • Verify every webhook's signature before acting on it — never trust an unverified payload.
  • Honor revocation immediately. If a merchant deletes your token or removes your webhook subscription, all access stops instantly on Kayroo's side — make sure your own app handles that gracefully (e.g. mark the connection as disconnected) rather than treating every failed request as a transient error.
  • Only use data pulled from a store for that same merchant's own benefit. Never aggregate, resell, or share one merchant's data with another, and never use it for anything the merchant didn't sign up for.
  • Define a data retention window for anything you cache from the API, and delete it when a merchant disconnects your integration or asks you to.

13. Current scope & known limitations

  • Read-only today. There are no endpoints yet to create or update anything on a store (no create-order, no update-stock, etc.) — everything above is GET only.
  • No self-serve developer account or app marketplace. A token is minted manually by each merchant from their own admin panel; there is no central place for you to register as a "Kayroo app" yet.
  • A token keeps working even if the merchant's subscription plan changes, until the merchant revokes or it expires — plan checks currently only happen when the token is first created.
  • Webhook delivery retries are limited: Kayroo does not currently retry a single failed delivery with backoff; a webhook subscription is simply disabled after 10 consecutive failures and the merchant is expected to re-enable it once your endpoint is healthy again.

API access and webhooks are available to merchants on Kayroo's Scale plan and the Pay-As-You-Go plan. If a merchant you're integrating with can't find Settings → API Tokens in their admin panel, that's usually why — ask them to check their current plan.

14. Questions or something missing?

This API will keep growing. If your integration needs a piece of data or an event that isn't covered here, don't look for a workaround through direct access — ask the merchant to pass your request on to the Kayroo team, or reach out directly at [email protected].

Kayroo Platform
back to top