Kayroo Connect
Everything an external developer needs to read a store's data and react to its events
On this page
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:
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:
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.
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:
{
"data": {
"id": "9f2c1a...",
"name": "Example Store",
"subdomain": "example-store",
"custom_domain": null,
"currency": "DZD",
"language": "fr",
"delivery_fee": 400,
"api_version": "v1"
}
}
Every request must include the token as a Bearer token in the Authorization header:
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:
HTTP/1.1 401 Unauthorized
{ "error": "Invalid or expired token." }
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:
HTTP/1.1 403 Forbidden
{
"error": "insufficient_scope",
"message": "This token is not authorized for the \"products.read\" scope.",
"required_ability": "products.read"
}
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.
Basic information about the store: name, subdomain, custom domain (if any), currency, storefront language, and flat delivery fee.
curl "https://example-store.kayroo.app/api/v1/store" \
-H "Authorization: Bearer kt_live_XXXX"
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) |
{
"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.
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) |
{
"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": { "...": "..." }
}
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).
{
"data": {
"new": 128,
"repeat": 54,
"champions": 12,
"at_risk": 31
},
"meta": { "lookback_days": 90 }
}
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) |
{
"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"
}
]
}
List endpoints (products, orders, abandoned checkouts) are paginated. Every list response has three top-level keys: data (the array of records for this page), links (first/last/prev/next URLs), and meta (current_page, last_page, per_page, total). Pass ?page=2 to move to the next page, or ?per_page=100 to request the maximum page size.
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.
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 |
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:
{
"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"
}
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 |
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:
Example verification in 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:
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 || '')
);
}
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.
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].