> 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/2.-mapping-engine.md).

# Mapping Engine

How to transform data between your system and Lexamica using field mappings.

***

## Table of Contents

1. [Overview](#-overview)
2. [Key Terms](#-key-terms)
3. [How It Works](#️-how-it-works)
4. [Key Concepts](#-key-concepts)
5. [Common Use Cases](#-common-use-cases)
6. [FAQ](#-faq)
7. [Technical Reference](#-technical-reference)

***

## 🎯 Overview

> **📌 TL;DR**
>
> Mappings translate field names between your system and Lexamica. Your `client_first_name` becomes Lexamica's `client.firstName`, and vice versa. Create a mapping once, and all data flows through it automatically.

Your CRM, case management system, or database probably uses different field names than Lexamica. The **Mapping Engine** bridges this gap by defining how fields correspond between systems.

Mappings are **bidirectional**:

* **Inbound:** When you send data to Lexamica, your fields are transformed to Lexamica's format
* **Outbound:** When Lexamica sends data back (in responses or webhooks), it's transformed to your format

This means you can work entirely in your own field names—the mapping handles the translation.

***

## 📖 Key Terms

| Term                        | Definition                                                                                       |
| --------------------------- | ------------------------------------------------------------------------------------------------ |
| **Mapping**                 | A named configuration that defines how fields translate between your system and Lexamica.        |
| **Field Mapping**           | A single field-to-field correspondence within a mapping (e.g., `client_email` ↔ `client.email`). |
| **Model**                   | The type of Lexamica data the mapping applies to (Case, CaseInvitation, etc.).                   |
| **Inbound Transformation**  | Converting your data format to Lexamica's format when sending data.                              |
| **Outbound Transformation** | Converting Lexamica's format to your format when receiving data.                                 |
| **Mapping ID**              | A unique identifier for a mapping, used in API endpoint URLs.                                    |

***

## ⚙️ How It Works

When data flows through the API, the Mapping Engine automatically transforms it:

```
Bidirectional Data Flow
───────────────────────

INBOUND (Your System → Lexamica)
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│  Your Request   │────▶│  Mapping Engine │────▶│    Lexamica     │
│                 │     │                 │     │                 │
│ {               │     │  client_fname   │     │ {               │
│   client_fname  │     │       ↓         │     │   client: {     │
│   client_lname  │     │  client.firstName    │   firstName  │
│   case_type     │     │                 │     │   lastName   │
│ }               │     │  client_lname   │     │   }             │
│                 │     │       ↓         │     │   caseType      │
│                 │     │  client.lastName│     │ }               │
└─────────────────┘     └─────────────────┘     └─────────────────┘

OUTBOUND (Lexamica → Your System)
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│    Lexamica     │────▶│  Mapping Engine │────▶│  Your System    │
│                 │     │                 │     │                 │
│ {               │     │  client.firstName    │ {               │
│   client: {     │     │       ↓         │     │   client_fname  │
│     firstName   │     │  client_fname   │     │   client_lname  │
│     lastName    │     │                 │     │   case_type     │
│   }             │     │  client.lastName│     │ }               │
│   caseType      │     │       ↓         │     │                 │
│ }               │     │  client_lname   │     │                 │
└─────────────────┘     └─────────────────┘     └─────────────────┘
```

> **🎯 Key Takeaway**
>
> You define the mapping once, and it works in both directions. Send data using your field names, receive data in your field names.

***

## 💡 Key Concepts

### Supported Models

Each mapping is tied to a specific data model. Choose the model based on what data you're working with:

| Model              | Use For                                  | Common Fields                                                   |
| ------------------ | ---------------------------------------- | --------------------------------------------------------------- |
| **Case**           | Case/matter data, client info, incidents | `client.firstName`, `client.email`, `caseType`, `incident.date` |
| **CaseInvitation** | Invitation status and lifecycle          | `accepted`, `declined`, `expires`, `referral._id`               |
| **CaseUpdate**     | Case notes and status updates            | `title`, `content`, `referral._id`                              |
| **LawFirm**        | Firm information                         | `name`, `_id`                                                   |
| **LawFirmUser**    | User/attorney information                | `givenName`, `familyName`, `email`                              |
| **Attachment**     | File metadata                            | `filename`, `mimetype`, `size`, `url`                           |

### Field Types

Each field mapping specifies data types to ensure proper conversion:

| Type         | Description                                 | Example                           |
| ------------ | ------------------------------------------- | --------------------------------- |
| **String**   | Text values                                 | Names, emails, descriptions       |
| **Number**   | Numeric values                              | Fees, percentages, amounts        |
| **Date**     | Date/time values                            | Incident dates, deadlines         |
| **Boolean**  | True/false values                           | Flags, toggles                    |
| **Constant** | Fixed values that don't come from your data | Always set `status` to `"active"` |

### Nested Field Syntax

Lexamica uses dot notation for nested objects. Your fields can be flat or nested—the mapping handles the translation:

```
Lexamica Nested Fields          Your Flat Fields
─────────────────────           ─────────────────
client.firstName          ↔     client_first_name
client.lastName           ↔     client_last_name
client.address.city       ↔     client_city
client.address.state      ↔     client_state
incident.address.line1    ↔     accident_street
```

### Custom Fields

For data that doesn't fit Lexamica's standard fields, use `customFields`:

```
customFields.your_field_name
```

Custom fields are stored with the case and returned in webhooks, preserving your data through the round trip.

**Example:** Your system tracks `lead_source` and `marketing_campaign`:

```
customFields.lead_source      ↔     lead_source
customFields.marketing_campaign ↔   campaign_id
```

***

## 📋 Common Use Cases

### 📗 Use Case: Creating a Basic Case Mapping

|            |                                                         |
| ---------- | ------------------------------------------------------- |
| **Goal**   | Map your CRM's case fields to Lexamica's Case model     |
| **How**    | Create a mapping with field correspondences             |
| **Result** | A Mapping ID you'll use for all case-related operations |

**Request:**

```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": "CRM Case Mapping",
    "modelName": "Case",
    "fieldMappings": [
      {
        "lexamicaField": "client.firstName",
        "foreignField": "contact_first_name",
        "lexamicaFieldType": "String",
        "foreignFieldType": "String"
      },
      {
        "lexamicaField": "client.lastName",
        "foreignField": "contact_last_name",
        "lexamicaFieldType": "String",
        "foreignFieldType": "String"
      },
      {
        "lexamicaField": "client.email",
        "foreignField": "contact_email",
        "lexamicaFieldType": "String",
        "foreignFieldType": "String"
      },
      {
        "lexamicaField": "client.phoneNumber",
        "foreignField": "contact_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.synopsis",
        "foreignField": "case_description",
        "lexamicaFieldType": "String",
        "foreignFieldType": "String"
      }
    ]
  }'
```

**Response:**

```json
{
  "_id": "64f1a2b3c4d5e6f7a8b9c0d2",
  "label": "CRM Case Mapping",
  "modelName": "Case",
  "organization": "64f1a2b3c4d5e6f7a8b9c0d1",
  "fieldMappings": [
    {
      "lexamicaField": "client.firstName",
      "foreignField": "contact_first_name",
      "lexamicaFieldType": "String",
      "foreignFieldType": "String"
    }
  ],
  "created": "2026-01-15T10:30:00.000Z",
  "updated": "2026-01-15T10:30:00.000Z"
}
```

> **💡 Tip:** Save the `_id` from the response—this is your Mapping ID that you'll use in inbound webhook URLs.

### 📗 Use Case: Mapping with Custom Fields

|            |                                                                          |
| ---------- | ------------------------------------------------------------------------ |
| **Goal**   | Include CRM-specific data that Lexamica doesn't have standard fields for |
| **How**    | Map to `customFields.*` paths                                            |
| **Result** | Your custom data flows through and returns in webhooks                   |

**Adding custom fields to your mapping:**

```json
{
  "fieldMappings": [
    {
      "lexamicaField": "customFields.lead_source",
      "foreignField": "lead_source",
      "lexamicaFieldType": "String",
      "foreignFieldType": "String"
    },
    {
      "lexamicaField": "customFields.crm_record_id",
      "foreignField": "record_id",
      "lexamicaFieldType": "String",
      "foreignFieldType": "String"
    }
  ]
}
```

### 📗 Use Case: Using Constant Values

|            |                                                        |
| ---------- | ------------------------------------------------------ |
| **Goal**   | Always send a fixed value for a field                  |
| **How**    | Set the field type to `Constant` and specify the value |
| **Result** | The constant is included in every request              |

**Example:** Always set update frequency to 90 days:

```json
{
  "lexamicaField": "updates.frequency",
  "foreignField": "update_frequency",
  "lexamicaFieldType": "Number",
  "foreignFieldType": "Constant",
  "constantValue": 90,
  "constantValueType": "Number"
}
```

***

## ❓ FAQ

### ❓ "Do I need separate mappings for inbound and outbound?"

**📝 Full Answer:** No. Each mapping works bidirectionally. When you send data (inbound), your fields are transformed to Lexamica fields. When you receive data (outbound), Lexamica fields are transformed back to your fields. One mapping handles both directions.

***

### ❓ "How do I map fields that don't exist in Lexamica?"

**🔍 Quick Check:**

* ✅ Use `customFields.*` for additional data you want to preserve
* ✅ Custom fields are stored and returned in webhooks

**📝 Full Answer:** Use the `customFields` namespace. For example, if your CRM has a `referral_source` field, map it to `customFields.referral_source`. This data will be stored with the case and included when Lexamica sends data back to you via webhooks or API responses.

***

### ❓ "Can I have multiple mappings for the same model?"

**📝 Full Answer:** Yes. You might want different mappings for different use cases. For example:

* A "Full Case Mapping" with all fields for new case creation
* A "Basic Case Mapping" with just client info for updates

Each mapping gets its own ID, and you choose which to use in each API call.

***

### ❓ "What happens if a field is missing from my request?"

**📝 Full Answer:** Missing fields are simply not included in the transformed data. Lexamica will use defaults or leave optional fields empty. For required fields (like `client.email` or `client.phoneNumber`), you'll receive a validation error if they're missing.

***

### ❓ "How do I update an existing mapping?"

**🔍 Quick Check:**

* ✅ Use the `/mapping/{mapId}/update` endpoint
* ✅ Include the complete `fieldMappings` array (it replaces the existing one)

**📝 Full Answer:** Send a POST request to update with your Mapping ID:

```bash
curl -X POST \
  "https://integration.lexamica.com/organization/{orgId}/mapping/{mapId}/update" \
  -H "Authorization: Bearer your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Updated CRM Mapping",
    "fieldMappings": [...]
  }'
```

***

## 🔧 Technical Reference

### Available Lexamica Fields

You can retrieve all available fields for mapping via the API:

```bash
curl -X GET \
  "https://integration.lexamica.com/organization/{orgId}/mapping/lexamica/fields" \
  -H "Authorization: Bearer your_private_key"
```

### Case Model Fields

| Field                    | Type   | Description                                |
| ------------------------ | ------ | ------------------------------------------ |
| `_id`                    | String | Case ID (for updates to existing cases)    |
| `client.firstName`       | String | Client's first name                        |
| `client.lastName`        | String | Client's last name                         |
| `client.email`           | String | Client's email (required if no phone)      |
| `client.phoneNumber`     | String | Client's phone (required if no email)      |
| `client.address.line1`   | String | Client address line 1                      |
| `client.address.line2`   | String | Client address line 2                      |
| `client.address.city`    | String | Client city                                |
| `client.address.state`   | String | Client state                               |
| `client.address.zipCode` | String | Client ZIP code                            |
| `caseType`               | String | Practice area/case type                    |
| `incident.date`          | Date   | Date of incident                           |
| `incident.synopsis`      | String | Description of incident                    |
| `incident.address.*`     | String | Incident location fields                   |
| `payment.feeType`        | String | `percentage` or `custom`                   |
| `payment.percentage`     | Number | Fee percentage                             |
| `payment.custom`         | String | Custom fee amount                          |
| `updates.frequency`      | Number | Update frequency (30, 60, 90, or 120 days) |
| `customFields.*`         | Any    | Your custom data                           |

### CaseInvitation Model Fields

| Field           | Type   | Description                              |
| --------------- | ------ | ---------------------------------------- |
| `_id`           | String | Invitation ID                            |
| `referral._id`  | String | Associated case ID                       |
| `accepted`      | Date   | When invitation was accepted             |
| `declined`      | Date   | When invitation was declined             |
| `evaluated`     | Date   | When invitation was marked as evaluating |
| `expires`       | Date   | Invitation expiration                    |
| `declineReason` | String | Reason for decline                       |

### CaseUpdate Model Fields

| Field          | Type    | Description                |
| -------------- | ------- | -------------------------- |
| `_id`          | String  | Update ID                  |
| `referral._id` | String  | Associated case ID         |
| `title`        | String  | Update title               |
| `content`      | String  | Update content/notes       |
| `overdue`      | Boolean | Whether update was overdue |

> **🔧 Technical Deep-Dive: Field Mapping Structure**
>
> Each field mapping in the `fieldMappings` array follows this structure:
>
> ```json
> {
>   "lexamicaField": "client.firstName",
>   "foreignField": "contact_first_name",
>   "lexamicaFieldType": "String",
>   "foreignFieldType": "String",
>   "constantValue": null,
>   "constantValueType": null,
>   "subMappings": []
> }
> ```
>
> * `lexamicaField`: The dot-notation path in Lexamica's data structure
> * `foreignField`: Your system's field name
> * `*FieldType`: One of `String`, `Number`, `Date`, `Boolean`, `Constant`
> * `constantValue/Type`: Used when one side is a fixed value
> * `subMappings`: For nested object transformations

***

*Last updated: January 2026*
