This guide helps you import, update and keep in sync your customer and organization data from HubSpot to Atlassian Customer Service Management (CSM). Using our bulk APIs, you can migrate customer information, contact details, and organizational data efficiently. This guide covers the integration patterns and best practices.
Atlassian CSM provides powerful bulk APIs that allow you to migrate all your customer data from HubSpot:
The bulk APIs are designed for scalability and include built-in idempotency to safely retry operations without accidentally duplicating data. This makes it easy to move your entire customer database from HubSpot to CSM.
HubSpot and Atlassian Customer Service Management use different terminology for similar concepts. Understanding these mappings is essential for successful integration:
| HubSpot Concept | CSM Equivalent | Description |
|---|---|---|
| Contact | Customer | Individual customer records in the system |
| Company | Organization | Groups of customers sharing a common entity |
| Contact Properties | Customer Detail Fields | Custom attributes and metadata associated with customers |
As an example, to import your HubSpot contacts into CSM, you'll use the create customer profile API, which allows you to map HubSpot contact properties to CSM detail fields while automatically creating the customer records. The bulk API supports up to 50 customer profiles per request, making it possible to migrate large contact lists in bulk from HubSpot to CSM.
Customers are usually the end-users or clients who submit requests or tickets. These are managed in the system as users who can create and track their requests via the customer portal. These are Contacts in HubSpot.
Organizations are used to group customers. This allows you to manage and organize customers into logical groups, often corresponding to the company or organization they belong to. You can set up organizations so that multiple users (customers) can belong to the same organization, and they can share and view each other's requests if permissions allow. These are Companies in HubSpot.
Customer details might include user information available in the user management section, such as name, email, and organization membership. Interaction history is tracked through the tickets or requests submitted by the customer. Additional details may require integration with other tools or custom fields to track specific information. These are contact properties in HubSpot.
Before you can use the CSM bulk APIs, ensure you have:
Different APIs use different fields to identify customers:
| API | Required Field | Optional Field |
|---|---|---|
| Bulk manage customer accounts | email (for create) | customerId |
| Bulk manage customer profiles | email or customerId | Either can be used |
| Update detail fields | email or customerId | Either can be used |
Best Practice: Always provide email for new customer creation, even in UPSERT operations. Providing only customerId won't create new customers if they don't exist.
This pattern imports HubSpot contacts to CSM as customer profiles with their associated organizations.
HubSpot defines customers as "contacts" and stores their information in "columns". In Atlassian Customer Service Management (CSM), these concepts are called "customers" and "detail fields" respectively. To migrate this data from HubSpot to CSM, use the POST /api/v1/customer/profile/bulk API endpoint. Format your HubSpot contacts data according to the CSM customer profile structure shown in the implementation example below.
1 2curl -X POST https://api.atlassian.com/api/v1/customer/profile/bulk \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "X-ExperimentalApi: opt-in" \ -H "Content-Type: application/json" \ -d '{ "customers": [ { "operationType": "CREATE", "payload": { "email": "john.doe@example.com", "displayName": "John Doe", "details": [ {"name": "Phone", "values": ["+1-555-0123"]}, {"name": "Company", "values": ["Acme Corporation"]} ], "associateOrganizations": [1, 4] } }, { "operationType": "CREATE", "payload": { "email": "jane.smith@example.com", "displayName": "Jane Smith", "details": [ {"name": "Phone", "values": ["+1-555-0124"]}, {"name": "Company", "values": ["Tech Innovators"]} ], "associateOrganizations": [2] } } ] }'
1 2{ "taskId": "2bfad33c-beec-4577-97ca-f07bc337c554", "statusUrl": "https://api.atlassian.com/api/v1/tasks/2bfad33c-beec-4577-97ca-f07bc337c554" }
1 2curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ https://api.atlassian.com/api/v1/tasks/2bfad33c-beec-4577-97ca-f07bc337c554
Response while processing:
1 2{ "taskId": "2bfad33c-beec-4577-97ca-f07bc337c554", "status": "PROCESSING", "createdDate": "2026-01-15T10:00:00Z" }
Response when complete:
1 2{ "taskId": "2bfad33c-beec-4577-97ca-f07bc337c554", "status": "COMPLETED", "createdDate": "2026-01-15T10:00:00Z", "completedDate": "2026-01-15T10:01:23Z", "failures": [ { "index": 1, "message": "Customer with email 'invalid@' is not valid" } ] }
Import organizations to CSM that correspond to HubSpot companies.
HubSpot stores company-level information in "companies" with properties stored in dedicated fields. In Atlassian CSM, these are called "organizations" and can have their own custom detail fields just like customers. To import your HubSpot companies to CSM organizations, use the POST /api/v1/organization/profile/bulk API endpoint. This allows you to batch create and update company records with their associated properties mapped as organization detail fields.
1 2curl -X POST https://api.atlassian.com/api/v1/organization/profile/bulk \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "X-ExperimentalApi: opt-in" \ -H "Content-Type: application/json" \ -d '{ "organizations": [ { "operationType": "CREATE", "payload": { "name": "Acme Corporation", "details": [ {"name": "Industry", "values": ["Manufacturing"]}, {"name": "Website", "values": ["https://acme.example.com"]}, {"name": "Employee Count", "values": ["500"]} ] } }, { "operationType": "CREATE", "payload": { "name": "Tech Innovators", "details": [ {"name": "Industry", "values": ["Software"]}, {"name": "Website", "values": ["https://techinnovators.example.com"]}, {"name": "Employee Count", "values": ["150"]} ] } } ] }'
Import specific detail field values for customers from HubSpot to CSM.
HubSpot allows you to store custom properties on contacts, such as "support tier", "health score", or "renewal date". In CSM, these custom properties are called "detail fields". To import these specific field values from HubSpot to CSM for existing customers, use the POST /api/v1/customer/details/bulk API endpoint. This is particularly useful when you need to update specific fields across many customers without re-importing entire customer profiles.
1 2curl -X POST https://api.atlassian.com/api/v1/customer/details/bulk \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "X-ExperimentalApi: opt-in" \ -H "Content-Type: application/json" \ -d '{ "customers": [ { "customerId": "customer-123", "operations": [ { "operationType": "UPDATE", "payload": { "name": "Support Tier", "values": ["Premium"] } }, { "operationType": "UPDATE", "payload": { "name": "Health Score", "values": ["95"] } } ] }, { "customerId": "customer-456", "operations": [ { "operationType": "UPDATE", "payload": { "name": "Support Tier", "values": ["Standard"] } }, { "operationType": "UPDATE", "payload": { "name": "Health Score", "values": ["78"] } } ] } ] }'
Create multiple customer accounts in bulk when importing a large set of contacts from HubSpot.
When you need to create a large number of basic customer accounts in CSM (without detailed profile information initially), you can use the streamlined account creation approach. HubSpot contacts can be quickly imported as CSM customers using just their email and display name. To batch create multiple customer accounts, use the POST /api/v1/customer/bulk API endpoint. This is ideal for initial bulk imports or when you want to create customer accounts first and populate detail fields later through Pattern 3.
1 2curl -X POST https://api.atlassian.com/api/v1/customer/bulk \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "X-ExperimentalApi: opt-in" \ -H "Content-Type: application/json" \ -d '{ "customers": [ { "email": "alice.johnson@example.com", "displayName": "Alice Johnson" }, { "email": "bob.wilson@example.com", "displayName": "Bob Wilson" }, { "email": "carol.brown@example.com" } ] }'
Note: You can create up to 50 customer accounts in a single request with this endpoint. If no displayName is provided, the email will be used as the display name.
Cause: Email field contains invalid characters or format.
Solution: Validate emails in HubSpot before syncing. Use a regex pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/
Cause: Attempting to update a customer that doesn't exist.
Solution:
Cause: Reusing an idempotency key with a different request payload.
Solution: Generate a new UUID for each request. Only reuse keys if you need to retry the exact same request.
Cause: Too many requests in a short time.
Solution:
Log all bulk API interactions for debugging:
1 2const migrationLog = { timestamp: new Date(), hubspotRecordCount: customers.length, taskId: result.taskId, idempotencyKey: idempotencyKey, statusUrl: result.statusUrl }; // After polling completes migrationLog.finalStatus = taskStatus.status; migrationLog.failureCount = taskStatus.failures?.length || 0; migrationLog.completedDate = taskStatus.completedDate; console.log('Migration batch complete:', migrationLog);
Before importing, deduplicate records from HubSpot:
1 2const uniqueContacts = {}; hubspotContacts.forEach(contact => { if (!uniqueContacts[contact.properties.email]) { uniqueContacts[contact.properties.email] = contact; } }); const deduplicatedContacts = Object.values(uniqueContacts);
Import records in phases to reduce risk and verify data quality:
1 2// Phase 1: Migrate test batch first const testBatch = await getHubSpotContacts(limit: 100); await importToCSM(testBatch); // Verify data quality and mappings await verifyImportResults(); // Phase 2: Migrate remaining contacts const remainingContacts = await getHubSpotContacts(offset: 100); await importToCSM(remainingContacts);
Implement a dead-letter queue for failed records:
1 2const failures = taskStatus.failures || []; if (failures.length > 0) { // Log failures for manual review failures.forEach(failure => { deadLetterQueue.push({ recordIndex: failure.index, error: failure.message, timestamp: new Date() }); }); // Alert team if failure rate exceeds threshold if (failures.length / totalRecords > 0.05) { sendAlert('High failure rate in CSM migration'); } }
Document your HubSpot to CSM field mapping clearly:
| HubSpot Property | CSM Detail Field | Type | Required |
|---|---|---|---|
email | Used for identification | ✓ | |
firstname/lastname | displayName | Text | ✗ |
hs_lead_status | support-tier | Dropdown | ✗ |
lifecyclestage | lifecycle | Text | ✗ |
company | Organization name | Text | ✗ |
Perform a complete import of all customers from HubSpot to CSM:
Import only customers that meet certain criteria:
1 2const eligibleContacts = hubspotContacts.filter(contact => { return contact.properties.hs_lead_status === 'Qualified' && contact.properties.lifecyclestage === 'customer'; });
Maintain data integrity during import across multiple operations:
1 2// 1. Migrate organizations first await migrateOrganizations(companies); // 2. Wait for organization import to complete await waitForTaskCompletion(orgTaskId); // 3. Then import customer profiles with organization associations await migrateCustomerProfiles(contacts); // 4. Verify all import succeeded before decommissioning HubSpot await verifyAllRecordsImported();
Q: How long will the job take?
A: This depends on your data volume. A single request should take at most a few minutes.
Start with a test batch to estimate timing.
Q: Can I perform the migration gradually?
A: Yes! You can import in phases:
This reduces risk and allows you to validate data quality at each step.
Q: What if a job fails mid-way?
A: The bulk API processes records independently. If 10 out of 100 records fail, 90 succeed. Check the task status to see which records failed and retry only those records.
Q: Is there a limit on how much data I can import?
A: Yes, there are per-request limits:
For large-scale imports (millions of records), split into batches.
Q: How do I test my import before production?
A: Use a CSM sandbox environment:
Q: How do I verify all my data was created correctly?
A: Compare record counts and sample data:
SELECT COUNT(*) FROM contactsNeed help? Contact Atlassian Support with:
Rate this page: