Beispiel Anbindung SalesViewer API mit dem SDK-Konnektor
Die SalesViewer-API (Dokumentation: https://salesviewer.github.io/salesviewer-api/definition) liefert je Aufruf geschachtelte Daten:
Session ⟶ enthält Visits (Liste) und Company (Objekt).
Die Standard-REST-Verbindung kann diese Teilobjekte nicht separat als eigenständige Objekte ausgeben.
Ziel: Session, Visit und Company in eigene Schemaobjekte auftrennen, um sie mit Syncler einzeln abrufen, transformieren und synchronisieren zu können.
Lösung: Einsatz des SDK-Konnektors mit zwei C#-Skripten
- Schema-Skript – beschreibt die vier Schemaobjekte
- GetData-Skript – ruft SalesViewer ab, entfaltet die verschachtelten Daten und gibt die gefragte Objektmenge zurück
Voraussetzungen
- Ein SDK-Konnektor in Syncler (mit API-Key als Parameter, z. B.
ApiKey) - Zwei Skripts im SDK-Konnektor:
- SalesViewerSchema (liefert Schema/Metadaten)
- SalesViewerGetData (liefert Daten)
- Optional: Sync-Konfiguration je Objekt (company, visit, session, sessionCompany) inkl. Änderungsgrenzwert (Feld
lastActivityAt)
1) Schema-Skript (C#)
- Definiert vier Schemaobjekte:
company– eindeutige ID:id, Updated-Feld:lastActivityAtvisit– eindeutige ID:id, Updated-Feld:lastActivityAtsession– eindeutige ID:guid, Updated-Feld:lastActivityAt; enthält kopiertes FeldcompanyIDsessionCompany– Variante des Session-Schemas, eindeutige ID:companyID(Session auf Company verdichtet)
- Liefert die Schemaobjekte als JSON-Array
using SIS; using Newtonsoft.Json.Linq; public class SalesViewerSchema { // SDK helper public SisHelper Helper { get; set; } // Your operation to return json data public string Execute() { #region Company Schema JObject Company = new() { { "title", "company" }, { "uniqueidentifier", new JArray() { "id" } } }; //Company Eigenschaften JObject CompanyProperties = new() { { "id", new JObject() { { "type", "string" }, { "title", "ID of company" } } }, { "name", new JObject() { { "type", "string" }, { "title", "Name of company" } } }, { "city", new JObject() { { "type", "string" }, { "title", "City of company" } } }, { "zip", new JObject() { { "type", "string" }, { "title", "Zip Code of company" } } }, { "street", new JObject() { { "type", "string" }, { "title", "Street of company" } } }, { "phone", new JObject() { { "type", "string" }, { "title", "Phone Number of company" } } }, { "email", new JObject() { { "type", "string" }, { "title", "E-Mail address of company" } } }, { "url", new JObject() { { "type", "string" }, { "title", "URL of website" } } }, { "countryCode", new JObject() { { "type", "string" }, { "title", "Country Code" } } }, { "countryCode3", new JObject() { { "type", "string" }, { "title", "Country Code ISO3" } } }, { "state", new JObject() { { "type", "string" }, { "title", "State of company" } } }, { "stateCode", new JObject() { { "type", "string" }, { "title", "State code of company" } } }, { "phoneCode", new JObject() { { "type", "string" }, { "title", "Phone code of company" } } }, { "isCustomer", new JObject() { { "type", "boolean" }, { "title", "IsCustomer" } } }, { "isFavorite", new JObject() { { "type", "boolean" }, { "title", "IsFavorite" } } }, { "isCompetitor", new JObject() { { "type", "boolean" }, { "title", "IsCompetitor" } } }, { "note", new JObject() { { "type", "string" }, { "title", "Note of company" } } }, { "intro_text", new JObject() { { "type", "string" }, { "title", "Intro of company" } } }, { "lastActivityAt", new JObject() { { "type", "string" }, { "format", "date-time" }, { "title", "Session company last activity at" } } }, { "distance", new JObject() { { "type", "number" }, { "title", "Distance" } } }, { "cardUrl", new JObject() { { "type", "string" }, { "title", "Card URL" } } }, { "xingUrl", new JObject() { { "type", "string" }, { "title", "Xing URL" } } }, { "linkedinUrl", new JObject() { { "type", "string" }, { "title", "LinkedIn URL" } } }, { "sector", new JObject() { { "type", "object" }, { "title", "Sector" }, { "properties", new JObject(){ { "id", new JObject(){ { "type", "string" }, { "title", "ID" } } }, { "name", new JObject(){ { "type", "string" }, { "title", "Name" } } } } }} }, { "category", new JObject() { { "type", "object" }, { "title", "Category" }, { "properties", new JObject(){ { "id", new JObject(){ { "type", "string" }, { "title", "ID" } } }, { "name", new JObject(){ { "type", "string" }, { "title", "Name" } } } } }} }, { "meta", new JObject() { { "type", "object" }, { "title", "Meta" }, { "properties", new JObject(){ { "title", new JObject(){ { "type", "string" }, { "title", "Title" } } }, { "description", new JObject(){ { "type", "string" }, { "title", "Description" } } } } }} } }; Company.Add("properties", CompanyProperties); //Änderungsdatum Company.Add("updated", "lastActivityAt"); #endregion #region Visit Schema JObject Visit = new() { { "title", "visit" }, { "uniqueidentifier", new JArray() { "id" } } }; //Visit Eigenschaften JObject VisitProperties = new() { { "id", new JObject() { { "type", "integer" }, { "title", "ID of Session visit" } } }, { "sessionGuid", new JObject() { { "type", "string" }, { "title", "GUID of Session" } } }, { "startedAt", new JObject() { { "type", "string" }, { "format", "date-time" }, { "title", "Session visit started at" } } }, { "lastActivityAt", new JObject() { { "type", "string" }, { "format", "date-time" }, { "title", "Session visit last activity at" } } }, { "url", new JObject() { { "type", "string" }, { "title", "URL of the session visit" } } }, { "referer", new JObject() { { "type", "string" }, { "title", "Referer" } } }, { "refererMedium", new JObject() { { "type", "string" }, { "title", "Referer medium" } } }, { "duration", new JObject() { { "type", "string" }, { "title", "Duration" } } }, { "duration_secs", new JObject() { { "type", "integer" }, { "title", "Duration seconds" } } } }; Visit.Add("properties", VisitProperties); //Änderungsdatum Visit.Add("updated", "lastActivityAt"); #endregion #region Session Schema JObject Session = new() { { "title", "session" }, { "uniqueidentifier", new JArray() { "guid" } } }; //Session Eigenschaften JObject SessionProperties = new() { { "guid", new JObject() { { "type", "string" }, { "title", "GUID of Session" } } }, { "companyID", new JObject() { { "type", "string" }, { "title", "ID of the company" } } }, { "startedAt", new JObject() { { "type", "string" }, { "format", "date-time" }, { "title", "Session visit started at" } } }, { "lastActivityAt", new JObject() { { "type", "string" }, { "format", "date-time" }, { "title", "Session visit last activity at" } } }, { "duration", new JObject() { { "type", "string" }, { "title", "Duration" } } }, { "language", new JObject() { { "type", "string" }, { "title", "Language" } } }, { "referer", new JObject() { { "type", "object" }, { "title", "Referer" }, { "properties", new JObject(){ { "url", new JObject(){ { "type", "string" }, { "title", "URL" } } }, { "medium", new JObject(){ { "type", "string" }, { "title", "Medium" } } }, { "source", new JObject(){ { "type", "string" }, { "title", "Source" } } }, { "term", new JObject(){ { "type", "string" }, { "title", "Term" } } } } }} }, { "campaign", new JObject() { { "type", "boolean" }, { "title", "Campaign" } } }, { "offline_campaign", new JObject() { { "type", "boolean" }, { "title", "Offline campaign" } } }, { "duration_secs", new JObject() { { "type", "integer" }, { "title", "Duration seconds" } } }, { "video_url", new JObject() { { "type", "string" }, { "title", "Video URL" } } }, { "interests", new JObject() { { "type", "array" }, { "title", "Interests" }, { "items", new JObject(){ { "type", "object" }, { "title", "Interests" }, { "properties", new JObject(){ { "id", new JObject(){ { "type", "string" }, { "title", "ID" } } }, { "name", new JObject(){ { "type", "string" }, { "title", "Name" } } } } } } } } }, { "company", new JObject() { { "type", "object" }, { "title", "Company" }, { "properties", CompanyProperties } } }, { "visits", new JObject() { { "type", "array" }, { "title", "Visits" }, { "items", new JObject(){ { "type", "object" }, { "title", "Visits" }, { "properties", VisitProperties } } } } } }; Session.Add("properties", SessionProperties); //Änderungsdatum Session.Add("updated", "lastActivityAt"); #endregion #region SessionCompany Schema - PrimaryKey ist CompanyId JObject SessionCompany = new() { { "title", "sessionCompany" }, { "uniqueidentifier", new JArray() { "companyID" } }, { "properties", SessionProperties }, //Änderungsdatum { "updated", "lastActivityAt" } }; #endregion JArray Response = new() { Company, Visit, Session, SessionCompany }; return Response.ToString(); } }
2) GetData-Skript (C#)
- Ruft
https://api.salesviewer.com/sessions.jsonmit API-Key, Paging und optionalem From-Filter (LAST_SYNC_DATE) auf - Liefert je nach
Helper.TargetObjectnur die gefragte Menge zurück (company/visit/session/sessionCompany) - Duplikatschutz (Company): Da Company je Session vorkommt, wird über Pages hinweg eine Liste gesehener Company-IDs in Helper-Parametern gespeichert (
COMPANY_ID), um Doppelübernahme zu verhindern - Einzelabruf (
GETDATA_ID) ist nicht vorgesehen und wird abgewehrt
using System; using System.Linq; using SIS; using Newtonsoft.Json.Linq; using System.Collections.Generic; using SIS.Public; public class SalesViewerGetData { // SDK helper public SisHelper Helper { get; set; } // Your operation to return json data public string Execute() { try { JArray Result = new(); //Einzelabfragen nicht zulässig if (!string.IsNullOrEmpty(Helper.GetParam("GETDATA_ID"))) return Result.ToString(); #region Url definieren string API_Key = Helper.GetParam("ApiKey"); string Url = "https://api.salesviewer.com/sessions.json?apiKey=" + API_Key; if (!string.IsNullOrEmpty(Helper.GetParam("GETDATA_WHERE"))) Url += Helper.GetParam("GETDATA_WHERE"); //Abfrage enthält Änderungsanforderung if (!string.IsNullOrEmpty(Helper.GetParam("LAST_SYNC_DATE"))) Url += "&from=" + Helper.GetParam<DateTime>("LAST_SYNC_DATE").ToString("yyyy-MM-dd HH:mm:ss"); //Helper übergibt Page-Number (SalesViewer ist 1-basiert) Url += "&page=" + (Helper.Page + 1); Url += "&pageSize=50"; Helper.InsertMessage("SalesViewer Url: " + Url, 5); #endregion #region Service abrufen string ServiceResponse = Helper.InvokeUrl(Url, "GET", null, ""); if (!string.IsNullOrEmpty(ServiceResponse)) { JObject ResponseObject = JObject.Parse(ServiceResponse); if (ResponseObject["result"] is JArray ResponseArray) foreach (JObject SessionObject in ResponseArray) { #region Firma wurde angefordert if (Helper.TargetObject == "company") { if (SessionObject.ContainsKey("company")) { //Firma kann mehrfach enthalten sein. //Duplikate sollen über Pages hinweg vermieden werden. //Helper bietet übergreifenden Storage if (string.IsNullOrEmpty(Helper.GetParam("COMPANY_ID"))) Helper.SetParam("COMPANY_ID", new JArray()); JArray CompanyIdList = JArray.Parse(Helper.GetParam("COMPANY_ID")); if (SessionObject["company"] is JObject Company) { string CompanyId = Company["id"]?.ToString() ?? ""; if (!CompanyIdList.Any(id => id.ToString() == CompanyId)) { if (Company.ContainsKey("lastActivityAt")) Company["lastActivityAt"] = SessionObject["lastActivityAt"]; else Company.Add("lastActivityAt", SessionObject["lastActivityAt"]); Result.Add(Company); CompanyIdList.Add(CompanyId); Helper.SetParam("COMPANY_ID", CompanyIdList); } } } } #endregion #region Visit wurde angefordert if (Helper.TargetObject == "visit") { if (SessionObject.ContainsKey("visits")) { string SessionGuid = SessionObject["guid"]?.ToString() ?? ""; if (SessionObject["visits"] is JArray VisitArray) foreach (JObject Visit in VisitArray) { Visit.Add("sessionGuid", SessionGuid); if (Visit.ContainsKey("lastActivityAt")) Visit["lastActivityAt"] = SessionObject["lastActivityAt"]; else Visit.Add("lastActivityAt", SessionObject["lastActivityAt"]); Result.Add(Visit); } } } #endregion #region Session wurde angefordert if (Helper.TargetObject == "session") { string CompanyId = (SessionObject["company"] as JObject)?["id"]?.ToString() ?? ""; JObject ResultSessionObject = new(SessionObject) { //CompanyId aus Unterobjekt kopieren { "companyID", CompanyId } }; Result.Add(ResultSessionObject); } #endregion #region Session mit Company-ID wurde angefordert if (Helper.TargetObject == "sessionCompany") { string CompanyId = (SessionObject["company"] as JObject)?["id"]?.ToString() ?? ""; JObject ResultSessionCompany = new(SessionObject) { //CompanyId aus Unterobjekt kopieren { "companyID", CompanyId } }; Result.Add(ResultSessionCompany); } #endregion } } #endregion return Result.ToString(); } catch (Exception Exp) { Helper.InsertLog(Exp.Message, 1); throw; } } }
Ergebnis
Mit dem SDK-Konnektor werden die verschachtelten SalesViewer-Antworten in flache, einzeln synchronisierbare Objektmengen zerlegt.
So lassen sich Company, Visit, Session (sowie SessionCompany) unabhängig auslesen, transformieren und in Zielsysteme schreiben – inkl. Delta-Verarbeitung und Duplikatschutz.