The CRM

Contacts, companies, deals, interactions and follow-ups, for programs and agents.

All paths are under https://your-workspace.albaticket.com/api/v1. A contact is a person the workspace deals with, a company is an organization (a customer or not), an interaction is what happened with them (a note, a call, a meeting, an email or a task), and a deal is a ticket in a sales project. They are the records the CRM's pages show, so what a program writes here is on those pages at once.

Everything a program does here it does as the member, under the member's CRM permissions: reading needs See the CRM, which a read-only token keeps; creating and changing contacts and companies and logging interactions need Edit the CRM for the company concerned. A member whose CRM role is on single companies reads those companies, their contacts and the interactions about them, and nothing else: the lists leave the rest out and the rest is not found (404). A member the CRM is closed to finds no contact and no company (404) and is refused the lists (403).

Personal data

A contact's details are personal data about somebody who never signed up to anything. A program sees them only as its member does, and is asked to use them for the task in hand: nothing about a contact is written to the server's log, and a member's own details stay {id, name} as everywhere in the API. Recording consent, exporting a contact's data, erasing a contact, merging and importing are not in the API; a person does those on the contact's page. A contact's consent is given in GET /contacts/{id} so that a program can tell whether somebody agreed to be written to.

Contacts

GET /contacts

The contacts the member may see, newest first. All arguments are optional.

Argument
q Words in the name, the job title or an email address
company A company's name or id
stage lead, qualified, customer or former
owner me, or a member by name or id
archived true for the archived contacts instead
limit, offset Up to 100 a page, 20 by default
GET /contacts?q=lee&company=ACME
{
  "contacts": [
    {
      "id": "5d0c…",
      "name": "Ann Lee",
      "job_title": "Buyer",
      "stage": "customer",
      "company": {"id": "6b1d…", "name": "ACME"},
      "owner": {"id": "5f0c…", "name": "Ada Lovelace"},
      "email": "ann@acme.example",
      "archived": false,
      "url": "https://your-workspace.albaticket.com/contacts/5d0c…"
    }
  ],
  "total": 1,
  "limit": 20,
  "offset": 0
}

email is the contact's primary address.

GET /contacts/{id}

