Skip to content

Data Sync Overview

The Onboarded™ application synchronizes data from the Onboarded™ platform to Salesforce using an event-feed delta sync architecture. A single scheduled poller consumes Onboarded's cursor-paginated /events feed and applies each change through the same shared apply-core used by the real-time inbound webhook — so there is exactly one code path responsible for turning an Onboarded™ change into a Salesforce record, regardless of whether that change arrived via the feed or the webhook.

Forms are the exception — they are not event-sourced. Onboarded™ does not emit form create/update events to the /events feed, so the poller never syncs forms. Forms sync through a dedicated Form catalog batch (a full pull of the forms catalog). See How the sync dispatches by object below.

How the sync dispatches by object

A sync run — whether it fires on schedule or you click Run Sync — reads the per-object sync checkboxes in Object Configuration and launches the right engine for each selected object:

If you enable…The sync runs…Because…
Formsthe Form batch (FormSyncBatch) — a full pull of the forms catalogforms are not on the /events feed
Employer, Employee, Client, Job, Placement, Task (any)the event-feed poller (OnboardedEventSyncQueueable) oncethese objects are delta-synced from /events
nothing (or only Placement Form)nothing is launchedthere is no work to do

So checking Forms and running a sync does produce a forms sync (the Form batch); checking an event-sourced object runs the poller. The two are independent engines and can run in the same nightly window. Forms can also be reconciled on demand at any time via Pull All Forms.

Event-Feed Delta Sync Model

  • Poller: OnboardedEventSyncQueueable, enqueued on a schedule by OnboardedSyncScheduler. Each execution fetches one page (up to 500 events) from /events and calls the shared apply-core (OnboardedEventSyncServiceImpl.applyEvents) to create or update the corresponding Salesforce records.
  • Chaining: If the API reports more events are available (has_more), the poller enqueues a fresh Queueable execution carrying the next page's cursor. A large backlog drains across as many chained executions as needed — each execution gets a fresh heap and callout budget, so one page never blocks the next.
  • Delta only: The poller never re-fetches records that haven't changed. It only pulls what's new since the last run — this is what makes the feed cheap enough to run frequently (for example, hourly) without a heavy API cost.
  • Shared apply-core: Both the poller and the webhook flatten nested API objects (address, progress, next_action, subtasks, custom_attributes), resolve relationships, and write fields through the same Data-Authority-aware logic. The only differences between the two paths are described in Feed vs. Webhook Scoping below.
  • Non-throwing, per-record errors: A single bad or rejected event never stops the page. Per-record failures are logged to Onboarded_Error_Log__c and the poller continues; a genuinely unhandled abort (e.g. a governor limit) is caught by an attached Finalizer and logged as well, so a poller failure is never silent.
  • Recommended cadence: Schedule the poller to run at least daily. Because each run only pulls what changed, you can safely schedule it much more frequently (for example, hourly) if you want Salesforce to stay closer to real time between webhook deliveries.

Initial Data Load

Initial data population is performed by the Onboarded™ ETL when your org is first connected — not by an in-Salesforce full sync. Once that initial load completes, the delta poller automatically picks up subsequent changes on its schedule. There is nothing to configure in Salesforce to seed or start the feed — it begins syncing changes on its own once the connection is established.

If sync stops for an extended period, the most common cause is a scheduled job that stopped running (a deactivated user or a removed CRON job) — see Sync Not Running in Troubleshooting. If the feed can't resume on its own after a long gap, contact Onboarded™ support.

Feed vs. Webhook Scoping

The delta poller (the "feed") and the real-time inbound webhook are complementary, not redundant, and they are gated differently:

PathGated by the object's sync toggle + mapping in Object Configuration?When it runs
Feed (poller)Yes — requires BOTH the object's sync toggle to be on AND the object to be mapped to a Salesforce objectOn its schedule, pulling everything that changed since its last run
WebhookNo — always applies regardless of the object's sync toggleImmediately, whenever Onboarded™ pushes a change

