Published at: 2025-10-30

Custom Connector Configuration Guide


1 Document Usage Instructions

The custom connector is designed to integrate ShareCRM with other SaaS or on-premise systems that provide APIs, such as customer-developed services or third-party SaaS systems. After integration, users can synchronize business documents between systems automatically through the connector without manually logging into both systems to enter or verify data.

This document provides step-by-step guidance and FAQs for the Custom Connector. Intended audience: implementation consultants, technical consultants, sales managers, CSMs, and similar roles.

2 Custom Connector Implementation and Configuration

2.1 Pre-implementation Requirements

Before implementation, confirm that the customer tenant is activated and that the customer has purchased the Custom Connector product (verify that the order is active).

2.2 Implementation and Configuration

2.2.1 Connection Configuration

Create a new connector and select connector type: Custom Connector. Fill in the connector information:

image

Result format — instructions: If the API returns JSON like the example below, map the connector fields as follows: error code → code, error message → message, data → data, and success code = 0.

{ “code” : “0”, “message” : “成功”, “data” : { … } }

Get header script — instructions: There are two ways to add headers to requests. If you configure both, Headers parameter configuration takes precedence.

  1. Headers parameter configuration: parameter values support placeholders. Currently placeholders support only tenantId and push token (Connector → API Configuration → Time Subscription → Parameter Description → Header Parameter → token).

image

image

  1. Custom APL function, e.g.:

return [“token”:”test123”, “tenantId”:context.tenantId]

2.2.2 API Configuration

Continue to configure object structures and fields according to the customer’s API examples and API documentation. After configuration, you can inspect requests and responses via API Configuration. Use the request path and request template to send verification requests with Postman and compare the response body against the sample to ensure protocol compatibility.

image

image

2.2.3 API Adaptation

Use API functions to implement Create/Read/Update/Delete for objects. If the tenant service protocol is not compatible with the standard connector, use custom functions to call the tenant service and transform the response to match the connector configuration protocol. The following are examples of custom functions for each request type. You may also choose the appropriate function template when creating functions.

image

Note: After creating a function, set a parameter in the top-right: Type: Map, Name: syncArg. syncArg contains objectData, whose meaning varies across API interfaces.

image

API function common return value description:

image

Below are detailed parameter definitions and function examples by sync action.

2.2.3.1 Create

objectData parameter description:

Field Name Meaning Notes
objAPIName ERP object API name  
masterFieldVal Primary Object data  
detailFieldVals Sub-object data key = sub-object apiName, value = list of detail records

API function example:

/** * Connector object API - Create * Todo: modify or add implementation as required by the customer. * Ensure parameter Map type syncArg is configured in the top-right. **/ String errorCodeKey = “code” // Error code field name — matches connector’s error code field String successCode = “0” // Success code — matches connector’s success code String errorMessageKey = “message” // Error message field name — matches connector’s error msg field String dataKey = “data” // Data field name — matches connector’s data field String dataIdKey = “masterDataId” // Primary Object data id field name String detailDataIdsKey = “detailDataIds” // Sub-object data id field name

Map objectData = syncArg[“objectData”] as Map def apiName = objectData[“objAPIName”] // ERP object apiName, e.g. BD_MATERIAL def masterData = objectData[“masterFieldVal”] // Primary Object data // detail object data: key=sub-object apiName, value=list of detail records Map<String, List<Map<String, Object»> detailMap = objectData[“detailFieldVals”] as Map

// todo: create Map<String, String> headers = [“token”: “xxxxxx”] def url = “http://xxx/xxx//create” Map<String, Object> arg = [“objAPIName”: apiName, “masterData”: masterData, “detailMap”: detailMap] def (Boolean error, HttpResult httpResult, String msg) = http.post(url, headers, arg) if (error) { log.info(“Error creating ERP object: “ + msg) // return error Map<String, Object> result = [:] result[errorCodeKey] = “500” result[errorMessageKey] = msg return result } log.info(“Create ERP object, url:” + url + “ args:” + arg + “ response:” + httpResult) Map createDataResult = httpResult.content as Map

// todo: build return data String masterDataId = createDataResult[“data”][“masterDataId”] // todo: detail object IDs — key=sub-object apiName, value=list of detail IDs; must return IDs in the same order as input Map<String, List> detailIdsMap = createDataResult["data"]["detailDataIds"] as Map

Map<String, Object> data = [:] data[dataIdKey] = masterDataId data[detailDataIdsKey] = detailIdsMap

