Entity Mapping
Create mappings between Kruncher entities (person, company, opportunity) and external provider IDs. This enables bidirectional synchronization with CRM systems like Affinity, Attio, Pipedrive, and other third-party platforms.
Endpoint
POST https://api.kruncher.ai/api/integration/map
Headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Your API key (format: YOUR_API_KEY) |
Content-Type | Yes | Must be application/json |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
entityType | string | Yes | Type of entity: person, company, or opportunity |
provider | string | Yes | External provider name (e.g., affinity, attio, pipedrive, zapier) |
externalId | string | Yes | ID used by the external provider for this entity |
kruncherId | string | Yes | ID used internally by Kruncher for this entity |
Entity Types
| Type | Description | Example Use Case |
|---|---|---|
person | Individual contacts, founders, investors | Sync contact information with CRM |
company | Organizations, startups, portfolio companies | Link company records across systems |
opportunity | Investment opportunities, deals, projects | Track deals in multiple platforms |
Supported Providers
| Provider | Platform | Integration Type |
|---|---|---|
affinity | Affinity CRM | Relationship intelligence platform |
attio | Attio | Modern CRM for startups |
pipedrive | Pipedrive | Sales CRM and pipeline management |
zapier | Zapier | Automation platform |
custom | Custom Integration | Your own system |
Note: Contact support to enable additional provider integrations.
Use Cases
When to Create Mappings
- CRM Sync: Link Kruncher companies to CRM records
- Bidirectional Updates: Keep data in sync across platforms
- External References: Maintain links to external systems
- Data Migration: Map existing records during migration
- Automation: Enable Zapier or custom integrations
- Multi-System Workflow: Connect multiple tools together
Code Examples
JavaScript/TypeScript
Basic
const API_KEY = "YOUR_API_KEY_HERE";
const response = await fetch("https://api.kruncher.ai/api/integration/map", {
method: "POST",
headers: {
"Authorization": `${API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
entityType: "company",
provider: "affinity",
externalId: "affinity_12345",
kruncherId: "kruncher_67890"
})
});
const result = await response.json();
console.log("Mapping created:", result);Result: Creates a mapping between Kruncher company and Affinity organization.
Python
Basic
import requests
API_KEY = "YOUR_API_KEY_HERE"
url = "https://api.kruncher.ai/api/integration/map"
headers = {
"Authorization": f"{API_KEY}",
"Content-Type": "application/json"
}
data = {
"entityType": "company",
"provider": "affinity",
"externalId": "affinity_12345",
"kruncherId": "kruncher_67890"
}
response = requests.post(url, headers=headers, json=data)
if response.status_code == 200:
print("Mapping created:", response.json())
else:
print(f"Error: {response.status_code} {response.text}")Result: Creates a single entity mapping.
cURL
Company
curl -X POST "https://api.kruncher.ai/api/integration/map" \
-H "Authorization: YOUR_API_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"entityType": "company",
"provider": "affinity",
"externalId": "affinity_12345",
"kruncherId": "proj_abc123"
}'Response
Success Response (200 OK)
{
"code": "1000",
"title": "Success",
"description": "Mapping created successfully",
"data": {
"entityType": "company",
"provider": "affinity",
"externalId": "affinity_12345",
"kruncherId": "proj_abc123",
"createdAt": "2024-01-15T10:30:00Z"
}
}Error Responses
400 Bad Request
{
"code": "4000",
"title": "Bad Request",
"description": "Invalid entity type or missing required fields"
}409 Conflict
{
"code": "4090",
"title": "Conflict",
"description": "Mapping already exists for this entity"
}Common Workflows
Workflow 1: Sync Kruncher with Affinity
// Fetch companies from both systems
const kruncherCompanies = await getKruncherCompanies();
const affinityOrgs = await getAffinityOrganizations();
// Match by name or other criteria
const matched = matchCompanies(kruncherCompanies, affinityOrgs);
// Create mappings
const manager = new KruncherMappingManager(API_KEY);
const results = await manager.syncWithAffinity(
matched.kruncher,
matched.affinity
);
console.log(`Mapped ${results.successful.length} companies`);Workflow 2: Bidirectional Sync
# Create mapping
manager = KruncherMappingManager()
manager.map_company("proj_123", "affinity", "affinity_org_456")
# Now updates can flow both ways:
# - Update in Kruncher → sync to Affinity using external ID
# - Update in Affinity → sync to Kruncher using kruncher ID
# Get external ID for syncing
external_id = manager.get_cached_external_id("company", "affinity", "proj_123")
update_affinity(external_id, data)Workflow 3: Migration Mapping
# Map all existing records during migration
import csv
manager = KruncherMappingManager()
mappings = []
with open('migration_mapping.csv') as f:
reader = csv.DictReader(f)
for row in reader:
mappings.append({
"entityType": row['entity_type'],
"provider": row['provider'],
"externalId": row['external_id'],
"kruncherId": row['kruncher_id']
})
# Process in batches
results = manager.bulk_map(mappings, batch_size=50, delay_seconds=0.5)
stats = manager.get_mapping_stats(results)
print(f"Migration complete: {stats['success_rate']}")
if stats['failed_mappings']:
print(f"Failed mappings: {len(stats['failed_mappings'])}")
for failed in stats['failed_mappings']:
print(f" - {failed['kruncher_id']}: {failed['error']}")Integration Examples
Affinity CRM Sync
async function syncAffinityCompanies() {
const manager = new KruncherMappingManager(API_KEY);
// Get companies from Kruncher
const kruncherResponse = await fetch(
`${BASE_URL}/integration/projects`,
{ headers: { "Authorization": `${API_KEY}` } }
);
const kruncherData = await kruncherResponse.json();
// Get organizations from Affinity (using their API)
const affinityOrgs = await fetchAffinityOrganizations();
// Match by company name
const mappings = [];
for (const company of kruncherData.data) {
const affinityOrg = affinityOrgs.find(
org => org.name.toLowerCase() === company.companyName.toLowerCase()
);
if (affinityOrg) {
mappings.push({
entityType: "company",
provider: "affinity",
externalId: affinityOrg.id.toString(),
kruncherId: company.id
});
}
}
const results = await manager.bulkMap(mappings);
return results;
}Attio Integration
def sync_attio_contacts():
"""Sync Kruncher people with Attio contacts."""
manager = KruncherMappingManager()
# Get people from both systems
kruncher_people = get_kruncher_people()
attio_contacts = get_attio_contacts()
# Match by email
mappings = []
for person in kruncher_people:
attio_contact = next(
(c for c in attio_contacts if c['email'] == person['email']),
None
)
if attio_contact:
mappings.append({
"entityType": "person",
"provider": "attio",
"externalId": attio_contact['id'],
"kruncherId": person['id']
})
results = manager.bulk_map(mappings)
return resultsBest Practices
Matching Strategy
- Use unique identifiers (email, website, name + domain)
- Validate matches before creating mappings
- Log unmatched entities for manual review
- Consider fuzzy matching for name variations
Error Handling
- Check for existing mappings before creating
- Handle 409 Conflict errors gracefully
- Retry failed mappings with exponential backoff
- Log all mapping operations for audit
Performance
- Batch mappings to reduce API calls
- Use parallel processing for large datasets
- Add delays between batches to avoid rate limits
- Cache mappings locally
Data Integrity
- Verify entity exists in both systems
- Validate external IDs format
- Keep mapping records for rollback
- Monitor sync success rates
Related Endpoints
- Create Company - Create Kruncher entities to map
- Find Companies - Get Kruncher IDs for mapping
- Configuration - Get provider list
- Integrations - Provider-specific documentation
Troubleshooting
”Mapping already exists”
- Check if mapping was created previously
- Delete old mapping if updating
- Use different external ID if needed
Invalid Entity Type
- Use exactly:
person,company, oropportunity - Check for typos or capitalization
Provider Not Supported
- Verify provider name spelling
- Contact support to enable provider
- Use
customfor custom integrations
IDs Not Matching
- Verify entity exists in both systems
- Check ID format (string vs number)
- Ensure IDs are from correct environment (staging vs production)
Need Help?
- New provider? Contact support to enable integrations
- Bulk migration? Ask about assisted migration services
- Custom mapping? Discuss custom provider integration
- Sync issues? Check provider-specific integration docs
Last updated on