01 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.
02 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:
- 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.
- 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).
- Your application stores that token securely and sends it as a Bearer token on every API request it makes to that merchant's store.
- 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.
03 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.
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"
}
}
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.
04 Authentication
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." }
05 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:
HTTP/1.1 403 Forbidden
{
"error": "insufficient_scope",
"message": "This token is not authorized for the \"products.read\" scope.",
"required_ability": "products.read"
}
06 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.
/api/v1/store
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"
/api/v1/products
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.
/api/v1/orders
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": { "...": "..." }
}
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.
/api/v1/customers/segments
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 }
}
/api/v1/abandoned-checkouts
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"
}
]
}
07 Pagination
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.
08 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.
09 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:
{
"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:
- Take the exact raw bytes of the request body (do not re-serialize or reformat the JSON).
- Compute HMAC-SHA256 of those bytes using the shared secret as the key.
- Compare the result, as a lowercase hex string, to the X-Webhook-Signature header, using a constant-time comparison.
- 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:
$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 || '')
);
}
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].