API Principles
Luigi's Box provides HTTP-based APIs for two main purposes: serving search results to users (Public) and managing your data/configuration (Private).
1. Service Reference & Endpoints
Note
Base URL Note: Most services (Search, Content, Recommender) live on live.luigisbox.com. The Analytics Event API lives on api.luigisbox.com.
Versioning Strategy
Our APIs are versioned (e.g., /v1/, /v2/). While the principles below apply to all versions, always check the specific integration guide for the latest stable version number.
Public API (Unauthenticated)
Auth: Requires only your public tracker_id.
Usage: Safe to call from Frontend (Browsers, Mobile Apps).
| Category | Method | Base URL | Endpoint | Description |
| Search |
GET/POST
|
live.luigisbox.com |
/search |
Full-text search & facets. |
| Autocomplete | GET |
live.luigisbox.com |
/autocomplete/v* |
Prefix-based suggestions. |
| Recommender | POST |
live.luigisbox.com |
/v*/recommend |
Product recommendations. |
| Shopping Assistant | POST |
live.luigisbox.com |
/v*/assistant |
AI-powered structured dialogue that helps customers discover products. |
| Top items | GET |
live.luigisbox.com |
/v*/top_items |
Most popular items. |
| Trending queries | GET |
live.luigisbox.com |
/v*/trending_queries |
Trending search terms. |
| Analytics | POST |
api.luigisbox.com |
/v* |
Events API. Ingest user interactions. |
Private API (Authenticated)
Auth: Requires HMAC Signature using your Private Key. Usage: Backend Server ONLY.
Indexing Hub (Content Management)
Manage your product catalog.
| Method | Base URL | Endpoint | Description |
POST |
live.luigisbox.com |
/v*/content |
Create/Replace. Add new products. |
PATCH |
live.luigisbox.com |
/v*/content |
Partial Update. Update specific fields. |
DELETE |
live.luigisbox.com |
/v*/content |
Delete. Remove products. |
PATCH |
live.luigisbox.com |
/v*/update_by_query |
Batch Update. Update items matching a query. |
GET |
live.luigisbox.com |
/v*/content_export |
Export. Download your current index data. |
Recommender Customization
Manage pinning rules and batch recommendations.
| Method | Base URL | Endpoint | Description |
POST |
live.luigisbox.com |
/v*/recommender/pin/{ID}/scopes |
Define pinning scopes (rules). |
GET |
live.luigisbox.com |
/v*/recommender/pin/{ID}/summary |
Get pinning configuration summary. |
POST |
live.luigisbox.com |
/v*/recommender/batching/{ID}/users |
Trigger batch recommendation generation for users. |
* |
live.luigisbox.com |
/v*/recommender/pin/* |
Various CRUD endpoints for managing pins. |
Danger Security Warning: Never call the Private API (Content/Pinning) from a frontend application. Doing so exposes your Private Key and allows attackers to corrupt your data.
2. Authentication (HMAC)
Only the Private API endpoints require a custom HMAC-SHA256 signature.
Credentials
You will need your API credentials found in Luigi's Box App > Settings > Integration Settings:
- Tracker_ID (Public Key): Identifies your account.
- Secret Key (Private Key): Used to sign requests.
The Signing Flow
To authenticate, you must construct a specific "String to Sign," hash it, and attach it as a header.
Detailed Specification
Step 1: Required Headers
Every authenticated request must include these headers. The values used here must match the values used in the signature generation byte-for-byte.
| Header | Description |
Date |
The current timestamp in HTTP Date format (e.g., Thu, 29 Jun 2017 12:11:16 GMT).Note: Our server clock tolerance is ±5 seconds. You must regenerate the date and signature for every request. |
Content-Type |
Describes your payload (e.g., application/json; charset=utf-8). |
Authorization |
The authentication string. Format: AppName [tracker_id]:[signature]
|
Step 2: Canonical String Construction
Concatenate the following four strings, separated by a newline character (\n).
- HTTP Verb: Uppercase (e.g.,
POST,PUT,DELETE). - Content-Type: Exactly as sent in the header (e.g.,
application/json; charset=utf-8). - Date: Exactly as sent in the header.
- Resource Path: The absolute path excluding the query string (e.g.,
/v1/content, not/v1/content?foo=bar).
Step 3: Signature Calculation
- Compute the HMAC-SHA256 digest of the Canonical String using your Secret Key.
- Encode the binary digest into a Base64 string.
Example Implementations
require 'time'
require 'openssl'
require 'base64'
def digest(key, method, endpoint, date)
content_type = 'application/json; charset=utf-8'
data = "#{method}\n#{content_type}\n#{date}\n#{endpoint}"
dg = OpenSSL::Digest.new('sha256')
Base64.strict_encode64(OpenSSL::HMAC.digest(dg, key, data)).strip
end
date = Time.now.httpdate
digest("secret", "POST", "/v1/content", date)
<?php
function digest($key, $method, $endpoint, $date) {
$content_type = 'application/json; charset=utf-8';
$data = "{$method}\n{$content_type}\n{$date}\n{$endpoint}";
$signature = trim(base64_encode(hash_hmac('sha256', $data, $key, true)));
return $signature;
}
$date = gmdate('D, d M Y H:i:s T');
digest("secret", "POST", "/v1/content", $date);
// This configuration and code work with the Postman tool
// https://www.getpostman.com/
//
// Start by creating the required HTTP headers in the "Headers" tab
// - Content-Type: application/json; charset=utf-8
// - Authorization: {{authorization}}
// - date: {{date}}
//
// The {{variable}} is a postman variable syntax. It will be replaced
// by values precomputed by the following pre-request script.
var privateKey = "your-secret";
var publicKey = "your-tracker-id";
var contentType = "application/json; charset=utf-8";
var requestUri = request.url.replace(/^.*\/\/[^\/]+/, '').replace(/\?.*$/, '');
var timestamp = new Date().toUTCString();
var signature = [request.method, contentType, timestamp, requestUri].join("\n");
var encryptedSignature = CryptoJS.HmacSHA256(signature, privateKey).toString(CryptoJS.enc.Base64);
pm.request.headers.add({
key: "Content-Type",
value: contentType
});
pm.request.headers.add({
key: "Authorization",
value: "ApiAuth " + publicKey + ":" + encryptedSignature
});
pm.request.headers.add({
key: "Date",
value: timestamp
});
#!/bin/bash
digest() {
KEY=$1
METHOD=$2
CONTENT_TYPE="application/json; charset=utf-8"
ENDPOINT=$3
DATE=$4
DATA="$METHOD\n$CONTENT_TYPE\n$DATE\n$ENDPOINT"
printf "$DATA" | openssl dgst -sha256 -hmac "$KEY" -binary | base64
}
date=$(env LC_ALL=en_US date -u '+%a, %d %b %Y %H:%M:%S GMT')
echo $(digest "secret", "GET", "/v1/content", $date)
3. User Identification
While "Authentication" identifies your server to us, "User Identification" identifies your customer to the AI.
To maintain session continuity and personalization, you must handle two specific IDs correctly in every frontend request (Search, Autocomplete, Analytics).
| ID Type | Parameter | Description |
| Device ID | device_user_id |
Required. A persistent identifier for the browser/device (e.g., a cookie ID). Must remain constant for the entire session, regardless of login state. |
| Auth ID | auth_user_id |
Optional. The database ID of the logged-in user. Send this only when the user is logged in. |
The "Session Continuity" Rule
The device_user_id is the anchor. You must never change it mid-session, even if the user logs in or out.
Danger
Common Mistake: Do not replace the device_user_id with the auth_user_id upon login.
Wrong: Anonymous (
dev_1) -> Login -> Logged In (user_99)Result: The system thinks a new user has arrived. The session breaks, and personalization history is lost.
4. Rate Limiting (Throttling)
We enforce rate limits to ensure stability. Limits are applied per Tracker ID (Account level) and per IP Address.
| Endpoint | Account Limit | IP Limit |
| Content Updates | 500 req / min 5 concurrent reqs |
- |
| Autocomplete | 800 req / min | 30 req / 5s |
| Search | 350 req / min | 30 req / 5s |
| Recommender | 60 req / 5s | 30 req / 5s |
Handling 429 Errors (Smart Retry)
If you exceed a limit, you will receive a 429 Too Many Requests status. Your application must handle this gracefully.
We provide a Retry-After header indicating how many seconds you must wait.
Retry-After: 5 Note over Client: Wait 5 seconds Client->>API: POST /v1/content API-->>Client: 200 OK
Recommended Strategy:
- Realtime APIs (Search, Autocomplete): Do not retry immediately. Discard the request.
-
Batch APIs (Content Updates): Use an exponential backoff strategy (wait
Retry-After, then retry).
5. Error Handling
You should design your integration to be resilient to network failures.
| Code | Reason | Type | Action |
| 401 | Auth Failed | Fatal | Check your Signature generation. The response body contains the string we expected vs. what you sent. |
| 408 | Timeout | Transient | Safe to retry once. |
| 429 | Throttling | Transient | Wait and retry (see above). |
| 500 | Server Error | Fatal | Log the error and contact support. |
| 502 | Bad Gateway | Transient | Usually a deploy or network blip. Retry after 1s. |
| 503 | Service Unavailable | Transient | Check luigisboxstatus.com. |
Development Mode
To ensure your integration is robust, we may enable Development Mode on your account during the integration phase.
What it does:
- A small percentage of your requests will deliberately fail with various error codes (408, 429, 500).
- These errors are marked in the JSON body as
development_mode: true.
Why: This forces your developers to write proper error handling and retry logic before you go to production.
Note Note: Development mode is never enabled on Production accounts without explicit consent.