> 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/5a.-import-existing-webhook.md).

# Import Existing Cases with Webhooks

Import cases you're already tracking and receive status updates via webhooks.

***

## 🎯 Overview

> **📌 TL;DR**
>
> You have cases already being handled by specific partner firms outside of Lexamica. Import them to track status updates and settlements through the platform, with real-time webhook notifications.

**This guide is for you if:**

* You have existing referral relationships you want to track in Lexamica
* You already know which firm is handling each case (no Relay matching needed)
* You want webhook notifications for status updates and settlements

**What you'll build:**

* A Case mapping for importing case data
* Import cases with specific handler firms
* Webhook subscriptions for updates and settlements

**Key difference from other originator guides:**

* Uses `/case/{mapId}/create-existing` instead of `/case/{mapId}/send`
* Skips the Relay Engine—you specify the handler directly
* No relay events (matched/rejected)—just updates and settlements

***

## 📖 Key Terms

| Term                | Definition                                                   |
| ------------------- | ------------------------------------------------------------ |
| **Existing Case**   | A case already being handled, imported for tracking purposes |
| **Partner Firm ID** | The Lexamica ID of the firm handling the case                |

***

## ⚙️ Architecture

```
Import Existing Cases (Webhooks)
────────────────────────────────

┌─────────────────┐                     ┌─────────────────┐
│   Your System   │                     │   Your System   │
│                 │                     │                 │
│ Import existing │                     │ Webhook Handler │
│ case with known │                     │                 │
│ handler firm    │                     │ • Updates       │
│                 │                     │ • Settlements   │
└────────┬────────┘                     └────────▲────────┘
         │                                       │
         │ POST /create-existing                 │ Webhooks
         ▼                                       │
┌─────────────────────────────────────────────────────────┐
│                   LEXAMICA                              │
│                                                         │
│  Case Created ───▶ Linked to Partner ───▶ Track Status │
│  (No Relay)           Firm                              │
│                                                         │
│  Events: 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:**

* [ ] A publicly accessible HTTPS endpoint for webhooks

**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
* [ ] [Webhook Subscriptions](/4.-webhook-subscriptions.md) — receiving events from Lexamica

> **💡 Tip:** To get Partner Firm IDs, contact Lexamica support or use the platform to look them up.

***

## 💡 Step-by-Step Implementation

### Step 1: Create Your Case Mapping

```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": "client.email", "foreignField": "client_email", "lexamicaFieldType": "String", "foreignFieldType": "String" },
      { "lexamicaField": "client.phoneNumber", "foreignField": "client_phone", "lexamicaFieldType": "String", "foreignFieldType": "String" },
      { "lexamicaField": "caseType", "foreignField": "practice_area", "lexamicaFieldType": "String", "foreignFieldType": "String" },
      { "lexamicaField": "incident.date", "foreignField": "incident_date", "lexamicaFieldType": "Date", "foreignFieldType": "String" },
      { "lexamicaField": "incident.address.state", "foreignField": "incident_state", "lexamicaFieldType": "String", "foreignFieldType": "String" },
      { "lexamicaField": "incident.synopsis", "foreignField": "description", "lexamicaFieldType": "String", "foreignFieldType": "String" },
      { "lexamicaField": "customFields.original_case_id", "foreignField": "original_id", "lexamicaFieldType": "String", "foreignFieldType": "String" }
    ]
  }'
```

### Step 2: Create Webhook Subscriptions

Subscribe to update and settlement events.

```bash
# Status updates from handler
curl -X POST \
  "https://integration.lexamica.com/organization/{orgId}/webhook-subscriptions/create" \
  -H "Authorization: Bearer your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "Case Update Made",
    "url": "https://your-system.com/webhooks/lexamica",
    "secret": "your_webhook_secret",
    "mapping": "your_case_update_mapping_id",
    "description": "Receive status updates on imported cases",
    "active": true
  }'

# Stage changes
curl -X POST \
  "https://integration.lexamica.com/organization/{orgId}/webhook-subscriptions/create" \
  -H "Authorization: Bearer your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "Case Stage Changed",
    "url": "https://your-system.com/webhooks/lexamica",
    "secret": "your_webhook_secret",
    "mapping": "your_case_mapping_id",
    "description": "Track case stage changes",
    "active": true
  }'

# Settlement info
curl -X POST \
  "https://integration.lexamica.com/organization/{orgId}/webhook-subscriptions/create" \
  -H "Authorization: Bearer your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "Case Settlement",
    "url": "https://your-system.com/webhooks/lexamica",
    "secret": "your_webhook_secret",
    "mapping": "your_case_mapping_id",
    "description": "Track settlements",
    "active": true
  }'
```

### Step 3: Import Cases with Partner Firm ID

Use the `/create-existing` endpoint with the `partnerFirmId` parameter.

> **💡 Why this matters:** Lexamica doesn't dedupe on this endpoint either. 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.

**Request:**

```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",
    "client_email": "jane@example.com",
    "client_phone": "555-123-4567",
    "practice_area": "Personal Injury",
    "incident_date": "2025-06-15",
    "incident_state": "CA",
    "description": "Motor vehicle accident - existing case being tracked.",
    "original_id": "CASE-2025-001",
    "partnerFirmId": "64f1a2b3c4d5e6f7a8b9c0f1"
  }'
