REST API v1
API v1 на ProBG Time Tracking предоставя достъп само за четене до клиенти, проекти и отчетено време на текущия Account. API е предназначено за CRM/ERP интеграции, BI справки, външни отчети и синхронизация на данни.
API никога не приема
account_idот външната система за избор на Account. Account-ът се определя единствено от Bearer token-а.
Бърз старт
- Отворете API в администрацията като Account Administrator.
- Създайте отделен token за конкретната интеграция.
- Дайте само необходимите права:
clients:read,projects:readи/илиtime:read. - Копирайте token-а веднага — пълната му стойност се показва само веднъж.
- Изпращайте token-а с всеки request чрез HTTP Bearer authentication.
curl -H "Authorization: Bearer <TOKEN>" \
-H "Accept: application/json" \
"https://www.tracker.probg.com/api/v1/clients"
Достъп по план
API работи само когато Account-ът има активен entitlement api.
По подразбиране API е включено в плановете:
- Agency
- Enterprise
Platform Administrator може да промени entitlement-а на ниво план или чрез Account override.
Съществуващ token спира да работи веднага, ако:
- бъде отнет;
- срокът му изтече;
- Account-ът бъде спрян;
- текущият subscription вече няма API entitlement.
Authentication
Base URL:
https://www.tracker.probg.com/api/v1
Задължителни headers:
Authorization: Bearer ptt_...
Accept: application/json
Token-ите са Account-scoped. В базата се пази само SHA-256 hash; plaintext стойността не може да бъде възстановена.
Срок на token
При създаване може да изберете:
- 30 дни;
- 90 дни;
- 365 дни;
- без автоматично изтичане.
Token без автоматично изтичане трябва да бъде ръчно отнет, когато интеграцията вече не се използва.
Права
| Scope | Позволява |
|---|---|
clients:read |
Списък и детайли на клиенти |
projects:read |
Списък и детайли на проекти |
time:read |
Списък и детайли на отчетено време |
Token без необходимото право получава HTTP 403 и error.code = insufficient_scope.
Препоръка: не давайте и трите права, ако интеграцията използва само един ресурс.
Ограничение на заявките
На token:
- 120 requests / минута;
- 3000 requests / час.
Допълнителен IP safety ceiling:
- 600 requests / минута;
- 10 000 requests / час.
При достигане на лимит Laravel връща HTTP 429 Too Many Requests.
Pagination
Всички list endpoints използват pagination.
Параметър:
| Параметър | Тип | По подразбиране | Ограничение |
|---|---|---|---|
page |
integer | 1 | Номер на страницата |
per_page |
integer | 25 | 1–100 |
Примерна структура:
{
"data": [],
"meta": {
"current_page": 1,
"per_page": 25,
"last_page": 1,
"total": 0
},
"links": {
"first": "...",
"last": "...",
"prev": null,
"next": null
}
}
Използвайте links.next, докато стойността стане null.
Формати на данните
- Дати без час:
YYYY-MM-DD. - Date/time стойности: ISO 8601.
- Продължителност: секунди.
- Паричните decimal стойности се връщат като decimal strings или
null, за да не се губи точност. - Всички responses са JSON.
- ID стойностите са integer.
Clients
GET /clients
Изисква clients:read.
Връща клиенти от Account-а на token-а.
Филтри
| Параметър | Тип | Описание |
|---|---|---|
q |
string, max 100 | Търси по име, фирма, лице за контакт, имейл и фирмен идентификатор |
status |
enum | active (default), inactive, archived, all |
updated_since |
date/datetime | Само записи, обновени след посочения момент |
per_page |
integer | 1–100 |
Пример:
curl -H "Authorization: Bearer <TOKEN>" \
-H "Accept: application/json" \
"https://www.tracker.probg.com/api/v1/clients?status=all&updated_since=2026-10-01T00:00:00%2B03:00&per_page=50"
Полета на Client
| Поле | Тип |
|---|---|
id |
integer |
name |
string |
company |
string/null |
contact_name |
string/null |
email |
string/null |
phone |
string/null |
address |
string/null |
company_id |
string/null |
is_active |
boolean |
projects_count |
integer |
tracked_seconds |
integer |
archived_at |
ISO 8601/null |
created_at |
ISO 8601/null |
updated_at |
ISO 8601/null |
GET /clients/{id}
Изисква clients:read.
Връща един клиент. Архивиран клиент също може да бъде прочетен по ID.
ID от друг Account връща 404, без да разкрива дали ресурсът съществува.
Примерен response:
{
"data": {
"id": 42,
"name": "Example Client",
"company": "Example Ltd",
"contact_name": "Jane Doe",
"email": "jane@example.com",
"phone": "+359...",
"address": "Sofia",
"company_id": "BG123456789",
"is_active": true,
"projects_count": 3,
"tracked_seconds": 184500,
"archived_at": null,
"created_at": "2026-09-10T09:20:00+03:00",
"updated_at": "2026-10-05T17:14:00+03:00"
}
}
Projects
GET /projects
Изисква projects:read.
Филтри
| Параметър | Тип | Описание |
|---|---|---|
q |
string, max 100 | Търси по име и описание |
client_id |
integer | Проекти само за конкретен клиент |
status |
enum | active (default), completed, archived, all |
updated_since |
date/datetime | Само обновени записи |
per_page |
integer | 1–100 |
Пример:
curl -H "Authorization: Bearer <TOKEN>" \
-H "Accept: application/json" \
"https://www.tracker.probg.com/api/v1/projects?client_id=42&status=all"
Полета на Project
| Поле | Тип | Бележка |
|---|---|---|
id |
integer | |
client_id |
integer | |
client |
object/null | id, name, company |
name |
string | |
description |
string/null | |
status |
string | |
billing_model |
string | hourly, fixed_fee, retainer, non_billable |
hourly_rate |
decimal string/null | Записаната project rate |
effective_hourly_rate |
decimal string/null | Ефективната rate за Hourly проект |
billing_currency |
string | Валутата, използвана от проекта |
fixed_fee_amount |
decimal string/null | |
retainer_amount |
decimal string/null | |
estimated_seconds |
integer/null | |
tracked_seconds |
integer | |
starts_at |
YYYY-MM-DD/null | |
ends_at |
YYYY-MM-DD/null | |
created_at |
ISO 8601/null | |
updated_at |
ISO 8601/null |
В API не се публикуват internal labor-cost snapshots.
GET /projects/{id}
Изисква projects:read.
Връща един проект от текущия Account.
Time entries
GET /time-entries
Изисква time:read.
Филтри
| Параметър | Тип | Описание |
|---|---|---|
client_id |
integer | Само време за клиент |
project_id |
integer | Само време за проект |
task_id |
integer | Само време за задача |
user_id |
integer | Само време на потребител |
from |
YYYY-MM-DD | Начална дата, включително |
to |
YYYY-MM-DD | Крайна дата, включително; трябва да е >= from |
billable |
boolean | true/false или 1/0; празна стойност означава без филтър |
billed |
boolean | true/false или 1/0; празна стойност означава без филтър |
q |
string, max 100 | Търси в заглавие и описание |
updated_since |
date/datetime | Само обновени записи |
per_page |
integer | 1–100 |
Пример за месечен export на проект:
curl -H "Authorization: Bearer <TOKEN>" \
-H "Accept: application/json" \
"https://www.tracker.probg.com/api/v1/time-entries?project_id=12&from=2026-10-01&to=2026-10-31&per_page=100"
Полета на Time entry
| Поле | Тип |
|---|---|
id |
integer |
user_id |
integer/null |
client_id |
integer/null |
project_id |
integer/null |
task_id |
integer/null |
user |
object/null — id, name |
client |
object/null — id, name |
project |
object/null — id, name |
task |
object/null — id, title |
work_date |
YYYY-MM-DD/null |
started_at |
ISO 8601/null |
ended_at |
ISO 8601/null |
duration_seconds |
integer |
source |
string |
title |
string |
description |
string/null |
is_billable |
boolean |
is_billed |
boolean |
hourly_rate |
decimal string/null |
amount |
decimal string/null |
created_at |
ISO 8601/null |
updated_at |
ISO 8601/null |
Следните вътрешни полета не се публикуват:
cost_rate;cost_amount;- private notes.
GET /time-entries/{id}
Изисква time:read.
Връща един time entry от текущия Account.
Error responses
401 — липсващ Bearer token
{
"error": {
"code": "unauthenticated",
"message": "A bearer token is required."
}
}
401 — невалиден, изтекъл или отнет token
{
"error": {
"code": "invalid_token",
"message": "The API token is invalid, expired, or revoked."
}
}
403 — Account недостъпен
{
"error": {
"code": "account_unavailable",
"message": "The account is not available."
}
}
403 — API вече не е включено в subscription-а
{
"error": {
"code": "feature_unavailable",
"message": "API access is not included in the current subscription."
}
}
403 — липсва scope
{
"error": {
"code": "insufficient_scope",
"message": "The API token does not have the required scope [projects:read]."
}
}
404 — ресурсът не е достъпен
При неизвестен ID или ID от друг Account се връща 404.
422 — validation error
Невалидни query параметри използват стандартния Laravel JSON validation response:
{
"message": "The given data was invalid.",
"errors": {
"per_page": [
"The per page field must not be greater than 100."
]
}
}
429 — rate limit
Намалете честотата на заявките и приложете retry/backoff логика.
Практически модели за интеграция
Incremental sync
За периодична синхронизация пазете момента на последния успешно завършен import и при следващия request използвайте updated_since.
GET /clients?updated_since=2026-10-06T08:00:00Z
GET /projects?updated_since=2026-10-06T08:00:00Z
GET /time-entries?updated_since=2026-10-06T08:00:00Z
Не използвайте локалното време на клиента като доказателство, че всички промени са прочетени. Записвайте checkpoint едва след успешното обхождане на всички страници.
Проекти на конкретен клиент
GET /projects?client_id=42&status=all
Отчетено време за период
GET /time-entries?from=2026-10-01&to=2026-10-31&per_page=100
Security препоръки
- Създавайте отделен token за всяка интеграция.
- Използвайте минималния необходим набор scopes.
- Не записвайте token-а в Git, frontend JavaScript, screenshots или публични logs.
- Пазете го в secret manager / environment variable.
- Използвайте HTTPS.
- Отнемайте token-а веднага при компрометиране или спиране на интеграцията.
- За дългосрочни интеграции планирайте периодична token rotation.
- При
401не retry-вайте безкрайно; проверете token lifecycle. - При
429използвайте exponential backoff.
Версиониране
Breaking промени в authentication-а или response contract-а изискват нов namespace, например /api/v2.
В рамките на v1 могат да бъдат добавяни:
- нови optional response fields;
- нови optional query filters;
- нови endpoints.
Интеграциите не трябва да приемат, че response object съдържа само документирaните полета.
Текущи ограничения
API v1 в момента е read-only.
Все още не са част от API v1:
- създаване/редакция/изтриване на данни;
- Tasks endpoint;
- Reports endpoint;
- Invoices endpoint;
- Webhooks;
- OAuth/client credentials;
- bulk export endpoint.
Тези възможности изискват отделен versioned contract и security review.
Публична документация и Postman
Документацията е достъпна без вход в системата:
/api/docs— English;/api/docs/en— English;/api/docs/bg— Български;/api/docs/openapi.yaml— OpenAPI 3.1 specification;/api/docs/postman.json— Postman collection.
Работа с Postman
- Изтеглете
/api/docs/postman.json. - В Postman изберете Import и импортирайте JSON файла.
- Отворете collection variables.
- Задайте
base_url— по подразбиране еhttps://tracker.probg.com/api/v1. - Поставете API token-а в
token. - При необходимост задайте
client_id,project_idиtime_entry_id. - Изпращайте готовите requests от папките Clients, Projects и Time Entries.
Bearer authentication е настроено на ниво collection чрез {{token}}. Query параметрите, които не са необходими по подразбиране, са добавени като disabled и могат да бъдат включвани според интеграцията.
OpenAPI
От API документацията в администрацията може да изтеглите OpenAPI 3.1 YAML спецификация за импортиране в Postman, Insomnia, Swagger UI/Editor, Redoc и инструменти за SDK генерация.
Дати и часова зона на checkpoint
updated_since е включителна граница. ISO 8601 стойности с Z, +03:00 и други отмествания се преобразуват към часовата зона на приложението/съхранението преди сравнението. Самостоятелна дата означава полунощ в тази зона; дата и час без отместване също я използват. updated_at се съхранява с точност до секунда; дробна граница след дадена секунда изключва записите от нея. Еквивалентни моменти връщат едни и същи записи.
Използвайте status=all при синхронизация на клиенти или проекти. Филтърът използва собственото updated_at на ресурса; промени в свързани агрегати като tracked_seconds не го обновяват непременно. Няма поток за изтрити записи или фиксиран snapshot между страниците. Интеграциите трябва да припокриват границите, да премахват дубликати по ID и периодично да сверяват всички данни.
Валидация и синхронизация на фактурирания статус
Филтрите billable и billed приемат true/false и 1/0. Празна стойност означава без филтър; други стойности връщат 422. Нулеви, извън допустимия положителен целочислен диапазон, несъществуващи или чужди ресурсни ID връщат 404.
Издаването или анулирането на фактура обновява updated_at на свързаните записи за време в същата транзакция, която променя is_billed. Следващата включителна заявка с updated_since получава тези промени. Заключените часове, ставки и разходи остават непроменени. Повторното действие не измества timestamp-а; неуспешно издаване връща и него назад. При анулиране се следват свързаните исторически записи и след прехвърляне на клиент, като API достъпът остава ограничен до текущия акаунт.
След внедряване съществуващите интеграции трябва еднократно да синхронизират отново всички записи за време: стари промени на фактурирания статус не се попълват със задна дата. Продължават да важат застъпването на checkpoints и периодичната пълна сверка; поток за изтривания и стабилна снимка между страниците остават извън v1.