Sync changes back

How reverse sync works

Prepare mappings, permissions and worker entry points for sending DevRev changes to the external system.

Reverse sync prerequisites

  • Set is_loadable: true on the relevant external record types in external domain metadata.
  • Enable reverse mapping on the record type and the writable fields in initial domain mapping.
  • Configure the manifest's loading function and event routing; see manifest.
  • Give the external connection the scopes needed to create and update the supported records. Read-only extraction credentials may be insufficient.
  • Implement denormalization and HTTP writes for every item type the connector advertises as loadable.

The platform transforms DevRev changes into the external domain model before invoking a loading worker. Your worker then converts those transformed fields into the external API's request shape. This final conversion is denormalization; it is distinct from field mapping in the platform.

Loading event contracts

CapabilityIncoming start / continuationDefault worker fileSuccessful outcome
Data writesSTART_LOADING_DATA / CONTINUE_LOADING_DATAworkers/load-dataDATA_LOADING_DONE
Attachment writesSTART_LOADING_ATTACHMENTS / CONTINUE_LOADING_ATTACHMENTSworkers/load-attachmentsATTACHMENT_LOADING_DONE
Data loader state cleanupSTART_DELETING_LOADER_STATESDK-managedLOADER_STATE_DELETION_DONE
Attachment loader state cleanupSTART_DELETING_LOADER_ATTACHMENT_STATESDK-managedLOADER_ATTACHMENT_STATE_DELETION_DONE

Workers return a TaskResult. The SDK emits the phase-appropriate done, progress, delayed or error event exactly once. Connector code must not emit a second event. State cleanup removes synchronization state; it does not delete records in the external system.

Loading entry point

This is a complete loading entry point for a template project with resolveJsonModule enabled and compiled worker files alongside the entry point:

import { AirSyncEvent, spawn } from '@devrev/airsync-sdk';
import initialDomainMapping from '../external-system/initial_domain_mapping.json';

export type LoaderState = Record<string, never>;

export default async function run(events: AirSyncEvent[]): Promise<void> {
  for (const event of events) {
    await spawn<LoaderState>({
      event,
      initialState: {},
      initialDomainMapping,
      baseWorkerPath: __dirname,
    });
  }
}

The SDK resolves default worker paths from the incoming event. The public template loading entry point demonstrates this layout. Change worker routing only when the compiled layout differs.

What starts reverse sync

Changes to records participating in a sync unit can initiate loading. When testing a new DevRev record, select the subtype established by the import and provide its required fields. The subtype identifies the external record type and recipe; creating an unrelated stock record is not a sufficient test.

Verification

Verify both a new record and an update to an existing mapped record. Confirm external IDs are recorded, required fields and references survive transformation, and continuation does not duplicate writes. Test each claimed capability with the data loading, attachment loading and ordering and loop prevention contracts.

Loading state and continuation

The SDK tracks loading progress. Return its result and preserve connector-owned state needed by your external writes.

Extractor and loader state are separate. adapter.state contains connector-owned state; the SDK owns its file positions, completion flags and reports. Do not construct or modify SDK state directly.

adapter.loadItemTypes() and adapter.loadAttachments() return TaskResult and resume from SDK-managed file positions. Return their result unchanged. A delay keeps the current item pending; a progress outcome schedules continuation in a new invocation. The SDK's soft timeout is capped at ten minutes. Do not rely on older documentation's thirteen-minute worker budget.

External writes and mapper persistence are separate operations. If an external write succeeds but persisting its mapper fails, the phase fails and the same write can be attempted again. Use the external API's idempotency mechanism where available, with a stable key derived from sync-unit and DevRev object identity.

Next: Create and update external records.

Last updated on