> ## Documentation Index
> Fetch the complete documentation index at: https://alguna.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# External Sync

> Bidirectional sync with external systems

# External Sync

Alguna's External Sync enables bidirectional synchronization between Alguna and external systems like CRMs, ERPs, and accounting software. Keep your data in sync automatically with conflict detection and resolution.

***

## How It Works

```mermaid theme={null}
sequenceDiagram
    participant Alguna
    participant SyncEngine
    participant External as External System

    Note over SyncEngine: Scheduled/Triggered Sync

    SyncEngine->>Alguna: Fetch changes since last sync
    SyncEngine->>External: Fetch changes since last sync

    Note over SyncEngine: Detect conflicts

    alt No Conflicts
        SyncEngine->>Alguna: Apply external changes
        SyncEngine->>External: Apply Alguna changes
    else Conflicts Detected
        SyncEngine->>SyncEngine: Apply resolution strategy
        SyncEngine->>Alguna: Apply resolved data
        SyncEngine->>External: Apply resolved data
    end

    SyncEngine->>SyncEngine: Update sync state
```

***

## Supported Systems

| System     | Entities                          | Direction     |
| ---------- | --------------------------------- | ------------- |
| Salesforce | Accounts, Contacts, Opportunities | Bidirectional |
| HubSpot    | Companies, Contacts, Deals        | Bidirectional |
| QuickBooks | Customers, Invoices, Payments     | Bidirectional |
| NetSuite   | Customers, Invoices, Payments     | Bidirectional |
| Xero       | Contacts, Invoices, Payments      | Bidirectional |

***

## Configuration

### Enable Sync

```bash theme={null}
curl -X POST https://api.alguna.io/integrations/salesforce/sync-config \
  -H "Authorization: Bearer $ALGUNA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "direction": "bidirectional",
    "entities": ["accounts", "contacts", "subscriptions"],
    "conflictResolution": "alguna_wins",
    "schedule": "*/15 * * * *"
  }'
```

### Sync Direction Options

| Direction            | Description                     |
| -------------------- | ------------------------------- |
| `alguna_to_external` | Push Alguna changes to external |
| `external_to_alguna` | Pull external changes to Alguna |
| `bidirectional`      | Sync both ways                  |

***

## Field Mapping

Map fields between systems:

```javascript theme={null}
await alguna.syncConfig.setFieldMappings({
  integrationId: 'int_salesforce',
  entity: 'accounts',
  mappings: [
    {
      algunaField: 'name',
      externalField: 'Name',
      direction: 'bidirectional',
    },
    {
      algunaField: 'email',
      externalField: 'Email__c',
      direction: 'bidirectional',
    },
    {
      algunaField: 'billingAddress.line1',
      externalField: 'BillingStreet',
      direction: 'alguna_to_external',
    },
    {
      algunaField: 'mrr',
      externalField: 'MRR__c',
      direction: 'alguna_to_external',
      transform: 'number_to_currency',
    },
  ],
});
```

### Transform Functions

| Transform            | Description                    |
| -------------------- | ------------------------------ |
| `none`               | Pass through as-is             |
| `number_to_currency` | Format as currency             |
| `date_to_iso`        | Convert to ISO format          |
| `boolean_to_string`  | Convert true/false to Yes/No   |
| `custom`             | Use custom JavaScript function |

***

## Conflict Resolution

When the same record is modified in both systems:

### Resolution Strategies

| Strategy        | Description                    |
| --------------- | ------------------------------ |
| `alguna_wins`   | Alguna data takes precedence   |
| `external_wins` | External data takes precedence |
| `latest_wins`   | Most recent modification wins  |
| `manual`        | Flag for manual review         |

### Per-Field Resolution

```javascript theme={null}
await alguna.syncConfig.setConflictResolution({
  integrationId: 'int_salesforce',
  entity: 'accounts',
  default: 'latest_wins',
  perField: {
    'name': 'external_wins', // CRM is source of truth for names
    'email': 'manual', // Review email conflicts
    'mrr': 'alguna_wins', // Billing is source of truth for MRR
  },
});
```

***

## Sync Triggers

### Scheduled Sync

Run sync on a schedule:

```json theme={null}
{
  "schedule": "*/15 * * * *",
  "description": "Every 15 minutes"
}
```

### Real-Time Sync

Trigger sync on changes:

```json theme={null}
{
  "triggers": {
    "onAlgunaChange": true,
    "onWebhook": true,
    "webhookUrl": "https://api.alguna.io/integrations/sync/trigger"
  }
}
```

### Manual Sync

```bash theme={null}
curl -X POST https://api.alguna.io/integrations/salesforce/sync/trigger \
  -H "Authorization: Bearer $ALGUNA_API_KEY" \
  -d '{
    "entities": ["accounts"],
    "fullSync": false
  }'
```

