Custom fields

Custom fields let an organization extend any supported entity with schema it controls — without touching the codebase. Admins create field definitions in the settings UI; the new fields immediately become available on detail pages, in list filters, and through the JSON API.

Supported entities

Entity Use cases
Lead Industry vertical, lead source detail, BANT scoring
Contact LinkedIn URL, preferred channel, DOB
Account ABM tier, ARR, renewal date
Opportunity Competitor, expected delivery date
Task Estimated hours, billable flag
Case (Ticket) Severity, SLA, escalation level
Invoice / Estimate / RecurringInvoice PO number, tax exemption ID, payment terms

Field types

  • text — single-line string.
  • textarea — multi-line string.
  • number — integer or float.
  • checkbox — boolean.
  • date — ISO YYYY-MM-DD.
  • dropdown — pick from an admin-defined [ { value, label } ] list.

Creating a field

In the web app:

  1. Go to Settings → Custom fields.
  2. Pick the entity (e.g. Leads).
  3. Click Add field and choose a key, label, type, and whether it is required or filterable.

A key is the JSON property name — it must match ^[a-z][a-z0-9_]*$ and is immutable once created. You can rename the label freely.

Reading and writing values

Every entity that supports custom fields exposes a custom_fields JSON object on its read serializer. For example, a lead with two custom fields:

{
  "id": "ab12…",
  "title": "Acme renewal interest",
  "status": "qualified",
  "custom_fields": {
    "industry": "saas",
    "bant_score": 72
  }
}

To write values, include the same object in your POST or PATCH body. The backend validates every value against the org's active definitions:

  • Unknown keys are dropped silently and logged.
  • Dropdown values must match one of the allowed values.
  • Required fields error out if neither the request nor the existing record carries a value.

Soft delete preserves history

When you delete a field definition, BottleCRM deactivates it instead of dropping the data. Existing records keep their values, but new writes for that key are rejected as unknown. Reactivate the definition any time and the data is back.

Filtering by custom fields

If a field is marked filterable, the list endpoint accepts cf_<key>=<value> query parameters:

GET /api/leads/?cf_industry=saas&cf_bant_score__gte=50

On the web app, those filters appear automatically in the list view's filter drawer.