API Reference
Send customer profiles, order history, and product catalogue data into Replenit. Once connected, the decision engine begins making 1:1 replenishment, cross-sell, and retention decisions automatically.
Overview
Replenit exposes three POST endpoints for ingesting data — customers, orders, and products — and four DELETE endpoints for removing records. All POST endpoints are upsert operations: resending the same ID updates the existing record.
Authentication
Every request requires two values: your Tenant ID passed in the URL path, and your API key in the x-replenit-auth-key header.
Retrieve both from your dashboard under Settings → API Keys.
POST https://api.replen.it/customers/{tenantId} x-replenit-auth-key: YOUR_API_KEY Content-Type: application/json
Base URL & endpoints
| Endpoint | Method | Purpose | Batch |
|---|---|---|---|
| /customers/{tenantId} | POST | Upsert customer profiles | 100–500 |
| /customers/{tenantId} | DELETE | Delete customer by ID or email | Single record |
| /orders/{tenantId} | POST | Upsert orders with line items | 50–200 |
| /orders/{tenantId}/{orderId} | DELETE | Delete an entire order | Single record |
| /orders/{tenantId}/{orderId}/items | DELETE | Delete a single line item | Single record |
| /products/{tenantId} | POST | Upsert product catalogue | 50–100 |
| /products/{tenantId}/{productId} | DELETE | Delete product and all variants | Single record |
| /products/{tenantId}/{productId}/variants/{variantId} | DELETE | Delete a single variant | Single record |
Data flow
Once your data is connected, it passes through five stages before decisions are dispatched. The API integration covers the first stage. The remaining stages run automatically inside Replenit.
Integration sequence
A typical initial integration follows this order. After the initial load, each endpoint syncs independently in real time.
Internal pipeline
Dashboard data and health metrics reflect ingested records within 24 hours of your first sync.
Response format
All POST endpoints return the same envelope. Check success before reading data.
{
"success": true,
"message": "Records saved.",
"data": {
"count": 3,
"processedAt": "2025-08-22T21:00:00.000Z"
}
}{
"success": false,
"message": "Validation failed",
"data": {},
"errors": {
"[0].Email": ["The Email field is required."],
"[0].CustomerId": ["Maximum length is 100 characters."]
}
}POST /customers/{tenantId}
CustomerId or Email is the upsert key — at least one is required.Request body — array of customer objects
CustomerId or Email is required. They can be sent individually or together. Send whichever identifier your dispatch destination can resolve — see the note below.| Field | Type | Description | |
|---|---|---|---|
| CustomerId | string | Required* | Your unique customer identifier. Max 100 chars. Upsert key — sending the same value updates the existing record. Required if not sending Email. |
| string | Required* | Valid email address. Upsert key when CustomerId is absent. Required if not sending CustomerId. | |
| Name | string | Optional | First name. Included in the decision payload for personalisation at the execution layer. |
| Surname | string | Optional | Last name / surname. |
CustomerId but your destination cannot resolve it, decisions arrive but cannot be matched to a record. When in doubt, send both.| Field | Type | Description | |
|---|---|---|---|
| Phone | string | Optional | E.164 format, e.g. +14155550123. Profiling signal; passed in the decision payload to downstream platforms. |
| Language | string | Optional | BCP 47 tag, e.g. en-US, es-ES. Used by the reasoning layer to contextualise decisions and match localised product content. |
| Username | string | Optional | Platform username. Included in the decision payload for personalisation at the execution layer. |
Optional flags indicating which channels are available for this customer. Replenit uses them as behavioural profiling signals — understanding which channels a customer is reachable on informs how decisions are contextualised. Consent management and message suppression are handled by your marketing automation platform at execution time.
| Field | Type | Description | |
|---|---|---|---|
| EmailOptin | boolean | Optional | Customer is reachable via email. |
| SmsOptin | boolean | Optional | Customer is reachable via SMS. |
| WhatsappOptin | boolean | Optional | Customer is reachable via WhatsApp. |
| AppPushOptin | boolean | Optional | Customer is reachable via mobile push notification. |
| Field | Type | Description | |
|---|---|---|---|
| GdprOptin | boolean | Optional | Controls whether Replenit is permitted to process and profile this customer. When false, no processing, enrichment, or decision generation occurs. Defaults to false. Only send customers for whom you have obtained valid consent. Replenit does not manage consent collection, validation, or staleness — that responsibility sits with your systems before data reaches this API. |
| IsExcluded | boolean | Optional | When true, this customer is excluded from the decision pipeline entirely. Use for internal test accounts. Defaults to false. |
Example request
[
{
"CustomerId": "C-123",
"Email": "john.doe@example.com",
"Name": "John",
"Surname": "Doe",
"Phone": "+14155550123",
"Language": "en-US",
"EmailOptin": true,
"SmsOptin": false,
"WhatsappOptin": true,
"AppPushOptin": true,
"GdprOptin": true,
"IsExcluded": false
}
]Code examples
curl -X POST "https://api.replen.it/customers/YOUR_TENANT_ID" \
-H "Content-Type: application/json" \
-H "x-replenit-auth-key: YOUR_API_KEY" \
-d '[{"CustomerId":"C-123","Email":"john@example.com","GdprOptin":true}]'const res = await fetch(`https://api.replen.it/customers/${TENANT_ID}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-replenit-auth-key": API_KEY
},
body: JSON.stringify([
{ CustomerId: "C-123", Email: "john@example.com", GdprOptin: true }
])
});
const { success, data } = await res.json();import requests
resp = requests.post(
f"https://api.replen.it/customers/{TENANT_ID}",
headers={"x-replenit-auth-key": API_KEY},
json=[{"CustomerId": "C-123", "Email": "john@example.com", "GdprOptin": True}]
)
print(resp.json())Response
{ "success": true, "message": "Customers saved.", "data": { "count": 1, "processedAt": "2025-08-22T21:00:00.000Z" } }DELETE /customers/{tenantId}
customerId or email. Pass either as a query parameter. Asynchronous — queued and applied idempotently.| Query param | Type | Description | |
|---|---|---|---|
| customerId | string | Optional | Delete by customer ID. Use this or email. |
| string | Optional | Delete by email address. Use this or customerId. |
curl -X DELETE "https://api.replen.it/customers/YOUR_TENANT_ID?customerId=C-123" \ -H "x-replenit-auth-key: YOUR_API_KEY"
POST /orders/{tenantId}
OrderItems array containing at least one item.Request body — array of order objects
| Field | Type | Description | |
|---|---|---|---|
| OrderId | string | Required | Unique order identifier. Upsert key — resend to update (e.g. cancellations). |
| CustomerId | string | Required | Links to the customer's CustomerId. |
| string | Required | Customer email. Used as a fallback if CustomerId is not matched. | |
| OrderDate | string | Required | ISO 8601 UTC datetime, e.g. 2025-08-22T21:00:00Z. Baseline for replenishment timing. |
| TotalRevenue | number | Required | Total order value as a decimal in the order's currency. |
| Currency | string | Required | ISO 4217 code, e.g. USD, EUR, GBP. |
| OrderItems | array | Required | Array of line item objects. Minimum one item required. |
| TotalQuantity | integer | Optional | Total units across all line items. |
| UniqueQuantity | integer | Optional | Number of distinct product SKUs in the order. |
| IsOrderCancelled | boolean | Optional | Set to true for cancelled orders. Excluded from timing models. Defaults to false. |
| Field | Type | Description | |
|---|---|---|---|
| ProductId | string | Required | Links to the product's ProductId. |
| Sku | string | Required | Must exactly match a ProductVariants[].Sku. Case-sensitive. |
| Quantity | integer | Required | Units purchased. Used to calculate depletion rate. |
| Price | number | Required | Actual price paid per unit after discounts. |
| OriginalPrice | number | Optional | Full retail price before discounts. |
| Size | string | Optional | Size or volume, e.g. 500ml, XL. |
| Color | string | Optional | Colour of the variant purchased. |
| Brand | string | Optional | Brand name of the item. |
| IsGift | boolean | Optional | When true, item was a gift. Replenit adjusts replenishment timing accordingly. Defaults to false. |
Example request
[
{
"OrderId": "O-789",
"CustomerId": "C-123",
"Email": "john.doe@example.com",
"OrderDate": "2025-08-22T21:00:00Z",
"TotalRevenue": 89.97,
"Currency": "USD",
"TotalQuantity": 3,
"UniqueQuantity": 2,
"IsOrderCancelled": false,
"OrderItems": [
{
"ProductId": "P-42",
"Sku": "SKU-42-RED-L",
"Quantity": 2,
"Price": 29.99,
"OriginalPrice": 39.99,
"Size": "L",
"Color": "red",
"Brand": "Acme",
"IsGift": false
},
{
"ProductId": "P-43",
"Sku": "SKU-43-BLUE-M",
"Quantity": 1,
"Price": 29.99,
"IsGift": true
}
]
}
]Code examples
curl -X POST "https://api.replen.it/orders/YOUR_TENANT_ID" \ -H "Content-Type: application/json" \ -H "x-replenit-auth-key: YOUR_API_KEY" \ -d @orders.json
Response
{ "success": true, "message": "Orders saved.", "data": { "count": 1, "processedAt": "2025-08-22T21:00:00.000Z" } }DELETE /orders/{tenantId}/{orderId}
curl -X DELETE "https://api.replen.it/orders/YOUR_TENANT_ID/O-789" \ -H "x-replenit-auth-key: YOUR_API_KEY"
DELETE /orders/{tenantId}/{orderId}/items
productId and sku as query parameters.| Query param | Type | Description | |
|---|---|---|---|
| productId | string | Required | The product ID of the line item to remove. |
| sku | string | Required | The SKU of the specific variant to remove. |
curl -X DELETE "https://api.replen.it/orders/YOUR_TENANT_ID/O-789/items?productId=P-42&sku=SKU-42-RED-L" \ -H "x-replenit-auth-key: YOUR_API_KEY"
POST /products/{tenantId}
ProductVariants array. After ingestion, the reasoning layer automatically processes each product — see Product enrichment.Request body — array of product objects
| Field | Type | Description | |
|---|---|---|---|
| ProductId | string | Required | Unique product identifier. Upsert key. Must match ProductId values used in OrderItems. |
| ProductName | string | Required | Human-readable product name. Used in the decision payload and message content. |
| ProductVariants | array | Required | Array of variant objects. A product with no distinct variants should still include one variant for the base product. |
| Taxonomy | array<string> | Optional | Ordered category path, broadest to most specific, e.g. ["Apparel","Women","Activewear"]. Used for category-level targeting. |
| IsOfflineExclusive | boolean | Optional | When true, only available in-store. Replenit adapts decision context accordingly. Defaults to false. |
| Field | Type | Description | |
|---|---|---|---|
| VariantId | string | Required | Unique variant identifier. Upsert key within a product. |
| Sku | string | Required | Must exactly match the Sku used in OrderItems. Case-sensitive. |
| Name | string | Required | Variant display name shown in the decision payload. |
| OriginalPrice | number | Required | Full retail price. Shown even when a sale price is active. |
| Currency | string | Required | ISO 4217 code for OriginalPrice and SalePrice. |
| IsAvailable | boolean | Required | true if purchasable online. When false, this variant is excluded from decision generation. |
| Image | string | Optional | Public HTTPS image URL. Min 600×600px recommended. |
| Size | string | Optional | Size or volume, e.g. 500ml, XL, 100g. |
| Stock | integer | Optional | Current inventory count. |
| SalePrice | number | Optional | Promotional price. When lower than OriginalPrice, Replenit highlights the saving in the decision payload. |
| Language | string | Optional | BCP 47 tag for this variant's content locale. Matched to the customer's Language field. |
| BrandName | string | Optional | Brand name for this variant. Included in the decision payload. |
Example request
[
{
"ProductId": "P-42",
"ProductName": "Women's Training Tank Top",
"Taxonomy": ["Apparel", "Women", "Activewear", "Tops"],
"IsOfflineExclusive": false,
"ProductVariants": [
{
"VariantId": "V-42-BLK-S",
"Sku": "SKU-42-BLK-S",
"Name": "Black / Small",
"Image": "https://cdn.example.com/products/tank-black-s.jpg",
"Size": "S",
"Stock": 84,
"OriginalPrice": 34.99,
"SalePrice": 27.99,
"Currency": "USD",
"IsAvailable": true,
"Language": "en-US",
"BrandName": "Acme Active"
}
]
}
]Code examples
curl -X POST "https://api.replen.it/products/YOUR_TENANT_ID" \ -H "Content-Type: application/json" \ -H "x-replenit-auth-key: YOUR_API_KEY" \ -d @products.json
Response
{ "success": true, "message": "Products saved.", "data": { "count": 1, "processedAt": "2025-08-22T21:00:00.000Z" } }DELETE /products/{tenantId}/{productId}
curl -X DELETE "https://api.replen.it/products/YOUR_TENANT_ID/P-42" \ -H "x-replenit-auth-key: YOUR_API_KEY"
DELETE /products/{tenantId}/{productId}/variants/{variantId}
curl -X DELETE "https://api.replen.it/products/YOUR_TENANT_ID/P-42/variants/V-42-BLK-S" \ -H "x-replenit-auth-key: YOUR_API_KEY"
Product enrichment
After a product is ingested, Replenit's reasoning layer automatically analyses each product record and generates a structured set of internal semantic attributes. You do not send these attributes — they are produced by Replenit and used exclusively by the decision engine.
How it works
ProductName, Taxonomy, variant attributes, and pricing are received and stored as the source of record for the reasoning layer.Enrichment runs automatically after every product upsert. The more complete your product data — particularly ProductName, Taxonomy, BrandName, and descriptive variant Name fields — the more precise the output.
Taxonomy, BrandName, descriptive variant Name, Size, Language — gives the reasoning layer more signal. The more complete your product data, the more precise the output and the better the decisions downstream.Customer enrichment
Replenit transforms customer transactions into continuously evolving behavioural state. Rather than relying on static scores, segments, or predefined rules, the platform continuously interprets purchasing behaviour over time — identifying intent, behavioural shifts, consumption patterns, and lifecycle signals as customer behaviour evolves.
Each new interaction updates the customer's contextual state, allowing downstream decision systems to reason over evolving behaviour rather than isolated transactions or historical scores.
How it works
Error codes
| Status | Meaning | Action |
|---|---|---|
| 200 | Success | Request processed. Continue normal flow. |
| 400 | Validation error | Fix request data — check errors object for field-level detail |
| 401 | Unauthorized | Verify x-replenit-auth-key header and key value |
| 404 | Tenant not found | Verify tenant ID is the correct GUID from Settings → API |
| 429 | Rate limited | Reduce request rate; use Retry-After header; implement exponential backoff |
| 500 | Server error | Retry with backoff. If persistent, contact support@replen.it |
Common 400 causes: request body is not an array, required field missing, string exceeds max length, malformed email, OrderItems is empty.
Rate limits
Standard tier: 100 requests/minute, 5,000 requests/hour. All responses include rate limit headers.
X-RateLimit-Limit: 100 X-RateLimit-Remaining: 95 X-RateLimit-Reset: 1640000000 Retry-After: 30 // present on 429 responses
Best practices
OrderItems reference their SKUs. Missing SKU references won't fail the order ingest, but the reasoning layer won't be able to contextualise those line items until the product is present.EmailOptin, SmsOptin, WhatsappOptin, and AppPushOptin. Replenit uses these as behavioural profiling signals — stale values will skew how decisions are contextualised for that customer.Stock and IsAvailable whenever inventory changes. When IsAvailable is false, that variant will not be included in decisions — keeping this current prevents decisions being generated for products that cannot be fulfilled.Taxonomy, BrandName, variant Name, Size, Language — gives the reasoning layer more signal to work with. The more complete your records, the more precise and well-contextualised the decisions Replenit generates.GdprOptin defaults to false — Replenit will not process, enrich, or generate decisions for any customer where this is false. Sending only customers with valid, current consent is a legal obligation that must be met in your systems before data reaches this API. Replenit does not validate, manage, or refresh consent state. Message-level suppression at delivery time is handled by your connected marketing automation platform.CustomerId and your destination cannot resolve it, the decision will arrive but cannot be matched to a customer record. When in doubt, send both CustomerId and Email on every customer record.Sku in OrderItems must exactly match a ProductVariants[].Sku — case-sensitive. Mismatches break the link between purchase history and the product catalogue, degrading reasoning quality.OrderDate values must be UTC ISO 8601: 2025-08-22T21:00:00Z. Localised date strings will be rejected with a 400 error.[{...}] not {...}. This is the most common cause of 400 errors.Talk to the integration team
Stuck on a payload, an SKU mapping, or production limits? Reach our engineers directly and we'll get you unblocked.
