Sync Patterns Guide

Keep your CRM in sync with your Propstreet data.

This guide shows you how to sync contacts, companies, relationships, projects, prospects, and properties between Propstreet and your CRM so nothing falls through the cracks. The examples use contacts for brevity, but the same cursor, delta-sync, and delete-handling patterns apply to every v1 list endpoint that exposes updated_since, include_deleted, and page_size.

Cursor-Based Pagination

All list endpoints use cursor-based pagination for efficient handling of large datasets.

How It Works

  1. Request with page_size (max 500, default 500)
  2. Response includes nextCursor if more data exists
  3. Pass cursor to the next request
  4. Continue until hasMore is false

Example

# First request
curl "https://app.propstreet.com/api/v1/network/contacts?page_size=500" \
  -H "Authorization: Bearer $TOKEN"

Response:

{
  "data": [...],
  "hasMore": true,
  "nextCursor": "eyJ1IjoiMjAyNS0wMS0xNVQxMDowMDowMFoiLCJpIjoxMjM0NX0="
}
# Subsequent requests
curl "https://app.propstreet.com/api/v1/network/contacts?cursor=eyJ1Ijo..." \
  -H "Authorization: Bearer $TOKEN"

How Long Will My Sync Take?

Network Size Pages Time (at 600 req/min)
10,000 contacts 20 ~2 seconds
50,000 contacts 100 ~10 seconds
100,000 contacts 200 ~20 seconds

Delta Sync

After the initial sync, use delta sync to fetch only changes. This keeps your CRM current without re-downloading everything.

How It Works

  1. Store updatedUtc from your last sync
  2. Use updated_since parameter with that timestamp
  3. Set include_deleted=true to discover removed records
  4. Check deletedUtc to detect deletions

Example

# Get all changes since last sync
curl "https://app.propstreet.com/api/v1/network/contacts?\
updated_since=2025-01-15T10:00:00Z&\
include_deleted=true&\
page_size=500" \
  -H "Authorization: Bearer $TOKEN"

Response includes both updated and deleted records:

{
  "data": [
    {
      "id": 123,
      "firstName": "Jane",
      "updatedUtc": "2025-01-16T08:30:00Z",
      "deletedUtc": null
    },
    {
      "id": 456,
      "firstName": "John",
      "updatedUtc": "2025-01-16T09:00:00Z",
      "deletedUtc": "2025-01-16T09:00:00Z"
    }
  ]
}

[!important] Always use include_deleted=true for bidirectional sync. Otherwise you won't know when records are removed from Propstreet.

Initial Sync

1. Fetch all pages with page_size=500
2. Store each returned record in your CRM
3. Record the highest updatedUtc as your sync checkpoint

Incremental Sync (run every 5-15 minutes)

1. Fetch with updated_since={checkpoint}&include_deleted=true
2. For each record:
   - If `deletedUtc` is set → remove it from your CRM
   - Otherwise → create or update it in your CRM
3. Update your checkpoint to the highest updatedUtc seen

Bidirectional Sync

When syncing changes from your CRM back to Propstreet:

  1. Compare updatedUtc timestamps
  2. If Propstreet is newer → update your CRM
  3. If your CRM is newer → push to Propstreet
  4. For simultaneous edits → use business rules to decide

Webhooks for Real-Time Updates

For instant notifications instead of polling, use webhooks:

  1. Subscribe to events (contact.created, contact.updated, etc.)
  2. Receive HTTP POST to your endpoint when changes occur
  3. Use delta sync as backup to reconcile missed events

See the Webhooks Guide for setup and configuration.

When to Use Each Approach

Approach Best For
Polling Batch processing, guaranteed eventual consistency
Webhooks Real-time UI updates, instant reactions
Both Production systems needing reliability + speed

Recommended production strategy:

  1. Handle webhooks for immediate updates
  2. Run delta sync periodically (hourly/daily) to catch any missed events
  3. Use webhook delivery history to identify and replay failures

External References

Track your CRM's IDs in Propstreet using externalRefs:

curl -X POST "https://app.propstreet.com/api/v1/network/contacts" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Jane",
    "lastName": "Doe",
    "externalRefs": [
      {"namespace": "salesforce", "id": "003xx000004TmiN"}
    ]
  }'

Benefits:

  • Find Propstreet resources by your CRM's ID
  • Avoid duplicates during sync
  • Track which records came from which system