or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

api-client.mdbase-stream-classes.mdcrm-streams.mdcustom-objects.mdengagement-streams.mderror-handling.mdindex.mdmarketing-sales-streams.mdproperty-history-streams.mdsource-connector.mdweb-analytics.md

property-history-streams.mddocs/

0

# Property History Streams

1

2

Specialized streams for tracking changes to CRM object properties over time. These streams provide detailed audit trails showing when and how property values changed for contacts, companies, and deals.

3

4

## Capabilities

5

6

### Companies Property History

7

8

Stream for tracking changes to company properties over time.

9

10

```python { .api }

11

class CompaniesPropertyHistory(IncrementalStream):

12

"""

13

Stream for HubSpot company property change history.

14

15

Provides access to property history data including:

16

- Property value changes over time

17

- Change timestamps and source attribution

18

- User or system attribution for changes

19

- Property metadata and context

20

- Bulk import tracking

21

22

Requires OAuth scope: crm.schemas.companies.read

23

"""

24

```

25

26

### Contacts Property History

27

28

Stream for tracking changes to contact properties over time.

29

30

```python { .api }

31

class ContactsPropertyHistory(IncrementalStream):

32

"""

33

Stream for HubSpot contact property change history.

34

35

Provides access to property history data including:

36

- Contact property value changes

37

- Change timestamps and attribution

38

- Form submission property updates

39

- Email engagement property changes

40

- Integration sync property updates

41

42

Requires OAuth scope: crm.schemas.contacts.read

43

"""

44

```

45

46

### Deals Property History

47

48

Stream for tracking changes to deal properties over time.

49

50

```python { .api }

51

class DealsPropertyHistory(IncrementalStream):

52

"""

53

Stream for HubSpot deal property change history.

54

55

Provides access to property history data including:

56

- Deal stage progression tracking

57

- Amount and close date changes

58

- Owner assignment changes

59

- Pipeline movements

60

- Custom property modifications

61

62

Requires OAuth scope: crm.schemas.deals.read

63

"""

64

```

65

66

## Usage Examples

67

68

### Company Property Tracking

69

70

```python

71

from source_hubspot.streams import API

72

from source_hubspot.source import SourceHubspot

73

74

# Setup authentication

75

credentials = {

76

"credentials_title": "OAuth Credentials",

77

"client_id": "your_client_id",

78

"client_secret": "your_client_secret",

79

"refresh_token": "your_refresh_token"

80

}

81

82

config = {

83

"credentials": credentials,

84

"start_date": "2023-01-01T00:00:00Z"

85

}

86

87

# Get company property history

88

source = SourceHubspot(catalog=None, config=config, state=None)

89

streams = source.streams(config)

90

91

# Find property history stream

92

companies_history = next(

93

s for s in streams

94

if s.name == "companies_property_history"

95

)

96

97

# Process property changes

98

for record in companies_history.read_records(sync_mode="incremental"):

99

company_id = record['objectId']

100

property_name = record['propertyName']

101

old_value = record.get('previousValue')

102

new_value = record['value']

103

timestamp = record['timestamp']

104

105

print(f"Company {company_id}: {property_name}")

106

print(f" Changed from '{old_value}' to '{new_value}'")

107

print(f" At: {timestamp}")

108

```

109

110

### Contact Property Audit

111

112

```python

113

# Track specific contact property changes

114

contacts_history = next(

115

s for s in streams

116

if s.name == "contacts_property_history"

117

)

118

119

# Filter for specific properties

120

target_properties = ['email', 'firstname', 'lastname', 'lifecyclestage']

121

122

for record in contacts_history.read_records(sync_mode="incremental"):

123

if record['propertyName'] in target_properties:

124

contact_id = record['objectId']

125

property_name = record['propertyName']

126

change_source = record.get('sourceType', 'Unknown')

127

change_user = record.get('sourceId', 'System')

128

129

print(f"Contact {contact_id} - {property_name}")

130

print(f" Source: {change_source} by {change_user}")

131

print(f" Value: {record['value']}")

132

```

133

134

### Deal Pipeline Analysis

135

136

```python

137

# Analyze deal stage progression

138

deals_history = next(

139

s for s in streams

140

if s.name == "deals_property_history"

141

)

142

143

stage_changes = {}

144

for record in deals_history.read_records(sync_mode="incremental"):

145

if record['propertyName'] == 'dealstage':

146

deal_id = record['objectId']

147

new_stage = record['value']

148

timestamp = record['timestamp']

149

150

if deal_id not in stage_changes:

151

stage_changes[deal_id] = []

152

153

stage_changes[deal_id].append({

154

'stage': new_stage,

155

'timestamp': timestamp

156

})

157

158

# Calculate average time in each stage

159

for deal_id, changes in stage_changes.items():

160

changes.sort(key=lambda x: x['timestamp'])

161

print(f"Deal {deal_id} progression:")

162

for i, change in enumerate(changes):

163

print(f" Stage {i+1}: {change['stage']} at {change['timestamp']}")

164

```

165

166

## OAuth Scopes Required

167

168

Property history streams require specific OAuth scopes to access schema information:

169

170

- **Companies Property History**: `crm.schemas.companies.read`

171

- **Contacts Property History**: `crm.schemas.contacts.read`

172

- **Deals Property History**: `crm.schemas.deals.read`

173

174

These scopes are in addition to the basic object read permissions and must be explicitly granted during OAuth configuration.

175

176

## Data Structure

177

178

Each property history record contains:

179

180

```python

181

{

182

"objectId": "12345", # ID of the object that changed

183

"propertyName": "email", # Name of the property that changed

184

"value": "new@example.com", # New property value

185

"previousValue": "old@example.com", # Previous value (may be null)

186

"timestamp": "2023-01-15T10:30:00Z", # When the change occurred

187

"sourceType": "FORM", # How the change was made

188

"sourceId": "form-123", # Specific source identifier

189

"sourceLabel": "Contact Form", # Human-readable source description

190

"objectTypeId": "0-1" # HubSpot object type identifier

191

}

192

```

193

194

## Incremental Sync

195

196

Property history streams support incremental synchronization using timestamp-based cursors:

197

198

- **Cursor Field**: `timestamp`

199

- **Cursor Granularity**: Millisecond precision

200

- **Lookback Window**: 24 hours (configurable)

201

- **State Format**: ISO 8601 datetime string

202

203

The streams automatically handle pagination and ensure complete data consistency during incremental updates.