Skip to main content

Custom Data Layers API

Create, manage, version, and query proprietary geospatial vector layers (points, polylines, polygons) directly hosted on the Sovereign Cloud GIS infrastructure.


Overview & Solution​

Enterprises possess unique spatial assets - such as private warehouse footprints, fiber cable conduits, internal dealership polygons, and security zones. The Custom Data Layers API allows creating and updating dedicated spatial tables with full CRUD capabilities.

Before a layer can be used through this API, its schema - the set of fields it holds and their types - is defined through the Intelomatic User interface.


Industry Use Cases​

1. Enterprise Asset Management​

  • Infrastructure Inventories: Maintain live maps of cell towers, solar inverters, electric vehicle charging bays, and utility pipelines.

2. Custom Business Geographies​

  • Dynamic Sales Territories: Update distributor territory boundary polygons without waiting for IT engineering releases.

3. Supply Chain Restricted Corridors​

  • No-Entry & Hazardous Zones: Publish dynamic no-go polygons for autonomous drones and transport fleets.


API reference​

Custom Integrations · Requires Intelomatic tenant

Field definitions: Field data types

Endpoints​

MethodPathPurpose
POST/api/app-base/data-layer/{layerName}/layer-detailGet a layer's field definitions (schema)
POST/api/app-base/data-layer/{layerName}Create a record
POST/api/app-base/data-layer/{layerName}/searchSearch records
PUT/api/app-base/data-layer/{layerName}/{id}Update a record
DELETE/api/app-base/data-layer/{layerName}/{id}Delete a record
GET/api/app-base/data-layer/{layerName}/{id}/detailGet a single record with all its values

All requests require a bearer token and the api-key query parameter:

Authorization: Bearer <access_token>
?api-key=<apiKey>

Get a layer's field definitions (schema)​

POST /api/app-base/data-layer/{layerName}/layer-detail

Request Parameters

ParameterInTypeRequiredDescriptionExample
layerNamepathstringYesData layer nameSAMPLE_DATA, CUSTOMER, PRODUCT
propertiesbodyobjectNo
properties.layerSettingsbodybooleanNo
properties.isTakeAllbodybooleanNo

Request body

{
"properties": {
"layerSettings": true,
"isTakeAll": true
}
}

Response Schema

200 OK

{
"layerName": "SAMPLE_DATA",
"version": 8,
"properties": [
{
"propertyName": "sample_data_invoice_number",
"displayName": "Invoice number",
"dataType": 3,
"required": false,
"isSystem": false,
"isAdditional": true
},
{
"propertyName": "sample_data_option",
"displayName": "Option",
"dataType": 10,
"required": false,
"isSystem": false,
"isAdditional": true
}
],
"layerSettings": {}
}
FieldTypeDescription
layerNamestringLayer the schema belongs to.
versionintegerSchema version. It increases every time the layer definition is changed - compare it to detect that your integration is reading an outdated field list.
propertiesarrayOne entry per field on the layer. This is the list of keys a create or update body may use.
properties[]object
properties[].propertyNamestring
properties[].displayNamestring
properties[].dataTypeinteger
properties[].requiredboolean
properties[].isSystemboolean
properties[].isAdditionalboolean
layerSettingsobjectLayer-level configuration, returned when layerSettings: true is requested.

Read this before writing to the layer. properties[] is the authoritative field list - a create or update body may only use these propertyName keys.

Property attributeMeaning
propertyNameThe key to send in a request body
displayNameHuman label shown in the platform UI - never sent to the API
dataTypeNumeric type code. See Field data types for the codes and the JSON value each expects
requiredtrue means the field must be present on create
isSystemSet by the platform. Do not send these, except Title and Description
isAdditionalA custom field defined for this tenant

Fields of dataType 10 (List) also carry their allowed values, or the layer they read from and any dependency on another field - see Field data types.

Create a record​

POST /api/app-base/data-layer/{layerName}

Request Parameters

