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.