***

## Sync Status

### Check Sync State

```bash theme={null}
curl https://api.alguna.io/integrations/salesforce/sync/status \
  -H "Authorization: Bearer $ALGUNA_API_KEY"
```

**Response:**

```json theme={null}
{
  "integrationId": "int_salesforce",
  "lastSync": "2024-01-20T10:15:00Z",
  "status": "healthy",
  "stats": {
    "accounts": {
      "synced": 1250,
      "created": 5,
      "updated": 23,
      "conflicts": 2,
      "errors": 0
    },
    "contacts": {
      "synced": 3400,
      "created": 12,
      "updated": 45,
      "conflicts": 0,
      "errors": 1
    }
  },
  "nextScheduledSync": "2024-01-20T10:30:00Z"
}
```

### View Sync History

```bash theme={null}
curl https://api.alguna.io/integrations/salesforce/sync/history \
  -H "Authorization: Bearer $ALGUNA_API_KEY" \
  -d '{"limit": 10}'
```

***

## Handling Errors

### Error Types

| Error              | Description                          | Resolution            |
| ------------------ | ------------------------------------ | --------------------- |
| `field_validation` | External system rejected field value | Check field mapping   |
| `rate_limit`       | External API rate limited            | Automatic retry       |
| `auth_expired`     | Authentication expired               | Reconnect integration |
| `not_found`        | Record doesn't exist                 | Skip or create        |

### Error Webhooks

```javascript theme={null}
app.post('/webhooks/alguna', (req, res) => {
  const event = req.body;

  if (event.type === 'sync.error') {
    console.error('Sync error:', event.data);
    // Alert team, create ticket, etc.
  }

  res.sendStatus(200);
});
```

### Retry Failed Syncs

```bash theme={null}
curl -X POST https://api.alguna.io/integrations/salesforce/sync/retry \
  -H "Authorization: Bearer $ALGUNA_API_KEY" \
  -d '{
    "recordIds": ["acc_123", "acc_456"]
  }'
```

***

## Entity Matching

### By External ID

Link records using external IDs:

```javascript theme={null}
await alguna.accounts.create({
  name: 'Acme Corp',
  externalId: 'salesforce:001ABC123', // Salesforce Account ID
});
```

### By Email/Name

Configure matching rules:

```json theme={null}
{
  "matching": {
    "accounts": {
      "fields": ["email", "name"],
      "strategy": "exact", // or "fuzzy"
      "createIfNotFound": true
    }
  }
}
```

***

## Salesforce Example

### Complete Setup

```javascript theme={null}
// 1. Connect Salesforce
const integration = await alguna.integrations.connect({
  provider: 'salesforce',
  credentials: {
    // OAuth flow handles this
  },
});

// 2. Configure sync
await alguna.syncConfig.create({
  integrationId: integration.id,
  entities: {
    accounts: {
      enabled: true,
      externalObject: 'Account',
      direction: 'bidirectional',
      mappings: [
        { alguna: 'name', external: 'Name' },
        { alguna: 'email', external: 'Email__c' },
        { alguna: 'mrr', external: 'MRR__c' },
      ],
    },
    subscriptions: {
      enabled: true,
      externalObject: 'Opportunity',
      direction: 'alguna_to_external',
      mappings: [
        { alguna: 'planId', external: 'Product__c' },
        { alguna: 'status', external: 'Stage' },
        { alguna: 'currentVersion.mrr', external: 'Amount' },
      ],
    },
  },
  schedule: '*/15 * * * *',
});

// 3. Run initial sync
await alguna.integrations.sync.trigger(integration.id, {
  fullSync: true,
});
```

***

## Best Practices

<CardGroup cols={2}>
  <Card title="Start One-Way" icon="arrow-right">
    Begin with one-way sync, then enable bidirectional once stable.
  </Card>

  <Card title="Monitor Conflicts" icon="triangle-exclamation">
    Review conflicts regularly to tune resolution strategies.
  </Card>

  <Card title="Test in Sandbox" icon="flask">
    Test sync configuration in sandbox environments first.
  </Card>

  <Card title="Map Carefully" icon="map">
    Document field mappings and transformation logic.
  </Card>
</CardGroup>

***

## Webhooks

| Event            | Description                              |
| ---------------- | ---------------------------------------- |
| `sync.completed` | Sync job finished                        |
| `sync.error`     | Sync encountered errors                  |
| `sync.conflict`  | Conflict detected (if manual resolution) |

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Salesforce" icon="cloud" href="/integrations/crm/salesforce">
    Salesforce integration setup.
  </Card>

  <Card title="HubSpot" icon="hubspot" href="/integrations/crm/hubspot">
    HubSpot integration setup.
  </Card>
</CardGroup>
