Separate the four concepts
| Concept | Example | Why it matters | |---|---|---| | Source object | Contact | Determines route and direction | | Target object | Company | Determines route and permission | | Record ID | 123 | Selects the records | | Association type | Numeric or labeled definition | Describes the relationship |
Two valid records can still fail when the association type is not valid for that object pair.
Confirm records first
Fetch the contact and company independently. Confirm that both exist in the same HubSpot account and that the token can access them. Do not debug association metadata while one ID is a spreadsheet row number or an ID from another environment.
Keep source-system IDs separate from HubSpot IDs. A mapping table should contain source system, source ID, object type, HubSpot ID, account context, and last verification.
Request shape
Follow the current CRM associations documentation for the endpoint version you use. A conceptual request includes the target ID and a types array:
Treat the numbers as examples only. Load the correct definition before production.
{
"inputs": [
{
"from": { "id": "CONTACT_ID" },
"to": { "id": "COMPANY_ID" },
"types": [
{
"associationCategory": "HUBSPOT_DEFINED",
"associationTypeId": 1
}
]
}
]
}
Common causes of failure
The source and target are reversed, the type belongs to a different object pair, the ID is inactive, the app lacks the required scope, the record is archived, or the request uses a legacy endpoint. A 400 can indicate a malformed association body; a 403 can indicate access; a 404 can indicate a record or route problem.
Classify the response and log object pair, account alias, type metadata version, and status. Do not log tokens or full contact details.
Duplicate associations
Before creating an association repeatedly, read existing relationships or use an idempotent batch design. A retry after a timeout may have succeeded. Decide whether duplicate relationship requests are harmless or should be deduplicated before replay.
When a relationship label changes, decide whether to update the existing association, create a second labeled relationship, or send it to review. These are business decisions, not merely API mechanics.
Test a real business path
Create or select a test contact and company. Associate them with the intended type. Fetch both records and verify the relationship from the read endpoint. Test removing the association, using a second type, and handling a missing record. Repeat in staging and production because definitions can differ.
Include one case where the token has object read access but not write access. The error should produce a useful operational message.
Monitor relationship quality
Track association creation success, 400/403/404 rates, duplicates, unknown type IDs, and records with no expected company relationship. A successful API response does not prove the relationship is the one your reporting model expects.
Run a reconciliation job for important relationships. It should compare the source mapping with HubSpot state and produce a review report rather than deleting relationships automatically.
The trap: copying a popular association type ID without checking the account and object pair. The number is not a universal meaning.
Avoid relationship drift
Define the source system’s relationship rules before writing the adapter. Decide whether one contact may belong to several companies, whether one company can have several labeled relationships, and what a source deletion means. The API can execute a relationship request successfully while the resulting graph is still wrong for your business.
For imports, preview relationship creates, updates, removals, and ambiguous rows. Require approval when a source company name matches several HubSpot records. After execution, reconcile a sample and then the complete set of important relationships. Keep source IDs so a failed association can be retried without searching by a person’s name.
Use account-scoped metadata caches and refresh them after a 400 that indicates an invalid type. Do not turn an unknown type into the default relationship automatically. When labels are changed, record the old and new definition and decide whether historical relationships need migration.
Monitor missing expected relationships and sudden spikes in new relationship count. These signals often reveal a reversed source/target mapping or a connector that is emitting duplicate events.
Review the alert with both the CRM owner and integration owner. Review relationship alerts with both the CRM owner and integration owner.
Keep the source relationship ID so the team can investigate a single edge without exporting the entire CRM graph.
This also makes replay safer.
Prove the relationship, not just the response
For a test association, record the source object, target object, type category, type ID, and both record IDs. After the write, fetch the relationship from the target side as well as the source side. This catches reversed direction and an apparently successful default relationship that does not match the business label. Keep one fixture for an unlabeled association and one for a labeled association when the portal uses both.
Where these facts come from