Skip to main content
This guide walks you through searching for data objects in Pretectum using the API. You will learn how to authenticate, construct search queries, and handle the results.

Overview

Pretectum stores your master data as “data objects” organized within a hierarchical structure:
  • Business Areas: High-level organizational categories (e.g., Customer, Product, Supplier)
  • Schemas: Define the structure and fields for data objects within a business area
  • Datasets: Collections of data objects that share the same schema
The Search API allows you to find data objects across this structure using full-text search and filters.

Before You Begin

To use the Search API, you need:
1

Get API Credentials

Contact your Pretectum tenant administrator to obtain your client_id and client_secret. These credentials identify your application and grant access to the API.
2

Understand Your Data

Familiarize yourself with the business areas, schemas, and datasets in your tenant. This knowledge helps you construct effective search queries.
3

Set Up Your Environment

Ensure you have a way to make HTTP requests from your application. This guide includes examples using cURL, JavaScript, and Python.

Step 1: Obtain an Access Token

Before searching, you need to exchange your credentials for an access token.
curl -X POST https://api.pretectum.io/oauth2/token \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "your_client_id",
    "client_secret": "your_encrypted_client_secret"
  }'
The response includes your access token:
{
  "access_token": "eyJraWQiOiJ...",
  "expires_in": 3600,
  "token_type": "Bearer"
}
Store the access token securely. It grants access to your data and expires after the time specified in expires_in (in seconds).

Step 2: Search for Data Objects

With your access token, you can now search for data objects. Include the token in the Authorization header.
Unlike standard Bearer token authentication, pass the token directly without the “Bearer” prefix.
Search for data objects containing a specific term:
curl -X GET "https://api.pretectum.io/dataobjects/search?query=John" \
  -H "Authorization: your_access_token"

Search with Filters

Narrow your search by specifying business area, schema, or dataset.
To get the list of business area names available to your application, use the List Business Areas endpoint. See the Working with Business Areas guide for complete examples.
To get the list of schema names within a business area, use the List Schemas endpoint. See the Working with Schemas guide for complete examples.
To get the list of dataset names within a schema, use the List Datasets endpoint. See the Working with Datasets guide for complete examples.
# Search within a specific business area
curl -X GET "https://api.pretectum.io/dataobjects/search?query=John&businessArea=Customer" \
  -H "Authorization: your_access_token"

# Search within a specific schema
curl -X GET "https://api.pretectum.io/dataobjects/search?query=John&businessArea=Customer&schema=Individual%20Customer" \
  -H "Authorization: your_access_token"

# Search within a specific dataset
curl -X GET "https://api.pretectum.io/dataobjects/search?query=John&dataSet=US%20Customers" \
  -H "Authorization: your_access_token"

Advanced Query Syntax

The search query supports two types of searches: full-text search across all fields, and field-specific search for filtering by attribute values.
Combine terms with AND, OR, NOT operators:
# Find records with both terms
query=John AND Smith

# Find records with either term
query=John OR Jane

# Exclude records with a term
query=John NOT Doe

# Group conditions with parentheses
query=(John OR Jane) AND Smith
Filter by specific attribute values using field:value syntax:
# Search by first name
query=firstName:John

# Search by last name with multiple values
query=lastName:(Smith OR Johnson)

# Search by email domain
query=email:*@example.com

# Search nested fields with dot notation
query=address.city:"New York"
query=address.state:CA

# Combine multiple field filters
query=firstName:John AND address.state:NY

# Check if field exists
query=_exists_:email

# Check if field is missing
query=NOT _exists_:phone
Filter by numeric or date ranges:
# Inclusive range (18 to 65)
query=age:[18 TO 65]

# Greater than
query=age:>21

# Less than or equal
query=price:<=100

# Date range
query=createdDate:[2024-01-01 TO 2024-12-31]

# After a specific date
query=updatedDate:>2024-01-01
Use comparison operators with bracket notation for field names with spaces:
# Equals - find customers where First Name is "Tim"
query=[First Name] eq "Tim"

# Not equals - exclude inactive records
query=[Status] ne "Inactive"

# Greater than
query=[Age] gt 21

# Less than or equal
query=[Price] le 500

# Contains substring
query=[Email] contains "example.com"

# Starts with
query=[Last Name] startswith "Sm"

# Combine operators with and/or
query=[First Name] eq "Tim" and [Last Name] eq "Smith"
query=[State] eq "CA" or [State] eq "NY"

# Complex conditions
query=([State] eq "CA" or [State] eq "NY") and [Status] eq "Active"
Combine multiple search patterns:
# Customer in California with name John
query=firstName:John AND address.state:CA

# Products in price range with specific category
query=category:Electronics AND price:[100 TO 500]

# Active customers with recent orders
query=status:Active AND lastOrderDate:>2024-01-01

# Multi-condition search
query=(firstName:John OR firstName:Jane) AND address.state:NY AND NOT status:Inactive

# Full-text combined with field filters
query="premium customer" AND customerType:Enterprise
For a complete reference of all query syntax options, see the Search API Reference.

Step 3: Handle the Response

The search response includes matching data objects and a total count:
{
  "hits": [
    {
      "_dataObjectId": "20240601120000123f1a2b3c4d5e6789012345678901234",
      "_businessAreaName": "Customer",
      "_schemaName": "Individual Customer",
      "_dataSetName": "US Customers",
      "First Name": "John",
      "Last Name": "Smith",
      "Email": "john.smith@example.com",
      "City": "New York",
      "State": "NY"
    }
  ],
  "total": 1
}

Understanding the Response

FieldDescription
hitsArray of matching data objects
totalTotal number of matches (use for pagination)
_dataObjectIdUnique identifier for each data object
_businessAreaNameThe business area the object belongs to
_schemaNameThe schema defining the object’s structure
_dataSetNameThe dataset containing the object
Additional fields in each hit depend on the schema configuration for that data object.

Step 4: Implement Pagination

For large result sets, retrieve data in pages:
async function searchWithPagination(accessToken, query, pageSize = 20) {
  let allResults = [];
  let from = 0;
  let total = 0;

  do {
    const params = new URLSearchParams({
      query,
      from: from.toString(),
      size: pageSize.toString()
    });

    const response = await fetch(
      `https://api.pretectum.io/dataobjects/search?${params}`,
      {
        headers: { 'Authorization': accessToken }
      }
    );

    const data = await response.json();
    allResults = allResults.concat(data.hits);
    total = data.total;
    from += pageSize;

    console.log(`Retrieved ${allResults.length} of ${total} records`);
  } while (allResults.length < total);

  return allResults;
}

Complete Example

Here is a complete example that authenticates and searches for data objects:
const API_BASE = 'https://api.pretectum.io';

class PretectumClient {
  constructor(clientId, clientSecret) {
    this.clientId = clientId;
    this.clientSecret = clientSecret;
    this.accessToken = null;
    this.tokenExpiry = null;
  }

  async authenticate() {
    const response = await fetch(`${API_BASE}/oauth2/token`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        client_id: this.clientId,
        client_secret: this.clientSecret
      })
    });

    if (!response.ok) {
      throw new Error('Authentication failed');
    }

    const data = await response.json();
    this.accessToken = data.access_token;
    this.tokenExpiry = Date.now() + (data.expires_in * 1000);
  }

  async ensureAuthenticated() {
    if (!this.accessToken || Date.now() >= this.tokenExpiry) {
      await this.authenticate();
    }
  }

  async search(query, options = {}) {
    await this.ensureAuthenticated();

    const params = new URLSearchParams({ query, ...options });
    const response = await fetch(
      `${API_BASE}/dataobjects/search?${params}`,
      {
        headers: { 'Authorization': this.accessToken }
      }
    );

    if (!response.ok) {
      throw new Error(`Search failed: ${response.statusText}`);
    }

    return response.json();
  }
}

// Usage
const client = new PretectumClient('your_client_id', 'your_secret');

const results = await client.search('John', {
  businessArea: 'Customer',
  size: 50
});

console.log(`Found ${results.total} customers named John`);
results.hits.forEach(customer => {
  console.log(`- ${customer.firstName} ${customer.lastName}`);
});

Error Handling

Handle common error scenarios in your application:
ErrorCauseSolution
401 UnauthorizedToken expired or invalidRequest a new access token
403 ForbiddenMissing permissionsContact your tenant administrator
400 Bad RequestInvalid query syntaxCheck your query parameters
async function safeSearch(client, query, options) {
  try {
    return await client.search(query, options);
  } catch (error) {
    if (error.message.includes('401')) {
      // Token expired, re-authenticate
      await client.authenticate();
      return await client.search(query, options);
    }
    throw error;
  }
}

Next Steps