Save rooftop details
Saves the rooftop profile, the admin's phone and the rooftop's vehicle types in one call.
This call fans out to several writes in parallel and waits for them:
- Updates the rooftop record: name, website, address, coordinates, region, timezone and website listing URL. It also updates the admin user's ISD code and phone (
rooftopData.userData). - Saves the rooftop configuration (
domain: rooftop,entity: INFO) withvehicleTypeand any department addresses. Keys you leave out are kept. - When
entityis one ofsales_inbound,sales_outbound,service_inbound,service_outbound, it also saves the agent configuration for that entity withentityConfig. The rooftop UI sendsentity: "INFO", so this write does not run from the UI. - When
rooftopData.addressis present, it syncs the address to the dealer website location record. A failure there is logged and ignored.
When all writes finish, it tries to update the checklist task named in taskName for productLineId. Errors from that step are logged and ignored. The response does not echo saved data.
Before you call it
-
You need
enterpriseId,teamIdand the rooftop name. -
The rooftop record update rejects the request unless all of these are set:
rooftopData.website(a non-empty string;https://is added if missing)rooftopData.addresswith non-emptyaddressLine1,city,state,countryandzipcode, plusaddressLine2anddistrictas strings (can be empty)rooftopData.geoCoordinates.latandlngas numbers in rangerooftopData.timeZonerooftopData.regionTyperooftopData.websiteListingUrl, which must be a valid URL when sent
-
Always send
entityConfig, even if it only holdsvehicleType. Leaving it out returns 500. -
Authentication: Bearer token of a signed-in console user. The same token is forwarded to each write.
-
Rate limit: Not documented
-
Processing: Synchronous. Waits for every write (30 second timeout each). The writes are not a transaction: if one fails after another succeeded, the successful write is not rolled back.
Request
- Read the current values with Get rooftop details and Get vehicle types and department addresses.
- Build
rooftopDatawith the full address and coordinates. - Send
entityConfig.vehicleTypewithnewandpreOwned. - Send
domain: "rooftop"andentity: "INFO", as the UI does. - On 2xx, call Mark a checklist task done with
{teamId, taskName: "RoofTop Setup", isCompleted: true}.
| Parameter | Type | Required | Description |
|---|---|---|---|
| Headers | — | — | Sent as HTTP headers. |
Authorization | string | Required | Bearer YOUR_TOKEN |
Content-Type | string | Required | application/json |
| Body | — | — | Sent as a JSON body. |
enterpriseId | string | Required | Dealer group ID. |
teamId | string | Required | Rooftop ID. |
teamName | string | Required | Rooftop name to save. |
enterpriseName | string | Optional | Dealer group name, stored on the configuration record. |
rooftopData | object | Required | Rooftop profile. |
rooftopData.website | string | Required | Rooftop website. See Before you call it. |
rooftopData.websiteListingUrl | string | Optional | Inventory listing page URL. |
rooftopData.address | object | Required | addressLine1, addressLine2, city, state, district, country, zipcode. See Before you call it. |
rooftopData.geoCoordinates | object | Required | {lat, lng} numbers. See Before you call it. |
rooftopData.regionType | string | Required | Region code. See Before you call it. |
rooftopData.timeZone | string | Required | IANA timezone, e.g. America/Chicago. See Before you call it. |
rooftopData.userData | object | Optional | {userId, name, email, contactNo, isdCode}. Only isdCode and contactNo are saved, for userId. |
entityConfig | object | Required | Leaving it out returns 500. |
entityConfig.vehicleType | object | Optional | {new: boolean, preOwned: boolean}. |
entityConfig.salesAddress / serviceAddress / partsAddress / financeAddress | object | Optional | {address, geoCoordinates{lat, lng}}. The UI does not send these. |
domain | string | Optional | Used only for the agent configuration write. The UI sends rooftop. |
entity | string | Optional | sales_inbound, sales_outbound, service_inbound or service_outbound also triggers the agent configuration write. The UI sends INFO. |
productLineId | string | Optional | With taskName, updates that checklist task. The UI does not send it. |
taskName | string | Optional | Checklist task to update. |
segmentName | string | Optional | Agent segment of the task. Needed for Vini product lines. |
isCompleted | boolean | Optional | true = complete the task, otherwise start it. |
Sample request
curl -X POST "https://api.spyne.ai/console/v1/product-onboarding/update-rooftop-data" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"enterpriseId": "<enterpriseId>",
"enterpriseName": "Example Motors Group",
"teamId": "<teamId>",
"teamName": "Example Motors",
"domain": "rooftop",
"entity": "INFO",
"rooftopData": {
"website": "https://www.example.com",
"websiteListingUrl": "https://www.example.com/used-inventory",
"address": {
"addressLine1": "100 Example Ave", "addressLine2": "", "city": "Austin",
"state": "TX", "district": "", "country": "United States", "zipcode": "78701"
},
"geoCoordinates": { "lat": 30.2672, "lng": -97.7431 },
"regionType": "AMER",
"timeZone": "America/Chicago",
"userData": { "userId": "<userId>", "name": "Jane Doe", "email": "[email protected]", "contactNo": "5550100000", "isdCode": "+1" }
},
"entityConfig": { "vehicleType": { "new": true, "preOwned": true } }
}'import requests
payload = {
"enterpriseId": "<enterpriseId>",
"enterpriseName": "Example Motors Group",
"teamId": "<teamId>",
"teamName": "Example Motors",
"domain": "rooftop",
"entity": "INFO",
"rooftopData": {
"website": "https://www.example.com",
"websiteListingUrl": "https://www.example.com/used-inventory",
"address": {"addressLine1": "100 Example Ave", "addressLine2": "", "city": "Austin",
"state": "TX", "district": "", "country": "United States", "zipcode": "78701"},
"geoCoordinates": {"lat": 30.2672, "lng": -97.7431},
"regionType": "AMER",
"timeZone": "America/Chicago",
"userData": {"userId": "<userId>", "name": "Jane Doe", "email": "[email protected]",
"contactNo": "5550100000", "isdCode": "+1"},
},
"entityConfig": {"vehicleType": {"new": True, "preOwned": True}},
}
res = requests.post(
"https://api.spyne.ai/console/v1/product-onboarding/update-rooftop-data",
json=payload,
headers={"Authorization": "Bearer YOUR_TOKEN"},
)
print(res.status_code, res.json())const res = await fetch("https://api.spyne.ai/console/v1/product-onboarding/update-rooftop-data", {
method: "POST",
headers: { Authorization: "Bearer YOUR_TOKEN", "Content-Type": "application/json" },
body: JSON.stringify({
enterpriseId: "<enterpriseId>",
enterpriseName: "Example Motors Group",
teamId: "<teamId>",
teamName: "Example Motors",
domain: "rooftop",
entity: "INFO",
rooftopData: {
website: "https://www.example.com",
websiteListingUrl: "https://www.example.com/used-inventory",
address: { addressLine1: "100 Example Ave", addressLine2: "", city: "Austin", state: "TX", district: "", country: "United States", zipcode: "78701" },
geoCoordinates: { lat: 30.2672, lng: -97.7431 },
regionType: "AMER",
timeZone: "America/Chicago",
userData: { userId: "<userId>", name: "Jane Doe", email: "[email protected]", contactNo: "5550100000", isdCode: "+1" },
},
entityConfig: { vehicleType: { new: true, preOwned: true } },
}),
});
console.log(res.status, await res.json());Sample response
{ "success": true, "message": "Successfully updated rooftop data", "data": {}, "error": false }{ "error": true, "message": "Missing required fields: enterpriseId, teamId, teamName, and rooftopData are required" }{
"message": "Address.zipcode: zipcode is required, Timezone: Timezone must be a non-empty string",
"error": true,
"details": { "message": "Address.zipcode: zipcode is required, Timezone: Timezone must be a non-empty string", "error": true, "code": "ERROR_BAD_REQ_400", "details": null, "data": null }
}{ "message": "Invalid Token", "error": true, "code": "ERROR_AUTH_401", "details": "", "data": null }{ "message": "connect ECONNREFUSED ...", "error": true, "code": "ERROR_REQ_TIMEOUT_408", "details": "", "data": null }{ "message": "No response received from one or more APIs", "error": true, "details": null }{ "message": "Error setting up API requests", "error": true, "details": null }Response fields
| Parameter | Type | Description |
|---|---|---|
success | boolean | true on 200. |
message | string | Successfully updated rooftop data. |
data | object | Always {}. |
error | boolean | false on 200. |
Errors
| Status | Reason | When it happens |
|---|---|---|
400 | Missing required fields | enterpriseId, teamId, teamName or rooftopData is missing. |
4xx / 5xx | Passed through | A downstream write answered with an error status. message is the downstream message and details is the downstream body. For example, 400 for rooftop field validation (a missing rooftopData.website also returns 400 here), or 401 from the configuration write. |
401 | ERROR_AUTH_401 | Missing or invalid bearer token. |
408 | ERROR_REQ_TIMEOUT_408 | The token check could not reach the auth service. |
502 | No response received from one or more APIs | A downstream write timed out or did not answer. |
500 | Error setting up API requests | The request could not be built. This includes a missing entityConfig. |
Checklist-task errors (unknown task, task not started yet) are not returned. The call still returns 200.
Next
After a 2xx, call Mark a checklist task done with {teamId: "<teamId>", taskName: "RoofTop Setup", isCompleted: true}. Task names are matched without regard to case. With no segmentName, the task is completed for every segment of the rooftop. The UI does this without waiting for the result. CNAM Registration later reads the saved address and website.
- Called before: Get rooftop details, Get vehicle types and department addresses.
- Called after: Mark a checklist task done, Submit or save the brand registration.
Updated about 1 hour ago
