Connect your systems to Harmoniq to read and update employee records, units, leave, performance, training and other company data. The API uses JSON over HTTPS, with separate keys for each system and permissions for each resource.
As a company owner or admin, open Access → API keys and choose New key.
Name the key after the system that will use it. Grant only the read or write permissions it needs and, where possible, restrict access to the system’s IP addresses.
Copy the key: it is shown once. Harmoniq keeps only a fingerprint of it.
Call your company’s address with the key in the Authorization header.
Send the key in the Authorization header as a Bearer token. A key works only at its own company’s address. It can expire, be suspended and resumed, or revoked at any time; it can be limited to IP addresses or ranges. Changes are recorded under the name of the person who created the key. If they lose permission to manage API keys, the key retains read access but can no longer write data.
Authorization: Bearer hq_12_••••••••
Scopes
For each resource, a key can have read ({resource}:read) and write ({resource}:write) permissions. These apply to data across the whole company. Two additional scopes are available: sensitive, for reading and writing custom fields marked as sensitive, and metrics:write, for sending KPI values using business references.
Requests and responses
Requests and responses use JSON with UTF-8 encoding. Include Content-Type: application/json when sending a request body.
Use YYYY-MM-DD for dates and ISO 8601 for timestamps. Responses use UTC, for example 2026-05-01T08:00:00Z.
A single record is returned as {"data": {…}}; a list as {"data": […], "meta": {page, per_page, total, last_page}, "links": {next, prev}}.
Lists: page (from 1), per_page (25 by default, at most 100), sort (id, created_at, updated_at; a minus for descending), updated_since (records modified after a given timestamp, for synchronisation), plus each resource’s filters.
Create records with POST and update them with PATCH, sending only the changed fields. DELETE returns 204. Requests containing fields that cannot be written are rejected.
Write operations are atomic: all changes are saved together, or none are saved.
GET https://compania-mea.harmoniq.ro/api/v1/employees?status=active&updated_since=2026-05-01T00:00:00Z&page=2
Errors
Errors are returned as {"error": "<code>", "message": "<text>"}. Invalid data returns status 422 with details in "errors" for each affected field.
Status
Code
Meaning
401
invalid_token
The key is missing, unknown or belongs to another company.
403
token_inactive
The key is suspended or expired.
403
insufficient_scope
The key lacks the scope required for this operation.
403
ip_not_allowed
The key does not accept calls from this address.
403
token_owner_inactive
The key’s creator may no longer manage keys: it reads, but does not write.
404
—
No such resource or record in your company (or not in your plan).
405
—
The resource does not offer this operation.
409
in_use
The record is still used elsewhere and cannot be deleted.
422
—
Invalid data; nothing was saved.
429
—
Too many requests; try again after Retry-After seconds.
Limits
The limit is 120 requests per minute per key and 300 per IP address. Exceeding it returns status 429. The Retry-After header specifies how long to wait before trying again.
Versions
The current version is 1 (/api/v1). New resources, fields and filters are added to this version. Incompatible changes will be introduced in a new version, announced in advance.
Personal data
The CNP (Romanian personal numeric code) cannot be read or written through the API.
Access to sensitive custom fields requires the sensitive scope.
Anonymous survey results are available only as totals. They remain unavailable while responses are sealed or too few to protect participants’ anonymity.
The API log retains the key, endpoint, response status and duration for 30 days, without the request or response content. Recent calls are available in Access → API keys.
Pushing KPI values
Systems that only send KPI values (sales, reviews, counts) can do it by business reference instead of ids: POST /api/v1/metrics/{key}/values with a period and the values for employees (by employee number), units or departments (by code). Needs the metrics:write scope; GET /api/v1/metrics lists the metrics that accept them.
The tree of countries, regions and zones the units belong to; it also sets area managers’ reach. Names are unique among siblings. Deleting one is refused while units or sub-areas use it.
Scopes: geo_areas:read, geo_areas:write
Endpoints
GET/api/v1/geo-areasList
GET/api/v1/geo-areas/{id}One record
POST/api/v1/geo-areasCreate
PATCH/api/v1/geo-areas/{id}Change
DELETE/api/v1/geo-areas/{id}Delete
Fields
Name
Type
Description
id
integerread only
Identifier.
name
stringrequired
Name, unique among the areas with the same parent.
level_label
string | null
What this level is called (country, region, zone).
parent_id
integer | null
The area it sits in; null for a top-level area. Never itself or one of its own sub-areas.
The fields the company added to its own records, read only: what each id in a record’s custom_fields means, its type and choices. Sensitive employee fields are listed only for a key with the sensitive scope. Fields are defined in the app.
Scopes: custom_fields:read
Endpoints
GET/api/v1/custom-fieldsList
GET/api/v1/custom-fields/{id}One record
Fields
Name
Type
Description
id
integerread only
Identifier; the key in a record’s custom_fields.
entity
employee | work_unit | department | position | team | companyread only
The kind of record it belongs to.
label
stringread only
Its name, in the language of the request (Accept-Language).
type
text | textarea | number | date | boolean | select | multiselect | urlread only
What it holds: text, textarea, number, date (Y-m-d), boolean, select, multiselect or url.
options
array | nullread only
The choices of a select or multiselect: id and label; the value stored is the id.
is_required
booleanread only
Whether a value is required.
visibility
reach | sensitiveread only
reach (everyone who sees the employee) or sensitive.
is_active
booleanread only
Whether it is in use.
created_at
datetimeread only
Created.
updated_at
datetimeread only
Last changed.
Filters
entity
employee | work_unit | department | position | team | company
The company’s people. Creating one also creates their first placement; later moves go through /placements. The CNP (personal numeric code) is never read or written through the API. Logins are created in the app.
Scopes: employees:read, employees:write
Endpoints
GET/api/v1/employeesList
GET/api/v1/employees/{id}One record
POST/api/v1/employeesCreate
PATCH/api/v1/employees/{id}Change
DELETE/api/v1/employees/{id}Delete
Fields
Name
Type
Description
id
integerread only
Identifier.
employee_number
string | null
Your employee number, unique in the company (used to match KPI values).
first_name
stringrequired
First name.
last_name
stringrequired
Last name.
email
string | null
Work email.
phone
string | null
Phone.
birth_date
date | null
Date of birth.
hire_date
date | null
Hire date (the first placement starts on it).
termination_date
date | null
Leaving date.
status
active | inactive | terminated
active, inactive or terminated.
work_unit_id
integerrequired
Unit of the current main placement; required on create, read-only after.
department_id
integer | null
Department of the current main placement (create only).
position_id
integer | null
Position of the current main placement (create only).
has_login
booleanread only
Whether the person can sign in.
custom_fields
object
The company’s own fields, by field id; sensitive ones only with the sensitive scope.
Where each person works: unit, department and position, from when to when. A new main placement takes over from the previous one, which stays as a current secondary placement until it is ended.
Scopes: placements:read, placements:write
Endpoints
GET/api/v1/placementsList
GET/api/v1/placements/{id}One record
POST/api/v1/placementsCreate
DELETE/api/v1/placements/{id}Delete
POST/api/v1/placements/{id}/endEnds the placement on valid_to (not before it began).
POST/api/v1/placements/{id}/make-primaryMakes it the person’s main placement; the previous main one becomes secondary.
Fields
Name
Type
Description
id
integerread only
Identifier.
employee_id
integerrequired
The person.
work_unit_id
integerrequired
The unit.
department_id
integer | null
The department.
position_id
integer | null
The position.
is_primary
boolean
Whether it is the person’s main placement.
valid_from
daterequired
First day.
valid_to
date | null
Last day (empty: still current).
created_at
datetimeread only
Created.
updated_at
datetimeread only
Last changed.
Filters
employee_id
integer
Only this person’s.
work_unit_id
integer
Only in this unit.
current
boolean
true: only placements in force today.
/api/v1/placements/{id}/end: valid_to (date) — The last day of the placement (Y-m-d).
Leave requests, through the same rules as the app: the working days are counted, the balance and overlapping requests are checked, and the company’s approval flow starts. Approving and rejecting follow the request’s flow: the key’s creator must be an approver of the current step.
Scopes: leave_requests:read, leave_requests:write
Endpoints
GET/api/v1/leave-requestsList
GET/api/v1/leave-requests/{id}One record
POST/api/v1/leave-requestsCreate
POST/api/v1/leave-requests/{id}/approveApproves the current step (comment optional).
POST/api/v1/leave-requests/{id}/rejectRejects the request; comment (the reason) required.
POST/api/v1/leave-requests/{id}/cancelCancels a pending or approved request.
Fields
Name
Type
Description
id
integerread only
Identifier.
employee_id
integerrequired
The person on leave.
leave_type_id
integerrequired
The kind of leave.
starts_on
daterequired
First day.
ends_on
daterequired
Last day.
days
numberread only
Days counted (working days, holidays excluded).
status
pending | approved | rejected | cancelledread only
pending, approved, rejected or cancelled.
replacement_employee_id
integer | null
The colleague who covers.
reference
string | null
Reference number (for example a medical certificate).
note
text | null
Note.
created_at
datetimeread only
Filed.
updated_at
datetimeread only
Last changed.
Filters
employee_id
integer
Only this person’s.
status
pending | approved | rejected | cancelled
Only with this status.
from
date
Touching this day or later.
to
date
Touching this day or earlier.
/api/v1/leave-requests/{id}/approve: comment (text) — Optional comment for the person.
/api/v1/leave-requests/{id}/reject: comment (text) — The reason, shown to the person (required).
Each person’s yearly balance per leave type that counts days. Listing a year opens it for every active person, pro rata and with carry-over, as the app does; used, pending and available are computed. The entitlement, adjustment and carry-over can be changed — never for the key creator’s own record.
Scopes: leave_balances:read, leave_balances:write
Endpoints
GET/api/v1/leave-balancesList
GET/api/v1/leave-balances/{id}One record
PATCH/api/v1/leave-balances/{id}Change
Fields
Name
Type
Description
id
integerread only
Identifier.
employee_id
integerread only
The person.
leave_type_id
integerread only
The leave type.
year
integerread only
The year.
entitlement
number
Days for the year (0–365).
adjustment
number
Days added or taken (−365–365).
carried_over
number
Days carried over from last year.
carried_over_expires_on
date | null
Until when the carried days can be used.
carried_usable
numberread only
Carried days still usable today.
earlier
numberread only
Days still left from the years before the previous one, usable today.
earlier_expires_on
date | nullread only
Until when the earliest of those days can be taken.
The company calendar. Participants (or the unit) are notified of a new event, a new time or a new place. A new event may repeat: each occurrence becomes its own event in one series and is changed, cancelled or deleted on its own.
What the company measures: each metric’s key, unit, the subjects it is measured for (grain) and how often (period). Read only; metrics are defined in the app. Values can be sent through the API only to metrics whose source is “api”.
Scopes: kpi_metrics:read
Endpoints
GET/api/v1/kpi-metricsList
GET/api/v1/kpi-metrics/{id}One record
Fields
Name
Type
Description
id
integerread only
Identifier.
key
stringread only
The metric’s key, used in formulas and when sending values.
label
stringread only
Name, in the company’s language.
description
string | nullread only
What it measures.
unit
currency | percent | count | score | days | hours | ratioread only
Unit: currency, percent, count, score, days, hours or ratio.
value_type
decimal | integer | percent | booleanread only
Kind of value: decimal, integer, percent or boolean.
grain
employee | team | department | work_unit | geo_area | companyread only
Whom it is measured for: employee, team, department, work_unit, geo_area or company.
period
day | week | month | quarter | yearread only
How often: day, week, month, quarter or year.
aggregation
sum | avg | last | min | max | countread only
How values add up over a longer period.
source_type
manual | import | module | derived | api | objective | reviewread only
Where its values come from (manual, import, api, a module…).
The value of a metric for one subject in one period. Creating one writes it (or replaces the value already there for that subject and period); only metrics whose source is “api” accept values. A missing value (null) means “no data”, never zero. To send many values by business reference (employee number, unit code) use POST /metrics/{key}/values.
Scopes: metric_values:read, metric_values:write
Endpoints
GET/api/v1/metric-valuesList
GET/api/v1/metric-values/{id}One record
POST/api/v1/metric-valuesCreate
Fields
Name
Type
Description
id
integerread only
Identifier.
metric
stringrequired
The metric’s key.
subject_type
employee | team | department | work_unit | geo_area | companyread only
The kind of subject (the metric’s grain).
subject_id
integerrequired
The subject’s id (an employee, unit, department, area or team id; 0 for the company).
Scorecards and every version of them (draft, published, archived): the parts a score is made of, their weights, and the levels a score falls into. Read only; scorecards are built in the app, and a published version never changes.
Scopes: kpi_scorecards:read
Endpoints
GET/api/v1/kpi-scorecardsList
GET/api/v1/kpi-scorecards/{id}One record
Fields
Name
Type
Description
id
integerread only
Identifier of this version.
family
stringread only
The scorecard across its versions.
version
integerread only
Version number.
name
stringread only
Name.
description
string | nullread only
Description.
grain
employee | team | department | work_unit | geo_area | companyread only
Whom it scores.
period
day | week | month | quarter | yearread only
How often it scores.
status
draft | published | archivedread only
draft, published or archived.
effective_from
date | nullread only
In force from.
effective_to
date | nullread only
In force until.
published_at
datetime | nullread only
When this version was published.
components
arrayread only
Its parts: key, label, weight (0–1), target, display format, whether the employee sees it.
levels
arrayread only
Its levels: name, the lowest score that reaches it, colour.
Scores on the scorecards: the current result of each subject and period, the level it reaches, and each part’s value and points. A total or part without data is null, never zero. Read only; results are produced when a period is closed.
Scopes: kpi_results:read
Endpoints
GET/api/v1/kpi-resultsList
GET/api/v1/kpi-results/{id}One record
Fields
Name
Type
Description
id
integerread only
Identifier.
scorecard_id
integerread only
The scorecard version that scored it.
scorecard
stringread only
Its name.
subject_type
employee | team | department | work_unit | geo_area | companyread only
The kind of subject.
subject_id
integerread only
The subject’s id.
subject
string | nullread only
The subject’s name.
period
dateread only
First day of the period.
total
string | nullread only
The score, as a decimal string; null when there is no data.
level
string | nullread only
The level reached.
level_color
string | nullread only
The level’s colour.
bonus
string | nullread only
The bonus, when the scorecard computes one.
parts
arrayread only
Each part: key, label, value and the points it brings (decimal strings; null for no data).
created_at
datetimeread only
When it was computed.
Filters
scorecard_id
integer
Only this scorecard version.
period
date
First day of the period (Y-m-d).
subject_type
employee | team | department | work_unit | geo_area | company
Objectives under a rule (for example “focus products”): their period, parameters and unit targets. The rule and period are fixed once created. The record action stores what people or units achieved; they are scored when the period is scored. An objective already scored cannot be deleted.
Scopes: objectives:read, objectives:write
Endpoints
GET/api/v1/objectivesList
GET/api/v1/objectives/{id}One record
POST/api/v1/objectivesCreate
PATCH/api/v1/objectives/{id}Change
DELETE/api/v1/objectives/{id}Delete
POST/api/v1/objectives/{id}/recordRecord what subjects achieved: their measures replace what was recorded before; empty measures forget it (no data again).
Fields
Name
Type
Description
id
integerread only
Identifier.
rule_id
integerrequired
The rule that scores it (create only).
rule
stringread only
The rule’s name.
name
stringrequired
Name.
description
text | null
Description.
period
stringrequired
The period’s key, in the rule’s period (create only), for example 2026-09.
period_start
dateread only
First day.
period_end
dateread only
Last day.
params
object
Values for the rule’s parameters, by name (others are ignored); omitted: the rule’s defaults.
targets
array
Unit targets: a list of {work_unit_id, target}. When there are targets, the objective is only for those units.
external_ref
string | null
Your own reference (create only).
created_at
datetimeread only
Created.
updated_at
datetimeread only
Last changed.
Filters
rule_id
integer
Only under this rule.
period_start
date
First day of the period (Y-m-d).
external_ref
string
Your exact reference.
/api/v1/objectives/{id}/record: achievements (array) — A list of {subject_id, measures: {measure name: number}}; subjects at the rule’s grain, in the target units.
Evaluations given on the grids: whom, by whom, for which period, the points and result, and each criterion’s answer. Read only; evaluations are given in the app. Drafts are the evaluator’s work in progress and are never listed.
Scopes: reviews:read
Endpoints
GET/api/v1/reviewsList
GET/api/v1/reviews/{id}One record
Fields
Name
Type
Description
id
integerread only
Identifier.
form_id
integerread only
The grid version.
form
stringread only
The grid’s name.
employee_id
integerread only
The person evaluated.
evaluator_id
integer | nullread only
The login of who evaluated.
period_start
dateread only
First day of the period.
period_end
dateread only
Last day.
status
submitted | cancelledread only
submitted or cancelled.
total_points
string | nullread only
Points obtained.
max_points
string | nullread only
Points possible.
result
string | nullread only
The result (points, or a percentage when the grid gives one).
comment
text | nullread only
The evaluator’s comment, as plain text.
submitted_at
datetime | nullread only
When it was submitted.
cancelled_at
datetime | nullread only
When it was cancelled.
answers
arrayread only
Each criterion: key, the options chosen, a value, its points and a comment.
The course catalogue. Title and description are written in the company’s language (other languages are translated in the app); chapters and covers are written in the app. A course can be deleted only while nobody was ever assigned it — archive it otherwise.
Scopes: courses:read, courses:write
Endpoints
GET/api/v1/coursesList
GET/api/v1/courses/{id}One record
POST/api/v1/coursesCreate
PATCH/api/v1/courses/{id}Change
DELETE/api/v1/courses/{id}Delete
Fields
Name
Type
Description
id
integerread only
Identifier.
title
stringrequired
Title.
description
text | null
Short description, plain text.
category_id
integer | null
Category.
category
string | nullread only
Category name.
author
string | null
Author.
status
draft | published | archivedrequired
draft, published or archived; only published courses can be assigned.
estimated_minutes
integer | null
Estimated duration in minutes.
validity_months
integer | null
How many months the certificate stays valid; empty: no expiry.
issues_certificate
boolean
Whether finishing it issues a certificate.
recertifies
boolean
Whether people are re-enrolled before the certificate expires.
points
integerrequired
Points earned on finishing.
chapters_count
integerread only
Number of chapters.
created_at
datetimeread only
Created.
updated_at
datetimeread only
Last changed.
Filters
status
draft | published | archived
Only with this status.
category_id
integer
Only in this category.
q
string
Part of the title.
Example request
POST https://compania-mea.harmoniq.ro/api/v1/courses
{
"title": "Siguranța la incendiu",
"status": "published",
"estimated_minutes": 20,
"validity_months": 12,
"issues_certificate": true,
"recertifies": false,
"points": 10
}
A published course (or a standalone test) given to people: everyone, a unit, an area, a department, a position or named employees. The people are enrolled at once. Deleted only while nobody has started.
Permits, contracts and rules, with their expiry. The API reads a document’s details and its current file’s name, size and type; the file itself is downloaded in the app. A file is sent as {"name", "content_base64"} (the same types as in the app — PDF, Office, images, ZIP — at most 50 MB); sending a file to an existing document adds a new version. Deleting moves the document to the trash, where it can be restored in the app.
Scopes: documents:read, documents:write
Endpoints
GET/api/v1/documentsList
GET/api/v1/documents/{id}One record
POST/api/v1/documentsCreate
PATCH/api/v1/documents/{id}Change
DELETE/api/v1/documents/{id}Delete
Fields
Name
Type
Description
id
integerread only
Identifier.
title
stringrequired
Title.
description
text | null
Description.
category_id
integer | null
Category (see /document-categories).
work_unit_id
integer | null
The unit it belongs to; empty for a company document. Set on create only.
is_internal
boolean
Seen only by who manages documents.
expires_on
date | null
Expiry date.
expiry_state
valid | expiring | expired | nullread only
valid, expiring or expired (empty without an expiry date).
repeat_months
integer | null
Renewed every this many months.
alert_days
array | null
Days before expiry when reminders go out (at most 6).
versions
integerread only
How many versions of the file there are.
file_name
string | nullread only
The current file’s name.
file_size
integer | nullread only
Its size in bytes.
file_mime
string | nullread only
Its type.
file
filerequired
The file: {"name": "…", "content_base64": "…"}. Required on create; on update it adds a version.
version_note
string | null
A note on the file’s version (shown: the current version’s).
created_at
datetimeread only
Created.
updated_at
datetimeread only
Last changed.
Filters
work_unit_id
integer
Only this unit’s documents.
category_id
integer
Only this category.
company
boolean
true: company documents only; false: unit documents only.
Requests to fix or provide something in a unit, with their history. Filed for the person given in requested_by (who must be able to file requests for that unit), or for the key’s creator; the category’s approval flow applies. Moved along with the move action, as the key’s creator may on the screen.
POST/api/v1/service-requests/{id}/moveMove the request to another status (in_progress, resolved, unresolved, open, cancelled), as the key’s creator may. Unresolved and reopening need a comment.
Fields
Name
Type
Description
id
integerread only
Identifier.
category_id
integerrequired
Category (see /service-categories).
work_unit_id
integerrequired
The unit it is for.
title
stringrequired
Short title.
description
textrequired
What is wrong or needed.
requested_by
integer
The user it is filed for (a person of the company); the key’s creator when left out.
employee_id
integerread only
The employee record of who filed it.
status
awaiting_approval | open | in_progress | resolved | unresolved | rejected | cancelledread only
awaiting_approval, open, in_progress, resolved, unresolved, rejected or cancelled.
/api/v1/service-requests/{id}/move: status (awaiting_approval | open | in_progress | resolved | unresolved | rejected | cancelled) — The new status.; comment (text) — Why (required for unresolved and when reopening).
Example request
POST https://compania-mea.harmoniq.ro/api/v1/service-requests
{
"category_id": 2,
"work_unit_id": 12,
"title": "Frigiderul de vaccinuri nu mai răcește",
"description": "text",
"requested_by": 17
}
Requests for materials, with their items. Filed for the person in requested_by (or the key’s creator), for an active material and a unit they may file for; then taken, completed (which takes the stock out) or cancelled, as the key’s creator may on the screen.
Published and closed surveys with their questions, and their results as totals only: how many chose each answer, a scale’s average, and how many answered a free-text question — never what they wrote. An anonymous survey’s results stay hidden while its answers are sealed and while it has fewer than 5 answers.
Scopes: surveys:read
Endpoints
GET/api/v1/surveysList
GET/api/v1/surveys/{id}One record
Fields
Name
Type
Description
id
integerread only
Identifier.
title
stringread only
Title.
description
text | nullread only
Description.
is_anonymous
booleanread only
Whether answers are anonymous.
is_mandatory
booleanread only
Whether answering is mandatory.
status
published | closedread only
published or closed.
opens_at
datetime | nullread only
When it opens.
closes_at
datetime | nullread only
When it closes.
published_at
datetime | nullread only
When it was published.
questions
arrayread only
The questions: id, type (single, multiple, scale, text), text, required, options.
results
objectread only
Totals: hidden, sealed, responses, assigned, completed, and per question how many answered, counts per option or scale value, the average.
Answers to named surveys, one response per person with its answers. An anonymous survey’s answers are never given one by one — only its totals, in /surveys.
Scopes: survey_responses:read
Endpoints
GET/api/v1/survey-responsesList
GET/api/v1/survey-responses/{id}One record
Fields
Name
Type
Description
id
stringread only
Identifier (a UUID).
survey_id
integerread only
The survey.
employee_id
integerread only
Who answered.
submitted_at
datetime | nullread only
When.
answers
arrayread only
The answers: question, chosen option, value (scale) or text.
Social posts for the whole company (not in a group), published. Created by the key’s creator: a post, or news, an announcement, a promotion or a contest when they may announce; the body is plain text, a blank line between paragraphs.
Scopes: posts:read, posts:write
Endpoints
GET/api/v1/postsList
GET/api/v1/posts/{id}One record
POST/api/v1/postsCreate
Fields
Name
Type
Description
id
integerread only
Identifier.
type
post | news | announcement | promotion | contestrequired
post, news, announcement, promotion or contest.
title
string | null
Title (optional).
body
textrequired
The text (plain text when read).
author
string | nullread only
Who wrote it.
comments_enabled
boolean
Whether people can comment.
comments_count
integerread only
How many comments.
published_at
datetime | null
When it is published; a future moment schedules it.
created_at
datetimeread only
Created.
updated_at
datetimeread only
Last changed.
Filters
type
post | news | announcement | promotion | contest
Only this type.
Example request
POST https://compania-mea.harmoniq.ro/api/v1/posts
{
"type": "announcement",
"title": "Program de sărbători",
"body": "Între 24 și 26 decembrie programul este 9–14.",
"comments_enabled": true
}
Example response
{
"data": {
"id": 120,
"type": "announcement",
"title": "Program de sărbători",
"body": "Între 24 și 26 decembrie programul este 9–14.",
"author": "Maria Matei",
"comments_enabled": true,
"comments_count": 3,
"published_at": "2026-05-01T08:00:00Z",
"created_at": "2026-05-01T08:00:00Z",
"updated_at": "2026-05-01T08:00:00Z"
}
}
Knowledge base articles /knowledge-articles
The knowledge base’s published articles (procedures, how-tos), with the body as plain text, in the language asked for (Accept-Language) or the company’s.
The people the company serves — customers and leads. An email is unique in the company (a second one is refused). Marketing consent is never written with the record: it changes only through the consent action, which keeps its history (given or withdrawn, how, when, by whom). The erase action wipes a person’s data on their request and cannot be undone: name, email, phone, notes and what was written about them go, the figures (purchases, deal values, scores) stay, and the record can no longer be changed.
Scopes: crm_contacts:read, crm_contacts:write
Endpoints
GET/api/v1/crm-contactsList
GET/api/v1/crm-contacts/{id}One record
POST/api/v1/crm-contactsCreate
PATCH/api/v1/crm-contacts/{id}Change
DELETE/api/v1/crm-contacts/{id}Delete
POST/api/v1/crm-contacts/{id}/consentRecord that the person gave or withdrew their marketing consent, and how.
POST/api/v1/crm-contacts/{id}/eraseErase the person’s data at their request (GDPR). Irreversible.
Fields
Name
Type
Description
id
integerread only
Identifier.
first_name
string | null
First name.
last_name
string | null
Last name.
email
string | null
Email address (unique in the company, stored in lowercase).
phone
string | null
Phone number, as written.
account_id
integer | null
The organisation they belong to (see /crm-accounts).
job_title
string | null
Their role there.
city
string | null
City.
country
string | null
Country, as a two-letter ISO code.
locale
string | null
The language to address them in (ro, en…).
status
lead | customer | inactive
lead, customer or inactive. A purchase or a won deal makes a lead a customer.
Where they came from: walk_in, website, phone, referral, campaign, event, partner or other.
work_unit_id
integer | null
The unit (store, hotel, office) that serves it; empty for none.
owner_id
integer | null
The user who looks after it; the key’s creator when left out on create.
tags
array
Tags (lowercase, at most 20).
notes
text | null
Notes.
marketing_consent
booleanread only
Whether they agree to marketing now (read only — changed through the consent action).
consent_updated_at
datetime | nullread only
When the consent last changed.
last_activity_at
datetime | nullread only
When something was last done with them.
erased_at
datetime | nullread only
When their data was erased on request (the record is then read only).
created_at
datetimeread only
Created.
updated_at
datetimeread only
Last changed.
Filters
q
string
Name, email or phone containing this.
email
string
This exact email (case does not matter).
phone
string
This phone number (only its digits are compared).
status
lead | customer | inactive
Only with this status.
work_unit_id
integer
Only this unit’s.
owner_id
integer
Only this user’s.
account_id
integer
Only this organisation’s.
tag
string
Only with this tag.
consent
boolean
true: only those who agree to marketing; false: only those who do not.
/api/v1/crm-contacts/{id}/consent: granted (boolean) — true: given; false: withdrawn.; channel (form | verbal | email | import | api | other) — How: form, verbal, email, import, api or other (api when left out).; note (string) — A note (for example where the form is kept).
The pipelines deals go through, with their stages (set up in the app). Every company has a default one. A stage is open (with the chance a deal there is won) or closes the deal as won or lost.
Scopes: crm_pipelines:read
Endpoints
GET/api/v1/crm-pipelinesList
GET/api/v1/crm-pipelines/{id}One record
Fields
Name
Type
Description
id
integerread only
Identifier.
name
stringread only
Name.
is_default
booleanread only
Whether new deals go here when no pipeline is given.
sort
integerread only
Position in lists.
stages
arrayread only
Its stages in order: id, name, kind (open, won or lost), probability (0–100) and sort.
Sales, bookings or contracts being worked through a pipeline. The pipeline and stage are chosen on create (the default pipeline’s first open stage when left out); afterwards a deal changes stage only through move, win, lose and reopen. Its status always follows its stage, and closed_at is set when it is won or lost. Winning a deal makes its contact a customer.
Scopes: crm_deals:read, crm_deals:write
Endpoints
GET/api/v1/crm-dealsList
GET/api/v1/crm-deals/{id}One record
POST/api/v1/crm-dealsCreate
PATCH/api/v1/crm-deals/{id}Change
DELETE/api/v1/crm-deals/{id}Delete
POST/api/v1/crm-deals/{id}/moveMove the deal to another stage (of its pipeline, or of another one — the deal moves with it).
POST/api/v1/crm-deals/{id}/winMark the deal won (its pipeline’s won stage).
POST/api/v1/crm-deals/{id}/loseMark the deal lost (its pipeline’s lost stage), with why.
POST/api/v1/crm-deals/{id}/reopenTake a closed deal back to its pipeline’s last open stage.
Fields
Name
Type
Description
id
integerread only
Identifier.
title
stringrequired
What is being sold.
pipeline_id
integer
The pipeline (see /crm-pipelines). Set on create only.
stage_id
integer
The stage. Set on create only; then through the actions.
status
open | won | lostread only
open, won or lost — its stage’s kind.
contact_id
integer | null
The customer (see /crm-contacts).
account_id
integer | null
The organisation (see /crm-accounts).
value
number | null
What it is worth.
currency
string
The value’s currency (ISO code); the company’s CRM currency when left out.
What was done, or is to be done, with customers: call, meeting, visit, email, note, task and purchase. A task waits until completed; anything else is done when logged (at done_at when given). A purchase needs its amount and makes its contact a customer. An activity of a deal takes the deal’s customer, organisation and unit when they are not given.
Scopes: crm_activities:read, crm_activities:write
Endpoints
GET/api/v1/crm-activitiesList
GET/api/v1/crm-activities/{id}One record
POST/api/v1/crm-activitiesCreate
PATCH/api/v1/crm-activities/{id}Change
DELETE/api/v1/crm-activities/{id}Delete
POST/api/v1/crm-activities/{id}/completeMark a task done (now).
POST/api/v1/crm-activities/{id}/reopenMark it not done again (not for purchases).
What customers said: feedback (a 0–10 score — how likely they are to recommend the business — and/or a comment) and complaints. Feedback needs a score or a comment. A complaint stays open until resolved with what was done; it can be reopened. The kind is set on create.
Scopes: crm_feedback:read, crm_feedback:write
Endpoints
GET/api/v1/crm-feedbackList
GET/api/v1/crm-feedback/{id}One record
POST/api/v1/crm-feedbackCreate
PATCH/api/v1/crm-feedback/{id}Change
DELETE/api/v1/crm-feedback/{id}Delete
POST/api/v1/crm-feedback/{id}/resolveResolve a complaint, saying what was done.
POST/api/v1/crm-feedback/{id}/reopenReopen a resolved complaint.
The producers and brands whose campaigns go into the company's display spaces and onto its shelves: one list for both modules. A name is unique in the company. Writing needs the key creator to hold "Manage partners".
Scopes: merch_partners:read, merch_partners:write
Endpoints
GET/api/v1/merch-partnersList
GET/api/v1/merch-partners/{id}One record
POST/api/v1/merch-partnersCreate
PATCH/api/v1/merch-partners/{id}Change
Fields
Name
Type
Description
id
integerread only
Identifier.
name
stringrequired
The partner's name (unique in the company).
code
string | null
Internal code.
contact_name
string | null
Contact person.
contact_email
string | null
The contact's email.
contact_phone
string | null
The contact's phone.
notes
text | null
Notes.
crm_account_id
integer | null
The matching CRM organisation (see /crm-accounts), if any.
is_active
boolean
Whether it can get new campaigns.
created_at
datetimeread only
Created.
updated_at
datetimeread only
Last changed.
Filters
q
string
Name containing the text.
is_active
boolean
true: active ones only; false: inactive ones only.
In-store spaces: the kinds of zone the company has in many locations (a click frame, a counter stand, a totem), with their usual measurements and capacity. The monthly price is written only by who sees money.
In-store spaces: each location's zones (where, how big, how much fits on each face), only in the locations the key's creator lays out. A zone stays in its location. A new zone of a type takes the type's measurements for what is missing. Fewer faces or less room than its running campaigns need is refused; a zone with campaigns cannot be deleted.
Scopes: space_zones:read, space_zones:write
Endpoints
GET/api/v1/space-zonesList
GET/api/v1/space-zones/{id}One record
POST/api/v1/space-zonesCreate
PATCH/api/v1/space-zones/{id}Change
DELETE/api/v1/space-zones/{id}Delete
Fields
Name
Type
Description
id
integerread only
Identifier.
work_unit_id
integerrequired
The location (unit) — on create only.
zone_type_id
integer | null
The zone type (see /space-zone-types), if any.
name
stringrequired
Name (e.g. "Totem right of the door").
description
text | null
Description.
width_cm
number | null
Width, in centimetres.
height_cm
number | null
Height, in centimetres.
depth_cm
number | null
Depth, in centimetres.
area_m2
number | null
Area, in square metres.
faces
integer
How many faces (1 or 2).
capacity
integer
How many items fit on one face.
capacity_label
string | null
What the capacity counts.
is_display
boolean
Whether it is a display space.
monthly_price
number | null
Monthly rate (written only by who sees money).
status
active | unavailable
active or unavailable (temporarily).
pin_x
number | nullread only
Position on the location's sketch, percent from the left (placed in the app).
pin_y
number | nullread only
Position on the location's sketch, percent from the top.
Shelf space: the kinds of fixture (a gondola, an end cap, a fridge) with the rate card — per product facing or per metre of shelf, a month. Rates are written only by who holds the shelf-prices right.
Shelf space: planograms described once — the fixture, the measurements, the shelves top to bottom with what fits on each (facings or centimetres) and its price factor. Sending shelves replaces the list of shelves; a shelf with campaigns cannot be taken away. A name is unique.
Shelf space: a planogram set up in a location, with its own label, note and costs, only in the locations the key's creator lays out. Deleting takes it out of the location: kept for its campaigns' history, or gone if it had none; never while a campaign runs on it. Costs are written only by who sees prices.
Campaigns of both modules (module: spaces — display zones; shelf — planogram shelves), written as the key's creator. A campaign starts as a draft: its locations (units) and the rules naming places in them (rules) become its places. The launch action checks room and sends it to each location; cancel stops it. A launched campaign keeps its dates and places; only its text, partner, money and photo requirement change. Value and cost are written only by who sees money.
Days a location has to take it down, after the end.
proof_required
boolean
Whether a location must send photos when confirming.
value
number | null
What the partner pays for the whole campaign, excluding VAT.
cost
number | null
What it costs the company (materials, set-up), excluding VAT.
currency
stringread only
The amounts' currency (from the module's settings).
status
draft | launched | cancelledread only
draft, launched or cancelled.
phase
draft | scheduled | running | ended | cancelledread only
draft, scheduled, running, ended or cancelled.
units
array
The locations (unit ids), together with rules.
rules
array
The rules naming places, together with units. spaces: [{zone_type_id or zone_id, face (A/B), quantity}]; shelf: [{planogram_id or placement_id, position (shelf, from the top), quantity, products}].
targets
arrayread only
The resulting places: per location, the zone and face or the placement and shelf, with the quantity.
A launched campaign in one location: who puts it up and by when, whether it is up, refused (with the reason), being taken down or done. Actions are done as the key's creator (who implements there or, for reopen, who runs the campaign). Photos are sent as base64 images; a campaign that asks for them cannot be confirmed without.
/api/v1/merch-executions/{id}/confirm: photos (array) — Photos: [{name, content_base64}], JPEG/PNG/WebP, at most 10 MB each, at most 10.; note (text) — Notes.
/api/v1/merch-executions/{id}/refuse: reason (text) — The reason.
/api/v1/merch-executions/{id}/removed: photos (array) — Photos after the take-down (optional): [{name, content_base64}].