KLIQ|Developers
CRM Integration

Salesforce Integration

Resolve Salesforce store records, link them to KLIQ locations, and push distribution-check facings back to Salesforce — all in a single SDK flow.

Per-tenant org configuration

The Salesforce integration runs against a per-tenant configured org. Each tenant may point to a sandbox or a production Salesforce org, mirroring the platform's SalesforcePush.env field. No credentials are required in the SDK — the API uses the org wired up in the platform admin panel for your tenant.

Overview

The Salesforce integration exposes three operations on tenant.salesforce:

MethodDescription
getStore(storeIdOrName, by?)Fetch a Salesforce store record together with its product list
link(params)Bind a Salesforce store to a KLIQ location and map individual products to tracked objects
push(params)Send the latest CV-detected facings for a location back to Salesforce

The typical flow is: resolve a store → link it to a KLIQ location → push facings after each observation cycle.

Endpoints

GET/v1/salesforce/stores/{storeIdOrName}Fetch a Salesforce store and its product list
POST/v1/salesforce/linkLink a Salesforce store to a KLIQ location with SKU mappings
POST/v1/salesforce/pushPush distribution-check facings to Salesforce

Step 1 — Resolve a Salesforce store

Use getStore to look up a store by its Salesforce ID (default) or by name.

// Look up by Salesforce store ID (default)
const store = await tenant.salesforce.getStore('0019000001XyZaA', 'id');

console.log(store.storeId);    // "0019000001XyZaA"
console.log(store.storeName);  // "Delhaize Flagey"
console.log(store.accountId);  // "0019000000AbCdE"

// Each product the store carries in Salesforce
store.storeProducts.forEach((p) => {
console.log(p.storeProductId);  // "01t9000000XyZ01"
console.log(p.productId);       // "01t9000000AbCd0"
console.log(p.productName);     // "Duvel 330ml 6-pack"
console.log(p.locationName);    // "Beverage aisle"
console.log(p.kliqFacings);     // 4  (last pushed value, or undefined)
console.log(p.kliqUpdateTime);  // "2026-07-20T09:15:00Z" (or undefined)
});

// Look up by store name instead
const byName = await tenant.salesforce.getStore('Delhaize Flagey', 'name');

SalesforceStoreDto fields

FieldTypeDescription
storeIdstringSalesforce store (Account) ID
storeNamestringHuman-readable store name
accountIdstringParent Salesforce Account ID
storeProductsSalesforceStoreProductDto[]Products listed for this store in SF

SalesforceStoreProductDto fields

FieldTypeDescription
storeProductIdstringSalesforce StoreProduct record ID
productIdstringSalesforce Product2 ID
productNamestringProduct display name
locationNamestring | undefinedStore location/aisle label in SF
kliqFacingsnumber | undefinedLast facing count pushed by KLIQ
kliqUpdateTimestring | undefinedISO timestamp of last KLIQ push

Step 2 — Link a store to a KLIQ location

link binds a Salesforce store to a KLIQ location and maps individual Salesforce products to KLIQ tracked objects. This only needs to be done once per store (or whenever the product set changes).

const { locationId, linkedSkus } = await tenant.salesforce.link({
locationId: 'loc_abc123',
salesforceStoreId: '0019000001XyZaA',
skuLinks: [
  {
    trackedObjectId: 'obj_duvel_330',
    salesforceProductId: '01t9000000AbCd0',
  },
  {
    trackedObjectId: 'obj_duvel_750',
    salesforceProductId: '01t9000000AbCd1',
  },
],
});

console.log(locationId);  // "loc_abc123"
console.log(linkedSkus);  // 2  — number of SKU pairs saved

SalesforceLinkParams fields

FieldTypeDescription
locationIdstringKLIQ location ID to bind
salesforceStoreIdstringSalesforce store ID to associate
skuLinksArray<{ trackedObjectId: string; salesforceProductId: string }>Product-to-SKU mappings

Step 3 — Push facings to Salesforce

After observations are captured and processed, call push to write the latest CV-detected facing counts back to the linked Salesforce store.

const result = await tenant.salesforce.push({
locationId: 'loc_abc123',
source: 'observation',   // 'admin' | 'observation' — defaults to 'admin'
});

console.log(result.pushId);           // "push_xyz789"
console.log(result.status);           // "ok" | "error"
console.log(result.productsSent);     // 2  — SKUs successfully written to SF
console.log(result.productsSkipped);  // 1  — SKUs that could not be written

// Inspect why individual SKUs were skipped
result.skipped.forEach((s) => {
console.log(s.trackedObjectId); // "obj_duvel_750"
console.log(s.reason);          // "no_salesforce_product_link"
});

SalesforcePushParams fields

FieldTypeDescription
locationIdstringKLIQ location whose facings to push
source'admin' | 'observation' | undefinedPush trigger context (optional)

SalesforcePushResult fields

FieldTypeDescription
pushIdstringUnique identifier for this push event
status'ok' | 'error'Overall push result
productsSentnumberNumber of SKUs successfully written
productsSkippednumberNumber of SKUs that could not be written
skippedArray<{ trackedObjectId: string; reason: string }>Per-SKU skip details

End-to-end example

Resolve a Salesforce store by name, link it to an existing KLIQ location, and push facings immediately.

// 1. Resolve the store by name
const store = await tenant.salesforce.getStore('Delhaize Flagey', 'name');

// 2. Link the store to a KLIQ location with product mappings
const { locationId, linkedSkus } = await tenant.salesforce.link({
locationId: 'loc_abc123',
salesforceStoreId: store.storeId,
skuLinks: store.storeProducts.map((p, i) => ({
  trackedObjectId: `obj_product_${i}`,
  salesforceProductId: p.productId,
})),
});

console.log(`Linked ${linkedSkus} SKUs to location ${locationId}`);

// 3. Push the latest observed facings to Salesforce
const result = await tenant.salesforce.push({
locationId,
source: 'observation',
});

if (result.status === 'ok') {
console.log(`Pushed ${result.productsSent} products to Salesforce`);
} else {
console.warn(`Push finished with errors — ${result.productsSkipped} skipped`);
result.skipped.forEach((s) => console.warn(s.trackedObjectId, s.reason));
}

Next steps

  • Missions & Routes — Salesforce-pulled routes link back to the stores resolved here
  • Observations — Capture the shelf photos that feed the facing counts
  • CV Jobs — Understand how facing counts are produced from observations
  • Webhooks — Get notified when a push completes or errors