Skip to main content
All CRM endpoints are under the prefix /api/brands/{brand}/crm/ and authenticate via EF-Access-Key.
The CRM is structured as:
Entity  (e.g. "Leads", "Deals")
  └── Pipeline  (e.g. "Sales Pipeline")
        └── Stage  (e.g. "Prospect", "Qualified", "Closed")
  └── Fields  (custom fields defined per entity)
  └── Entries  (the actual records)

Entity Presets

Before creating a custom entity you can list and apply built-in presets (e.g. Leads, Contacts, Deals) which come pre-configured with pipelines and fields.
GET /api/brands/{brand}/crm/entity-presets
cURL
curl https://app.elasticfunnels.io/api/brands/{brand_id}/crm/entity-presets \
  -H "EF-Access-Key: your_api_key_here"
{
  "presets": [
    { "key": "leads",    "label": "Leads",    "description": "Track inbound leads through a sales process" },
    { "key": "contacts", "label": "Contacts", "description": "Manage contacts and customers" },
    { "key": "deals",    "label": "Deals",    "description": "Deal tracking with revenue stages" }
  ]
}

Entities

Entities define the type of record tracked in the CRM (e.g. “Leads”, “Customers”). Each brand can have multiple entities.

List Entities

GET /api/brands/{brand}/crm/entities
cURL
curl https://app.elasticfunnels.io/api/brands/{brand_id}/crm/entities \
  -H "EF-Access-Key: your_api_key_here"
[
  {
    "id": 1,
    "name": "Leads",
    "slug": "leads",
    "singular_name": "Lead",
    "plural_name": "Leads",
    "icon": "user",
    "color": "#3b82f6",
    "brand_id": 42,
    "pipelines_count": 1,
    "fields_count": 5
  }
]

Get Entity

GET /api/brands/{brand}/crm/entities/{entity}
Returns the entity with its full pipelines (including stages) and fields loaded.
{
  "id": 1,
  "name": "Leads",
  "slug": "leads",
  "pipelines": [
    {
      "id": 1,
      "name": "Sales Pipeline",
      "stages": [
        { "id": 1, "name": "New Lead",   "position": 0, "color": "#94a3b8" },
        { "id": 2, "name": "Contacted",  "position": 1, "color": "#3b82f6" },
        { "id": 3, "name": "Qualified",  "position": 2, "color": "#10b981" },
        { "id": 4, "name": "Closed Won", "position": 3, "color": "#22c55e" }
      ]
    }
  ],
  "fields": [
    { "id": 1, "name": "Email",   "key": "email",   "type": "text" },
    { "id": 2, "name": "Phone",   "key": "phone",   "type": "text" },
    { "id": 3, "name": "Source",  "key": "source",  "type": "select",
      "options": ["Facebook", "Google", "Organic"] }
  ]
}

Create Entity

POST /api/brands/{brand}/crm/entities
name
string
required
Display name (e.g. Leads)
slug
string
required
URL-safe identifier — lowercase alphanumeric, hyphens, underscores (e.g. leads). Must be unique per brand.
singular_name
string
Singular label (e.g. Lead)
plural_name
string
Plural label (e.g. Leads)
icon
string
Icon identifier (max 64 chars)
color
string
Hex color (max 64 chars)
preset
string
Optional preset key from Entity Presets. When set, pre-populates pipelines and fields.
cURL
curl -X POST https://app.elasticfunnels.io/api/brands/{brand_id}/crm/entities \
  -H "EF-Access-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Leads",
    "slug": "leads",
    "singular_name": "Lead",
    "plural_name": "Leads",
    "icon": "user",
    "color": "#3b82f6",
    "preset": "leads"
  }'
{
  "id": 1,
  "name": "Leads",
  "slug": "leads",
  "singular_name": "Lead",
  "plural_name": "Leads",
  "icon": "user",
  "color": "#3b82f6",
  "brand_id": 42,
  "created_at": "2024-12-11T10:00:00.000000Z"
}

Update Entity

PUT /api/brands/{brand}/crm/entities/{entity}
Same fields as Create, all optional on update.

Delete Entity

DELETE /api/brands/{brand}/crm/entities/{entity}

Pipelines

Pipelines belong to an entity and contain an ordered list of stages.

List Pipelines

GET /api/brands/{brand}/crm/entities/{entity}/pipelines

Get Pipeline

GET /api/brands/{brand}/crm/pipelines/{pipeline}

Create Pipeline

POST /api/brands/{brand}/crm/entities/{entity}/pipelines
name
string
required
Pipeline name (e.g. Sales Pipeline)
cURL
curl -X POST https://app.elasticfunnels.io/api/brands/{brand_id}/crm/entities/1/pipelines \
  -H "EF-Access-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"name": "Sales Pipeline"}'
{
  "id": 1,
  "name": "Sales Pipeline",
  "crm_entity_id": 1,
  "brand_id": 42,
  "created_at": "2024-12-11T10:00:00.000000Z"
}

