Leads API

The Leads API is representative of every entity endpoint in BottleCRM — same shape, same conventions. Once you know this one, Contacts / Accounts / Opportunities / Tasks all behave identically.

Base URL

https://<your-host>/api/leads/

All requests require a valid bearer token (see Authentication).

List leads

GET /api/leads/
Authorization: Bearer <token>

Response:

{
  "count": 142,
  "next": "https://…/api/leads/?page=2",
  "previous": null,
  "results": [
    {
      "id": "ab12-cd34-…",
      "title": "Acme renewal interest",
      "first_name": "Jane",
      "last_name": "Doe",
      "email": "jane@acme.com",
      "status": "qualified",
      "source": "website_form",
      "assigned_to": { "id": "…", "email": "rep@yours.com" },
      "custom_fields": { "industry": "saas" },
      "created_at": "2026-04-01T10:14:33Z"
    }
  ]
}

Filtering

GET /api/leads/?status=qualified&source=website_form
GET /api/leads/?search=acme
GET /api/leads/?assigned_to=<profile_id>
GET /api/leads/?cf_industry=saas               # custom field filter
GET /api/leads/?ordering=-created_at

Filterable fields: status, source, assigned_to, tags, created_at__gte, created_at__lte, plus any custom field marked filterable.

Create a lead

POST /api/leads/
Content-Type: application/json
Authorization: Bearer <token>

{
  "title": "Acme renewal interest",
  "first_name": "Jane",
  "last_name": "Doe",
  "email": "jane@acme.com",
  "phone": "+1 555 1234",
  "status": "new",
  "source": "website_form",
  "custom_fields": { "industry": "saas", "bant_score": 72 }
}

201 Created returns the full record. Server-derived fields — org, created_by, id, created_at — must not be in the request body; they are populated by the view.

Retrieve / update / delete

GET    /api/leads/<id>/
PATCH  /api/leads/<id>/      # partial update — only fields in the body change
PUT    /api/leads/<id>/      # full update
DELETE /api/leads/<id>/      # soft-deletes

The detail GET response also includes custom_field_definitions so the frontend can render the right form fields without a second round-trip.

Convert a lead

POST /api/leads/<id>/convert/
{
  "account_name": "Acme Corp",
  "create_opportunity": true,
  "opportunity_name": "Acme — Annual 2026",
  "amount": 24000
}

The convert endpoint creates an Account, a Contact, and (optionally) an Opportunity in a single transaction, links them, and marks the lead as converted. If any step fails, the whole operation rolls back.

Bulk CSV upload

POST /api/leads/upload/
Content-Type: multipart/form-data

file=<leads.csv>

Response contains created, updated, and errors arrays — one entry per CSV row. The endpoint de-duplicates on email within the org.

Errors

Status Meaning
400 Validation failed. Body: { "errors": { "field": "reason" } }
401 Missing or invalid token
403 Authenticated but not authorized for this record/role
404 Record does not exist or belongs to another org
429 Rate limit exceeded

See Errors for the full structure.