> For the complete documentation index, see [llms.txt](https://integrate.lexamica.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://integrate.lexamica.com/example-integrations/5b.-import-existing-polling.md).

# Import Existing Cases with Polling

Import cases you're already tracking and poll for status updates.

***

## 🎯 Overview

> **📌 TL;DR**
>
> Import existing cases with known handler firms into Lexamica, then poll for status updates and settlements. Same functionality as webhooks, but you pull updates on your schedule.

**This guide is for you if:**

* You have existing referral relationships to track in Lexamica
* You already know which firm is handling each case
* You can't receive webhooks or prefer batch processing

For real-time webhooks instead, see [Import Existing Cases with Webhooks](/example-integrations/5a.-import-existing-webhook.md)

***

## 📖 Key Terms

| Term                | Definition                                          |
| ------------------- | --------------------------------------------------- |
| **Existing Case**   | A case already being handled, imported for tracking |
| **Partner Firm ID** | The Lexamica ID of the firm handling the case       |
| **Stored Event**    | An event record stored for polling retrieval        |

***

## ⚙️ Architecture

```
Import Existing Cases (Polling)
───────────────────────────────

          IMPORT                                POLL FOR UPDATES
          
┌─────────────────┐                     ┌─────────────────┐
│   Your System   │                     │   Your System   │
│                 │                     │                 │
│ Import existing │                     │ Every N min:    │
│ case with known │                     │ GET /stored-    │
│ handler firm    │                     │ events          │
└────────┬────────┘                     └────────┬────────┘
         │                                       │
         │ POST /create-existing                 │ Poll
         ▼                                       ▼
┌─────────────────────────────────────────────────────────┐
│                   LEXAMICA                              │
│                                                         │
│  Case Created ───▶ Linked to Partner ───▶ Events Stored│
│  (No Relay)           Firm                              │
│                                                         │
│  Stored: Case Update Made, Case Settlement,            │
│          Case Stage Changed                            │
└─────────────────────────────────────────────────────────┘
```

***

## 📋 Prerequisites

**Credentials:**

* [ ] Organization ID, Public Key, and Private Key from Lexamica
* [ ] Partner Firm IDs for the firms handling your cases

**Infrastructure:**

* [ ] Ability to run scheduled polling jobs (cron, Task Scheduler, etc.)

**Foundational Docs:**

* [ ] [Organizations and Authentication](/1.-organizations-and-authentication.md) — understand your API keys
* [ ] [Mapping Engine](/2.-mapping-engine.md) — how field transformations work
* [ ] [Inbound Webhooks](/3.-inbound-webhooks.md) — sending data to Lexamica
* [ ] [Event Storage and Polling](/5.-event-storage-polling.md) — polling for events from Lexamica

***

## 💡 Step-by-Step Implementation

### Step 1: Create Your Case Mapping

Same mapping as the webhook version:

```bash
curl -X POST \
  "https://integration.lexamica.com/organization/{orgId}/mapping/create" \
  -H "Authorization: Bearer your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Existing Case Import Mapping",
    "modelName": "Case",
    "fieldMappings": [
      { "lexamicaField": "_id", "foreignField": "lexamica_case_id", "lexamicaFieldType": "String", "foreignFieldType": "String" },
      { "lexamicaField": "client.firstName", "foreignField": "client_first_name", "lexamicaFieldType": "String", "foreignFieldType": "String" },
      { "lexamicaField": "client.lastName", "foreignField": "client_last_name", "lexamicaFieldType": "String", "foreignFieldType": "String" },
      { "lexamicaField": "caseType", "foreignField": "practice_area", "lexamicaFieldType": "String", "foreignFieldType": "String" },
      { "lexamicaField": "customFields.original_case_id", "foreignField": "original_id", "lexamicaFieldType": "String", "foreignFieldType": "String" }
    ]
  }'
```

### Step 2: Create Stored Event Subscriptions

```bash
# Status updates
curl -X POST \
  "https://integration.lexamica.com/organization/{orgId}/stored-event-subscriptions/create" \
  -H "Authorization: Bearer your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "Case Update Made",
    "mapping": "your_case_update_mapping_id",
    "description": "Store status updates for polling",
    "active": true
  }'

# Stage changes
curl -X POST \
  "https://integration.lexamica.com/organization/{orgId}/stored-event-subscriptions/create" \
  -H "Authorization: Bearer your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "Case Stage Changed",
    "mapping": "your_case_mapping_id",
    "description": "Store stage changes for polling",
    "active": true
  }'

# Settlements
curl -X POST \
  "https://integration.lexamica.com/organization/{orgId}/stored-event-subscriptions/create" \
  -H "Authorization: Bearer your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "Case Settlement",
    "mapping": "your_case_mapping_id",
    "description": "Store settlements for polling",
    "active": true
  }'
```

### Step 3: Import Cases

Same endpoint as the webhook version:

> **💡 Why this matters:** Lexamica doesn't dedupe on this endpoint. Re-running an import job — a scheduled batch, a retry after a partial failure — can easily call `create-existing` again for a record you already imported, and Lexamica has no way to know the two calls represent the same case: it will create two. Check your own case-mapping store for this `original_id` before calling create-existing; if a mapping already exists, the case is already in Lexamica — return it instead of importing again. See `importExistingCase` in the Complete Code Example below.

```bash
curl -X POST \
  "https://integration.lexamica.com/organization/{orgId}/inbound-webhooks/case/{mapId}/create-existing?Key=your_public_key" \
  -H "Content-Type: application/json" \
  -d '{
    "client_first_name": "Jane",
    "client_last_name": "Smith",
    "practice_area": "Personal Injury",
    "incident_date": "2025-06-15",
    "incident_state": "CA",
    "description": "Motor vehicle accident - existing case.",
    "original_id": "CASE-2025-001",
    "partnerFirmId": "64f1a2b3c4d5e6f7a8b9c0f1"
  }'
```

### Step 4: Poll for Updates

Query stored events to get updates and settlements.

***

## 🔧 Complete Code Example

```javascript
const axios = require('axios');

const config = {
  orgId: process.env.LEXAMICA_ORG_ID,
  publicKey: process.env.LEXAMICA_PUBLIC_KEY,
  privateKey: process.env.LEXAMICA_PRIVATE_KEY,
  mappingId: process.env.LEXAMICA_CASE_MAPPING_ID,
  baseUrl: 'https://integration.lexamica.com'
};

// ============================================
// IMPORT CASES
// ============================================

async function importExistingCase(caseData, partnerFirmId) {
  const existing = await findCaseMappingByOriginalId(caseData.original_id);
  if (existing) {
    // Already imported — return the existing mapping instead of creating
    // a duplicate case.
    return existing;
  }

  const response = await axios.post(
    `${config.baseUrl}/organization/${config.orgId}/inbound-webhooks/case/${config.mappingId}/create-existing`,
    { ...caseData, partnerFirmId },
    {
      headers: { 'Content-Type': 'application/json' },
      params: { Key: config.publicKey }
    }
  );

  // Store the Lexamica ID so a re-run of this import can't create a duplicate.
  await saveCaseMapping(caseData.original_id, response.data.lexamica_case_id);

  return response.data;
}

// Placeholder functions — implement for your system
async function findCaseMappingByOriginalId(originalId) {
  // Look up a previously saved mapping by your foreign/original case ID.
  // Return the stored record (e.g. { lexamica_case_id }) if one exists, or
  // null/undefined if this case hasn't been imported yet.
}

async function saveCaseMapping(originalId, lexamicaId) {
  console.log(`Mapped: ${originalId} -> ${lexamicaId}`);
}

// ============================================
// POLL FOR UPDATES
// ============================================

const EVENT_TYPES = [
  'Case Update Made',
  'Case Stage Changed',
  'Case Settlement'
];

class ExistingCasePoller {
  constructor() {
    this.lastPollTime = null;
  }

  async poll() {
    const now = new Date();
    const from = this.lastPollTime || new Date(now.getTime() - 24 * 60 * 60 * 1000);
    
    console.log(`Polling from ${from.toISOString()}`);
    
    try {
      for (const eventType of EVENT_TYPES) {
        const events = await this.fetchEvents(eventType, from, now);
        if (events.length > 0) {
          console.log(`Found ${events.length} ${eventType} event(s)`);
          await this.processEvents(eventType, events);
        }
      }
      
      this.lastPollTime = now;
      
    } catch (error) {
      console.error('Poll failed:', error.message);
    }
  }

  async fetchEvents(eventType, from, to) {
    const params = new URLSearchParams({
      event: eventType,
      from: from.toISOString(),
      to: to.toISOString(),
      limit: '100'
    });

    const response = await axios.get(
      `${config.baseUrl}/organization/${config.orgId}/stored-events?${params}`,
      { headers: { Authorization: `Bearer ${config.privateKey}` } }
    );

    return response.data.events || [];
  }

  async processEvents(eventType, events) {
    for (const event of events) {
      await this.handleEvent(eventType, event.payload);
    }
  }

  async handleEvent(eventType, payload) {
    switch (eventType) {
      case 'Case Update Made':
        console.log(`Update on ${payload.case_id}: ${payload.title}`);
        await this.recordUpdate(payload);
        break;
        
      case 'Case Stage Changed':
        console.log(`Stage changed for ${payload.lexamica_case_id}`);
        await this.updateStage(payload);
        break;
        
      case 'Case Settlement':
        console.log(`Settlement on ${payload.lexamica_case_id}`);
        await this.recordSettlement(payload);
        break;
    }
  }

  // Implement these for your system
  async recordUpdate(payload) {
    // Save status update to your database
  }

  async updateStage(payload) {
    // Update case stage in your system
  }

  async recordSettlement(payload) {
    // Record settlement info
  }
}

// ============================================
// RUN
// ============================================

const poller = new ExistingCasePoller();
const POLL_INTERVAL = 15 * 60 * 1000; // 15 minutes

async function run() {
  console.log('Polling for updates...');
  await poller.poll();
  console.log('Done. Next poll in 15 minutes.');
}

run();
setInterval(run, POLL_INTERVAL);
```

***

## 📋 Events You'll Receive

| Event                | When                 | Payload                  |
| -------------------- | -------------------- | ------------------------ |
| `Case Update Made`   | Handler posts update | title, content, case\_id |
| `Case Stage Changed` | Case moves stages    | new stage, case\_id      |
| `Case Settlement`    | Settlement starts    | settlement details       |

***

## ❓ FAQ

### ❓ "How often should I poll?"

| Use Case         | Interval            |
| ---------------- | ------------------- |
| Daily reports    | Once per day        |
| Regular tracking | Every 15-30 minutes |
| Near real-time   | Every 5 minutes     |

For existing cases, updates typically aren't urgent—daily or hourly polling is usually sufficient.

***

### ❓ "Can I import many cases at once?"

**📝 Full Answer:** Yes. Loop through your cases:

```javascript
async function bulkImport(cases) {
  const results = [];
  for (const c of cases) {
    try {
      const result = await importExistingCase(c.data, c.partnerFirmId);
      results.push({ success: true, id: result.lexamica_case_id });
      await delay(500); // Rate limit protection
    } catch (error) {
      results.push({ success: false, error: error.message });
    }
  }
  return results;
}
```

***

## ➡️ Next Steps

* **Need real-time updates?** See [Import Existing Cases with Webhooks](/example-integrations/5a.-import-existing-webhook.md)
* **Need file handling?** See [File Operations](/example-integrations/apx-1.-file-operations.md)
* **Want Relay matching?** See [Originator: Full Integration with Polling](/example-integrations/3b.-originator-full-polling.md)

***

*Last updated: January 2026*
