Contracting API: Best Practices
The Contracting API v2 surface is read-only — /v2/producers, /v2/contracts, /v2/contract-assignments, /v2/contract-assignment-changes, /v2/assigned-*, and the hierarchy endpoint. These notes cover getting a read integration right.
Sync with updated_since, Don't Requery Everything
Instead of re-fetching all records on a schedule, use updated_since to get only what changed:
GET /contracting/v2/contract-assignments?updated_since=2026-06-01T00:00:00Z
updated_sinceis an RFC3339 UTC timestamp, inclusive, available on/v2/producers,/v2/contracts,/v2/contract-assignments,/v2/contract-assignment-changes,/v2/assigned-carriers,/v2/assigned-products, and/v2/assigned-commission-levels.- Store the time you started each sync run and use it as the next run's
updated_since— a high-water mark. - Modified time tracks any column change, so a returned record is not necessarily a business-meaningful change; diff against your stored state.
- A pagination run is not a point-in-time snapshot: records updated mid-run may first appear on a later poll. Overlap your windows slightly rather than assuming exactly-once delivery.
Paginate All List Responses
Always paginate — don't assume a single response contains all records. See Pagination for the response envelope, query parameters, and a reusable Python paginator.
Two things to get right:
- The query parameter is
page_token, but the response field ispage.nextToken. An unrecognized parameter name is ignored rather than rejected, so a misspelling silently returns the first page forever. page_sizemust be1–250. Out-of-range values are rejected with a400rather than clamped, on Contracting and Identity alike.
Identify Uplines by ID, Not by Name
The v2 surface has no upline name field. A hierarchy node inlines producerName for the producer at that position and links upward with uplineContractAssignmentId — to name a node's upline, resolve that ID against the node it points to.
If you are migrating from v1, the
uplineName/uplineFirmName/uplinePersonNamefields you may have used there do not exist in v2. Key onuplineContractAssignmentIdinstead; it is stable across amendments and matches thecontractAssignmentIdinhierarchy.producer.*webhook events.
Let the Inlined Names Save You a Round Trip
v2 responses inline reference names next to their IDs — productName beside productId, commissionLevelName beside commissionLevelId, assignmentStatusName beside assignmentStatusId. You do not need a second call, or a cached lookup table, to render a row.
Reliability
- Implement exponential backoff for
429 Too Many Requestsand5xxerrors. See Rate Limits. - Reuse your access token — it is valid for 60 minutes, and fetching a new one per request is the most common way integrations hit the token endpoint limit.
- Capture the
DD-Trace-IDresponse header on failures and include it in support tickets. See Traceability.
Performance
- Rate limits are counted per credential, so parallel workers sharing a
client_idshare one budget rather than each getting their own. - Filter server-side with
updated_sincerather than fetching everything and filtering locally. - Prefer paged bulk reads over per-record polling.
Integration Patterns
Initial Data Load
When setting up a new integration:
- Read your account configuration —
GET /v2/assigned-carriers,/v2/assigned-products,/v2/assigned-commission-levels - Page through
GET /v2/producersfor your producer population - Page through
GET /v2/contract-assignmentsfor their placements - Fetch the hierarchy with
GET /v2/organizations/{organizationId}/hierarchies, fetching every page before reconstructing the tree — a child can appear on a later page than its parent - Record the start time of the run as your first high-water mark
Ongoing Sync
For keeping a downstream system in sync:
- Poll
GET /v2/contract-assignmentswithupdated_sinceset to your last sync timestamp — each row already carries the full current state with names inlined - Update your local records and advance your stored sync timestamp
- Subscribe to webhook events for near-real-time updates, and keep the
updated_sincepoll as a reconciliation safety net
Resolving Producer Contact Details
Contracting holds placement; addresses, phones, bank accounts, and E&O policies live in the Identity API. A producer's personId and firmId are Identity identifiers and resolve directly, with no mapping step — see Joining with the Contracting API.