Appearance
Estrutura Organizacional
A estrutura organizacional define onde e quanto custa o trabalho de cada profissional: departamentos (com hierarquia) para agrupar relatórios, cargos com custo-hora padrão e o histórico de tarifas por pessoa — a base de todo o cálculo financeiro do módulo.
Headers obrigatórios
Todas as requisições devem incluir X-Timesheet-Id e Authorization: Bearer {token}. As listagens (index, show, list) são abertas a qualquer profissional autenticado; criar, editar e remover exige gestor (isManager) — demais recebem 403 FORBIDDEN.
Departamentos
Setores da empresa, com hierarquia via parentId. Servem para agrupar relatórios e filtrar dashboards.
Estrutura de Dados
| Campo | Tipo | Descrição |
|---|---|---|
id | Number | Identificador do departamento. |
name | String | Nome (máx. 150 caracteres; o slug gerado deve ser único por instância). |
slug | String | Slug gerado automaticamente a partir do nome. |
parentId | Number | Departamento pai (opcional) — forma a hierarquia. |
costCenter | String | Centro de custo (máx. 100 caracteres, opcional). |
Endpoints
http
GET /v1/timesheet/departments
GET /v1/timesheet/departments/list
GET /v1/timesheet/departments/:id
POST /v1/timesheet/departments
PUT /v1/timesheet/departments/:id
DELETE /v1/timesheet/departments/:idListar Departamentos
GET /v1/timesheet/departments aceita page, perPage e search. GET /v1/timesheet/departments/list retorna [{ "value", "label" }] com search e limit (máx. 100).
Criar Departamento (gestor)
| Atributo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
name | string | Sim | Nome (máx. 150 caracteres, slug único por instância). |
parentId | number | Não | Departamento pai existente na instância. |
costCenter | string | Não | Centro de custo (máx. 100 caracteres). |
Respostas
201 Created
Retorna o ID do departamento criado. Atualizações e remoções respondem 204 No Content.
422 Unprocessable Entity
Nome duplicado (mesmo slug) ou parentId inexistente.
Cargos (Positions)
Cargos/funções da empresa. Carregam um custo-hora padrão (defaultHourlyCost) que serve de sugestão ao cadastrar alguém no cargo.
Estrutura de Dados
| Campo | Tipo | Descrição |
|---|---|---|
id | Number | Identificador do cargo. |
name | String | Nome (máx. 150 caracteres; slug único por instância). |
description | String | Descrição livre (opcional). |
seniority | String | Senioridade (máx. 50 caracteres, opcional) — ex.: junior, pleno, senior. |
defaultHourlyCost | Number | Custo-hora padrão do cargo (opcional). |
Endpoints
http
GET /v1/timesheet/positions
GET /v1/timesheet/positions/list
GET /v1/timesheet/positions/:id
POST /v1/timesheet/positions
PUT /v1/timesheet/positions/:id
DELETE /v1/timesheet/positions/:idCriar Cargo (gestor)
| Atributo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
name | string | Sim | Nome (máx. 150 caracteres, slug único por instância). |
description | string | Não | Descrição livre. |
seniority | string | Não | Senioridade (máx. 50 caracteres). |
defaultHourlyCost | number | Não | Custo-hora padrão (mín. 0). |
Tarifas (Rates)
O histórico de valor-hora por profissional: custo, valor de venda, encargos e multiplicadores. Existe separado do cadastro porque reajuste não pode reescrever o passado — cada tarifa tem uma vigência (effectiveFrom/effectiveTo), e os apontamentos congelam um snapshot da tarifa vigente no dia do trabalho.
Ao fechar um apontamento, a aplicação busca a tarifa vigente para o profissional na data do dia e calcula custo e faturamento (ver Ponto & Apontamentos).
Estrutura de Dados
| Campo | Tipo | Descrição |
|---|---|---|
id | Number | Identificador da tarifa. |
timesheetUserId | Number | Profissional ao qual a tarifa se aplica. |
hourlyCost | Number | Custo-hora (obrigatório, mín. 0). |
hourlyBillingRate | Number | Valor-hora de venda (opcional — sem ele, as horas não geram faturamento). |
currency | String | Moeda (3 letras, padrão: BRL). |
indirectCostRate | Number | Taxa de encargos indiretos (padrão: 0). |
overtimeMultiplier | Number | Multiplicador de hora extra (padrão: 1). |
weekendMultiplier | Number | Multiplicador de fim de semana (padrão: 1). |
holidayMultiplier | Number | Multiplicador de feriado (padrão: 1). |
nightMultiplier | Number | Multiplicador noturno (padrão: 1). |
effectiveFrom | Date | Início da vigência (YYYY-MM-DD). |
effectiveTo | Date | Fim da vigência (null = vigente indefinidamente). |
notes | String | Observações (opcional). |
Campos decimais
Nas respostas, os campos monetários e multiplicadores são decimais serializados como string — ex.: "hourlyCost": "80.0000", "weekendMultiplier": "2.0000". O mesmo vale para defaultHourlyCost dos cargos.
Regra de Vigências
Vigências do mesmo profissional não podem se sobrepor: a aplicação rejeita com 422 RATE_OVERLAP qualquer cadastro ou edição que colida com uma vigência existente (null em effectiveTo conta como 9999-12-31). Enviar effectiveTo anterior a effectiveFrom falha com 422 INVALID_EFFECTIVE_RANGE.
Endpoints (somente gestores)
Todos os endpoints de tarifas exigem isManager.
http
GET /v1/timesheet/rates?timesheetUserId=2
POST /v1/timesheet/rates
GET /v1/timesheet/rates/:id
PUT /v1/timesheet/rates/:id
DELETE /v1/timesheet/rates/:idListar Tarifas
GET /v1/timesheet/rates exige o filtro timesheetUserId e aceita page/perPage.
Criar Tarifa
| Atributo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
timesheetUserId | number | Sim | Profissional existente na instância. |
hourlyCost | number | Sim | Custo-hora (mín. 0). |
hourlyBillingRate | number | Não | Valor-hora de venda (mín. 0). |
currency | string | Não | Moeda, 3 letras (padrão: BRL). |
indirectCostRate | number | Não | Encargos indiretos (mín. 0). |
overtimeMultiplier | number | Não | Multiplicador de hora extra (mín. 0). |
weekendMultiplier | number | Não | Multiplicador de fim de semana (mín. 0). |
holidayMultiplier | number | Não | Multiplicador de feriado (mín. 0). |
nightMultiplier | number | Não | Multiplicador noturno (mín. 0). |
effectiveFrom | date | Sim | Início da vigência (YYYY-MM-DD). |
effectiveTo | date | Não | Fim da vigência (>= effectiveFrom). |
notes | string | Não | Observações. |
Exemplo de Requisição
bash
curl -X POST "https://api.us.basis.tavares.in/v1/timesheet/rates" \
-H "X-Timesheet-Id: 3fa85f64-5717-4562-b3fc-2c963f66afa6" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"timesheetUserId": 2,
"hourlyCost": 80,
"hourlyBillingRate": 150,
"weekendMultiplier": 1.5,
"holidayMultiplier": 2,
"effectiveFrom": "2026-01-01"
}'Respostas
201 Created
Retorna o ID da tarifa criada. Atualizações e remoções respondem 204 No Content.
422 Unprocessable Entity
Vigência sobreposta a outra tarifa do mesmo profissional.
json
{
"message": "Já existe uma vigência que se sobrepõe ao período informado",
"code": "RATE_OVERLAP"
}