Sync Events and Tasks to Another System

Run a sync on a schedule (for example every 15 minutes). The first run reads everything, a page at a time. Every later run asks only for what changed since the last run. The same steps work for events, tasks, task comments and miscellaneous expenses/credits.

1. Read everything once, a page at a time

Ask for 100 events at a time with $limit and $offset. The response says how many events match in all (total_records) and whether another page follows (has_more). In a URL, write $ as %24 (or quote the URL so your shell does not read $limit as a variable).
curl "https://api.exhibitday.com/v1/events?%24limit=100&%24offset=0" -H "api_key: YOUR_API_KEY"
The first page looks like this (event details shortened):
{"records_found": 100, "total_records": 240, "has_more": true, "list_type": "event", "list_data": [ ... ]}
For the next page, add the number of events you received to $offset (100, then 200) until has_more is false.

2. Remember the latest change

Save the largest event_last_update_timestamp you received, exactly as the API wrote it: in UTC, ending in Z (for example 2026-10-14T22:30:12Z).

3. Next time, read only what changed

Pass the saved timestamp in filter_by_last_update_timestamp_greater_than_or_equal_to. Events changed at exactly that time come back again, so skip ids you already processed with that timestamp. Added events are included, because adding an event sets its last-update timestamp.
curl "https://api.exhibitday.com/v1/events?filter_by_last_update_timestamp_greater_than_or_equal_to=2026-10-14T22:30:12Z&%24limit=100" -H "api_key: YOUR_API_KEY"
The same loop in Python:
import requests

BASE = "https://api.exhibitday.com/v1"
HEADERS = {"api_key": "YOUR_API_KEY"}

def changed_events(since=None):
    """Every event changed on or after `since` (every event when it is None), 100 at a time."""
    offset = 0
    while True:
        params = {"$limit": 100, "$offset": offset}
        if since:
            params["filter_by_last_update_timestamp_greater_than_or_equal_to"] = since
        page = requests.get(BASE + "/events", headers=HEADERS, params=params).json()
        yield from page["list_data"]
        if not page["has_more"]:
            break
        offset += page["records_found"]

events = list(changed_events("2026-10-14T00:00:00"))
latest = max((e["event_last_update_timestamp"] for e in events), default=None)
print(len(events), "changed events; next time pass", latest)
For tasks use /v1/tasks and task_last_update_timestamp; for task comments, /v1/tasks/comments and comment_last_update_timestamp; for miscellaneous expenses/credits, /v1/events/miscexpensecredits and event_misc_expense_credit_last_update_timestamp.

4. Keep your own id on each record

Store the other system's id in integration_metadata_field_1 (fields 1 to 5 are yours to use; only the API can read and write them). Later, find the event by that id with filter_by_integration_metadata_field_1.
curl -X PATCH https://api.exhibitday.com/v1/events -H "api_key: YOUR_API_KEY" -H "Content-Type: application/json" -d "{\"id\":12345,\"integration_metadata_field_1\":\"CRM-48213\"}"
curl "https://api.exhibitday.com/v1/events?filter_by_integration_metadata_field_1=CRM-48213" -H "api_key: YOUR_API_KEY"

5. Deleted records

A deleted record does not appear in a changed-since list. To find deletions, read the ids of all events now and then (for example nightly; $return_event_lites=true makes that fast) and remove the ones that are gone.