Integration API

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.

i
This reference covers all data ingestion and deletion endpoints. For the platform user guide, see the Platform Guide.

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.

Customers
Identity, contact details, and channel availability flags used for behavioural profiling and decision targeting.
Orders
Purchase history with full line-item detail. The primary input for customer enrichment and replenishment timing models.
Products
Catalogue with variants, pricing, and inventory. Enriched automatically with semantic attributes by the reasoning layer.

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.

Header
x-replenit-auth-key
Value
Your base64-encoded API key
Tenant ID
GUID — included as a path parameter on every request

Retrieve both from your dashboard under Settings → API Keys.

http
POST https://api.replen.it/customers/{tenantId}
x-replenit-auth-key: YOUR_API_KEY
Content-Type: application/json
!
Keep your API key secret. Do not expose it in client-side code or public repositories. Rotate compromised keys immediately in Settings.

Base URL & endpoints

Basehttps://api.replen.it
EndpointMethodPurposeBatch
/customers/{tenantId}POSTUpsert customer profiles100–500
/customers/{tenantId}DELETEDelete customer by ID or emailSingle record
/orders/{tenantId}POSTUpsert orders with line items50–200
/orders/{tenantId}/{orderId}DELETEDelete an entire orderSingle record
/orders/{tenantId}/{orderId}/itemsDELETEDelete a single line itemSingle record
/products/{tenantId}POSTUpsert product catalogue50–100
/products/{tenantId}/{productId}DELETEDelete product and all variantsSingle record
/products/{tenantId}/{productId}/variants/{variantId}DELETEDelete a single variantSingle record
i
DELETE endpoints are asynchronous. They return success once the request is durably accepted and queued. Deletions are applied idempotently downstream.

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.

Step 1
Send Products
Step 2
Send Customers
Step 3
Send Orders
Ongoing
Stream delta events
Initial load
Send your full product catalogue, existing customer base, and complete order history. This seeds the reasoning layer and allows enrichment to begin immediately.
Ongoing sync
Stream new orders, product updates, and customer changes as they occur. Each event updates the relevant enrichment context and may trigger a new decision cycle.
Delta events
All endpoints are upsert operations — resend only what has changed. Cancelled orders, inventory updates, and consent changes should be pushed as they happen, not batched.

Internal pipeline

Stage 1
Data Sources
You push customers, orders, and products via the API.
Stage 2
Data Ingestion & Quality
Schema validation, duplicate resolution, exclusion checks, and SKU linkage.
Stage 3
Reasoning Layer
Product and customer enrichment run in parallel. Each record is interpreted and contextualised.
Stage 4
Maestro
The 1:1 orchestrator evaluates every customer against active agents and selects the highest-priority action.
Stage 5
Decisions & Dispatching
Decisions are forwarded to connected platforms in an executable format ready for activation.

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.

json — 200
{
  "success": true,
  "message": "Records saved.",
  "data": {
    "count": 3,
    "processedAt": "2025-08-22T21:00:00.000Z"
  }
}
json — 400
{
  "success": false,
  "message": "Validation failed",
  "data": {},
  "errors": {
    "[0].Email": ["The Email field is required."],
    "[0].CustomerId": ["Maximum length is 100 characters."]
  }
}

POST /customers/{tenantId}

POSThttps://api.replen.it/customers/{tenantId}
Create or update customer profiles. Accepts a JSON array. CustomerId or Email is the upsert key — at least one is required.

Request body — array of customer objects

Identity(4 fields)
i
At least one of CustomerId or Email is required. They can be sent individually or together. Send whichever identifier your dispatch destination can resolve — see the note below.
FieldTypeDescription
CustomerIdstringRequired*Your unique customer identifier. Max 100 chars. Upsert key — sending the same value updates the existing record. Required if not sending Email.
EmailstringRequired*Valid email address. Upsert key when CustomerId is absent. Required if not sending CustomerId.
NamestringOptionalFirst name. Included in the decision payload for personalisation at the execution layer.
SurnamestringOptionalLast name / surname.
!
Match your identifier to your dispatch destination. Confirm whether your marketing automation platform or data platform resolves incoming decision events on email or customer ID. If you send only CustomerId but your destination cannot resolve it, decisions arrive but cannot be matched to a record. When in doubt, send both.
Contact(3 fields)
FieldTypeDescription
PhonestringOptionalE.164 format, e.g. +14155550123. Profiling signal; passed in the decision payload to downstream platforms.
LanguagestringOptionalBCP 47 tag, e.g. en-US, es-ES. Used by the reasoning layer to contextualise decisions and match localised product content.
UsernamestringOptionalPlatform username. Included in the decision payload for personalisation at the execution layer.
Channel availability flags(4 boolean fields)

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.