One contact: the summary above with emails and phones (each with a label, its type, and primary), postal_addresses (a label, its type, and the address as lines), notes as rich text, source, has_account (the person has an account here, as a helpdesk customer does), created_at, fields (their custom fields that have a value, by the field's name) and consent:

"consent": [
  {"purpose": "marketing_email", "granted": false, "recorded_at": "2026-09-20T08:00:00Z"},
  {"purpose": "newsletter", "granted": true, "recorded_at": "2026-09-01T10:00:00Z"}
]

That is the contact's latest answer for each purpose they were asked about. A purpose that is absent was never asked, which counts as no.

POST /contacts

Needs Edit the CRM for the company, or a workspace CRM role for a contact with no company. Answers 201 with the contact as GET /contacts/{id} gives it.

Field
name Required
job_title
company A company's name or id
stage lead when left out
owner me, or a member by name or id
notes Markdown
email, phone Their first address and number, each made primary
POST /contacts
Content-Type: application/json

{"name": "Bea Holm", "job_title": "CTO", "company": "ACME", "email": "bea@acme.example", "owner": "me"}

An email address belongs to one contact in the workspace, so creating a second contact with an address somebody has is refused with 422. Search first.

PATCH /contacts/{id}

Changes the fields given, any of name, job_title, company, stage, owner and notes, and leaves the rest. A company or owner of null clears it.

POST /contacts/{id}/emails

Adds an address: address (required), label, its type (work, home or other; work when left out), and primary (true makes it their first address). Answers 201 with the contact.

POST /contacts/{id}/phones

Adds a number: number (required, kept as written), label, its type (work, home, mobile or other), and primary. Answers 201 with the contact.

Companies

GET /organizations on the time page lists the same organizations by name for anyone; these endpoints are the CRM's view of them.

GET /companies

The companies the member may see, by name. Arguments, all optional: q (words in the name, the industry or a domain), stage (lead, prospect, customer, former), owner, customers (true for customers only), archived, limit and offset.

{
  "companies": [
    {
      "id": "6b1d…",
      "name": "ACME",
      "domains": ["acme.example"],
      "stage": "customer",
      "industry": "Rockets",
      "size": "51-200",
      "website": "https://acme.example",
      "owner": {"id": "5f0c…", "name": "Ada Lovelace"},
      "customer": true,
      "archived": false,
      "url": "https://your-workspace.albaticket.com/companies/6b1d…"
    }
  ],
  "total": 1,
  "limit": 20,
  "offset": 0
}

GET /companies/{id}

One company, by its id or its name: the summary above with its description, its contacts (as GET /contacts lists them) and its deals, open and closed, each with the ticket's key, summary, status and assignee and the deal's value, currency, expected_close and probability. Only the deals the member may see are listed.

PATCH /companies/{id}

Changes the CRM details given and leaves the rest: name, website, industry, size (1-10, 11-50, 51-200, 201-1000, 1000+), stage, owner, description (Markdown) and domains (a list, which replaces the ones it had). Needs Edit the CRM for the company. A company's billing details, and whether it is a customer, are an administrator's and are not changed here; companies are created in the browser.

Deals

A deal is a ticket in a project of kind sales, so the ticket endpoints find, read, create, change, move and assign it, and POST /boards/{number}/moves moves it along the pipeline. For a deal, a ticket's answer carries deal, for a member who may see the CRM:

"deal": {
  "company": {"id": "6b1d…", "name": "ACME"},
  "value": "12000",
  "currency": "EUR",
  "expected_close": "2026-12-01",
  "probability": "60",
  "lost_reason": null,
  "contacts": [{"id": "5d0c…", "name": "Ann Lee", "role": "champion"}]
}

A value is in its own currency and nothing is ever converted. To set a deal's fields, give fields to POST /tickets or PATCH /tickets/{key}, by key (deal_value, deal_currency, expected_close, probability), and its company with company:

POST /tickets
Content-Type: application/json

{
  "project": "SAL",
  "summary": "ACME renewal",
  "company": "ACME",
  "fields": {"deal_value": "12000", "deal_currency": "EUR", "expected_close": "2026-12-01"}
}

Losing a deal is the transition Lost, which asks why:

POST /tickets/SAL-12/transitions
Content-Type: application/json

{"transition": "Lost", "fields": {"lost_reason": "Price"}}

The people on a deal are read here and changed on the deal's page.

Interactions

GET /interactions

The interactions about one record, newest first. Give one of contact (a contact's id), company (a company's id or name) or ticket (a key: a deal's, or any ticket's). kind (note, call, meeting, email, task) narrows them, and limit and offset page them. An interaction about a ticket is listed only for a member who may see the ticket.

{
  "interactions": [
    {
      "id": "9b1e…",
      "kind": "call",
      "subject": "Went through the terms",
      "body": {"format": "markdown", "text": "They want net 60."},
      "occurred_at": "2026-09-30T08:00:00.000000Z",
      "duration_seconds": 1800,
      "author": {"id": "5f0c…", "name": "Ada Lovelace"},
      "contact": {"id": "5d0c…", "name": "Ann Lee"},
      "company": {"id": "6b1d…", "name": "ACME"},
      "ticket": "SAL-12",
      "due_at": null,
      "assignee": null,
      "done_at": null,
      "email": false,
      "url": "https://your-workspace.albaticket.com/tickets/SAL-12"
    }
  ],
  "limit": 20,
  "offset": 0
}

A call or meeting whose occurred_at is ahead of now is one that is planned. email is true for an interaction with a sent or received message behind it; author is null for a message a contact sent.

POST /interactions

Logs a note, a call, a meeting or a task. Needs Edit the CRM for the company concerned, and for a ticket, the ticket in view. Answers 201 with the interaction.

Field
kind Required: note, call, meeting or task. An email is sent or received, never typed in.
subject Required
body Markdown
contact, company, ticket What it is about: at least one. With a ticket or a company, contact says who it was with: one of that company's contacts or, on a deal, one of its people, whom the member may edit (422 for somebody else's contact, 404 for one the member cannot see). A contact's company is linked by itself.
occurred_at When it happened, or will: with an offset, or a local YYYY-MM-DDTHH:MM with timezone. Now when left out.
duration "30m", "1h 15m"
due_at, assignee For a task, which is a follow-up: when it is due, as occurred_at, and who does it (me, a member's name or id; the member when left out). The assignee is reminded when it comes due.
timezone An IANA name, required with a local time, as on the time page
POST /interactions
Content-Type: application/json

{
  "kind": "task",
  "subject": "Send the proposal",
  "ticket": "SAL-12",
  "contact": "5d0c…",
  "due_at": "2026-10-05T09:00",
  "timezone": "Europe/Berlin"
}

POST /interactions/{id}/complete

Marks a follow-up done, now. Its assignee may, and so may its author and whoever manages the CRM for its company. Answers with the interaction, its done_at set.

GET /follow-ups

The open follow-ups assigned to the member, the soonest due first and those with no due moment last, as {"follow_ups": [...]}. Empty for a member the CRM is closed to.

History

Every change a program makes is in the contact's, the company's or the interaction's history under the member's name, with the token's name beside it, as a ticket's changes are.

What is not here

Sending email to a contact, quotes, the sales reports, changing or deleting an interaction, the people on a deal, creating and archiving companies, merging contacts, and everything on the contact's data: consent, export and erasure.