In other words, the feed only backstops the objects you've explicitly checked in Object Configuration — it is the reconciliation/cleanup channel that catches anything the webhook missed (a dropped delivery, a period the org was unreachable, etc.). The webhook is always on and applies every event it receives the moment it arrives, whether or not that object's sync toggle is enabled. If you leave an object's Sync<Object>Enabled__c flag off because a different mechanism (or no mechanism) owns that object, the feed will not process it — but a webhook delivery for that same object still applies, because the webhook does not consult the flag at all.

Both paths still require the object to be mapped (a Salesforce object configured in Object Configuration) — an unmapped object type has no write target on either path.

Real-Time (Webhook) vs. Scheduled (Feed) Sync

The webhook and the scheduled feed serve different needs, and the trade-off has real operational consequences worth understanding before you decide what to sync and how:

  • Webhook — real-time, but it consumes your Salesforce API limit. Every change Onboarded™ pushes arrives as an inbound Salesforce API call, and Salesforce caps how many inbound API calls an org can accept in a rolling 24-hour period (the exact limit depends on your edition and licenses). Real-time updates are valuable, but for high-volume objects that traffic can consume a meaningful share of that daily allocation.
  • Scheduled feed — best for "current, but not real-time" data. The scheduled sync pulls accumulated changes on your cadence (see Data Operation Settings) rather than one call per change, so it keeps objects updated without spending your inbound API limit on every individual change. For objects that don't need to be current to the second, prefer the feed.
  • The feed only reaches back ~30 days. Onboarded™ retains create/update/delete events for roughly 30 days, then removes them. The scheduled feed is therefore a rolling 30-day catch-up window — it can reconcile anything that changed within that window, but it cannot retrieve changes older than that.

Be careful turning sync off — you can lose data. Because the feed only sees the last ~30 days of events, leaving an object's sync disabled for an extended period is risky: changes made while it is off are only caught if you re-enable sync before their events age past the 30-day window. Anything older is gone from the feed.

Enabling an object later carries the same risk. Turning on sync for an object that was previously off only picks up changes from within the current 30-day window — anything that changed earlier is missed. Enable sync for every object you care about from the start, and avoid long stretches with sync disabled. Recovering changes that have already aged out of the 30-day window requires a fresh data load from Onboarded™ — contact Onboarded™ support.

This 30-day risk does not apply to Forms. Forms are not on the event feed — they sync via a full-catalog Form batch, so enabling Forms later (or leaving it off for a while) loses nothing: the next Form batch (or a Pull All Forms) reconciles the entire current catalog regardless of age.

Custom Attributes Sync the Same Way as Standard Fields

A custom attribute you create via Create Custom Attribute in Object Configuration (see Custom Attribute Creation) is treated exactly like any other mapped field once it exists: it syncs on every inbound path — the real-time webhook and the scheduled feed alike. You don't need to configure anything differently for the two paths, and there's no separate step to make a custom attribute "work" with the webhook versus the poller.

The reverse is also true: if you haven't created and mapped a custom attribute for a given value, that value is simply not synced — on either path. Nothing fails and nothing is logged as an error; it's just skipped, the same as any other field that isn't mapped.

Object Configuration provides a Link Data option. This populates Lookup and Master-Detail relationship fields between records that have already been synced — for example, linking an Employee record to its associated Employer record once both exist in Salesforce. Link Data runs on its own schedule, separate from your regular sync (see Scheduled Sync Setup), so a newly-created relationship may not appear until the next time Link Data runs.

Records are linked in a fixed order so that parent records are already linked before their children try to reference them: Employer, Employee, Client, Job, Form, Placement, Task, Placement Form.

Tip: Enable/schedule Link Data if your mapping configuration includes relationship fields that need to be populated after records are synced by the feed or webhook.

Enabling a reference relationship after records are already synced? Existing records won't be back-filled by the inline resolution or the next feed run. Use Run Links Now on the Data Operation Settings page to relink that one object's existing records on demand (no API calls).

Feed Coverage and Guarantees

Each poller page:

  • Fetches from /events using cursor pagination (up to 500 events per page)
  • Matches records by Onboarded™ ID (unique identifier), never by name or other business keys
  • Creates new records or updates existing ones based on your mapping rules and the Enable Salesforce Record Creation setting for that object
  • Respects Data Authority settings for conflict resolution, exactly as the webhook does
  • Is idempotent — replaying the same event updates the same Salesforce record rather than duplicating it