Data API
Read Operations
Reference Fields

Reference Fields

Reference, choice, and user fields in DealCloud return rich objects by default. This page covers how to control their format for easier processing. Resolution uses the same read pipeline as other fields (intapp-rest-client).

Default Behavior

By default, reference fields return full objects:

contacts = dc.read_data("Contact", output="list")
 
# Default: Full reference object
print(contacts[0]["Company"])
# {
#     "id": 12345,
#     "name": "Acme Corp",
#     "type": 0,
#     "entryListId": 2011,
#     "url": "..."
# }

Reference Format Options

Use ReferenceFormat to control output:

from dealcloud_sdk import DealCloud, DealCloudConfig, ReferenceFormat
 
config = DealCloudConfig(
    siteUrl="yoursite.dealcloud.com",
    clientId=12345,
    clientSecret="your-secret",
)
dc = DealCloud.from_config_object(config)
# Full reference objects (default)
contacts = dc.read_data(
    "Contact",
    output="list"
    # reference_format defaults to FULL
)
 
print(contacts[0]["Company"])
# {"id": 12345, "name": "Acme Corp", "entryListId": 2011, ...}

With DataFrames

# DataFrame with name-resolved references
df = dc.read_data(
    "Contact",
    output="pandas",
    reference_format=ReferenceFormat.NAME
)
 
# Easy filtering on reference values
acme_contacts = df[df["Company"] == "Acme Corp"]

Reference Caching

When using ReferenceFormat.NAME, the SDK fetches display names via additional API calls. Use ReferenceCache for efficiency:

from dealcloud_sdk import ReferenceCache
 
# Create cache (LRU with max entries)
cache = ReferenceCache(max_entries=10000)
 
# First read populates cache
contacts = dc.read_data(
    "Contact",
    output="pandas",
    reference_format=ReferenceFormat.NAME,
    reference_cache=cache
)
 
# Subsequent reads use cached names (faster)
more_contacts = dc.read_data(
    "Contact",
    output="pandas",
    query="{Status: 'Active'}",
    reference_format=ReferenceFormat.NAME,
    reference_cache=cache  # Cache hits!
)
 
print(f"Cache size: {len(cache)}")

Cache Configuration

# Default: 10,000 entries
cache = ReferenceCache()
 
# Smaller for memory-constrained environments
cache = ReferenceCache(max_entries=1000)
 
# Larger for many references
cache = ReferenceCache(max_entries=50000)

Cache Methods

MethodDescription
get(object_id, entry_id)Get cached name or None
set(object_id, entry_id, name)Set a mapping
bulk_set(object_id, mappings)Set multiple mappings
get_missing(object_id, entry_ids)Find IDs not in cache
len(cache)Current cache size

Legacy resolve Parameter

The older resolve parameter is still supported for backward compatibility, and applies to all output formats (list, polars, polars_lazy, and pandas):

# Legacy approach (still works)
df = dc.read_data("Contact", output="pandas", resolve="name")
df = dc.read_data("Contact", output="pandas", resolve="id")
 
# Also works for polars and list outputs
pl_df = dc.read_data("Contact", output="polars", resolve="name")
rows = dc.read_data("Contact", output="list", resolve="name")
💡

reference_format is recommended over resolve for new code. It provides more control and supports caching.

💡

resolve is resolved locally from the reference objects already present in each row (no extra API calls), so unlike ReferenceFormat.NAME it does not perform name lookups. When both resolve and reference_format are supplied, reference_format takes precedence.

Multi-Select References

For multi-select reference fields:

# Full objects (default)
deals = dc.read_data("Deal", output="list")
print(deals[0]["Companies"])
# [
#     {"id": 123, "name": "Acme Corp", ...},
#     {"id": 456, "name": "Beta Inc", ...}
# ]
 
# IDs only
deals = dc.read_data(
    "Deal",
    output="list",
    reference_format=ReferenceFormat.ID
)
print(deals[0]["Companies"])
# [123, 456]
 
# Names only
deals = dc.read_data(
    "Deal",
    output="list",
    reference_format=ReferenceFormat.NAME
)
print(deals[0]["Companies"])
# ["Acme Corp", "Beta Inc"]

Choice Fields

Choice fields behave similarly:

# Full choice objects (default)
companies = dc.read_data("Company", output="list")
print(companies[0]["Industry"])
# {"id": 101, "name": "Technology", "seqNumber": 1, ...}
 
# ID only
companies = dc.read_data(
    "Company",
    output="list",
    reference_format=ReferenceFormat.ID
)
print(companies[0]["Industry"])
# 101
 
# Name only
companies = dc.read_data(
    "Company",
    output="list",
    reference_format=ReferenceFormat.NAME
)
print(companies[0]["Industry"])
# "Technology"

User Fields

User fields follow the same pattern:

# Full user objects (default)
deals = dc.read_data("Deal", output="list")
print(deals[0]["AssignedTo"])
# {"id": 5678, "name": "John Smith", "url": "mailto:john@example.com", ...}
 
# ID only
deals = dc.read_data(
    "Deal",
    output="list",
    reference_format=ReferenceFormat.ID
)
print(deals[0]["AssignedTo"])
# 5678
 
# Name only
deals = dc.read_data(
    "Deal",
    output="list",
    reference_format=ReferenceFormat.NAME
)
print(deals[0]["AssignedTo"])
# "John Smith"

Performance Considerations

FormatAPI CallsBest For
FULL1When you need all reference details
ID1When linking to other systems
NAME1 + lookupsReports, exports, display

Optimizing NAME Resolution

# Create cache before processing multiple objects
cache = ReferenceCache(max_entries=20000)
 
# Process objects that share references
for obj in ["Contact", "Deal", "Interaction"]:
    data = dc.read_data(
        obj,
        output="pandas",
        reference_format=ReferenceFormat.NAME,
        reference_cache=cache  # Shared cache
    )
    data.to_csv(f"{obj.lower()}.csv")

Working with Reference IDs

When you need to use reference IDs in updates:

# Read with IDs
contacts = dc.read_data(
    "Contact",
    output="list",
    reference_format=ReferenceFormat.ID
)
 
# Use IDs directly in updates
updates = []
for contact in contacts:
    if contact["Company"] == 12345:  # Old company ID
        updates.append({
            "EntryId": contact["EntryId"],
            "Company": 67890  # New company ID
        })
 
dc.update_data("Contact", updates)

Related