// return success Map<String, Object> result = [:] result[errorCodeKey] = successCode result[errorMessageKey] = “” result[dataKey] = data return result

2.2.3.2 Update

objectData parameter description:

Field Name Meaning Notes
objAPIName ERP object API name  
masterFieldVal Primary Object data  
detailFieldVals Sub-object data key = sub-object apiName, value = list of detail records

API function example:

/** * Connector object API - Update * Todo: modify or add implementation as required by the customer. * Ensure parameter Map type syncArg is configured in the top-right. **/ String errorCodeKey = “code” String successCode = “0” String errorMessageKey = “message” String dataKey = “data” String dataIdKey = “masterDataId” String detailDataIdsKey = “detailDataIds”

Map objectData = syncArg[“objectData”] as Map def apiName = objectData[“objAPIName”] def masterData = objectData[“masterFieldVal”] Map<String, List<Map<String, Object»> detailMap = objectData[“detailFieldVals”] as Map

// todo: update Map<String, String> headers = [“token”: “xxxxxx”] def url = “http://xxx/xxx//update” Map<String, Object> arg = [“objAPIName”: apiName, “masterData”: masterData, “detailMap”: detailMap] def (Boolean error, HttpResult httpResult, String msg) = http.post(url, headers, arg) if (error) { log.info(“Error updating ERP object: “ + msg) Map<String, Object> result = [:] result[errorCodeKey] = “500” result[errorMessageKey] = msg return result } log.info(“Update ERP object, url:” + url + “ args:” + arg + “ response:” + httpResult) Map updateDataResult = httpResult.content as Map

// todo: build return data String masterDataId = updateDataResult[“data”][“masterDataId”] as String Map<String, List> detailIdsMap = updateDataResult["data"]["detailDataIds"] as Map

Map<String, Object> data = [:] data[dataIdKey] = masterDataId data[detailDataIdsKey] = detailIdsMap

Map<String, Object> result = [:] result[errorCodeKey] = successCode result[errorMessageKey] = “” result[dataKey] = data return result

2.2.3.3 Batch Query for Update/Invalidation

The protocol for batch query-for-update and batch query-for-invalidate is the same. Note: One batch sync may call the batch query API multiple times with pagination using offset and limit.

objectData parameter description:

Field Name Meaning Notes
objAPIName ERP object API name  
startTime Change start timestamp unit: milliseconds
endTime Change end timestamp unit: milliseconds
offset Record offset  
limit Number of records in this request  

API function example:

/** * Connector object API - Query ERP data by time (batch) * Todo: modify or add implementation as required by the customer. * Ensure parameter Map type syncArg is configured in the top-right. **/ String errorCodeKey = “code” String successCode = “0” String errorMessageKey = “message” String dataKey = “data” String totalKey = “totalNum” String dataListKey = “dataList”

Map objectData = syncArg[“objectData”] as Map def apiName = objectData[“objAPIName”] def startTime = objectData[“startTime”] def endTime = objectData[“endTime”] def includeDetail = objectData[“includeDetail”] def offset = objectData[“offset”] def limit = objectData[“limit”]

// todo: get data Map<String, String> headers = [“token”: “xxxxxx”] def url = “http://xxx/xxx/queryMasterBatch?objAPIName=” + apiName + “&startTime=” + startTime + “&endTime=” + endTime + “&includeDetail=” + includeDetail + “&offset=” + offset + “&limit=” + limit def (Boolean error, HttpResult httpResult, String msg) = http.get(url, headers) if (error) { log.info(“Error querying ERP data by time: “ + msg) Map<String, Object> result = [:] result[errorCodeKey] = “500” result[errorMessageKey] = msg return result } log.info(“Query ERP by time, url:” + url + “ response:” + httpResult) Map<String, Object> queryDataByTimeResult = httpResult.content as Map int totalNum = queryDataByTimeResult[“data”][“totalNum”] as Integer List<Map<String, Object» dataList = queryDataByTimeResult[“data”][“dataList”] as List

// build return data Map<String, Object> data = [:] data[totalKey] = totalNum data[dataListKey] = dataList

Map<String, Object> result = [:] result[errorCodeKey] = successCode result[errorMessageKey] = “” result[dataKey] = data return result

2.2.3.4 Single Record (by ID) Query

objectData parameter description:

Field Name Meaning Notes
objAPIName ERP object API name  
dataId Data id  
includeDetail Whether to include sub-object data  

API function example:

/** * Connector object API - Query by ID * Todo: modify or add implementation as required by the customer. * Ensure parameter Map type syncArg is configured in the top-right. **/ String errorCodeKey = “code” String successCode = “0” String errorMessageKey = “message” String dataKey = “data” String masterDataKey = “masterFieldVal” String detailDataKey = “detailFieldVals”

Map objectData = syncArg[“objectData”] as Map def apiName = objectData[“objAPIName”] def dataId = objectData[“dataId”] def includeDetail = objectData[“includeDetail”]

// todo: get object data Map<String, String> headers = [“token”: “xxxxxx”] def url = “http://xxx/xxx/queryMasterById?objAPIName=” + apiName + “&dataId=” + dataId + “&includeDetail=” + includeDetail def (Boolean error, HttpResult httpResult, String msg) = http.get(url, headers) if (error) { log.info(“Error retrieving ERP object: “ + msg) Map<String, Object> result = [:] result[errorCodeKey] = “500” result[errorMessageKey] = msg return result } log.info(“Get ERP object, url:” + url + “ response:” + httpResult) Map<String, Object> erpData = httpResult.content as Map

// todo: split primary and sub-object data Map<String, Object> masterData = erpData[“data”][“masterData”] as Map // sub-object data: key=sub-object apiName, value=list of sub-object records Map<String, List<Map<String, Object»> detailsDataList = dataResult[“data”][“detailData”] as Map

// build return data Map<String, Object> data = [:] data[masterDataKey] = masterData data[detailDataKey] = detailsDataList

// return success Map<String, Object> result = [:] result[errorCodeKey] = successCode result[errorMessageKey] = “” result[dataKey] = data return result

2.2.3.5 Invalidate

objectData parameter description:

Field Name Meaning Notes
objAPIName ERP object API name  
masterFieldVal Primary Object data primary object id field: “_id”

API function example:

/** * Connector object API - Invalidate * Todo: modify or add implementation as required by the customer. * Ensure parameter Map type syncArg is configured in the top-right. **/ String errorCodeKey = “code” String successCode = “0” String errorMessageKey = “message”

Map objectData = syncArg[“objectData”] as Map def apiName = objectData[“objAPIName”] def dataId = objectData[“masterFieldVal”][“_id”]

// todo: invalidate Map<String, String> headers = [“token”: “xxxxxx”] def url = “http://xxx/xxx//invalid” Map<String, Object> arg = [“objAPIName”: apiName, “masterFieldVal”: [“_id”: dataId]] def (Boolean error, HttpResult httpResult, String msg) = http.post(url, headers, arg) if (error) { log.info(“Error invalidating ERP object: “ + msg) Map<String, Object> result = [:] result[errorCodeKey] = “500” result[errorMessageKey] = msg return result } log.info(“Invalidate ERP object, url:” + url + “ args:” + arg + “ response:” + httpResult)

// return success Map<String, Object> result = [:] result[errorCodeKey] = successCode result[errorMessageKey] = “” return result

2.2.3.6 Re-enable (Un-disable)

objectData parameter description:

Field Name Meaning Notes
objAPIName ERP object API name  
masterFieldVal Primary Object data primary object id field: “_id”

API function example:

/** * Connector object API - Re-enable * Todo: modify or add implementation as required by the customer. * Ensure parameter Map type syncArg is configured in the top-right. **/ String errorCodeKey = “code” String successCode = “0” String errorMessageKey = “message”

Map objectData = syncArg[“objectData”] as Map def apiName = objectData[“objAPIName”] def dataId = objectData[“masterFieldVal”][“_id”]

// todo: re-enable Map<String, String> headers = [“token”: “xxxxxx”] def url = “http://xxx/xxx//enable” Map<String, Object> arg = [“objAPIName”: apiName, “masterFieldVal”: [“_id”: dataId]] def (Boolean error, HttpResult httpResult, String msg) = http.post(url, headers, arg) if (error) { log.info(“Error re-enabling ERP object: “ + msg) Map<String, Object> result = [:] result[errorCodeKey] = “500” result[errorMessageKey] = msg return result } log.info(“Re-enable ERP object, url:” + url + “ args:” + arg + “ response:” + httpResult)

// return success Map<String, Object> result = [:] result[errorCodeKey] = successCode result[errorMessageKey] = “” return result

2.2.3.7 Invalidate Detail Record

objectData parameter description:

Field Name Meaning Notes
objAPIName ERP object API name  
masterFieldVal Primary Object data primary object id field: “_id”
detailFieldVals Detail object data key = sub-object apiName, value = sub-object data id

API function example:

/** * Connector object API - Invalidate sub-object * Todo: modify or add implementation as required by the customer. * Ensure parameter Map type syncArg is configured in the top-right. **/ String errorCodeKey = “code” String successCode = “0” String errorMessageKey = “message”

Map objectData = syncArg[“objectData”] as Map def apiName = objectData[“objAPIName”] def dataId = objectData[“masterFieldVal”][“_id”] // sub-object data: key=sub-object apiName, value=sub-object data id Map<String, String> detailDataIdMap = objectData[“detailFieldVals”] as Map

// todo: invalidate detail Map<String, String> headers = [“token”: “xxxxxx”] def url = “http://xxx/xxx//invalidDetail” Map<String, Object> arg = [“objAPIName”: apiName, “masterFieldVal”: [“_id”: dataId], “detailFieldVal”: detailDataIdMap] def (Boolean error, HttpResult httpResult, String msg) = http.post(url, headers, arg) if (error) { log.info(“Error invalidating ERP sub-object: “ + msg) Map<String, Object> result = [:] result[errorCodeKey] = “500” result[errorMessageKey] = msg return result } log.info(“Invalidate ERP sub-object, url:” + url + “ args:” + arg + “ response:” + httpResult)

// return success Map<String, Object> result = [:] result[errorCodeKey] = successCode result[errorMessageKey] = “” return result

2.2.3.8 Event Subscription

objectData parameter description (special note: For Kingdee K3C push, masterFieldVal must include “id”:”ID”. For more details, see Event Subscription):

Field Name Meaning Notes
objAPIName ERP object API name  
masterFieldVal Primary Object data  
detailFieldVals Sub-object data key = sub-object apiName, value = list of detail records

API function example:

todo: modify or add implementation as required by the customer. * Ensure parameter Map type syncArg is configured in the top-right. **/ String errorCodeKey = “code” String successCode = “0” String errorMessageKey = “message” String dataKey = “data” String dataListKey = “dataList” String masterDataKey = “masterFieldVal” String detailDataKey = “detailFieldVals”

Map objectData = syncArg[“objectData”] as Map def apiName = objectData[“objAPIName”] Map<String, Object> masterData = objectData[“masterFieldVal”] as Map Map<String, List<Map<String, Object»> detailMap = objectData[“detailFieldVals”] as Map

// todo: adjust data Map<String, String> headers = [“token”: “xxxxxx”] def url = “http://xxx/xxx//asyncpush” Map<String, Object> arg = [“objAPIName”: apiName, “masterFieldVal”: [“_id”: masterData[“dataId”]]] def (Boolean error, HttpResult httpResult, String msg) = http.post(url, headers, arg) if (error) { log.info(“Error pushing ERP object: “ + msg) Map<String, Object> result = [:] result[errorCodeKey] = “500” result[errorMessageKey] = msg return result } log.info(“Push ERP object, url:” + url + “ args:” + arg + “ response:” + httpResult) Map<String, Object> dataResult = httpResult.content as Map

// todo: build object data Map<String, Object> object = dataResult[“data”][“masterData”] as Map Map<String, List<Map<String, Object»> detailsDataList = dataResult[“data”][“detailData”] as Map

Map<String, Object> pushData = [:] pushData[masterDataKey] = object pushData[detailDataKey] = detailsDataList Map<String, Object> data = [:] data[dataListKey] = [pushData]

// return success Map<String, Object> result = [:] result[errorCodeKey] = successCode result[errorMessageKey] = “” result[dataKey] = data return result

2.3 Optional: Support via Proxy Service

If the tenant environment cannot access the public internet or does not expose services externally, use the proxy service (attach contains proxy program code). Proxy service configuration:

Modify application.properties token to authenticate incoming calls and ensure requests originate from the Integration Platform.

Note: Configure the same X-fs-erpdss-token value in the connection headers as set in the proxy service.

image

image

Implement RouterAdaptController:

  • create: called when creating in ERP
  • update: called when updating in ERP
  • invalid: invalidates ERP primary data
  • queryMasterBatch: ERP -> CRM sync uses this to query ERP incremental data
  • queryMasterById: ERP -> CRM uses this to query a single record by ERP primary key

3 FAQ

Under construction…

Attachments

erpdss-template-stdapi.zip 315.0 KB

https://saas.bk-cdn01.com/t/e77d24d5-3d21-4bbc-8ec5-886214579a51/u/94794ae2-e207-45f4-ad4c-20efe8d21ba1/1736417363228/erpdss-template-stdapi.zip

Submit Feedback