> 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/3.-inbound-webhooks.md).

# Inbound Webhooks

How to send data INTO Lexamica from your system.

***

## Table of Contents

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

***

## 🎯 Overview

> **📌 TL;DR**
>
> Inbound webhooks let you push data to Lexamica—create cases, respond to invitations, upload files, and more. Send requests using your field names, and the mapping engine transforms them automatically.

Inbound webhooks are endpoints where **you send data TO Lexamica**. They're the primary way to:

* Create new cases and send them to the Relay Engine for partner matching
* Accept or decline case invitations from other firms
* Upload documents and files to cases
* Post case updates and status changes
* Manage the invitation lifecycle

All inbound webhook endpoints use your **Public Key** for authentication and your **Mapping ID** to transform your data format to Lexamica's.

***

## 📖 Key Terms

| Term                | Definition                                                                                    |
| ------------------- | --------------------------------------------------------------------------------------------- |
| **Inbound Webhook** | An API endpoint that receives data from your system and processes it in Lexamica.             |
| **Relay Engine**    | Lexamica's automatic matching system that routes cases to appropriate partner firms.          |
| **Case Invitation** | A request from one firm to another to handle a case. Can be accepted, declined, or evaluated. |
| **Case Update**     | A status note or update posted to a case, typically required every 90 days.                   |
| **Mapping ID**      | The identifier of the mapping configuration to use for transforming your data.                |

***

## ⚙️ How It Works

When you send data to an inbound webhook:

```
Inbound Webhook Flow
────────────────────

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   Your System   │────▶│  Integration    │────▶│    Lexamica     │
│                 │     │      API        │     │                 │
│ POST request    │     │                 │     │ Case created,   │
│ with your data  │     │ 1. Authenticate │     │ invitation      │
│ format          │     │ 2. Load mapping │     │ processed, etc. │
│                 │     │ 3. Transform    │     │                 │
└─────────────────┘     └─────────────────┘     └─────────────────┘
                                │
                                ▼
                        ┌─────────────────┐
                        │    Response     │
                        │                 │
                        │ Transformed back│
                        │ to YOUR format  │
                        └─────────────────┘
```

**Key points:**

1. You send data using **your field names** (e.g., `contact_first_name`)
2. The mapping transforms it to **Lexamica's fields** (e.g., `client.firstName`)
3. Lexamica processes the request
4. The response is transformed back to **your field names**

> **🎯 Key Takeaway**
>
> Every inbound webhook URL includes your Mapping ID. The same endpoint can work differently depending on which mapping you use.

***

## 💡 Available Operations

### Case Operations

| Operation            | Endpoint                        | Purpose                                                       |
| -------------------- | ------------------------------- | ------------------------------------------------------------- |
| **Send Case**        | `/case/{mapId}/send`            | Create a case and send to Relay Engine for partner matching   |
| **Create Existing**  | `/case/{mapId}/create-existing` | Create a case that's already being handled by a known partner |
| **Create Draft**     | `/case/{mapId}/draft`           | Create a draft case without sending to Relay                  |
| **Edit Case**        | `/case/{mapId}/edit`            | Update client or incident details on an existing case         |
| **Create Update**    | `/case/{mapId}/update`          | Post a status update or note to a case                        |
| **Start Settlement** | `/case/{mapId}/settlement`      | Begin the settlement process for a case                       |

### Invitation Operations

| Operation             | Endpoint                                     | Purpose                                       | Who Can Use     |
| --------------------- | -------------------------------------------- | --------------------------------------------- | --------------- |
| **Send**              | `/case-invitation/{mapId}/send`              | Invite a specific firm to handle a case       | Case originator |
| **Accept**            | `/case-invitation/{mapId}/accept`            | Accept an invitation you received             | Invitee         |
| **Decline**           | `/case-invitation/{mapId}/decline`           | Decline an invitation with a reason           | Invitee         |
| **Evaluate**          | `/case-invitation/{mapId}/evaluate`          | Mark invitation as under evaluation           | Invitee         |
| **Contact Attempted** | `/case-invitation/{mapId}/contact-attempted` | Mark that you attempted to contact the client | Invitee         |
| **Consult Complete**  | `/case-invitation/{mapId}/consult-complete`  | Mark that consultation is complete            | Invitee         |
| **Cancel**            | `/case-invitation/{mapId}/cancel`            | Cancel an invitation you sent                 | Originator      |
| **Close**             | `/case-invitation/{mapId}/close`             | Close an invitation you sent                  | Originator      |
| **Extend**            | `/case-invitation/{mapId}/extend`            | Extend the expiration of an invitation        | Originator      |

### File Operations

| Operation       | Endpoint                    | Purpose                                     |
| --------------- | --------------------------- | ------------------------------------------- |
| **Upload File** | `/case/{mapId}/file/upload` | Upload a file directly to a case            |
| **Stream File** | `/case/{mapId}/file/stream` | Upload a file from a URL (for larger files) |
| **Remove File** | `/case/{mapId}/file/remove` | Delete a file from a case                   |

***

## 📋 Common Use Cases

### 📗 Use Case: Sending a New Case to Relay

|            |                                                                  |
| ---------- | ---------------------------------------------------------------- |
| **Goal**   | Create a case and have Lexamica find a matching partner firm     |
| **How**    | POST to the `/case/{mapId}/send` endpoint with case details      |
| **Result** | Case enters the Relay Engine; you'll receive events when matched |

**Request:**

```bash
curl -X POST \
  "https://integration.lexamica.com/organization/{orgId}/inbound-webhooks/case/{mapId}/send?Key=your_public_key" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_first_name": "Jane",
    "contact_last_name": "Smith",
    "contact_email": "jane.smith@example.com",
    "contact_phone": "555-123-4567",
    "practice_area": "Personal Injury",
    "incident_date": "2026-01-10",
    "incident_state": "CA",
    "case_description": "Rear-end collision on Highway 101. Client was stopped at red light.",
    "lead_source": "Website Form"
  }'
```

**Response (in your field format):**

```json
{
  "case_id": "64f1a2b3c4d5e6f7a8b9c0d3",
  "contact_first_name": "Jane",
  "contact_last_name": "Smith",
  "contact_email": "jane.smith@example.com",
  "status": "pending_match",
  "created_at": "2026-01-15T10:30:00.000Z"
}
```

> **💡 Tip:** Store the `case_id` in your system—you'll need it for future operations and to correlate webhook events.

### 📗 Use Case: Accepting an Invitation

|            |                                                                  |
| ---------- | ---------------------------------------------------------------- |
| **Goal**   | Accept a case invitation that was sent to your firm              |
| **How**    | POST to `/case-invitation/{mapId}/accept` with the invitation ID |
| **Result** | You're now the handler for this case                             |

**Request:**

```bash
curl -X POST \
  "https://integration.lexamica.com/organization/{orgId}/inbound-webhooks/case-invitation/{mapId}/accept" \
  -H "Authorization: Bearer your_public_key" \
  -H "Content-Type: application/json" \
  -d '{
    "invitation_id": "64f1a2b3c4d5e6f7a8b9c0d4"
  }'
```

**Response:**

```json
{
  "invitation_id": "64f1a2b3c4d5e6f7a8b9c0d4",
  "case_id": "64f1a2b3c4d5e6f7a8b9c0d3",
  "status": "accepted",
  "accepted_at": "2026-01-15T14:22:00.000Z"
}
```

### 📗 Use Case: Posting a Case Update

|            |                                                                |
| ---------- | -------------------------------------------------------------- |
| **Goal**   | Add a status update to a case (required every 90 days)         |
| **How**    | POST to `/case/{mapId}/update` with case ID and update content |
| **Result** | Update is recorded and visible to all parties                  |

**Request:**

```bash
curl -X POST \
  "https://integration.lexamica.com/organization/{orgId}/inbound-webhooks/case/{mapId}/update" \
  -H "Authorization: Bearer your_public_key" \
  -H "Content-Type: application/json" \
  -d '{
    "case_id": "64f1a2b3c4d5e6f7a8b9c0d3",
    "update_title": "Discovery Phase Complete",
    "update_content": "All depositions completed. Moving to settlement negotiations.",
    "update_type": "status"
  }'
```

> **ℹ️ Note:** The `update_type` field maps to Lexamica's `type` field. Use `status` for required status updates or `note` for general case notes.

### 📗 Use Case: Uploading a Case Document

|            |                                                         |
| ---------- | ------------------------------------------------------- |
| **Goal**   | Attach a document to an existing case                   |
| **How**    | POST multipart form data to `/case/{mapId}/file/upload` |
| **Result** | File is stored and accessible to case participants      |

**Request:**

```bash
curl -X POST \
  "https://integration.lexamica.com/organization/{orgId}/inbound-webhooks/case/{mapId}/file/upload" \
  -H "Authorization: Bearer your_public_key" \
  -F "caseId=64f1a2b3c4d5e6f7a8b9c0d3" \
  -F "file=@/path/to/document.pdf" \
  -F "fileName=medical_records.pdf"
```

### 📕 Use Case: Declining an Invitation

|            |                                                        |
| ---------- | ------------------------------------------------------ |
| **Goal**   | Decline a case invitation with an explanation          |
| **How**    | POST to `/case-invitation/{mapId}/decline` with reason |
| **Result** | Invitation marked as declined; originator is notified  |

**Request:**

