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_since is 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 is page.nextToken. An unrecognized parameter name is ignored rather than rejected, so a misspelling silently returns the first page forever.
  • page_size must be 1–250. Out-of-range values are rejected with a 400 rather 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 / uplinePersonName fields you may have used there do not exist in v2. Key on uplineContractAssignmentId instead; it is stable across amendments and matches the contractAssignmentId in hierarchy.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 Requests and 5xx errors. 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-ID response header on failures and include it in support tickets. See Traceability.

Performance

  • Rate limits are counted per credential, so parallel workers sharing a client_id share one budget rather than each getting their own.
  • Filter server-side with updated_since rather 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:

  1. Read your account configuration — GET /v2/assigned-carriers, /v2/assigned-products, /v2/assigned-commission-levels
  2. Page through GET /v2/producers for your producer population
  3. Page through GET /v2/contract-assignments for their placements
  4. 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
  5. Record the start time of the run as your first high-water mark

Ongoing Sync

For keeping a downstream system in sync:

  1. Poll GET /v2/contract-assignments with updated_since set to your last sync timestamp — each row already carries the full current state with names inlined
  2. Update your local records and advance your stored sync timestamp
  3. Subscribe to webhook events for near-real-time updates, and keep the updated_since poll 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.