ParameterInTypeRequiredDescriptionExample
layerNamepathstringYesLayer the new record is created in. The body must use that layer's field namesSAMPLE_DATA, CUSTOMER, PRODUCT
TitlebodystringNo
DescriptionbodystringNo
sample_data_datebodystringNo
sample_data_invoice_numberbodystringNo
sample_data_customer_addressbodystringNo
sample_data_mobile_numberbodystringNo
sample_data_geocodebodystringNo
sample_data_optionbodystringNo
sample_data_statebodystringNo
sample_data_districtbodystringNo
sample_data_sub_districtbodystringNo
sample_data_remarksbodystringNo

Request body

{
"Title": "INV-2026-0042",
"Description": "Record created through the API",
"sample_data_date": "2026-09-07T09:30:00Z",
"sample_data_invoice_number": "INV-2026-0042",
"sample_data_customer_address": "12 MG Road, Pune, MAHARASHTRA - 411001",
"sample_data_mobile_number": "919000000042",
"sample_data_geocode": "{\"type\":\"Point\",\"coordinates\":[73.8567,18.5204]}",
"sample_data_option": "1",
"sample_data_state": "13",
"sample_data_district": "267",
"sample_data_sub_district": "01823",
"sample_data_remarks": "Created from the API reference example"
}

More request examples

SAMPLE_DATA layer

{
"Title": "INV-2026-0042",
"Description": "Record created through the API",
"sample_data_date": "2026-09-07T09:30:00Z",
"sample_data_invoice_number": "INV-2026-0042",
"sample_data_customer_address": "12 MG Road, Pune, MAHARASHTRA - 411001",
"sample_data_mobile_number": "919000000042",
"sample_data_geocode": "{\"type\":\"Point\",\"coordinates\":[73.8567,18.5204]}",
"sample_data_option": "1",
"sample_data_state": "13",
"sample_data_district": "267",
"sample_data_sub_district": "01823",
"sample_data_remarks": "Created from the API reference example"
}

SAMPLE_DATA layer - minimum

{
"Title": "INV-2026-0043",
"sample_data_invoice_number": "INV-2026-0043"
}

CUSTOMER layer

{
"customer_full_name": "Sample Record",
"customer_phone_number": "919000000001",
"customer_email": "[email protected]",
"customer_category": "Default",
"customer_postal_code": "412108",
"customer_address": "Mulshi, Pune, MAHARASHTRA - 412108",
"customer_location": "{\"coordinates\":[73.55986487231496,18.462925230845542],\"type\":\"Point\"}",
"customer_is_active": "true"
}

Response Schema

200 OK

{
"Id": "00000000-0000-0000-0000-000000000001",
"Layer": "SAMPLE_DATA",
"Title": "INV-2026-0042",
"CreatedDate": "2026-09-07T09:30:12Z",
"CreatedUser": "<user>",
"sample_data_invoice_number": "INV-2026-0042",
"sample_data_created_from": 3
}
FieldTypeDescription
IdstringIdentifier of the record just created. Keep it - update, detail and delete all address the record by this value.
LayerstringLayer the record was written to, echoing the layerName in the path.
TitlestringDisplay label of the record.
CreatedDatestringServer timestamp of the creation, in UTC.
CreatedUserstringUsername of the account whose token made the call.
sample_data_invoice_numberstringExample of a custom field, returned with the value you sent.
sample_data_created_fromintegerChannel the record originated from, set by the platform: 1 Mobile, 2 Web, 3 Others. API calls get 3.

How to build the body for your own layer

The body is a flat JSON object keyed by propertyName. Call layer-detail on the layer first and send the properties it lists - anything else is ignored. Every value must respect the field's declared data type. The example above is the demo SAMPLE_DATA layer.

See Field data types for the dataType codes, the JSON value each one expects, and how list fields and their dependency chains work.

Do not send system fields. Id, CreatedDate, CreatedUser, ModifiedDate, ModifiedUser and the *_created_from / *_last_modified_from markers are set by the platform. Title and Description are system fields you may set - Title is the record's display label.

Validators declared on a field are enforced. On SAMPLE_DATA, sample_data_mobile_number must be 8-12 characters.

No field on SAMPLE_DATA is mandatory, so a create call with only Title succeeds - but a layer of your own may declare required fields, which layer-detail reports as required: true.

Search records​

POST /api/app-base/data-layer/{layerName}/search

Request Parameters

ParameterInTypeRequiredDescriptionExample
layerNamepathstringYesData layer nameSAMPLE_DATA, CUSTOMER, PRODUCT
skipbodyintegerNo
takebodyintegerNo