```

**Response:**

```json
{
  "lexamica_case_id": "64f1a2b3c4d5e6f7a8b9c0d3",
  "client_first_name": "Jane",
  "client_last_name": "Smith",
  "practice_area": "Personal Injury",
  "status": "existing",
  "created": "2026-01-15T10:30:00.000Z"
}
```

> **ℹ️ Note:** If you omit `partnerFirmId`, Lexamica runs a projection analysis to suggest potential partners from your network but doesn't send invitations.

***

## 🔧 Complete Code Example

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

const app = express();
app.use(express.json({ verify: (req, res, buf) => { req.rawBody = buf; } }));

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

// Import an existing case
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 payload = {
    ...caseData,
    partnerFirmId: partnerFirmId
  };

  const response = await axios.post(
    `${config.baseUrl}/organization/${config.orgId}/inbound-webhooks/case/${config.mappingId}/create-existing`,
    payload,
    {
      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;
}

// Bulk import example
async function importCasesFromLegacySystem(cases) {
  const results = [];
  
  for (const legacyCase of cases) {
    try {
      const result = await importExistingCase({
        client_first_name: legacyCase.clientFirstName,
        client_last_name: legacyCase.clientLastName,
        client_email: legacyCase.clientEmail,
        client_phone: legacyCase.clientPhone,
        practice_area: legacyCase.caseType,
        incident_date: legacyCase.incidentDate,
        incident_state: legacyCase.state,
        description: legacyCase.description,
        original_id: legacyCase.id
      }, legacyCase.handlerFirmLexamicaId);
      
      results.push({ success: true, originalId: legacyCase.id, lexamicaId: result.lexamica_case_id });
    } catch (error) {
      results.push({ success: false, originalId: legacyCase.id, error: error.message });
    }
  }
  
  return results;
}

// Webhook handler
function verifySignature(rawBody, signature) {
  if (!signature) return false;
  const expected = 'sha256=' + crypto
    .createHmac('sha256', config.webhookSecret)
    .update(rawBody)
    .digest('hex');
  try {
    return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
  } catch { return false; }
}

const webhookHandlers = {
  'Case Update Made': async (payload) => {
    console.log(`Update on case ${payload.case_id}: ${payload.title}`);
    await recordUpdate(payload.case_id, {
      title: payload.title,
      content: payload.content,
      date: new Date()
    });
  },
  
  'Case Stage Changed': async (payload) => {
    console.log(`Case ${payload.lexamica_case_id} stage: ${payload.stage}`);
    await updateCaseStage(payload.lexamica_case_id, payload.stage);
  },
  
  'Case Settlement': async (payload) => {
    console.log(`Settlement on case ${payload.lexamica_case_id}`);
    await markCaseSettling(payload.lexamica_case_id, {
      settlementDate: new Date(),
      // Settlement details in payload
    });
  }
};

app.post('/webhooks/lexamica', async (req, res) => {
  const signature = req.headers['x-lexamica-signature'];
  const eventType = req.headers['x-lexamica-event'];
  
  if (!verifySignature(req.rawBody, signature)) {
    return res.status(401).send('Invalid signature');
  }
  
  res.status(200).send('OK');
  
  const handler = webhookHandlers[eventType];
  if (handler) {
    try {
      await handler(req.body);
    } catch (error) {
      console.error(`Error processing ${eventType}:`, error);
    }
  }
});

// Placeholder functions
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.
  console.log(`Look up mapping for: ${originalId}`);
}

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

async function recordUpdate(caseId, update) {
  console.log('Update:', caseId, update);
}

async function updateCaseStage(caseId, stage) {
  console.log('Stage:', caseId, stage);
}

async function markCaseSettling(caseId, details) {
  console.log('Settlement:', caseId, details);
}

app.listen(3000, () => console.log('Server running'));
```

***

## 📋 Events You'll Receive

| Event                | When It Fires                 | What It Contains            |
| -------------------- | ----------------------------- | --------------------------- |
| `Case Update Made`   | Handler posts a status update | Update title, content, date |
| `Case Stage Changed` | Case moves to new stage       | New stage label             |
| `Case Settlement`    | Settlement process starts     | Settlement details          |

Note: You won't receive relay events since the case bypasses the Relay Engine.

***

## ❓ FAQ

### ❓ "Where do I get the Partner Firm ID?"

**📝 Full Answer:**

* From the Lexamica platform (firm profile page)
* Via the API (contact support for firm lookup endpoints)
* From previous integrations where you stored the firm ID

***

### ❓ "What if I don't specify a partner firm?"

**📝 Full Answer:** If you omit `partnerFirmId`, Lexamica:

1. Creates the case as a draft
2. Runs a projection analysis from your partner network
3. Does NOT send invitations
4. Suggests potential partners you can select in-platform

***

### ❓ "Can I import cases in bulk?"

**📝 Full Answer:** Yes. Loop through your cases and call the endpoint for each. Add delays (100-200ms) between calls to avoid rate limits. See the bulk import example in the code above.

***

## ➡️ Next Steps

* **Can't receive webhooks?** See [Import Existing Cases with Polling](/example-integrations/5b.-import-existing-polling.md)
* **Need to attach files?** See [File Operations](/example-integrations/apx-1.-file-operations.md)
* **Want Relay matching instead?** See [Originator: Full Integration with Webhooks](/example-integrations/3a.-originator-full-webhook.md)

***

*Last updated: January 2026*