FieldTypeDescription
EmailOptinbooleanOptionalCustomer is reachable via email.
SmsOptinbooleanOptionalCustomer is reachable via SMS.
WhatsappOptinbooleanOptionalCustomer is reachable via WhatsApp.
AppPushOptinbooleanOptionalCustomer is reachable via mobile push notification.
Profiling & pipeline flags(2 fields)
FieldTypeDescription
GdprOptinbooleanOptionalControls 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.
IsExcludedbooleanOptionalWhen true, this customer is excluded from the decision pipeline entirely. Use for internal test accounts. Defaults to false.

Example request

json
[
  {
    "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
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}]'
javascript
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();
python
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

Returns200400401404
json — 200
{ "success": true, "message": "Customers saved.", "data": { "count": 1, "processedAt": "2025-08-22T21:00:00.000Z" } }

DELETE /customers/{tenantId}

DELETEhttps://api.replen.it/customers/{tenantId}
Delete a customer record by customerId or email. Pass either as a query parameter. Asynchronous — queued and applied idempotently.
Query paramTypeDescription
customerIdstringOptionalDelete by customer ID. Use this or email.
emailstringOptionalDelete by email address. Use this or customerId.
curl
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}

POSThttps://api.replen.it/orders/{tenantId}
Ingest order events with full line-item detail. Each order object must include an OrderItems array containing at least one item.

Request body — array of order objects

Order-level fields(10 fields)
FieldTypeDescription
OrderIdstringRequiredUnique order identifier. Upsert key — resend to update (e.g. cancellations).
CustomerIdstringRequiredLinks to the customer's CustomerId.
EmailstringRequiredCustomer email. Used as a fallback if CustomerId is not matched.
OrderDatestringRequiredISO 8601 UTC datetime, e.g. 2025-08-22T21:00:00Z. Baseline for replenishment timing.
TotalRevenuenumberRequiredTotal order value as a decimal in the order's currency.
CurrencystringRequiredISO 4217 code, e.g. USD, EUR, GBP.
OrderItemsarrayRequiredArray of line item objects. Minimum one item required.
TotalQuantityintegerOptionalTotal units across all line items.
UniqueQuantityintegerOptionalNumber of distinct product SKUs in the order.
IsOrderCancelledbooleanOptionalSet to true for cancelled orders. Excluded from timing models. Defaults to false.
Order item fields(9 fields per item)
FieldTypeDescription
ProductIdstringRequiredLinks to the product's ProductId.
SkustringRequiredMust exactly match a ProductVariants[].Sku. Case-sensitive.
QuantityintegerRequiredUnits purchased. Used to calculate depletion rate.
PricenumberRequiredActual price paid per unit after discounts.
OriginalPricenumberOptionalFull retail price before discounts.
SizestringOptionalSize or volume, e.g. 500ml, XL.
ColorstringOptionalColour of the variant purchased.
BrandstringOptionalBrand name of the item.
IsGiftbooleanOptionalWhen true, item was a gift. Replenit adjusts replenishment timing accordingly. Defaults to false.

Example request