Update Pipeline

PUT /api/brands/{brand}/crm/pipelines/{pipeline}

Delete Pipeline

DELETE /api/brands/{brand}/crm/pipelines/{pipeline}

Stages

Stages belong to a pipeline and represent progress steps (e.g. “Prospect → Qualified → Closed”).

List Stages

GET /api/brands/{brand}/crm/pipelines/{pipeline}/stages

Get Stage

GET /api/brands/{brand}/crm/stages/{stage}

Create Stage

POST /api/brands/{brand}/crm/pipelines/{pipeline}/stages
name
string
required
Stage name (e.g. Qualified)
color
string
Hex color for the stage badge
position
number
Sort order (0-based integer). Use Reorder to batch-update positions.
cURL
curl -X POST https://app.elasticfunnels.io/api/brands/{brand_id}/crm/pipelines/1/stages \
  -H "EF-Access-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"name": "Qualified", "color": "#10b981", "position": 2}'
{
  "id": 3,
  "name": "Qualified",
  "color": "#10b981",
  "position": 2,
  "pipeline_id": 1,
  "created_at": "2024-12-11T10:00:00.000000Z"
}

Update Stage

PUT /api/brands/{brand}/crm/stages/{stage}

Reorder Stages

PUT /api/brands/{brand}/crm/stages/reorder
stages
array
required
Array of {id, position} objects in the desired order.
cURL
curl -X PUT https://app.elasticfunnels.io/api/brands/{brand_id}/crm/stages/reorder \
  -H "EF-Access-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "stages": [
      {"id": 1, "position": 0},
      {"id": 3, "position": 1},
      {"id": 2, "position": 2},
      {"id": 4, "position": 3}
    ]
  }'

Delete Stage

DELETE /api/brands/{brand}/crm/stages/{stage}

Custom Fields

Custom fields define the schema for entry data. Each entity has its own set of fields.

List Fields

GET /api/brands/{brand}/crm/entities/{entity}/fields

Get Field

GET /api/brands/{brand}/crm/fields/{field}

Create Field

POST /api/brands/{brand}/crm/entities/{entity}/fields
name
string
required
Field label (e.g. Email Address)
key
string
required
Slug key used in values on entries (e.g. email). Lowercase alphanumeric + underscores.
type
string
required
Field type: text, number, date, boolean, select, multi_select, url, email, phone
options
array
For select and multi_select types — array of option strings.
required
boolean
Whether this field is required on entry creation (default: false)
position
number
Display order
cURL
curl -X POST https://app.elasticfunnels.io/api/brands/{brand_id}/crm/entities/1/fields \
  -H "EF-Access-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Lead Source",
    "key": "lead_source",
    "type": "select",
    "options": ["Facebook", "Google", "Organic", "Referral"],
    "required": false,
    "position": 2
  }'
{
  "id": 4,
  "name": "Lead Source",
  "key": "lead_source",
  "type": "select",
  "options": ["Facebook", "Google", "Organic", "Referral"],
  "required": false,
  "position": 2,
  "crm_entity_id": 1,
  "created_at": "2024-12-11T10:00:00.000000Z"
}

Update Field

PUT /api/brands/{brand}/crm/fields/{field}

Delete Field

DELETE /api/brands/{brand}/crm/fields/{field}

Entries

Entries are the individual records in a CRM entity (e.g. a single lead or deal). They are stored and queried via Elasticsearch.

List Entries

GET /api/brands/{brand}/crm/entities/{entity}/entries
entity
string
required
Entity ID
per_page
number
Results per page (max 100, default: 25)
page
number
Page number (default: 1)
pipeline_id
number
Filter by pipeline
stage_id
number
Filter by stage
reference_type
string
Filter by external reference type (e.g. conversion, lead)
reference_id
string
Filter by external reference ID
q
string
Full-text search on title
include_customer
boolean
Attach matched customer record to each entry (default: false)
cURL
curl "https://app.elasticfunnels.io/api/brands/{brand_id}/crm/entities/1/entries?pipeline_id=1&stage_id=2&per_page=50" \
  -H "EF-Access-Key: your_api_key_here"
{
  "data": [
    {
      "id": "es-doc-id-abc",
      "title": "Jane Doe",
      "pipeline_id": 1,
      "stage_id": 2,
      "crm_entity_id": 1,
      "brand_id": 42,
      "reference_type": "conversion",
      "reference_id": "conv-123",
      "assigned_to_user_id": null,
      "values": [
        { "key": "email",       "value": "jane@example.com" },
        { "key": "lead_source", "value": "Facebook" }
      ],
      "values_flat": {
        "email": "jane@example.com",
        "lead_source": "Facebook"
      },
      "updated_at": "2024-12-10T14:00:00Z"
    }
  ],
  "current_page": 1,
  "last_page": 4,
  "per_page": 25,
  "total": 87
}