Request body

{
"skip": 0,
"take": 20
}

skip and take are paging properties:

  • skip - number of records to skip before the page starts. 0 is the first page.
  • take - maximum number of records returned in this page. -1 returns every match, which is only safe on small datasets.

The response reports total, the number of records matching the query regardless of paging - keep requesting pages until skip + take reaches it.

Response Schema

200 OK

{
"data": [
{
"Id": "00000000-0000-0000-0000-000000000001",
"Layer": "CUSTOMER",
"Path": "/…",
"CreatedDate": "2026-07-15T11:15:45Z",
"CreatedUser": "admin_apidemo",
"Title": "Sample Record",
"customer_full_name": "Sample Record",
"customer_phone_number": "919000000001"
}
],
"total": 1
}
FieldTypeDescription
dataarrayThe page of matching records. Each entry carries the layer's own fields plus the system fields every record has.
data[]object
data[].Idstring
data[].Layerstring
data[].Pathstring
data[].CreatedDatestring
data[].CreatedUserstring
data[].Titlestring
data[].customer_full_namestring
data[].customer_phone_numberstring
totalintegerTotal number of records matching the query, ignoring skip and take - use it to drive paging.

Update a record​

PUT /api/app-base/data-layer/{layerName}/{id}

Request Parameters

ParameterInTypeRequiredDescriptionExample
layerNamepathstringYesLayer holding the record to updateSAMPLE_DATA, CUSTOMER, PRODUCT
idpathstringYesId of the record to updatecd8588a9-52ff-4817-881e-e6a801ff4eb5
sample_data_remarksbodystringNo

Request body

{
"sample_data_remarks": "Updated remark"
}

Response Schema

200 OK

{
"Id": "cd8588a9-52ff-4817-881e-e6a801ff4eb5",
"id": "cd8588a9-52ff-4817-881e-e6a801ff4eb5",
"Layer": "ZFLCFX_SAMPLE_DATA",
"Name": "f7b9ed17-9206-4ded-a1b5-45e3bc8ffcf9",
"Title": null,
"Description": null,
"Created": "2026-09-08T03:45:47.479Z",
"Creator": "apidemo_sovereignsolutions",
"Modified": "2026-09-08T03:45:47.479Z",
"Modifier": "apidemo_sovereignsolutions",
"Path": "/<internal storage path>",
"ParentIdPath": "/2/6025/6053/99689425",
"NodeId": 99772164,
"ParentId": 99689425,
"LayerData": {
"sample_data_remarks": "Updated remark",
"sample_data_last_modified_from": "2"
},
"Properties": [
{
"Name": "sample_data_remarks",
"DisplayName": null,
"Value": "Updated remark",
"DataType": 3,
"Format": null
},
{
"Name": "sample_data_last_modified_from",
"DisplayName": null,
"Value": "2",
"DataType": 10,
"Format": null
}
],
"sample_data_last_modified_from": 2
}
FieldTypeDescription
IdstringThe record you updated - same value you sent in the path.
idstringDuplicate of Id in lower case. Read either one; they always carry the same value.
LayerstringInternal layer name: your tenant's system code plus the layer name. Search and detail return the plain layer name instead.
NamestringInternal node name of the record. Not the Id, and not used by any other endpoint.
TitlestringDisplay label. null unless the record has one - an update that does not touch Title leaves it as is.
Descriptionstring
CreatedstringWhen the record was created, UTC.
CreatorstringAccount that created the record.
ModifiedstringWhen this update was applied, UTC.
ModifierstringAccount whose token made this call.
PathstringInternal storage location. Read-only, and of no use to an integration.
ParentIdPathstringInternal hierarchy path of numeric node IDs. Read-only.
NodeIdintegerInternal numeric node ID. Read-only.
ParentIdintegerInternal numeric ID of the parent node. Read-only.
LayerDataobjectThe fields this call actually wrote, keyed by propertyName, including the *_last_modified_from marker the platform sets itself. Values are returned as strings here, whatever the field type.
LayerData.sample_data_remarksstring
LayerData.sample_data_last_modified_fromstring
PropertiesarrayThe same changed fields in expanded form, each with its DataType. See Field data types.
Properties[]object
Properties[].Namestring
Properties[].DisplayNamestring
Properties[].Valuestring
Properties[].DataTypeinteger
Properties[].Formatstring
sample_data_last_modified_fromintegerChannel of the last change, set by the platform: 1 Mobile, 2 Web, 3 Others.

The update response is not shaped like search or detail. It returns the internal node record, so it carries platform fields (NodeId, ParentId, Name, Path, ParentIdPath, MimeType) that no other endpoint uses and that you should ignore. Call {id}/detail afterwards if you need the record in its normal shape.

Only the fields you sent come back changed. LayerData and Properties list exactly what this call wrote; untouched fields are not echoed. To confirm the full record, read it back with {id}/detail.

Only keys defined on the layer are stored. A key outside the layer's schema is echoed at the top level of the response but not persisted - it will not appear in LayerData, Properties, or any later read. Check LayerData to confirm which fields the update actually wrote.

Modified reflects the record's creation, not this update - it can come back equal to Created. Use LayerData rather than Modified to confirm a write took effect.

Several system fields come back null (Title, Description, Type, Status, Template, Content) whenever the update did not set them.

Delete a record​

DELETE /api/app-base/data-layer/{layerName}/{id}

Request Parameters

ParameterInTypeRequiredDescriptionExample
layerNamepathstringYesLayer holding the record to deleteSAMPLE_DATA, CUSTOMER, PRODUCT
idpathstringYesId of the record to delete, as returned by search or create00000000-0000-0000-0000-000000000001

Response Schema

200 OK

{
"count": 1
}
FieldTypeDescription
countintegerNumber of records actually deleted. 1 = the record was found and removed, 0 = nothing matched the ID. The call returns 200 OK either way, so check this value to confirm the delete.

Get a single record with all its values​

GET /api/app-base/data-layer/{layerName}/{id}/detail

Request Parameters

ParameterInTypeRequiredDescriptionExample
layerNamepathstringYesData layer nameSAMPLE_DATA, CUSTOMER, PRODUCT
idpathstringYesRecord ID

Response Schema

200 OK

{
"Id": "<uuid>",
"Layer": "PRODUCT",
"Path": "/…",
"CreatedDate": "2026-07-15T11:15:45Z",
"CreatedUser": "<user>",
"ModifiedDate": "2026-07-15T11:15:45Z",
"ModifiedUser": "<user>",
"Title": "<title>",
"product_name": "<value>"
}
FieldTypeDescription
IdstringRecord identifier, the value to pass to update and delete.
LayerstringLayer the record belongs to.
PathstringInternal storage location. Read-only.
CreatedDatestringWhen the record was created, UTC.
CreatedUserstringAccount that created it.
ModifiedDatestringWhen the record was last changed, UTC.
ModifiedUserstringAccount that last changed it.
TitlestringDisplay label of the record.
product_namestring

Example​

curl -X POST '$BASE_URL/api/app-base/data-layer/SAMPLE_DATA/layer-detail?api-key=$API_KEY' \
-H 'Authorization: Bearer $TOKEN' \
-H 'Content-Type: application/json' \
-d '{"properties": {"layerSettings": true, "isTakeAll": true}}'

Notes​

Conventions that hold for every layer:

  • Search responses are always wrapped as { "data": [...], "total": N }.
  • Every record carries a fixed set of system fields alongside its typed properties:
FieldMeaning
IdRecord identifier (UUID)
LayerThe layer this record belongs to
Path / ParentPathInternal storage location
CreatedDate / CreatedUserWhen and by whom it was created
ModifiedDate / ModifiedUserWhen and by whom it was last changed
TitleDisplay label for the record

These appear on every layer, including each entry inside the search envelope's data[].

Schema vs. detail - do not confuse these two read operations: layer-detail returns the layer's schema (field definitions, no record ID in the path); {id}/detail returns one record's data (record ID in the path).

Integration datasets, folded in: market centre, village and dealer-territory datasets (e.g. MC_TERRITORY_VILLAGES, DEALER_WISE_TEHSIL_WISE_IND, DEALER_LONGITUDE_LATITUDE, DEALER_MAPPING) are just data layers like any other, queried through this same interface - there is no separate integration endpoint. Layer names are tenant-specific by design.