json
[
  {
    "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
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

Returns200400401
json — 200
{ "success": true, "message": "Orders saved.", "data": { "count": 1, "processedAt": "2025-08-22T21:00:00.000Z" } }

DELETE /orders/{tenantId}/{orderId}

DELETEhttps://api.replen.it/orders/{tenantId}/{orderId}
Delete an entire order and all its line items. Asynchronous.
curl
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

DELETEhttps://api.replen.it/orders/{tenantId}/{orderId}/items
Delete a single line item within an order. Pass productId and sku as query parameters.
Query paramTypeDescription
productIdstringRequiredThe product ID of the line item to remove.
skustringRequiredThe SKU of the specific variant to remove.
curl
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}

POSThttps://api.replen.it/products/{tenantId}
Sync your product catalogue including all variants. Each product must include a ProductVariants array. After ingestion, the reasoning layer automatically processes each product — see Product enrichment.

Request body — array of product objects

Product-level fields(5 fields)
FieldTypeDescription
ProductIdstringRequiredUnique product identifier. Upsert key. Must match ProductId values used in OrderItems.
ProductNamestringRequiredHuman-readable product name. Used in the decision payload and message content.
ProductVariantsarrayRequiredArray of variant objects. A product with no distinct variants should still include one variant for the base product.
Taxonomyarray<string>OptionalOrdered category path, broadest to most specific, e.g. ["Apparel","Women","Activewear"]. Used for category-level targeting.
IsOfflineExclusivebooleanOptionalWhen true, only available in-store. Replenit adapts decision context accordingly. Defaults to false.
Variant fields(12 fields per variant)
FieldTypeDescription
VariantIdstringRequiredUnique variant identifier. Upsert key within a product.
SkustringRequiredMust exactly match the Sku used in OrderItems. Case-sensitive.
NamestringRequiredVariant display name shown in the decision payload.
OriginalPricenumberRequiredFull retail price. Shown even when a sale price is active.
CurrencystringRequiredISO 4217 code for OriginalPrice and SalePrice.
IsAvailablebooleanRequiredtrue if purchasable online. When false, this variant is excluded from decision generation.
ImagestringOptionalPublic HTTPS image URL. Min 600×600px recommended.
SizestringOptionalSize or volume, e.g. 500ml, XL, 100g.
StockintegerOptionalCurrent inventory count.
SalePricenumberOptionalPromotional price. When lower than OriginalPrice, Replenit highlights the saving in the decision payload.
LanguagestringOptionalBCP 47 tag for this variant's content locale. Matched to the customer's Language field.
BrandNamestringOptionalBrand name for this variant. Included in the decision payload.

Example request

json
[
  {
    "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
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

Returns200400401
json — 200
{ "success": true, "message": "Products saved.", "data": { "count": 1, "processedAt": "2025-08-22T21:00:00.000Z" } }

DELETE /products/{tenantId}/{productId}

DELETEhttps://api.replen.it/products/{tenantId}/{productId}
Delete a product and all its variants. Cascades — removing the parent removes all child variant records. Asynchronous.
curl
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}

DELETEhttps://api.replen.it/products/{tenantId}/{productId}/variants/{variantId}
Delete a single product variant without affecting the parent product or other variants. Asynchronous.
curl
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

1 — Ingest
Raw product data
Your ProductName, Taxonomy, variant attributes, and pricing are received and stored as the source of record for the reasoning layer.
2 — Reason
Semantic interpretation
A reasoning layer reads the product data and interprets it — inferring category, audience, use case, brand positioning, and product-type-specific characteristics not explicitly present in the raw fields.
3 — Enrich
Structured attributes
A structured set of semantic attributes is attached to the product record internally, covering subcategory, audience targeting, purchase intent, use case, and physical characteristics.
4 — Inform decisions
Decision engine input
Enriched product attributes are passed into Maestro as contextual input when running the Cross-Sell and Replenishment agents — matching the right products to the right customers at the right time.

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.

i
Enrichment attributes are internal to Replenit. They are not returned via the API and are not exposed in the dashboard schema. Their sole purpose is to improve the quality of decisions made by Maestro's agents.
+
Send complete product records, even for optional fields. Every additional data point — 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

1 — Ingest
Behavioural history
Every order contributes to a chronological behavioural record — what was purchased, in what combination, at what intervals, and in what sequence. The system treats timing, repetition, and purchase transitions as core behavioural signals, not just transactional totals.
2 — Reason
Behavioural interpretation
A reasoning layer continuously interprets the customer's evolving behavioural state to identify contextual patterns and intent signals that rigid rules and static scoring systems fail to capture — reasoning over purchasing rhythm changes, category expansion, premiumisation, gifting behaviour, lifecycle transitions, household dynamics, and emerging intent.
3 — Enrich
Semantic context
Products and transactions are enriched with contextual metadata — category relationships, brand positioning, replenishment behaviour, pricing dynamics, audience signals, and consumption patterns — composed into a continuously evolving customer context.
4 — Inform decisions
Contextual input to Maestro
The interpreted behavioural state is passed into Maestro and downstream decision agents as contextual input. Decisions are generated based on behavioural momentum, lifecycle state, intent, and evolving preferences — not static segment-level probabilities or predefined campaign logic.
i
Customer enrichment is a continuously evolving profile, not a snapshot. It is re-evaluated as new orders arrive — there is no batch schedule. The interpreted context is internal to Replenit and is not returned via the API.
+
Send historical orders at integration time. The reasoning layer produces more accurate and nuanced behavioural profiles with more history to work from. An initial bulk load of 12–24 months of order history is strongly recommended to avoid a cold-start period.

Error codes

StatusMeaningAction
200SuccessRequest processed. Continue normal flow.
400Validation errorFix request data — check errors object for field-level detail
401UnauthorizedVerify x-replenit-auth-key header and key value
404Tenant not foundVerify tenant ID is the correct GUID from Settings → API
429Rate limitedReduce request rate; use Retry-After header; implement exponential backoff
500Server errorRetry 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.

response headers
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640000000
Retry-After: 30 // present on 429 responses

Best practices

+
Batch your requests. Send arrays of up to 500 records per call (100–200 for orders and products). Batching dramatically reduces API overhead for initial historical loads.
+
Send products before orders. Product records should exist before 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.
+
Keep channel availability flags current. Always send the latest values for EmailOptin, SmsOptin, WhatsappOptin, and AppPushOptin. Replenit uses these as behavioural profiling signals — stale values will skew how decisions are contextualised for that customer.
+
Update inventory in real time. Sync 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.
+
Send complete records, even for optional fields. Every additional data point — 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.
i
Only send consented customers to Replenit. 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.
!
Send the identifier your destination can resolve. Before integrating, confirm whether your marketing automation platform or data platform matches incoming decision events on email address or customer ID. If you send only 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.
!
Match SKUs exactly. The 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.
!
ISO 8601 dates only. All OrderDate values must be UTC ISO 8601: 2025-08-22T21:00:00Z. Localised date strings will be rejected with a 400 error.
!
Request body must be an array. All POST endpoints expect a JSON array, even for a single record: [{...}] not {...}. This is the most common cause of 400 errors.
Need a hand?

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.