```bash
curl -X POST \
  "https://integration.lexamica.com/organization/{orgId}/inbound-webhooks/case-invitation/{mapId}/decline" \
  -H "Authorization: Bearer your_public_key" \
  -H "Content-Type: application/json" \
  -d '{
    "invitation_id": "64f1a2b3c4d5e6f7a8b9c0d4",
    "decline_reason": "Conflict of interest - we represent the defendant."
  }'
```

***

## ❓ FAQ

### ❓ "What's the difference between Send and Create Existing?"

**🔍 Quick Check:**

* ✅ Need Lexamica to find a partner? Use **Send** (`/case/{mapId}/send`)
* ✅ Already know who's handling it? Use **Create Existing** (`/case/{mapId}/create-existing`)

**📝 Full Answer:**

* **Send** submits the case to the Relay Engine, which automatically matches it with partner firms based on practice area, location, and availability.
* **Create Existing** creates a case that you're already tracking with a known partner—it skips the matching process entirely.

***

### ❓ "How do I know if my case was matched?"

**🔍 Quick Check:**

* ✅ Set up a webhook subscription for `Case Relay Matched` events
* ✅ Or poll stored events if you can't receive webhooks

**📝 Full Answer:** After sending a case to Relay, you'll receive events as the matching process progresses:

* `Case Relay Matched` — A partner was found and invited
* `Case Relay Rejected` — No partners available for this case type/location
* `Case Relay Missed` — Partners were invited but none accepted
* `Case Invitation Accepted` — A partner accepted the case

See the [Webhook Subscriptions](https://github.com/Lexamica/lexamica-docs/blob/main/services/universal-integration/webhook-subscriptions.md) guide for setting up event notifications.

***

### ❓ "What fields are required for sending a case?"

**📝 Full Answer:** For the `/case/{mapId}/send` endpoint, your mapping must resolve these required fields:

| Lexamica Field           | Description                             |
| ------------------------ | --------------------------------------- |
| `client.firstName`       | Client's first name                     |
| `client.lastName`        | Client's last name                      |
| `client.phoneNumber`     | Client's phone number                   |
| `caseType`               | Practice area (e.g., "Personal Injury") |
| `incident.date`          | Date of the incident                    |
| `incident.address.state` | State where incident occurred           |
| `incident.synopsis`      | Description of what happened            |

All other fields are optional but recommended for better matching.

***

### ❓ "Can I use the same mapping for different operations?"

**📝 Full Answer:** It depends on the model type:

* **Case mappings** work with all case operations (send, edit, update, settlement)
* **CaseInvitation mappings** work with all invitation operations (accept, decline, etc.)

You can have multiple mappings of the same type for different purposes (e.g., a "full mapping" for new cases and a "minimal mapping" for updates).

***

### ❓ "What happens if my request fails?"

**🔍 Quick Check:**

* ✅ Check the error response for details
* ✅ Common issues: missing required fields, invalid mapping, authentication errors

**📝 Full Answer:** Error responses include details about what went wrong:

```json
{
  "error": "Bad Request",
  "message": "Missing required field: client.phoneNumber",
  "details": {
    "missingFields": ["client.phoneNumber"]
  }
}
```

Common error causes:

* **400 Bad Request**: Missing required fields or invalid data format
* **401 Unauthorized**: Invalid or missing API key
* **404 Not Found**: Invalid organization ID, mapping ID, or case/invitation ID

***

## 🔧 Technical Reference

### Endpoint URL Pattern

All inbound webhook endpoints follow this pattern:

```
POST /organization/{orgId}/inbound-webhooks/{resource}/{mapId}/{action}
```

* `{orgId}` — Your organization ID
* `{resource}` — `case`, `case-invitation`, or file-related
* `{mapId}` — Your mapping ID
* `{action}` — The operation (send, accept, etc.)

### Authentication

Use your **Public Key** via either:

* Query parameter: `?Key=your_public_key`
* Header: `Authorization: Bearer your_public_key`

### Required Fields by Operation

> **🔧 Technical Deep-Dive: Required Field Mappings**
>
> Each operation has specific field requirements. Your mapping must be able to resolve these fields from your request data.
>
> **Send Case (`/case/{mapId}/send`):**
>
> * `client.firstName`, `client.lastName`, `client.phoneNumber`
> * `caseType`, `incident.date`, `incident.address.state`, `incident.synopsis`
>
> **Edit Case (`/case/{mapId}/edit`):**
>
> * `_id` (the case ID to edit)
>
> **Create Update (`/case/{mapId}/update`):**
>
> * `referral` (case ID), `title`, `content`, `type`
>
> **Invitation Operations:**
>
> * Most require just `_id` (invitation ID)
> * Decline also requires `declineReason`
> * Extend requires `expires` (new expiration date)

### Get Available URLs

You can retrieve all inbound webhook URLs for your organization:

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

This returns a list of all endpoints with your organization ID pre-populated.

***

*Last updated: January 2026*
