Save the service scheduler integration
Save the rooftop's chosen partner for CRM, vehicle history or service scheduler, and register the partner link where the entity needs it.
Service agents need the service scheduler. On this page send
entity: SERVICE_SCHEDULER.
The console forwards the body to the central configuration service. That service validates entityconfig for the entity, runs the entity's downstream steps, then saves the record for enterpriseId + teamId + domain + entity. A save replaces the whole stored entityconfig; it does not merge. The userId in the body is ignored; the user id from the token is used.
What runs before the save
| Entity | What runs |
|---|---|
CRM, listed partner (api.partnerId and api.dealerId set) | Registers or updates the rooftop's CRM link (registryId = partnerId, dealer id sent as the external id, sync every 60 minutes). Picking a different CRM partner creates a second link; the earlier one is not removed. |
CRM, partner not in the list (no api.partnerId, api.partnerName set) | Opens an onboarding request for the partner team with the partner name and contact details. If that request fails, the save still succeeds. |
CAR_HISTORY | Nothing runs. Only the record is saved. |
SERVICE_SCHEDULER, when api is present | The three steps below, in order. |
- Scheduler link. Registers, updates or switches the rooftop's scheduler link. The dealer identifiers sent depend on the exact lowercase
partnerName:xtime,tekion,cdk,pbs,updatepromiseuseexternalId(ordealerId);dealerfxneedsexternalIdordealerId, andoemName;mykaarmaneedsexternalIdordealerId, anddepartmentUUID;evenflowneedsserviceCenterId,usernameandpassword. If the name is not one of these, the required values are missing, or there is nopartnerId, this step is skipped without an error. - Service agent settings. Writes price display, transfer rules, upsell rules and, per partner, service rules, supported makes, available services and transportation options. For
pbsandcdkit also writes slot settings (slot length, default 30; bookings per slot, default 1). Supported operations are reset to an empty list on every save. - Partner not in the list (no
partnerId,partnerNameset and notspyne): opens an onboarding request. If that request fails, the save still succeeds.
If step 1 or 2 fails, or the CRM link call fails, the request returns 500 and the record is not saved. Steps that already ran are not undone.
The same endpoint also accepts entity: "DMS". That flow is not covered here.
Before you call it
- You need the bearer token of a signed-in console user. The console checks it, then the configuration service checks the same token again. The route does not check that
teamIdbelongs to the caller. enterpriseIdandteamIdcome from the onboarding session.- For CRM and service scheduler:
partnerId,partnerNameandlogofrom List CRM and scheduler partners, and the rooftop's dealer id at that partner. - For vehicle history:
partnerId,partnerNameandlogofrom List inventory and history partners.logomust not be empty. - Use exact entity casing:
CRM,CAR_HISTORY,SERVICE_SCHEDULER. Validation accepts any casing, but other casings fail with500after the downstream steps have run. - The partner not in the list option is shown only inside the onboarding wizard, not on the Settings integration pages.
- Synchronous. The console waits up to 30 seconds for the configuration service. Partner onboarding requests are awaited, but their failures are ignored. Rate limit: not documented.
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
| Headers | — | — | — |
Authorization | string | Required | Bearer YOUR_TOKEN |
Content-Type | string | Required | application/json |
| All entities | — | — | — |
enterpriseId | string | Required | <enterpriseId> of the dealer group. |
teamId | string | Required | <teamId> of the rooftop. |
domain | string | Required | integration. |
entity | string | Required | CRM, CAR_HISTORY or SERVICE_SCHEDULER. |
entityconfig | object | Required | Shape per entity, below. Unknown keys are dropped. |
enterpriseName | string | Optional | Dealer group name, stored with the record. |
teamName | string | Optional | Rooftop name, stored with the record. |
userId | string | Optional | Ignored. The token's user is used. |
entityconfig for CRM | — | — | — |
partnerProviderTypes | string[] | Required | At least one value. The UI sends ["CRM"]. |
api | object | Optional | Partner details. Without api, only the record is saved. |
api.partnerId | string | Optional | Registry id from the CRM partner list. When set, api.dealerId is required. |
api.dealerId | string | Required if | The rooftop's id at the CRM. Required when partnerId is set. |
api.partnerName | string | Required if | Partner name. Required when partnerId is not set. |
api.logo | string or null | Optional | Logo URL. |
api.approved | boolean | Required if | Required when partnerId is not set. The UI sends false. |
api.poc_name | string | Required if | Required when partnerId is not set. Contact at the CRM. |
api.poc_email | string | Required if | Required when partnerId is not set. |
api.poc_contact | string | Required if | Required when partnerId is not set. Phone number. |
api.configStrategy, api.isActive, api.workflowId, api.email | various | Optional | Accepted and stored. Not sent by the UI. |
app, console | boolean | Optional | Default false. |
entityconfig for CAR_HISTORY | — | — | — |
partnerId | string | Required | Partner id from the partner list with category=CarHistory. |
partnerName | string | Required | Partner name. |
logo | string | Required | Partner logo URL. Must not be empty. |
entityconfig for SERVICE_SCHEDULER | — | — | — |
api | object | Optional | Partner details. Without api, no downstream step runs and only the record is saved. |
api.partnerId | string | Optional | Registry id from the scheduler partner list. Without it, the scheduler link step is skipped. |
api.partnerName | string | Optional | Partner name. Matched in lowercase against xtime, tekion, cdk, pbs, updatepromise, dealerfx, mykaarma, evenflow. For a partner not in the list, send only partnerName and approved. |
api.dealerId | string | Optional | The rooftop's id at the scheduler. Used when externalId is not set. |
api.externalId | string | Optional | Overrides dealerId as the external id. |
api.oemName | string | Required if | Needed for dealerfx. |
api.departmentUUID | string | Required if | Needed for mykaarma. Not collected by the UI. |
api.serviceCenterId, api.username, api.password | string | Required if | Needed for evenflow. Not collected by the UI. Stored as sent. |
api.logo | string or null | Optional | Logo URL. |
api.approved, api.isActive | boolean | Optional | The UI sends approved: false. |
serviceSchedulerConfig | object | Required if | Service agent settings. Optional in the schema, but send it whenever api is present: the server reads highlightPrices, transferScenarios and upselling.isOpted, so a request with api and no serviceSchedulerConfig.upselling fails with 500 after the link step. The UI always sends it. |
serviceSchedulerConfig.highlightPrices | boolean | Optional | Whether the agent quotes prices. |
serviceSchedulerConfig.transferScenarios | string[] | Optional | Extra callback and transfer rules. |
serviceSchedulerConfig.upselling | object | Optional | isOpted (boolean, default false) and optional data (string). data is used only when isOpted is true. |
serviceSchedulerConfig.serviceRules | string[] | Optional | Used for xtime, tekion, dealerfx. |
serviceSchedulerConfig.supportedMakes | string[] | Optional | Used for pbs and for partners outside the named list. |
serviceSchedulerConfig.availableServices | string[] | Optional | Used for partners outside the named list. |
serviceSchedulerConfig.serviceFacilities | object | Optional | pickAndDropoff, loanerBookings, shuttle, each boolean, default false. Becomes transportation options (waiter is always included). Used for xtime and partners outside the named list. |
serviceSchedulerConfig.slotDuration | number | Optional | Slot length in minutes for pbs and cdk. Default 30. Must be a number; null fails validation. |
serviceSchedulerConfig.capacityPerSlot | number | Optional | Bookings per slot for pbs and cdk. Default 1. Must be a number; null fails validation. |
For CAR_HISTORY, other keys are dropped (the UI also sends approved: false). There is no partner not in the list path for vehicle history.
- Headers: set
Authorization: Bearer YOUR_TOKENandContent-Type: application/json. - Identify the record: send
enterpriseId,teamId,domain: "integration"andentity. - Build the config: send
entityconfigin the shape for the entity. - Check the result: treat any response without
success: trueas a failure. - Finish: for CRM, set the lead sync rules next. Then mark the checklist task done with the task name for the entity.
Sample request
curl -X POST "https://api.spyne.ai/console/v1/product-onboarding/integration" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"enterpriseId": "<enterpriseId>",
"enterpriseName": "Example Motors Group",
"teamId": "<teamId>",
"teamName": "Example Motors",
"domain": "integration",
"entity": "CRM",
"entityconfig": {
"api": {
"partnerId": "<partnerId>",
"partnerName": "examplecrm",
"dealerId": "<dealerId>",
"logo": "https://example.com/logo.png",
"approved": false
},
"partnerProviderTypes": ["CRM"]
}
}'curl -X POST "https://api.spyne.ai/console/v1/product-onboarding/integration" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"enterpriseId": "<enterpriseId>",
"teamId": "<teamId>",
"domain": "integration",
"entity": "CRM",
"entityconfig": {
"api": {
"partnerName": "Example CRM Co",
"approved": false,
"poc_name": "<contact name>",
"poc_email": "<contact email>",
"poc_contact": "<contact phone>"
},
"partnerProviderTypes": ["CRM"]
}
}'import requests
res = requests.post(
"https://api.spyne.ai/console/v1/product-onboarding/integration",
headers={"Authorization": "Bearer YOUR_TOKEN"},
json={
"enterpriseId": "<enterpriseId>",
"teamId": "<teamId>",
"domain": "integration",
"entity": "CAR_HISTORY",
"entityconfig": {
"partnerId": "<partnerId>",
"partnerName": "Example History Reports",
"logo": "https://example.com/logo.png",
},
},
)
body = res.json()
assert body.get("success") is Trueconst res = await fetch(
"https://api.spyne.ai/console/v1/product-onboarding/integration",
{
method: "POST",
headers: {
Authorization: "Bearer YOUR_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({
enterpriseId: "<enterpriseId>",
teamId: "<teamId>",
domain: "integration",
entity: "SERVICE_SCHEDULER",
entityconfig: {
api: {
partnerId: "<partnerId>",
partnerName: "xtime",
dealerId: "<dealerId>",
logo: "https://example.com/logo.png",
approved: false,
},
serviceSchedulerConfig: {
serviceFacilities: { pickAndDropoff: true, loanerBookings: false, shuttle: true },
serviceRules: ["Example rule"],
highlightPrices: true,
transferScenarios: ["Example transfer rule"],
upselling: { isOpted: false },
},
},
}),
}
);
const body = await res.json();Sample response
{
"success": true,
"message": "Integration configuration created successfully",
"data": {
"_id": "<configId>",
"enterpriseId": "<enterpriseId>",
"teamId": "<teamId>",
"enterpriseName": "Example Motors Group",
"teamName": "Example Motors",
"userId": "<userId>",
"domain": "integration",
"type": "single",
"entity": "CAR_HISTORY",
"entityconfig": {
"partnerId": "<partnerId>",
"partnerName": "Example History Reports",
"logo": "https://example.com/logo.png"
},
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-01-01T00:00:00.000Z"
}
}{
"success": false,
"message": "Validation error",
"error": "Invalid request data",
"errors": [
{ "code": "custom", "message": "When partnerId is provided, dealerId is required", "path": ["entityconfig", "api", "dealerId"] }
]
}{ "message": "Invalid Token", "error": true, "code": "ERROR_AUTH_401", "details": "<details>", "data": null }{ "status": "401", "message": "Invalid Auth key" }{ "message": "<error message>", "error": true, "code": "ERROR_REQ_TIMEOUT_408", "details": "<details>", "data": null }{ "success": false, "message": "Failed to create integration configuration", "error": "<downstream error message>" }{ "message": "No response received from integration API", "error": "<error message>" }Response parameters
| Parameter | Type | Description |
|---|---|---|
success | boolean | true when saved. |
message | string | Integration configuration created successfully on every successful save, including updates. |
data | object | The saved record. Same fields as Read a saved integration. |
data.entityconfig | object | What was stored, after unknown keys were dropped and defaults applied. |
data.entityconfig.api.username, data.entityconfig.api.password | string | SERVICE_SCHEDULER only, present when sent. Credential field returned by the API. Never log or display it. |
Errors
| Status | Code | When it happens |
|---|---|---|
400 | Validation error | Missing enterpriseId, teamId, domain or entity; entity not allowed for the domain; or entityconfig breaks the entity rules (for example CRM partnerId without dealerId, CRM without partnerProviderTypes, vehicle history without logo, scheduler slotDuration: null). |
401 | Invalid Token or token error | The console token check failed. |
401 | Invalid Auth key | The configuration service token check failed. |
401 | User ID not found in token | The token has no user id. |
408 | Timeout | The console could not reach user management. |
500 | Failed to create integration configuration | A downstream step failed (CRM link, scheduler link, service agent settings, slot settings) or the save failed. error carries the downstream message. Earlier downstream steps are not undone. |
500 | No response received from integration API | The configuration service did not answer within 30 seconds. |
A failed partner onboarding request (partner not in the list) is not reported; the save returns 201.
What happens next
- CRM: set the CRM lead sync rules. The UI also saves activity sync settings at the same time when the user turns them on. Only when both succeed does the UI mark
CRM Integrationdone. - Vehicle history: mark
Vehicle History Integrationdone. Nothing else is registered for vehicle history. - Service scheduler: mark
Service Schedulerdone.
Mark the task with Mark a checklist task done in the Checklist section. The UI sends no segmentName, so the task is completed in every segment the rooftop has it.
Updated about 1 hour ago
