Skip to content

Accounts API

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

List

GET /api/accounts/?industry=software&search=acme
Authorization: Bearer <token>
{
  "count": 122,
  "next": "https://…/api/accounts/?page=2",
  "previous": null,
  "results": [
    {
      "id": "a001-…",
      "name": "Acme Corp",
      "industry": "software",
      "website": "https://acme.com",
      "annual_revenue": "12000000.00",
      "employees": 240,
      "parent": null,
      "owner": { "id": "u034-…", "email": "rep@yours.com" },
      "billing_address": {
        "street": "1 Main St",
        "city": "San Francisco",
        "state": "CA",
        "postcode": "94105",
        "country": "US"
      },
      "tags": ["enterprise", "west-coast"],
      "custom_fields": { "abm_tier": "gold", "arr": 240000 },
      "created_at": "2026-01-08T14:11:30Z"
    }
  ]
}

Filterable fields: industry, owner, tags, parent, search (name + website + email domain), cf_<key>.

Create

POST /api/accounts/
Content-Type: application/json

{
  "name": "Acme Corp",
  "industry": "software",
  "website": "https://acme.com",
  "annual_revenue": "12000000",
  "employees": 240,
  "billing_address": {
    "street": "1 Main St",
    "city": "San Francisco",
    "state": "CA",
    "postcode": "94105",
    "country": "US"
  },
  "tags": ["enterprise"],
  "custom_fields": { "abm_tier": "gold" }
}

Detail

GET /api/accounts/<id>/

Returns the account plus contacts, opportunities, recent activities, and custom_field_definitions for the entity. Everything the detail page needs in a single round-trip.

Update / delete

PATCH  /api/accounts/<id>/
PUT    /api/accounts/<id>/
DELETE /api/accounts/<id>/

DELETE is a hard delete. There is no deletion log and nothing to restore from, so take a database backup rather than relying on the application to keep a copy.

What accounts do not do

Two things this page used to document do not exist, and no endpoint serves them:

  • No hierarchy. Account has no parent field, so holding companies and subsidiaries are not modelled and there is no subtree to walk.
  • No roll-up. Nothing aggregates revenue or ticket counts across a group of accounts.

The full account surface is list, detail, a mail action, comments, attachments, and duplicates.

Duplicates and merging

POST /api/accounts/duplicates/                {"name": ..., "email": ..., "phone": ..., "website": ...}
GET  /api/accounts/<id>/duplicates/
POST /api/accounts/<keeper id>/merge/     {"merge_id": "<id merged away>"}

The check (a POST that writes nothing, so an email or phone never sits in a URL or an access log; from django-crm 1.13.0 an API token needs only accounts:read for it) and the record GET answer up to ten accounts you can open, each with only id, name, email, phone, matched_on and can_delete. Names match once case, punctuation, a leading "The" and a legal suffix ("Inc", "Ltd", "LLC") are set aside; websites match on the host.

The merge needs both accounts readable (either one hidden or missing is 404) and the right to delete the one merged away (an admin or its creator, else 403). The kept account's values win and its blank fields are filled from the other; contacts, deals, tickets, orders, invoices, estimates, recurring invoices and tasks move across; the other account is deleted, with an account.deleted webhook (its assigned_to lists the owners the merged account had, even those the merge moved to the kept one) and an audit-log entry. Merging an account into itself, or a malformed merge_id, is 400.