Contracting & Hierarchies API Overview
Before a producer can sell a carrier's product, they have to be contracted for it — approved to sell that product, at agreed commission terms, in specific states. Keeping track of who is contracted for what, and at what rate, is the work this API automates.
Those relationships also form a chain. A producer contracts with an agency, the agency sits below an IMO (Independent Marketing Organization), and the IMO connects to the carrier. Every commission payout, every "ready to sell" check, and every compliance review depends on knowing that chain accurately.
What you can get:
- Producers — the individuals and firms contracted in your organization
- Contracts and contract assignments — who is contracted to sell which product, and the status of each
- Assignment changes — a dated record of every amendment, for reconciliation and audit
- Carriers, products, and commission levels — your contracting catalog and compensation structure
- Your distribution hierarchy — every position, with its upline, commission level, states, and status — see Hierarchy Nodes
- The hierarchy as it looked on any past date — for answering "who was this producer's upline when this commission was earned?"
Common Use Cases
Commissions — determine the upline chain at transaction time by querying the hierarchy with as_of set to the transaction date and walking the upline links. Commission level names and values are inlined on each node, so no second call is needed. Detect changes in real time via hierarchy.producer.changed.
Reconciliation and audit — pull the node list as of a reconciliation date and diff against your local records. Compare two as_of snapshots to identify what changed in a window; there is no date-range filter.
Carriers — synchronize your product catalog so assignments always reflect current offerings, and track amendments over time with updated_since on assignment changes.
Agencies and MGAs — read your account configuration (assigned carriers, products, and commission levels) in three calls, then keep downstream systems current with updated_since polling plus webhook events.
Technology partners — integrate contracting data into agency management systems or producer portals, and build automated compliance checkpoints on assignment status.
How It Works
The customer-facing API is versioned under /v2 and is read-only — every endpoint is a GET. Contracting records are created and maintained in the AgentSync application; your integration consumes them.
Hierarchies are not a separate system layered on top. A hierarchy position is a contract assignment, and the tree is formed by the upline links between assignments. That is why the two share one base URL, one set of credentials, one scope model, and one set of response conventions — and why you need carrier, product, and contract assignment data before hierarchy data means anything.
Responses are purpose-built for integrations:
- Inlined names — reference data appears as an
...Idplus a...Namecompanion (assignmentStatusId/assignmentStatusName), so there are no lookup round trips. - Incremental sync —
updated_since(RFC3339 UTC) returns only records modified at or after that instant. Supported on producers, contracts, contract assignments, assignment changes, assigned carriers, assigned products, and assigned commission levels. - Field conventions — JSON fields are
lowerCamelCase; query parameters arelower_snake_case. Timestamps end inAt(RFC3339 UTC); dates end inOn(yyyy-MM-dd). - Account scoping — a resource that doesn't exist or belongs to another customer returns
404, never403.
Reads require a contracting.* scope; see Authentication for the scope-to-endpoint mapping, Base URLs, and Pagination for the token-pagination contract.
Hierarchy Nodes
GET /v2/organizations/{organizationId}/hierarchies returns your distribution hierarchy as a token-paginated flat list of nodes. Each node is one position, keyed by contractAssignmentId — the same key the hierarchy.producer.* webhook events use, so you can update a stored tree directly from an event.
Four fields carry behavior worth knowing before you build against them:
| Field | Why it matters |
|---|---|
contractAssignmentId | The node's key. Stable across amendments. |
uplineContractAssignmentId | The parent's key, or null for root nodes. This is the edge that forms the tree. |
type, personId, firmId | type is AGENT or FIRM and determines which identifier is populated. Both are Identity API identifiers and resolve directly. |
active | Computed over the tree — a node is inactive when its own status is inactive or any node above it is. |
A producer is a single entity discriminated by type, not two records — an individual is never stored as both a person and a firm. Whichever identifier does not apply is null.
Detecting firms: test
firmIdfor presence, notpersonIdfor null. These fields behave differently across surfaces. On this REST resource aFIRMnode haspersonId: null. In thehierarchy.producer.*webhook events,personIdis always populated, withfirmIdalongside it for firms. Logic branching onpersonId == nullworks against REST, then silently classifies every firm as an individual when pointed at the event stream. CheckingfirmIdfor presence is correct in both.
Reconstructing the tree: identify root nodes (uplineContractAssignmentId == null), group the rest by uplineContractAssignmentId, then attach children to their parent keyed on contractAssignmentId. Fetch every page first — a child can appear on a later page than its parent.
Point-in-time snapshots: pass as_of=yyyy-MM-dd to get the hierarchy as it existed on that date. This is the primary mechanism for commissions reconciliation; omit it for current state, and always supply an explicit as_of when querying for historical purposes.
Not yet available on a node: carrier context, partnership fields, and commission split percentages. If your integration needs these, contact support@agentsync.io so we can factor it into prioritization.
Files and Versioning
Contract packets carry implicit versioning — an initial version and a counter-signed version, surfaced as distinct states.
Files uploaded through the onboarding upload component have no explicit version control. They are versioned at the storage layer, but that history is not exposed: there is no version list and no diff. Webhook events fire when a new file is loaded, so you can detect that a file changed even though you cannot retrieve its history.
Webhook Events
The API publishes events for contract, assignment, assignment-change, packet, producer-status, responsible-party, and hierarchy changes. Hierarchy lifecycle events are pushed alongside the contracting ones:
| Event | When it fires |
|---|---|
hierarchy.producer.added | A producer is newly placed under an upline |
hierarchy.producer.changed | A position changes — upline and/or commission level. Includes a changedFields array. |
hierarchy.producer.relationship.terminated | A hierarchy relationship ends — its assignment enters a terminal status |
See Contracting API Webhook Events for the full catalog with payload schemas, and the Webhooks Quick Start Guide to register an endpoint.
Getting Started
Start here: the Contracting & Hierarchies API Quick Start Guide walks through authentication, reading your account configuration, producers, assignments and hierarchy, reconstructing the tree, point-in-time snapshots, resolving contact details from Identity, and incremental sync — with curl and Python examples throughout.
For every endpoint, request/response schema, and field constraint, see the interactive API Reference.