Get Entry

GET /api/brands/{brand}/crm/entries/{entry}
GET /api/brands/{brand}/crm/entities/{entity}/entries/{entry}

Create Entry

POST /api/brands/{brand}/crm/entities/{entity}/entries
title
string
required
Human-readable label for the entry (e.g. the lead’s name or email)
pipeline_id
number
required
ID of the pipeline this entry belongs to
stage_id
number
required
ID of the initial stage
values
object
Flat key-value object of custom field values (e.g. {"email": "jane@example.com", "lead_source": "Facebook"}). Keys must match a defined field key on the entity.
reference_id
string
External ID to link the entry to another record (e.g. a conversion ID)
reference_type
string
Type of external reference (e.g. conversion, lead, order)
assigned_to_user_id
number
Assign to a specific team member by user ID
assigned_to_team_id
number
Assign to a CRM team by team ID
cURL
curl -X POST https://app.elasticfunnels.io/api/brands/{brand_id}/crm/entities/1/entries \
  -H "EF-Access-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Jane Doe",
    "pipeline_id": 1,
    "stage_id": 1,
    "reference_type": "conversion",
    "reference_id": "conv-123",
    "values": {
      "email": "jane@example.com",
      "phone": "+15551234567",
      "lead_source": "Facebook"
    }
  }'
Python
import requests

r = requests.post(
    'https://app.elasticfunnels.io/api/brands/{brand_id}/crm/entities/1/entries',
    headers={'EF-Access-Key': 'your_api_key_here', 'Content-Type': 'application/json'},
    json={
        'title': 'Jane Doe',
        'pipeline_id': 1,
        'stage_id': 1,
        'reference_type': 'conversion',
        'reference_id': 'conv-123',
        'values': {
            'email': 'jane@example.com',
            'lead_source': 'Facebook',
        },
    },
)
entry = r.json()
print(entry['id'])
{
  "id": "es-doc-id-xyz",
  "title": "Jane Doe",
  "pipeline_id": 1,
  "stage_id": 1,
  "crm_entity_id": 1,
  "brand_id": 42,
  "reference_type": "conversion",
  "reference_id": "conv-123",
  "values": [
    { "key": "email",       "value": "jane@example.com" },
    { "key": "lead_source", "value": "Facebook" }
  ],
  "values_flat": {
    "email": "jane@example.com",
    "lead_source": "Facebook"
  },
  "created_at": "2024-12-11T10:00:00Z",
  "updated_at": "2024-12-11T10:00:00Z"
}

Update Entry

PUT /api/brands/{brand}/crm/entries/{entry}
PUT /api/brands/{brand}/crm/entities/{entity}/entries/{entry}
Same body as Create. All fields optional — only provided fields are updated.
cURL — update values and reassign
curl -X PUT https://app.elasticfunnels.io/api/brands/{brand_id}/crm/entries/es-doc-id-xyz \
  -H "EF-Access-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "values": { "lead_source": "Google", "phone": "+15559876543" },
    "assigned_to_user_id": 7
  }'

Move Entry to Stage

Move an entry to a different stage within the same pipeline.
PUT /api/brands/{brand}/crm/entries/{entry}/stage
PUT /api/brands/{brand}/crm/entities/{entity}/entries/{entry}/stage
stage_id
number
required
Target stage ID (must belong to the entry’s current pipeline)
cURL
curl -X PUT https://app.elasticfunnels.io/api/brands/{brand_id}/crm/entries/es-doc-id-xyz/stage \
  -H "EF-Access-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"stage_id": 3}'
{
  "id": "es-doc-id-xyz",
  "stage_id": 3,
  "updated_at": "2024-12-11T10:05:00Z"
}

Delete Entry

DELETE /api/brands/{brand}/crm/entries/{entry}
DELETE /api/brands/{brand}/crm/entities/{entity}/entries/{entry}

Automation: Create CRM Entry from Conversion

A common pattern is creating a CRM entry whenever a conversion is recorded. Using the EF automation pipeline or an external webhook:
Python
import requests

BRAND_ID = 42
API_KEY = "your_api_key_here"
BASE = f"https://app.elasticfunnels.io/api/brands/{BRAND_ID}/crm"
H = {"EF-Access-Key": API_KEY, "Content-Type": "application/json"}

def create_lead_from_conversion(conversion: dict) -> dict:
    """Create a CRM entry from a conversion webhook payload."""
    return requests.post(
        f"{BASE}/entities/1/entries",
        headers=H,
        json={
            "title": f"{conversion['first_name']} {conversion['last_name']}",
            "pipeline_id": 1,
            "stage_id": 1,   # "New Lead"
            "reference_type": "conversion",
            "reference_id": str(conversion["id"]),
            "values": {
                "email":       conversion.get("email"),
                "phone":       conversion.get("phone"),
                "lead_source": conversion.get("utm_source", "unknown"),
            },
        },
    ).json()