defineConnector in TypeScript, define_connector in Python,
ConnectorDefinition in PHP and Java, ConnectorRuntime in Go. Same model, same guarantees.
The two functions that matter
You implement two required readers,fetchProducts and fetchCustomers, and add the optional ones as
you need them:
Each reader takes a cursor and returns one page of records plus the next cursor, or a null cursor when
the entity is exhausted. Page everything that can grow; a reader that returns its whole table in one page
works in a demo and times out at a million rows.
A complete connector
This implements all four readers and the write-back applier, runs the sync, then drains approved prices. Leave outfetchQuotes, fetchOrders, or applyPrice and the runtime skips what you did not implement,
so a catalog-only storefront implements the first two and stops.
The sync is crash-safe
The checkpoint store saves the open batch id and each entity’s cursor after every page. A process that dies mid-sync resumes from the last saved cursor and the same open batch, and re-sent pages are deduplicated on your external ids, so a retry never doubles your data. UseInMemoryCheckpointStore
for a one-shot run and FileCheckpointStore (or your own store) for a scheduled job that must survive a
restart.
The runtime stages entities in dependency order (products, then customers, then quotes and orders) no
matter what order you pass, so a line always resolves to a product and customer already sent. The sync
report tells you what landed: status, the per-entity staged counts, skippedOverCap, and any
warnings.
Write-backs are leased
drainWritebacks claims a batch of approved prices, calls your applyPrice for each, and acknowledges
the results, with leases handled for you. Delivery is at-least-once, so make applyPrice idempotent:
setting the same price twice must be harmless. A task whose lease expires before you finish is counted
as expired and returned to the queue, never acknowledged, so it reaches you again on the next drain.
Echo the decision id on your quote lines. When you map a closed quote in
fetchQuotes, carry the
pricingDecisionId Elastly returned when it priced the line. That id is the whole learning loop: it
ties what Elastly recommended to what your rep charged. Quote lines without it are still ingested, but
the runtime warns loudly and the model learns nothing from them.