Overview
Schemas define the structure of your data objects in Pretectum. Each schema specifies:- Fields: The attributes that data objects contain (e.g., First Name, Email, Phone)
- Data Types: The type of data each field holds (string, number, date, etc.)
- Validation Rules: Requirements like mandatory fields and unique constraints
- Search Configuration: Which fields are indexed for searching
Business Area (e.g., Customer)
└── Schema (e.g., Individual Customer)
└── Fields (e.g., First Name, Email, Phone)
└── Data Objects (actual customer records)
Why Schemas Matter
Understanding your schemas is essential for:- Effective Searching: Know which fields are searchable and their exact names
- Data Validation: Understand required fields and data types
- Building Integrations: Create forms and interfaces that match your data structure
- Query Optimization: Target searches to specific fields for better results
Before You Begin
To use the Schema APIs, you need:1
Create an API Key
In the Pretectum app, go to Configuration → API Keys and create a key. It is shown once, at
creation, so copy it then. See API Keys.
2
Get Business Area IDs
Retrieve business area IDs using the List Business Areas endpoint. Schema queries require a business area ID.
Listing Schemas in a Business Area
To get schemas, you first need the business area ID, then query for schemas within that area.Step 1: Get Business Area ID
async function getBusinessAreaId(apiKey, businessAreaName) {
const response = await fetch('https://api.pretectum.io/v1/my/businessareas', {
headers: { 'Authorization': apiKey }
});
const areas = await response.json();
const area = areas.find(a => a.name === businessAreaName);
return area?.businessAreaId;
}
const businessAreaId = await getBusinessAreaId(apiKey, 'Customer');
def get_business_area_id(api_key, business_area_name):
response = requests.get(
'https://api.pretectum.io/v1/my/businessareas',
headers={'Authorization': api_key}
)
areas = response.json()
for area in areas:
if area['name'] == business_area_name:
return area['businessAreaId']
return None
business_area_id = get_business_area_id(api_key, 'Customer')
Step 2: List Schemas
curl -X GET "https://api.pretectum.io/v1/businessareas/20240115103000123a1b2c3d4e5f6789012345678901234/schemas" \
-H "Authorization: pre_your_api_key"
async function getSchemas(apiKey, businessAreaId) {
const response = await fetch(
`https://api.pretectum.io/v1/businessareas/${businessAreaId}/schemas`,
{
headers: {
'Authorization': apiKey,
'Accept': 'application/json'
}
}
);
return response.json();
}
const schemas = await getSchemas(apiKey, businessAreaId);
console.log('Available schemas:');
schemas.items.forEach(schema => {
console.log(`- ${schema.name}: ${schema.description}`);
});
def get_schemas(api_key, business_area_id):
response = requests.get(
f'https://api.pretectum.io/v1/businessareas/{business_area_id}/schemas',
headers={
'Authorization': api_key,
'Accept': 'application/json'
}
)
response.raise_for_status()
return response.json()
schemas = get_schemas(api_key, business_area_id)
print('Available schemas:')
for schema in schemas['items']:
print(f"- {schema['name']}: {schema['description']}")
Understanding the Response
{
"items": [
{
"schemaId": "20240115103000456d1e2f3a4b5c6789012345678901234",
"name": "Individual Customer",
"description": "Schema for individual customer records",
"businessAreaId": "20240115103000123a1b2c3d4e5f6789012345678901234",
"businessAreaName": "Customer",
"active": true,
"state": "published",
"fieldsCount": 12,
"dataSetCount": 3,
"version": 5,
"createdByEmail": "admin@example.com",
"updatedByEmail": "admin@example.com",
"createdDate": "2024-01-15T10:30:00Z",
"updatedDate": "2024-06-15T14:22:00Z"
},
{
"schemaId": "20240120090000789e2f3a4b5c6d7890123456789012345",
"name": "Business Customer",
"description": "Schema for business customer records",
"businessAreaId": "20240115103000123a1b2c3d4e5f6789012345678901234",
"businessAreaName": "Customer",
"active": true,
"state": "published",
"fieldsCount": 15,
"dataSetCount": 2,
"version": 3,
"createdByEmail": "admin@example.com",
"updatedByEmail": "admin@example.com",
"createdDate": "2024-01-20T09:00:00Z",
"updatedDate": "2024-05-10T11:30:00Z"
}
],
"nextPageKey": "eyJMYXN0RXZhbHVhdGVkS2V5Ijp7..."
}
| Field | Description |
|---|---|
schemaId | Unique identifier for the schema |
name | Display name used for filtering in search operations |
description | Explanation of the schema’s purpose |
businessAreaId | The parent business area ID |
businessAreaName | The parent business area name |
active | Whether the schema is currently active |
state | Current state of the schema (e.g., draft, published) |
fieldsCount | Number of fields defined in the schema |
dataSetCount | Number of datasets using this schema |
version | Version number for tracking changes |
nextPageKey | Pagination token for fetching the next page (if present) |
Getting Schema Details
Retrieve complete schema information including field definitions:curl -X GET "https://api.pretectum.io/v1/businessareas/20240115103000123a1b2c3d4e5f6789012345678901234/schemas/20240115103000456d1e2f3a4b5c6789012345678901234" \
-H "Authorization: pre_your_api_key"
async function getSchemaDetails(apiKey, businessAreaId, schemaId) {
const response = await fetch(
`https://api.pretectum.io/v1/businessareas/${businessAreaId}/schemas/${schemaId}`,
{
headers: {
'Authorization': apiKey,
'Accept': 'application/json'
}
}
);
return response.json();
}
const schema = await getSchemaDetails(apiKey, businessAreaId, '20240115103000456d1e2f3a4b5c6789012345678901234');
console.log(`Schema: ${schema.name}`);
console.log('Fields:');
schema.fields.forEach(field => {
const required = field.isRequired ? '(required)' : '';
const pii = field.isPII ? '[PII]' : '';
console.log(` - ${field.name} [${field.dataType}] ${required} ${pii}`);
});
def get_schema_details(api_key, business_area_id, schema_id):
response = requests.get(
f'https://api.pretectum.io/v1/businessareas/{business_area_id}/schemas/{schema_id}',
headers={
'Authorization': api_key,
'Accept': 'application/json'
}
)
response.raise_for_status()
return response.json()
schema = get_schema_details(api_key, business_area_id, '20240115103000456d1e2f3a4b5c6789012345678901234')
print(f"Schema: {schema['name']}")
print('Fields:')
for field in schema['fields']:
required = '(required)' if field.get('isRequired') else ''
pii = '[PII]' if field.get('isPII') else ''
print(f" - {field['name']} [{field['dataType']}] {required} {pii}")
Example Response
{
"schemaId": "20240115103000456d1e2f3a4b5c6789012345678901234",
"name": "Individual Customer",
"description": "Schema for individual customer records",
"businessAreaId": "20240115103000123a1b2c3d4e5f6789012345678901234",
"businessAreaName": "Customer",
"version": 5,
"createdBy": "admin@example.com",
"updatedBy": "admin@example.com",
"createdDate": "2024-01-15T10:30:00Z",
"updatedDate": "2024-06-15T14:22:00Z",
"fields": [
{
"fieldId": "20250115103500001a1b2c3d4e5f6789012345678901234",
"name": "First Name",
"description": "Customer's first name",
"active": true,
"dataType": "string",
"isPrimaryKey": false,
"isSortKey": false,
"isRequired": true,
"isMultivalue": false,
"isPII": true,
"min": 1,
"max": 100
},
{
"fieldId": "20250115103700002b2c3d4e5f6a7890123456789012345",
"name": "Last Name",
"description": "Customer's last name",
"active": true,
"dataType": "string",
"isPrimaryKey": false,
"isSortKey": true,
"isRequired": true,
"isMultivalue": false,
"isPII": true,
"min": 1,
"max": 100
},
{
"fieldId": "20250115104000003c3d4e5f6a7b8901234567890123456",
"name": "Email",
"description": "Customer's email address",
"active": true,
"dataType": "email",
"isPrimaryKey": true,
"isSortKey": false,
"isRequired": true,
"isMultivalue": false,
"isPII": true
},
{
"fieldId": "20250115104200004d4e5f6a7b8c9012345678901234567",
"name": "Customer Type",
"description": "Type of customer",
"active": true,
"dataType": "picklist",
"isPrimaryKey": false,
"isSortKey": false,
"isRequired": true,
"isMultivalue": false,
"isPII": false,
"picklistType": "static",
"staticPicklist": [
{ "code": "individual", "description": "Individual customer" },
{ "code": "corporate", "description": "Corporate customer" }
]
}
]
}
Using Schemas for Search
Use schema and field information to construct effective search queries.Filtering by Schema Name
# Search within a specific schema
curl -X GET "https://api.pretectum.io/v1/dataobjects/search?query=John&businessArea=Customer&schema=Individual%20Customer" \
-H "Authorization: pre_your_api_key"
async function searchInSchema(apiKey, query, businessAreaName, schemaName) {
const params = new URLSearchParams({
query,
businessArea: businessAreaName,
schema: schemaName
});
const response = await fetch(
`https://api.pretectum.io/v1/dataobjects/search?${params}`,
{
headers: { 'Authorization': apiKey }
}
);
return response.json();
}
// Search for "John" in Individual Customer schema
const results = await searchInSchema(
apiKey,
'John',
'Customer',
'Individual Customer'
);
def search_in_schema(api_key, query, business_area_name, schema_name):
response = requests.get(
'https://api.pretectum.io/v1/dataobjects/search',
params={
'query': query,
'businessArea': business_area_name,
'schema': schema_name
},
headers={'Authorization': api_key}
)
return response.json()
# Search for "John" in Individual Customer schema
results = search_in_schema(
api_key,
'John',
'Customer',
'Individual Customer'
)
Searching by Field Names
Use the field names from the schema to construct field-specific queries:# Using field names from the schema
query=[First Name] eq "John"
query=[Email] contains "@example.com"
query=[Last Name] startswith "Sm"
Field names with spaces must be enclosed in brackets when using comparison operators:
[First Name] eq "John"Complete Client Implementation
Here is a complete implementation that handles business areas, schemas, and searching:const API_BASE = 'https://api.pretectum.io';
class PretectumClient {
constructor(apiKey) {
this.apiKey = apiKey;
this._businessAreas = null;
this._schemas = {};
}
async getBusinessAreas() {
if (this._businessAreas) return this._businessAreas;
const response = await fetch(`${API_BASE}/v1/my/businessareas`, {
headers: { 'Authorization': this.apiKey }
});
this._businessAreas = await response.json();
return this._businessAreas;
}
async getBusinessAreaId(name) {
const areas = await this.getBusinessAreas();
const area = areas.find(a => a.name === name);
return area?.businessAreaId;
}
async getSchemas(businessAreaId) {
if (this._schemas[businessAreaId]) {
return this._schemas[businessAreaId];
}
const allSchemas = [];
let pageKey = null;
do {
const url = new URL(`${API_BASE}/v1/businessareas/${businessAreaId}/schemas`);
if (pageKey) url.searchParams.set('pageKey', pageKey);
const response = await fetch(url, {
headers: { 'Authorization': this.apiKey }
});
const data = await response.json();
allSchemas.push(...data.items);
pageKey = data.nextPageKey;
} while (pageKey);
this._schemas[businessAreaId] = allSchemas;
return allSchemas;
}
async getSchemasByBusinessAreaName(businessAreaName) {
const businessAreaId = await this.getBusinessAreaId(businessAreaName);
if (!businessAreaId) {
throw new Error(`Business area not found: ${businessAreaName}`);
}
return this.getSchemas(businessAreaId);
}
async getSchemaDetails(businessAreaId, schemaId) {
const response = await fetch(
`${API_BASE}/v1/businessareas/${businessAreaId}/schemas/${schemaId}`,
{
headers: { 'Authorization': this.apiKey }
}
);
if (!response.ok) {
if (response.status === 404) return null;
throw new Error(`Failed to fetch schema: ${response.statusText}`);
}
return response.json();
}
async getSchemaNames(businessAreaName) {
const schemas = await this.getSchemasByBusinessAreaName(businessAreaName);
return schemas.filter(s => s.active).map(s => s.name);
}
async getSearchableFields(businessAreaId, schemaId) {
const schema = await this.getSchemaDetails(businessAreaId, schemaId);
if (!schema) return [];
return schema.fields
.filter(f => f.searchable)
.map(f => f.name);
}
async search(query, options = {}) {
const params = new URLSearchParams({ query, ...options });
const response = await fetch(
`${API_BASE}/dataobjects/search?${params}`,
{
headers: { 'Authorization': this.apiKey }
}
);
return response.json();
}
}
// Usage
const client = new PretectumClient(process.env.PRETECTUM_API_KEY);
// Get all schemas in Customer business area
const schemas = await client.getSchemasByBusinessAreaName('Customer');
console.log('Customer schemas:', schemas.map(s => s.name));
// Get schema names for a dropdown
const schemaNames = await client.getSchemaNames('Customer');
console.log('Schema options:', schemaNames);
// Search within a specific schema
const results = await client.search('John', {
businessArea: 'Customer',
schema: 'Individual Customer'
});
console.log(`Found ${results.total} results`);
import os
import requests
from typing import Optional, Dict, List, Any
class PretectumClient:
API_BASE = 'https://api.pretectum.io'
def __init__(self, api_key: str):
self.api_key = api_key
self._business_areas: Optional[List[Dict]] = None
self._schemas: Dict[str, List[Dict]] = {}
def get_business_areas(self) -> List[Dict]:
if self._business_areas:
return self._business_areas
response = requests.get(
f'{self.API_BASE}/v1/my/businessareas',
headers={'Authorization': self.api_key}
)
response.raise_for_status()
self._business_areas = response.json()
return self._business_areas
def get_business_area_id(self, name: str) -> Optional[str]:
areas = self.get_business_areas()
for area in areas:
if area['name'] == name:
return area['businessAreaId']
return None
def get_schemas(self, business_area_id: str) -> List[Dict]:
if business_area_id in self._schemas:
return self._schemas[business_area_id]
all_schemas = []
page_key = None
while True:
params = {}
if page_key:
params['pageKey'] = page_key
response = requests.get(
f'{self.API_BASE}/v1/businessareas/{business_area_id}/schemas',
params=params,
headers={'Authorization': self.api_key}
)
response.raise_for_status()
data = response.json()
all_schemas.extend(data['items'])
page_key = data.get('nextPageKey')
if not page_key:
break
self._schemas[business_area_id] = all_schemas
return all_schemas
def get_schemas_by_business_area_name(self, business_area_name: str) -> List[Dict]:
business_area_id = self.get_business_area_id(business_area_name)
if not business_area_id:
raise ValueError(f"Business area not found: {business_area_name}")
return self.get_schemas(business_area_id)
def get_schema_details(self, business_area_id: str, schema_id: str) -> Optional[Dict]:
response = requests.get(
f'{self.API_BASE}/v1/businessareas/{business_area_id}/schemas/{schema_id}',
headers={'Authorization': self.api_key}
)
if response.status_code == 404:
return None
response.raise_for_status()
return response.json()
def get_schema_names(self, business_area_name: str) -> List[str]:
schemas = self.get_schemas_by_business_area_name(business_area_name)
return [s['name'] for s in schemas if s.get('active', False)]
def get_searchable_fields(self, business_area_id: str, schema_id: str) -> List[str]:
schema = self.get_schema_details(business_area_id, schema_id)
if not schema:
return []
return [
f['name'] for f in schema.get('fields', [])
if f.get('searchable', False)
]
def search(self, query: str, **options) -> Dict[str, Any]:
params = {'query': query, **options}
response = requests.get(
f'{self.API_BASE}/dataobjects/search',
params=params,
headers={'Authorization': self.api_key}
)
response.raise_for_status()
return response.json()
# Usage
client = PretectumClient(os.environ['PRETECTUM_API_KEY'])
# Get all schemas in Customer business area
schemas = client.get_schemas_by_business_area_name('Customer')
print('Customer schemas:', [s['name'] for s in schemas])
# Get schema names for a dropdown
schema_names = client.get_schema_names('Customer')
print('Schema options:', schema_names)
# Search within a specific schema
results = client.search('John', businessArea='Customer', schema='Individual Customer')
print(f"Found {results['total']} results")
Building a Schema-Aware Search Interface
Create cascading dropdowns for business area and schema selection:import { useState, useEffect } from 'react';
function SchemaAwareSearch({ client }) {
const [businessAreas, setBusinessAreas] = useState([]);
const [schemas, setSchemas] = useState([]);
const [selectedArea, setSelectedArea] = useState('');
const [selectedSchema, setSelectedSchema] = useState('');
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
// Load business areas on mount
useEffect(() => {
async function load() {
const areas = await client.getBusinessAreas();
setBusinessAreas(areas.filter(a => a.active));
}
load();
}, [client]);
// Load schemas when business area changes
useEffect(() => {
if (!selectedArea) {
setSchemas([]);
setSelectedSchema('');
return;
}
async function loadSchemas() {
const areaSchemas = await client.getSchemasByBusinessAreaName(selectedArea);
setSchemas(areaSchemas.filter(s => s.active));
setSelectedSchema('');
}
loadSchemas();
}, [selectedArea, client]);
const handleSearch = async () => {
const options = {};
if (selectedArea) options.businessArea = selectedArea;
if (selectedSchema) options.schema = selectedSchema;
const searchResults = await client.search(query, options);
setResults(searchResults.hits);
};
return (
<div>
<select
value={selectedArea}
onChange={(e) => setSelectedArea(e.target.value)}
>
<option value="">All Business Areas</option>
{businessAreas.map(area => (
<option key={area.businessAreaId} value={area.name}>
{area.name}
</option>
))}
</select>
<select
value={selectedSchema}
onChange={(e) => setSelectedSchema(e.target.value)}
disabled={!selectedArea}
>
<option value="">All Schemas</option>
{schemas.map(schema => (
<option key={schema.schemaId} value={schema.name}>
{schema.name}
</option>
))}
</select>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search..."
/>
<button onClick={handleSearch}>Search</button>
<ul>
{results.map(result => (
<li key={result._dataObjectId}>
{JSON.stringify(result)}
</li>
))}
</ul>
</div>
);
}
import os
from flask import Flask, request, jsonify
app = Flask(__name__)
client = PretectumClient(os.environ['PRETECTUM_API_KEY'])
@app.route('/api/business-areas')
def list_business_areas():
"""Get business areas for the first dropdown."""
areas = client.get_business_areas()
return jsonify([
{'name': a['name'], 'id': a['businessAreaId']}
for a in areas if a.get('active')
])
@app.route('/api/schemas/<business_area_name>')
def list_schemas(business_area_name):
"""Get schemas for the selected business area."""
try:
schemas = client.get_schemas_by_business_area_name(business_area_name)
return jsonify([
{'name': s['name'], 'id': s['schemaId']}
for s in schemas if s.get('active')
])
except ValueError as e:
return jsonify({'error': str(e)}), 404
@app.route('/api/search')
def search():
"""Search with optional business area and schema filters."""
query = request.args.get('query', '')
business_area = request.args.get('businessArea')
schema = request.args.get('schema')
options = {}
if business_area:
options['businessArea'] = business_area
if schema:
options['schema'] = schema
results = client.search(query, **options)
return jsonify(results)
Error Handling
Handle common errors when working with schemas:async function safeGetSchemas(client, businessAreaId) {
try {
return await client.getSchemas(businessAreaId);
} catch (error) {
if (error.message.includes('401')) {
await client.authenticate();
return await client.getSchemas(businessAreaId);
}
if (error.message.includes('404')) {
console.error('Business area not found');
return [];
}
throw error;
}
}
def safe_get_schemas(client, business_area_id):
try:
return client.get_schemas(business_area_id)
except requests.exceptions.HTTPError as e:
if e.response.status_code == 401:
client.authenticate()
return client.get_schemas(business_area_id)
elif e.response.status_code == 404:
print('Business area not found')
return []
raise
Best Practices
Cache Schema Data
Cache Schema Data
Schemas change infrequently. Cache responses to reduce API calls:
// Client already caches in this._schemas
// Force refresh when needed:
client._schemas = {};
const freshSchemas = await client.getSchemas(businessAreaId);
Use Schema Names for Search
Use Schema Names for Search
When filtering searches, use the schema
name, not the schemaId:// Correct
client.search('John', { schema: 'Individual Customer' });
// Incorrect
client.search('John', { schema: '20240115103000456d1e2f3a4b5c6789012345678901234' });
Check Field Searchability
Check Field Searchability
Before building field-specific queries, verify the field is searchable:
const schema = await client.getSchemaDetails(areaId, schemaId);
const searchableFields = schema.fields
.filter(f => f.searchable)
.map(f => f.name);
Handle Pagination
Handle Pagination
Always check for
pageKey in schema list responses:# The client implementation handles this automatically
# by looping until no more pageKey is returned
Next Steps
List Schemas API
View the complete List Schemas API reference
Get Schema API
View the Get Schema API reference
Search Data Objects
Learn how to search within schemas
Business Areas
Learn about business areas
