Data API
Create, read, update and delete records of any entity; run saved queries and stored procedures; filter, sort, page and aggregate.
- Service
- Data service
- Base path
https://your-data-host/api/v1- Authentication
- Bearer token and context headers. Every call is checked against your role's scope for the entity.
One set of endpoints serves every entity. The entity is named in the request, and the platform applies field rules, access scopes, approval locks, audit and your C# hooks.
Filters
A WhereClause is a list of Filters plus an optional FilterLogic such as 1 AND (2 OR 3), where the numbers are the filters' sequence. Each filter has a FieldName, an Operator and a Value.
| Operator | Value | Operator | Value |
|---|---|---|---|
| GreaterThan | 1 | Contains | 11 |
| LessThan | 2 | NotContains | 12 |
| EqualTo | 3 | StartsWith | 13 |
| IN | 4 | EndsWith | 15 |
| NOTIN | 5 | Between | 17 |
| IsNULL | 6 | NotBetween | 18 |
| IsNotNULL | 7 | ExistsIn | 21 |
| NotEqualTo | 8 | NotExistsIn | 22 |
| GreaterThanOrEqualTo | 9 | LessThanOrEqualTo | 10 |
Asynchronous writes
Writes are processed through the platform's message bus. When the result is ready within the wait window the response is 200 OK with the result; otherwise it is 202 Accepted with a CorrelationId. Read the record back, or listen on the real-time hub, to see the outcome.
/api/v1/records/insertCreate a record
Creates one record, including child records and lookups, in a single transaction. The platform stamps tenant, app, environment, owner and audit fields.
Request body
{
"EntityName": "Vendor",
"Fields": [
{
"FieldName": "Name",
"Value": "Northwind Traders"
},
{
"FieldName": "Country",
"Value": "India"
}
]
}Response
- 200 OK: the created record, in the platform's result envelope.
- 202 Accepted: a
CorrelationIdwhen the write is still being processed.
Error responses
- Validation errors from required fields, field rules or your C# validation hooks.
- A permission error when your role's create scope for the entity is None.
- A conflict error when a unique field already has the value.
- 401 Unauthorized when the token is missing or expired.
Example request
curl -X POST "https://your-data-host/api/v1/records/insert" \
-H "Authorization: Bearer $TAF_TOKEN" \
-H "TenantId: $TENANT_ID" \
-H "AppId: $APP_ID" \
-H "EnvironmentId: $ENVIRONMENT_ID" \
-H "Content-Type: application/json" \
-d '{
"EntityName": "Vendor",
"Fields": [
{
"FieldName": "Name",
"Value": "Northwind Traders"
},
{
"FieldName": "Country",
"Value": "India"
}
]
}'const res = await fetch("https://your-data-host/api/v1/records/insert", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
TenantId: tenantId,
AppId: appId,
EnvironmentId: environmentId,
"Content-Type": "application/json",
},
body: JSON.stringify({
"EntityName": "Vendor",
"Fields": [
{
"FieldName": "Name",
"Value": "Northwind Traders"
},
{
"FieldName": "Country",
"Value": "India"
}
]
}),
});
const result = await res.json();using var http = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://your-data-host/api/v1/records/insert");
request.Headers.Authorization = new("Bearer", token);
request.Headers.Add("TenantId", tenantId);
request.Headers.Add("AppId", appId);
request.Headers.Add("EnvironmentId", environmentId);
request.Content = JsonContent.Create(body); // body: the JSON shown in the cURL tab
var response = await http.SendAsync(request);Sends the request from your browser to your own environment. Nothing is stored by this page. Your environment must allow requests from this site.
/api/v1/records/updateUpdate records that match a filter
Updates the listed fields on every record that matches WhereClause. A request without a where-clause is refused.
Request body
{
"EntityName": "Vendor",
"Fields": [
{
"FieldName": "Country",
"Value": "United Kingdom"
}
],
"WhereClause": {
"Filters": [
{
"FieldName": "Id",
"Operator": 3,
"Value": "00000000-0000-0000-0000-000000000000"
}
],
"FilterLogic": "1"
}
}Response
- 200 OK or 202 Accepted, as for insert.
Error responses
- An approval-lock error when the record is under approval.
- A permission error when the record is outside your update scope.
Example request
curl -X PUT "https://your-data-host/api/v1/records/update" \
-H "Authorization: Bearer $TAF_TOKEN" \
-H "TenantId: $TENANT_ID" \
-H "AppId: $APP_ID" \
-H "EnvironmentId: $ENVIRONMENT_ID" \
-H "Content-Type: application/json" \
-d '{
"EntityName": "Vendor",
"Fields": [
{
"FieldName": "Country",
"Value": "United Kingdom"
}
],
"WhereClause": {
"Filters": [
{
"FieldName": "Id",
"Operator": 3,
"Value": "00000000-0000-0000-0000-000000000000"
}
],
"FilterLogic": "1"
}
}'const res = await fetch("https://your-data-host/api/v1/records/update", {
method: "PUT",
headers: {
Authorization: `Bearer ${token}`,
TenantId: tenantId,
AppId: appId,
EnvironmentId: environmentId,
"Content-Type": "application/json",
},
body: JSON.stringify({
"EntityName": "Vendor",
"Fields": [
{
"FieldName": "Country",
"Value": "United Kingdom"
}
],
"WhereClause": {
"Filters": [
{
"FieldName": "Id",
"Operator": 3,
"Value": "00000000-0000-0000-0000-000000000000"
}
],
"FilterLogic": "1"
}
}),
});
const result = await res.json();using var http = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Put, "https://your-data-host/api/v1/records/update");
request.Headers.Authorization = new("Bearer", token);
request.Headers.Add("TenantId", tenantId);
request.Headers.Add("AppId", appId);
request.Headers.Add("EnvironmentId", environmentId);
request.Content = JsonContent.Create(body); // body: the JSON shown in the cURL tab
var response = await http.SendAsync(request);Sends the request from your browser to your own environment. Nothing is stored by this page. Your environment must allow requests from this site.
/api/v1/records/deleteDelete records that match a filter
When the entity allows soft delete, records are marked deleted and disappear from queries; otherwise they are removed. Relationship rules decide whether children are cascaded or block the delete.
Request body
{
"EntityName": "Vendor",
"WhereClause": {
"Filters": [
{
"FieldName": "Id",
"Operator": 3,
"Value": "00000000-0000-0000-0000-000000000000"
}
]
}
}Response
- 200 OK or 202 Accepted.
Example request
curl -X DELETE "https://your-data-host/api/v1/records/delete" \
-H "Authorization: Bearer $TAF_TOKEN" \
-H "TenantId: $TENANT_ID" \
-H "AppId: $APP_ID" \
-H "EnvironmentId: $ENVIRONMENT_ID" \
-H "Content-Type: application/json" \
-d '{
"EntityName": "Vendor",
"WhereClause": {
"Filters": [
{
"FieldName": "Id",
"Operator": 3,
"Value": "00000000-0000-0000-0000-000000000000"
}
]
}
}'const res = await fetch("https://your-data-host/api/v1/records/delete", {
method: "DELETE",
headers: {
Authorization: `Bearer ${token}`,
TenantId: tenantId,
AppId: appId,
EnvironmentId: environmentId,
"Content-Type": "application/json",
},
body: JSON.stringify({
"EntityName": "Vendor",
"WhereClause": {
"Filters": [
{
"FieldName": "Id",
"Operator": 3,
"Value": "00000000-0000-0000-0000-000000000000"
}
]
}
}),
});
const result = await res.json();using var http = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Delete, "https://your-data-host/api/v1/records/delete");
request.Headers.Authorization = new("Bearer", token);
request.Headers.Add("TenantId", tenantId);
request.Headers.Add("AppId", appId);
request.Headers.Add("EnvironmentId", environmentId);
request.Content = JsonContent.Create(body); // body: the JSON shown in the cURL tab
var response = await http.SendAsync(request);/api/v1/records/bulk-insertInsert many records at once
Inserts rows in batches (default 1,000). Batches are sized to stay within the database's parameter limit.
Request body
{
"EntityName": "Vendor",
"Fields": [
"Name",
"Country"
],
"Values": [
[
"Northwind Traders",
"India"
],
[
"Contoso Supplies",
"United Kingdom"
]
],
"Options": {
"BatchSize": 1000
}
}Response
- 200 OK with the insert result.
Example request
curl -X POST "https://your-data-host/api/v1/records/bulk-insert" \
-H "Authorization: Bearer $TAF_TOKEN" \
-H "TenantId: $TENANT_ID" \
-H "AppId: $APP_ID" \
-H "EnvironmentId: $ENVIRONMENT_ID" \
-H "Content-Type: application/json" \
-d '{
"EntityName": "Vendor",
"Fields": [
"Name",
"Country"
],
"Values": [
[
"Northwind Traders",
"India"
],
[
"Contoso Supplies",
"United Kingdom"
]
],
"Options": {
"BatchSize": 1000
}
}'const res = await fetch("https://your-data-host/api/v1/records/bulk-insert", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
TenantId: tenantId,
AppId: appId,
EnvironmentId: environmentId,
"Content-Type": "application/json",
},
body: JSON.stringify({
"EntityName": "Vendor",
"Fields": [
"Name",
"Country"
],
"Values": [
[
"Northwind Traders",
"India"
],
[
"Contoso Supplies",
"United Kingdom"
]
],
"Options": {
"BatchSize": 1000
}
}),
});
const result = await res.json();using var http = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://your-data-host/api/v1/records/bulk-insert");
request.Headers.Authorization = new("Bearer", token);
request.Headers.Add("TenantId", tenantId);
request.Headers.Add("AppId", appId);
request.Headers.Add("EnvironmentId", environmentId);
request.Content = JsonContent.Create(body); // body: the JSON shown in the cURL tab
var response = await http.SendAsync(request);/api/v1/queries/selectRun an ad hoc query
Selects fields from an entity with filters, sorting, paging, lookups, child includes, grouping and aggregates. Rows outside your read scope are never returned.
Request body
{
"EntityName": "Vendor",
"SelectedFields": [
"Id",
"Name",
"Country"
],
"WhereClause": {
"Filters": [
{
"FieldName": "Country",
"Operator": 3,
"Value": "India",
"Sequence": 1
}
],
"FilterLogic": "1"
},
"Sort": [
{
"FieldName": "Name",
"Direction": 1
}
],
"Pager": {
"PageNumber": 1,
"PageSize": 25
}
}Response
- 200 OK: the matching rows and, when paging, the total count.
Example request
curl -X POST "https://your-data-host/api/v1/queries/select" \
-H "Authorization: Bearer $TAF_TOKEN" \
-H "TenantId: $TENANT_ID" \
-H "AppId: $APP_ID" \
-H "EnvironmentId: $ENVIRONMENT_ID" \
-H "Content-Type: application/json" \
-d '{
"EntityName": "Vendor",
"SelectedFields": [
"Id",
"Name",
"Country"
],
"WhereClause": {
"Filters": [
{
"FieldName": "Country",
"Operator": 3,
"Value": "India",
"Sequence": 1
}
],
"FilterLogic": "1"
},
"Sort": [
{
"FieldName": "Name",
"Direction": 1
}
],
"Pager": {
"PageNumber": 1,
"PageSize": 25
}
}'const res = await fetch("https://your-data-host/api/v1/queries/select", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
TenantId: tenantId,
AppId: appId,
EnvironmentId: environmentId,
"Content-Type": "application/json",
},
body: JSON.stringify({
"EntityName": "Vendor",
"SelectedFields": [
"Id",
"Name",
"Country"
],
"WhereClause": {
"Filters": [
{
"FieldName": "Country",
"Operator": 3,
"Value": "India",
"Sequence": 1
}
],
"FilterLogic": "1"
},
"Sort": [
{
"FieldName": "Name",
"Direction": 1
}
],
"Pager": {
"PageNumber": 1,
"PageSize": 25
}
}),
});
const result = await res.json();using var http = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://your-data-host/api/v1/queries/select");
request.Headers.Authorization = new("Bearer", token);
request.Headers.Add("TenantId", tenantId);
request.Headers.Add("AppId", appId);
request.Headers.Add("EnvironmentId", environmentId);
request.Content = JsonContent.Create(body); // body: the JSON shown in the cURL tab
var response = await http.SendAsync(request);Sends the request from your browser to your own environment. Nothing is stored by this page. Your environment must allow requests from this site.
/api/v1/queries/execute/{appObjectName}/{queryName}Run a saved query by name
Runs a saved query with parameters. You can add paging, sorting and a saved view.
| Name | In | Required | Description |
|---|---|---|---|
appObjectName | path | Yes | Entity name. |
queryName | path | Yes | Saved query name. |
Request body
{
"Reqtokens": {
"Country": "India"
},
"Pager": {
"PageNumber": 1,
"PageSize": 25
},
"Sort": [
{
"FieldName": "Name",
"Direction": 1
}
]
}Response
- 200 OK: the rows the saved query returns for your scope.
Example request
curl -X POST "https://your-data-host/api/v1/queries/execute/{appObjectName}/{queryName}" \
-H "Authorization: Bearer $TAF_TOKEN" \
-H "TenantId: $TENANT_ID" \
-H "AppId: $APP_ID" \
-H "EnvironmentId: $ENVIRONMENT_ID" \
-H "Content-Type: application/json" \
-d '{
"Reqtokens": {
"Country": "India"
},
"Pager": {
"PageNumber": 1,
"PageSize": 25
},
"Sort": [
{
"FieldName": "Name",
"Direction": 1
}
]
}'const res = await fetch("https://your-data-host/api/v1/queries/execute/{appObjectName}/{queryName}", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
TenantId: tenantId,
AppId: appId,
EnvironmentId: environmentId,
"Content-Type": "application/json",
},
body: JSON.stringify({
"Reqtokens": {
"Country": "India"
},
"Pager": {
"PageNumber": 1,
"PageSize": 25
},
"Sort": [
{
"FieldName": "Name",
"Direction": 1
}
]
}),
});
const result = await res.json();using var http = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://your-data-host/api/v1/queries/execute/{appObjectName}/{queryName}");
request.Headers.Authorization = new("Bearer", token);
request.Headers.Add("TenantId", tenantId);
request.Headers.Add("AppId", appId);
request.Headers.Add("EnvironmentId", environmentId);
request.Content = JsonContent.Create(body); // body: the JSON shown in the cURL tab
var response = await http.SendAsync(request);/api/v1/queries/execute/{queryId}Run a saved query by id
The route is part of the service today. Its request and response schema will be published here; until then, use the OpenAPI document on your environment.
/api/v1/lists/getGet dropdown values, paged
The route is part of the service today. Its request and response schema will be published here; until then, use the OpenAPI document on your environment.
/api/v1/database/executeRun a stored procedure or function
Runs a named stored procedure or function in the app's database with bound parameters.
Request body
{
"ObjectName": "usp_RecalculateVendorScores",
"ObjectType": 1,
"Parameters": []
}Response
- 200 OK with the procedure's result.
Example request
curl -X POST "https://your-data-host/api/v1/database/execute" \
-H "Authorization: Bearer $TAF_TOKEN" \
-H "TenantId: $TENANT_ID" \
-H "AppId: $APP_ID" \
-H "EnvironmentId: $ENVIRONMENT_ID" \
-H "Content-Type: application/json" \
-d '{
"ObjectName": "usp_RecalculateVendorScores",
"ObjectType": 1,
"Parameters": []
}'const res = await fetch("https://your-data-host/api/v1/database/execute", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
TenantId: tenantId,
AppId: appId,
EnvironmentId: environmentId,
"Content-Type": "application/json",
},
body: JSON.stringify({
"ObjectName": "usp_RecalculateVendorScores",
"ObjectType": 1,
"Parameters": []
}),
});
const result = await res.json();using var http = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://your-data-host/api/v1/database/execute");
request.Headers.Authorization = new("Bearer", token);
request.Headers.Add("TenantId", tenantId);
request.Headers.Add("AppId", appId);
request.Headers.Add("EnvironmentId", environmentId);
request.Content = JsonContent.Create(body); // body: the JSON shown in the cURL tab
var response = await http.SendAsync(request);/api/v1/accessGet your access scopes per entity
The route is part of the service today. Its request and response schema will be published here; until then, use the OpenAPI document on your environment.
/api/v1/access/clone-roleCopy one role's access to another
Request body
{
"SourceRoleId": "00000000-0000-0000-0000-000000000000",
"TargetRoleId": "00000000-0000-0000-0000-000000000000"
}Response
- 200 OK when the target role has the source role's access.
Example request
curl -X POST "https://your-data-host/api/v1/access/clone-role" \
-H "Authorization: Bearer $TAF_TOKEN" \
-H "TenantId: $TENANT_ID" \
-H "AppId: $APP_ID" \
-H "EnvironmentId: $ENVIRONMENT_ID" \
-H "Content-Type: application/json" \
-d '{
"SourceRoleId": "00000000-0000-0000-0000-000000000000",
"TargetRoleId": "00000000-0000-0000-0000-000000000000"
}'const res = await fetch("https://your-data-host/api/v1/access/clone-role", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
TenantId: tenantId,
AppId: appId,
EnvironmentId: environmentId,
"Content-Type": "application/json",
},
body: JSON.stringify({
"SourceRoleId": "00000000-0000-0000-0000-000000000000",
"TargetRoleId": "00000000-0000-0000-0000-000000000000"
}),
});
const result = await res.json();using var http = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://your-data-host/api/v1/access/clone-role");
request.Headers.Authorization = new("Bearer", token);
request.Headers.Add("TenantId", tenantId);
request.Headers.Add("AppId", appId);
request.Headers.Add("EnvironmentId", environmentId);
request.Content = JsonContent.Create(body); // body: the JSON shown in the cURL tab
var response = await http.SendAsync(request);/api/v1/permissionsGet your named permissions
The route is part of the service today. Its request and response schema will be published here; until then, use the OpenAPI document on your environment.
/hubs/crud-notificationsReal-time hub for write results and record changes
A SignalR hub. Clients receive the result of asynchronous writes and change notifications for registered entities.
The route is part of the service today. Its request and response schema will be published here; until then, use the OpenAPI document on your environment.