Skip to Content
Docs are evolving — expect frequent updates.
ConfigMappingEntity Mapping

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

HeaderRequiredDescription
AuthorizationYesYour API key (format: YOUR_API_KEY)
Content-TypeYesMust be application/json

Request Body

FieldTypeRequiredDescription
entityTypestringYesType of entity: person, company, or opportunity
providerstringYesExternal provider name (e.g., affinity, attio, pipedrive, zapier)
externalIdstringYesID used by the external provider for this entity
kruncherIdstringYesID used internally by Kruncher for this entity

Entity Types

TypeDescriptionExample Use Case
personIndividual contacts, founders, investorsSync contact information with CRM
companyOrganizations, startups, portfolio companiesLink company records across systems
opportunityInvestment opportunities, deals, projectsTrack deals in multiple platforms

Supported Providers

ProviderPlatformIntegration Type
affinityAffinity CRMRelationship intelligence platform
attioAttioModern CRM for startups
pipedrivePipedriveSales CRM and pipeline management
zapierZapierAutomation platform
customCustom IntegrationYour 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

CODE
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

CODE
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

CODE
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
{
  "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
{
  "code": "4000",
  "title": "Bad Request",
  "description": "Invalid entity type or missing required fields"
}

409 Conflict

CODE
{
  "code": "4090",
  "title": "Conflict",
  "description": "Mapping already exists for this entity"
}

Common Workflows

Workflow 1: Sync Kruncher with Affinity

CODE
// 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

CODE
# 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

CODE
# 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

CODE
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

CODE
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 results

Best 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

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, or opportunity
  • Check for typos or capitalization

Provider Not Supported

  • Verify provider name spelling
  • Contact support to enable provider
  • Use custom for 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