API do Selfcare
Liga o Selfcare ao teu ERP, ao software de ponto, ao BI, a uma app móvel ou a um assistente de IA. A API age em nome de uma pessoa e vê exatamente o que ela vê na app.
https://api.selfcare.work/v1Especificação OpenAPI 3.1https://api.selfcare.work/v1Começar
1. Na app, abre Definições → API e cria uma chave com os âmbitos de que precisas (pedimos um código por email). O segredo aparece uma só vez: guarda-o num cofre.
2. Faz o primeiro pedido. Todas as rotas vivem em https://api.selfcare.work/v1 e respondem em JSON com data, error e, nas listas, meta.
curl https://api.selfcare.work/v1/me \
-H "Authorization: Bearer sc_live_…"3. Em TypeScript, o SDK (@selfcare/api-sdk, gerado da especificação OpenAPI) trata da autenticação, das repetições e da paginação. O pacote ainda não está publicado no npm; até lá, usa a especificação OpenAPI com o gerador da tua preferência.
Nunca sai pela API: o processamento salarial, os atestados e outros documentos de saúde, os documentos disciplinares e o IBAN completo (sempre mascarado).
import { SelfcareClient } from "@selfcare/api-sdk";
const api = new SelfcareClient({ token: process.env.SELFCARE_API_KEY! });
const me = await api.getMe();
console.log(me.tenant.name, me.role, me.credential.scopes);
// Every approved absence this month, page after page
for await (const a of api.paginate((cursor) =>
api.listAbsences({ cursor, query: { from: "2026-11-01", to: "2026-11-30", status: "APPROVED" } }),
)) {
console.log(a.employee.fullName, a.startDate, a.endDate);
}Chaves de API
Cada pedido leva Authorization: Bearer seguido da chave (sc_live_… nas empresas reais, sc_test_… na empresa de teste). A chave pertence a uma pessoa numa empresa: a empresa vem sempre da chave e o papel recalcula-se em cada pedido, por isso a chave vê o que a pessoa vê hoje na app.
Mudar ou repor a palavra-passe revoga as chaves dessa pessoa. O dono e o RH veem e revogam as chaves de toda a empresa em Definições → Sistema → API da empresa, e podem bloquear a API inteira numa emergência. O cookie da app nunca é aceite. Para integrações de servidor sem pessoa associada, o dono ou o RH criam um utilizador de integração, que não entra na app.
OAuth 2.1
Para uma app usada por várias pessoas (uma app móvel, um assistente, um produto teu), usa OAuth 2.1 em vez de chaves: cada pessoa entra com a sua conta, escolhe a empresa e vê o que a app pede. Regista a app em Definições → API → As minhas apps. Uma app nativa ou de browser é pública (sem segredo); um servidor é confidencial e autentica-se com client_secret, mostrado só ao criar ou ao rodar.
Só há authorization code com PKCE S256. O state é obrigatório e o redirect_uri tem de ser exatamente um dos registados: um esquema próprio com ponto (work.selfcare.app:/oauth), https, ou loopback por IP (http://127.0.0.1/callback, com qualquer porta, RFC 8252). Os domínios do Selfcare (selfcare.work e subdomínios) não servem de redirect. Cada resposta ao teu redirect, com código ou com erro, traz iss=https://api.selfcare.work (RFC 9207): confirma-o junto com o state antes de trocar o código. Os metadados estão em /.well-known/oauth-authorization-server.
GET https://app.selfcare.work/oauth/authorize?response_type=code
&client_id=sc_app_…&redirect_uri=work.selfcare.app:/oauth
&scope=me:read%20absences:read%20absences:write&state=…
&code_challenge=BASE64URL(SHA256(code_verifier))&code_challenge_method=S256
POST https://api.selfcare.work/oauth/token
grant_type=authorization_code&client_id=sc_app_…&code=sc_ac_…
&redirect_uri=work.selfcare.app:/oauth&code_verifier=…
POST https://api.selfcare.work/oauth/token
grant_type=refresh_token&client_id=sc_app_…&refresh_token=sc_rt_…O access_token (sc_at_…) dura 1 hora e usa-se como Authorization: Bearer, tal como uma chave. O refresh_token (sc_rt_…) dura 90 dias e roda em cada uso: guarda sempre o novo e descarta o antigo. Reutilizar um refresh token já usado revoga a sessão inteira, porque só acontece se alguém o copiou.
A app age sempre como a pessoa: o acesso efetivo é o âmbito concedido cruzado com o que o papel dela permite na empresa. Para terminar a sessão, chama POST /oauth/revoke com o refresh token. A pessoa revoga a app em Definições → API → Apps autorizadas, e o dono e o RH veem as apps autorizadas na empresa.
import { OAuthSession, SelfcareClient, buildAuthorizeUrl, createPkcePair, exchangeCode, parseAuthorizationResponse, randomString } from "@selfcare/api-sdk";
const clientId = "sc_app_…";
const redirectUri = "work.selfcare.app:/oauth";
const { verifier, challenge } = await createPkcePair();
const state = randomString();
openSystemBrowser(buildAuthorizeUrl({ clientId, redirectUri, scopes: ["me:read", "absences:write"], state, codeChallenge: challenge }));
// On the redirect: check "state" and "iss" (RFC 9207), then exchange the code
const { code } = parseAuthorizationResponse(redirectedUrl, { state, issuer: "https://api.selfcare.work" });
const tokens = await exchangeCode({ clientId, code, redirectUri, codeVerifier: verifier });
const session = new OAuthSession(tokens, { clientId }, (t) => saveToKeychain(t)); // t === null: signed out
const api = new SelfcareClient({ token: () => session.accessToken(), onUnauthorized: () => session.forceRefresh() });Âmbitos
O acesso é a interseção entre os âmbitos da credencial e as permissões da pessoa na app: um âmbito nunca dá mais do que o papel. Os âmbitos sensíveis (contratos, remuneração, IBAN) marcam-se um a um, nunca entram nos atalhos, e uma chave com eles vale no máximo 90 dias. As escritas de contratos e remuneração são só para o dono e o RH.
| Âmbito | O que permite |
|---|---|
| me:read | Quem sou: utilizador, empresa e papel |
| absences:read | Ver ausências, férias e saldos |
| absences:write | Criar, editar e cancelar ausências |
| absences:decide | Aprovar e rejeitar ausências |
| expenses:read | Ver despesas e anexos |
| expenses:write | Criar, editar e submeter despesas |
| expenses:decide | Aprovar e rejeitar despesas |
| trips:read | Ver deslocações (ajudas de custo) |
| trips:write | Registar e cancelar deslocações |
| trips:decide | Aprovar e rejeitar deslocações |
| documents:read | Ver e descarregar documentos (nunca os de saúde) |
| documents:write | Carregar documentos e recibos |
| employees:read | Ver colaboradores |
| employees:write | Criar e editar colaboradores |
| teams:read | Ver equipas |
| teams:write | Gerir equipas |
| webhooks:manage | Gerir webhooks |
| contracts:readsensível | Ver contratos |
| contracts:writesensível | Alterar contratos |
| compensation:readsensível | Ver remunerações |
| compensation:writesensível | Alterar remunerações |
| bank-details:writesensível | Pedir mudanças de IBAN |
Paginação
As listas devolvem meta.nextCursor e meta.hasMore. Para a página seguinte, repete o pedido com cursor igual ao nextCursor e os mesmos filtros (um cursor com outros filtros dá 400 INVALID_CURSOR). limit vale 50 por omissão e vai até 200. Para sincronizar só o que mudou, usa updatedSince.
{
"data": [ … ],
"error": null,
"meta": { "nextCursor": "eyJj…", "hasMore": true }
}Erros
Os erros vêm em error, com um code estável, a mensagem na língua do Accept-Language (PT por omissão, ou EN), details por campo nos erros de validação, o requestId (também no cabeçalho Selfcare-Request-Id) e o docUrl desta página. Um recurso que não podes ver responde 404, nunca 403, para não revelar que existe.
| Código | Estado | Mensagem |
|---|---|---|
| BAD_REQUEST | 400 | O pedido está mal formado. |
| INVALID_CURSOR | 400 | O cursor de paginação é inválido ou não corresponde a estes filtros. |
| UNAUTHORIZED | 401 | É preciso uma chave de API ou um token válido no cabeçalho Authorization: Bearer. |
| PAYMENT_REQUIRED | 402 | A conta da empresa está bloqueada por falta de pagamento. |
| FORBIDDEN | 403 | Não tens permissão para fazer isto. |
| SCOPE_MISSING | 403 | A credencial não tem o âmbito necessário: …. |
| API_BLOCKED | 403 | A API está bloqueada nesta empresa. |
| NOT_FOUND | 404 | Não encontrado. |
| CONFLICT | 409 | O recurso está num estado que não permite esta operação, ou um pedido igual ainda está a correr. |
| CONFIRMATION_PENDING | 409 | A alteração fica pendente até o colaborador a confirmar na app. |
| PRECONDITION_FAILED | 412 | O recurso mudou desde que o leste (If-Match não corresponde ao ETag atual). Lê-o de novo. |
| PRECONDITION_REQUIRED | 428 | Esta escrita exige o cabeçalho indicado nos detalhes (If-Match com o ETag atual, ou Idempotency-Key). |
| VALIDATION_ERROR | 422 | Há campos inválidos no pedido. |
| IDEMPOTENCY_CONFLICT | 422 | Esta Idempotency-Key já foi usada com um pedido diferente. |
| CHECKSUM_MISMATCH | 422 | O sha256 do ficheiro recebido não corresponde ao declarado. |
| RATE_LIMITED | 429 | Demasiados pedidos. Tenta de novo daqui a pouco. |
| INTERNAL_ERROR | 500 | Ocorreu um erro inesperado. |
| SERVICE_UNAVAILABLE | 503 | Serviço temporariamente indisponível. |
HTTP/1.1 403 Forbidden
Selfcare-Request-Id: 6f0e…
{
"data": null,
"error": {
"code": "SCOPE_MISSING",
"message": "A credencial não tem o âmbito necessário: absences:write.",
"requestId": "6f0e…",
"docUrl": "https://api.selfcare.work/docs#error-scope-missing"
}
}Limites
Por credencial: 300 pedidos por minuto, dos quais 60 escritas. Por empresa, somando todas as credenciais: 1200 por minuto. Por app OAuth, em todas as empresas: 3000 por minuto. Antes de validar a credencial, há ainda 600 pedidos por minuto por IP. As respostas trazem RateLimit-Limit, RateLimit-Remaining e RateLimit-Reset; um 429 traz Retry-After em segundos. Espera esse tempo antes de repetir.
Idempotency-Key
Qualquer escrita (POST, PATCH, PUT, DELETE) aceita Idempotency-Key: um valor teu, único por operação (um UUID serve). Durante 24 horas, repetir o pedido com a mesma chave e o mesmo corpo devolve a mesma resposta sem repetir a ação, com o cabeçalho Idempotent-Replayed: true. A mesma chave com outro corpo dá 422 IDEMPOTENCY_CONFLICT; um pedido igual ainda a correr dá 409 CONFLICT. Nas escritas sensíveis (contratos e remuneração), a chave é obrigatória (428).
curl -X POST https://api.selfcare.work/v1/absences \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{ "absenceTypeCode": "FERIAS", "startDate": "2026-12-21", "endDate": "2026-12-24" }'
# Same key, same body, within 24 h: the same answer, with "Idempotent-Replayed: true".
# Same key, another body: 422 IDEMPOTENCY_CONFLICT. Still running: 409 CONFLICT.Para editar sem pisar uma alteração de outra pessoa, usa o ETag que vem nas leituras e nas escritas: manda-o em If-Match. Se o recurso mudou entretanto, a resposta é 412 PRECONDITION_FAILED. Nas edições sensíveis, If-Match é obrigatório.
curl -i https://api.selfcare.work/v1/absences/3f1c… # ETag: W/"…"
curl -X PATCH https://api.selfcare.work/v1/absences/3f1c… \
-H "Authorization: Bearer sc_live_…" -H "If-Match: W/\"…\"" \
-H "Content-Type: application/json" -d '{ "endDate": "2026-12-23" }'
# If the absence changed in the meantime: 412 PRECONDITION_FAILEDEmpresa de teste
Para desenvolver sem tocar em dados reais, cria uma empresa de teste em Definições → API: vem com colaboradores, duas equipas, ausências e despesas fictícios. Nessa empresa as chaves começam por sc_test_ e só funcionam lá; as sc_live_ só funcionam nas empresas reais. Os tokens OAuth servem a empresa escolhida no consentimento, seja de teste ou real.
Versões
A versão vai no caminho (/v1). Dentro de /v1 só entram mudanças compatíveis: campos, rotas, eventos e valores novos. Ignora os campos que não conheces e trata valores de enumeração novos com um caso por omissão. Uma mudança incompatível só numa /v2, anunciada com antecedência nesta página.
MCP (assistentes de IA)
O servidor MCP liga o Selfcare a assistentes de IA como o Claude, o ChatGPT ou o Cursor. Cada pessoa entra com a sua conta e o assistente passa a poder marcar férias, registar despesas, ver documentos e tratar aprovações, sempre a agir como ela e a ver só o que ela vê na app. As ferramentas usam os mesmos endpoints da API, com os mesmos âmbitos, limites e registo de auditoria (com a origem MCP).
Claude
1. Em Definições → Conectores, escolhe Adicionar conector personalizado.
2. Dá-lhe um nome (Selfcare) e cola o URL acima.
3. Carrega em Ligar: abre o ecrã de autorização do Selfcare. Entra, escolhe a empresa e confirma o que o assistente pode fazer.
ChatGPT
1. Em Definições → Apps e conectores, ativa o modo de programador (nas definições avançadas) e escolhe Criar.
2. Cola o URL acima e escolhe OAuth como autenticação.
3. Confirma no ecrã de autorização do Selfcare, como no Claude.
https://api.selfcare.work/mcpCursor
1. Abre as definições do Cursor, secção MCP, e acrescenta o servidor ao mcp.json (do projeto ou global).
2. Na primeira utilização, o Cursor abre o browser para entrares no Selfcare e autorizares.
{
"mcpServers": {
"selfcare": { "url": "https://api.selfcare.work/mcp" }
}
}Clientes que não fazem OAuth podem usar uma chave de API pessoal no cabeçalho Authorization. Cria-a com os âmbitos das ferramentas que vais usar:
{
"mcpServers": {
"selfcare": {
"url": "https://api.selfcare.work/mcp",
"headers": { "Authorization": "Bearer sc_live_…" }
}
}
}Nos três casos, o cliente regista-se sozinho (registo dinâmico, RFC 7591) e o Selfcare mostra um aviso de que se trata de um assistente de IA. Transporte Streamable HTTP sem sessão. Sem token, a resposta é 401 com WWW-Authenticate e resource_metadata (RFC 9728); os tokens são emitidos para o recurso https://api.selfcare.work/mcp (RFC 8707) e não servem na API REST, nem o contrário. Ferramentas:
| Ferramenta | Âmbito | Tipo |
|---|---|---|
| get_me | me:read | Leitura |
| get_my_summary | me:read | Leitura |
| get_vacation_balance | absences:read | Leitura |
| list_absence_types | absences:read | Leitura |
| list_absences | absences:read | Leitura |
| request_absence | absences:write | Escrita |
| cancel_absence | absences:write | Escrita |
| get_absence | absences:read | Leitura |
| list_pending_approvals | absences:read | Leitura |
| approve_absence | absences:decide | Escrita |
| reject_absence | absences:decide | Escrita |
| list_expenses | expenses:read | Leitura |
| get_expense | expenses:read | Leitura |
| list_expense_categories | expenses:read | Leitura |
| create_expense | expenses:write | Escrita |
| get_expense_receipt_upload_url | expenses:write | Escrita |
| add_expense_receipt | expenses:write | Escrita |
| submit_expense | expenses:write | Escrita |
| approve_expense | expenses:decide | Escrita |
| reject_expense | expenses:decide | Escrita |
| list_documents | documents:read | Leitura |
| get_document_link | documents:read | Leitura |
| search_employees | employees:read | Leitura |
Dos documentos, o assistente só vê o regulamento interno, as políticas e os manuais da empresa e os comprovativos de despesa da própria pessoa, cada um na sua pasta. Nunca vê recibos de vencimento, recibos de ajudas de custo, tipos de documento criados pela empresa, contratos e adendas, documentos de identificação (cartão de cidadão, passaporte, autorização de residência), comprovativos de NIF, NISS ou IBAN, documentos de saúde ou disciplinares, atestados, o IBAN completo (sempre mascarado) nem dados de processamento salarial, e não está disponível para contabilistas. Cada escrita fica no registo de auditoria da empresa com a origem MCP e a app. A pessoa revoga o acesso em Definições → API → Apps autorizadas, e os clientes registados que ninguém autoriza em 7 dias são apagados.
Webhooks
Os webhooks avisam um servidor teu quando algo muda: ausências, despesas, deslocações, documentos, pessoas e equipas. Cada endpoint é de uma pessoa e só recebe o que ela vê no momento da entrega. Cria-os em Definições → API → Webhooks ou pela API (POST /v1/webhook-endpoints, âmbito webhooks:manage), até 10 por pessoa, só em https público. O segredo (whsec_…) aparece ao criar e ao rodar.
Cada entrega é um POST JSON com o id do evento, o tipo, a empresa e os ids do recurso, da ficha e da pessoa, com o estado e as datas. Nunca leva o IBAN, motivos, tipos de ausência, nomes de documentos nem valores: lê o resto pela API, com as permissões de quem lê.
POST https://erp.example.pt/selfcare/webhooks
Selfcare-Signature: t=1760000000,v1=5257a869…
Selfcare-Event-Id: 0b8e…
Selfcare-Event-Type: absence.approved
Selfcare-Delivery-Attempt: 1
{
"id": "0b8e…",
"type": "absence.approved",
"apiVersion": "v1",
"createdAt": "2026-11-03T09:12:00.000Z",
"occurredAt": "2026-11-03T09:12:00.000Z",
"tenantId": "aaaa…",
"data": { "object": "absence", "id": "3f1c…", "employeeId": "…", "userId": "…", "status": "APPROVED" }
}Verifica sempre a assinatura antes de confiar no corpo. Selfcare-Signature traz t= (o instante em segundos) e um ou mais v1= (o HMAC-SHA256 em hex) do segredo sobre t.corpo (o corpo tal como chegou). Recusa assinaturas com mais de 5 minutos e deduplica pelo id do evento: a entrega é pelo menos uma vez, sem ordem garantida.
import { verifyWebhookSignature } from "@selfcare/api-sdk";
export async function POST(req: Request) {
const body = await req.text(); // the raw body, before JSON.parse
const ok = await verifyWebhookSignature({
header: req.headers.get("Selfcare-Signature"),
body,
secret: process.env.SELFCARE_WEBHOOK_SECRET!, // whsec_…
});
if (!ok) return new Response("bad signature", { status: 400 });
const event = JSON.parse(body);
if (await alreadyProcessed(event.id)) return new Response(null, { status: 200 }); // at least once
await handle(event); // then read the resource through the API
return new Response(null, { status: 200 });
}Sem o SDK, em Node:
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(header: string | null, body: string, secret: string): boolean {
if (!header) return false;
const parts = header.split(",").map((p) => p.trim());
const t = Number(parts.find((p) => p.startsWith("t="))?.slice(2));
if (!Number.isInteger(t) || Math.abs(Date.now() / 1000 - t) > 300) return false;
const expected = createHmac("sha256", secret).update(`${t}.${body}`).digest();
return parts
.filter((p) => p.startsWith("v1="))
.some((p) => {
const got = Buffer.from(p.slice(3), "hex");
return got.length === expected.length && timingSafeEqual(got, expected);
});
}Responde 2xx em menos de 10 segundos (trata o evento depois, numa fila). Sem 2xx, há até 8 tentativas em cerca de 24 horas (1 min, 5 min, 30 min, 2 h, 5 h, 8 h e 8 h). Ao fim de 3 dias seguidos a falhar, o endpoint desliga-se e o dono é avisado na app e por email. As entregas ficam 30 dias no registo, com os primeiros 2 KB da resposta, e podem ser reenviadas (POST /v1/webhook-deliveries/{id}/redeliver). Para experimentar, POST /v1/webhook-endpoints/{id}/test envia um webhook.test. Depois de rodar o segredo, o anterior continua a assinar (segundo v1) durante 24 horas.
Eventos: absence.created, absence.updated, absence.approved, absence.rejected, absence.cancellation_requested, absence.cancelled, expense.submitted, expense.approved, expense.rejected, expense.paid, expense.cancelled, business_trip.submitted, business_trip.approved, business_trip.rejected, business_trip.cancelled, document.created, document.version_created, document.deleted, document.acknowledged, document.expiring, document.expired, document.review_requested, document.reviewed, employee.created, employee.updated, employee.status_changed, employee.contract_changed, employee.compensation_changed, employee.bank_details_change_requested, employee.bank_details_changed, employee.bank_details_change_rejected, team.created, team.updated, team.deleted, team.member_added, team.member_removed.
Apps móveis
Este guia percorre uma app móvel de férias e despesas: login nativo com OAuth, push, ecrã inicial, pedir férias e registar uma despesa com a foto do recibo. A app é uma app pública (sem segredo). Regista-a em Definições → API → As minhas apps, com o tipo pública e o redirect no esquema da app.
1. Login nativo com PKCE
import { OAuthSession, SelfcareClient, buildAuthorizeUrl, createPkcePair, exchangeCode, parseAuthorizationResponse, randomString } from "@selfcare/api-sdk";
const clientId = "sc_app_…";
const redirectUri = "work.selfcare.app:/oauth";
const { verifier, challenge } = await createPkcePair();
const state = randomString();
openSystemBrowser(buildAuthorizeUrl({ clientId, redirectUri, scopes: ["me:read", "absences:write"], state, codeChallenge: challenge }));
// On the redirect: check "state" and "iss" (RFC 9207), then exchange the code
const { code } = parseAuthorizationResponse(redirectedUrl, { state, issuer: "https://api.selfcare.work" });
const tokens = await exchangeCode({ clientId, code, redirectUri, codeVerifier: verifier });
const session = new OAuthSession(tokens, { clientId }, (t) => saveToKeychain(t)); // t === null: signed out
const api = new SelfcareClient({ token: () => session.accessToken(), onUnauthorized: () => session.forceRefresh() });2. Registar o telefone e mostrar o ecrã inicial
Abre o authorization_endpoint no browser do sistema (ASWebAuthenticationSession no iOS, Custom Tabs no Android; nunca numa WebView), com um code_verifier e um state novos em cada login. Guarda os tokens no Keychain ou no Keystore. Depois do login, e em cada arranque, regista o telefone com POST /v1/me/devices: o dispositivo fica preso a esta sessão. Os push levam só type, resourceType, resourceId e uma frase curta; tipos: absence.approved, absence.rejected, approval.pending, expense.approved, expense.rejected, expense.reimbursed, document.requested, bank_details.confirmation_pending.
// After signing in, and on every launch
await api.registerMyDevice({ body: { platform: "ios", pushToken: apnsToken, locale: "pt-PT", appVersion: "1.0.0" } });
// Home screen: balance, upcoming absences, approvals, documents, unread notifications
const home = await api.getMySummary();// Push payload (APNs / FCM data): never names, amounts or absence types
{ "type": "absence.approved", "resourceType": "absence", "resourceId": "3f1c…" }
// On tap: api.getAbsence({ params: { id: resourceId } })3. Pedir férias
Mostra o saldo antes de pedir. O pedido verifica o saldo, os feriados, os dias de descanso da pessoa e os períodos bloqueados como a app, e segue para os aprovadores (as equipas da pessoa) se o tipo pedir aprovação. Usa uma Idempotency-Key por pedido para que uma repetição por falha de rede não crie dois.
const { data: types } = await api.listAbsenceTypes();
const balance = await api.getVacationBalance({ params: { id: me.employee!.id } });
const absence = await api.createAbsence({
body: { absenceTypeCode: "FERIAS", startDate: "2026-12-21", endDate: "2026-12-24" },
idempotencyKey: crypto.randomUUID(), // keep it if you retry
});
// absence.status: "PENDING" (goes to the approvers) or "APPROVED"4. Despesa com a foto do recibo
A despesa nasce em rascunho. O recibo vai direto para o armazenamento por um URL pré-assinado de 15 minutos (o bilhete vale 30); a confirmação verifica o sha256 e o tipo real do ficheiro. Depois, submete a despesa para aprovação. O estado de reembolso vê-se em status (APPROVED, PAID) e paidAt.
No logout, chama POST /oauth/revoke com o refresh token (no SDK, session.signOut()): a sessão e os dispositivos dela deixam de receber push. Se um refresh falhar com invalid_grant, volta ao login.
const expense = await api.createExpense({ body: { date: "2026-11-03", description: "Almoço com cliente", category: "MEALS" } });
// The receipt photo: PDF, JPEG, PNG or WebP, up to 10 MB
const upload = await api.createExpenseAttachmentUpload({
params: { id: expense.id },
body: { fileName: "recibo.jpg", contentType: "image/jpeg", sizeBytes: bytes.length, sha256: sha256Hex(bytes) },
});
await fetch(upload.url, { method: upload.method, headers: upload.headers, body: bytes });
await api.addExpenseAttachment({ params: { id: expense.id }, body: { ticket: upload.ticket, amountCents: 2450 } });
await api.submitExpense({ params: { id: expense.id } });Referência
Ausências e férias
Tipos de ausência da empresa
/v1/absence-typesParâmetros da query
limitintegerItens por página. Por omissão 50, máximo 200.
cursorstringO
meta.nextCursorda página anterior, com os mesmos filtros.
Respostas
200OK
dataarray<AbsenceType>obrigatórioCampos de AbsenceType
idstring (uuid)obrigatóriocodestringobrigatórionamestringobrigatóriocolorstringobrigatórioisPaidbooleanobrigatóriocountsCalendarDaysbooleanobrigatóriocountsAgainstVacationbooleanobrigatóriorequiresApprovalbooleanobrigatóriomaxDaysPerYearinteger | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser nullmetaobjectobrigatórioCampos
nextCursorstring | nullobrigatóriopode ser nullhasMorebooleanobrigatório
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/absence-typescurl "https://api.selfcare.work/v1/absence-types" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"code": "FERIAS",
"name": "Férias",
"color": "string",
"isPaid": true,
"countsCalendarDays": true,
"countsAgainstVacation": true,
"requiresApproval": true,
"maxDaysPerYear": 0,
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
}
],
"error": null,
"meta": {
"nextCursor": "string",
"hasMore": true
}
}Ausências que o utilizador vê na app
/v1/absencesSobreposição com o intervalo de from a to. Os rascunhos só aparecem ao próprio.
Parâmetros da query
fromstring (date)tostring (date)statusstringValores separados por vírgulas.
employeeIdstring (uuid)teamIdstring (uuid)updatedSincestring (date-time)limitintegerItens por página. Por omissão 50, máximo 200.
cursorstringO
meta.nextCursorda página anterior, com os mesmos filtros.
Respostas
200OK
dataarray<Absence>obrigatórioCampos de Absence
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
absenceTypeAbsenceTypeRefobrigatórioPara quem não pode ver o tipo de uma ausência de saúde, sai com
idnull, códigoAUSENCIAe nomeAusência, como na app.Campos de AbsenceTypeRef
idstring (uuid) | nullobrigatóriopode ser nullcodestringobrigatórionamestringobrigatóriocolorstringobrigatório
startDatestring (date)obrigatórioendDatestring (date)obrigatóriostartHalfDaybooleanobrigatórioendHalfDaybooleanobrigatórioworkingDaysnumberobrigatórioreasonstring | nullobrigatóriopode ser nullSó para quem o vê na app: administradores, o próprio e os aprovadores.
statusstringobrigatóriosourcestringobrigatóriosubmittedAtstring (date-time) | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nullcancellationRequestedAtstring (date-time) | nullobrigatóriopode ser nullapprovalsarray<object>obrigatórioCampos
approverIdstring (uuid)obrigatórioviaTeamsstringobrigatóriodecisionstring | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nullcommentstring | nullobrigatóriopode ser null
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser nullmetaobjectobrigatórioCampos
nextCursorstring | nullobrigatóriopode ser nullhasMorebooleanobrigatório
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/absencescurl "https://api.selfcare.work/v1/absences?from=2026-10-01&to=2026-10-01" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"absenceType": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"code": "string",
"name": "string",
"color": "string"
},
"startDate": "2026-10-16",
"endDate": "2026-10-16",
"startHalfDay": true,
"endHalfDay": true,
"workingDays": 0,
"reason": "string",
"status": "DRAFT",
"source": "string",
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"cancellationRequestedAt": "2026-10-16T09:30:00.000Z",
"approvals": [
{
"approverId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"viaTeams": "string",
"decision": "string",
"decidedAt": "2026-10-16T09:30:00.000Z",
"comment": "string"
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
}
],
"error": null,
"meta": {
"nextCursor": "string",
"hasMore": true
}
}Marcar uma ausência
/v1/absencesPara si (sem employeeId) ou, se for RH, dono ou líder do visado, para outra pessoa. A mesma validação da app: saldo de férias, dias úteis pela escala e feriados, dias bloqueados, máximo anual do tipo. Não deixa marcar por cima de outra ausência da mesma pessoa.
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Corpo do pedido
application/jsonemployeeIdstring (uuid)Por omissão, a ficha de quem usa a credencial.
absenceTypeCodestringobrigatóriostartDatestring (date)obrigatórioendDatestring (date)obrigatóriostartHalfDaybooleanMeio-dia no primeiro dia.
endHalfDaybooleanMeio-dia no último dia.
reasonstringforceBlockedbooleanDono e RH: marcar férias por cima de um período bloqueado (fica registado).
Respostas
201Criado
dataAbsenceobrigatórioNunca leva o anexo (atestado).
Campos de Absence
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
absenceTypeAbsenceTypeRefobrigatórioPara quem não pode ver o tipo de uma ausência de saúde, sai com
idnull, códigoAUSENCIAe nomeAusência, como na app.Campos de AbsenceTypeRef
idstring (uuid) | nullobrigatóriopode ser nullcodestringobrigatórionamestringobrigatóriocolorstringobrigatório
startDatestring (date)obrigatórioendDatestring (date)obrigatóriostartHalfDaybooleanobrigatórioendHalfDaybooleanobrigatórioworkingDaysnumberobrigatórioreasonstring | nullobrigatóriopode ser nullSó para quem o vê na app: administradores, o próprio e os aprovadores.
statusstringobrigatóriosourcestringobrigatóriosubmittedAtstring (date-time) | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nullcancellationRequestedAtstring (date-time) | nullobrigatóriopode ser nullapprovalsarray<object>obrigatórioCampos
approverIdstring (uuid)obrigatórioviaTeamsstringobrigatóriodecisionstring | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nullcommentstring | nullobrigatóriopode ser null
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/absencescurl -X POST "https://api.selfcare.work/v1/absences" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"absenceTypeCode": "FERIAS",
"startDate": "2026-11-02",
"endDate": "2026-11-06"
}'Criado
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"absenceType": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"code": "string",
"name": "string",
"color": "string"
},
"startDate": "2026-10-16",
"endDate": "2026-10-16",
"startHalfDay": true,
"endHalfDay": true,
"workingDays": 0,
"reason": "string",
"status": "DRAFT",
"source": "string",
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"cancellationRequestedAt": "2026-10-16T09:30:00.000Z",
"approvals": [
{
"approverId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"viaTeams": "string",
"decision": "string",
"decidedAt": "2026-10-16T09:30:00.000Z",
"comment": "string"
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Uma ausência
/v1/absences/{id}Parâmetros do caminho
idobrigatóriostring (uuid)
Respostas
200OK
dataAbsenceobrigatórioNunca leva o anexo (atestado).
Campos de Absence
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
absenceTypeAbsenceTypeRefobrigatórioPara quem não pode ver o tipo de uma ausência de saúde, sai com
idnull, códigoAUSENCIAe nomeAusência, como na app.Campos de AbsenceTypeRef
idstring (uuid) | nullobrigatóriopode ser nullcodestringobrigatórionamestringobrigatóriocolorstringobrigatório
startDatestring (date)obrigatórioendDatestring (date)obrigatóriostartHalfDaybooleanobrigatórioendHalfDaybooleanobrigatórioworkingDaysnumberobrigatórioreasonstring | nullobrigatóriopode ser nullSó para quem o vê na app: administradores, o próprio e os aprovadores.
statusstringobrigatóriosourcestringobrigatóriosubmittedAtstring (date-time) | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nullcancellationRequestedAtstring (date-time) | nullobrigatóriopode ser nullapprovalsarray<object>obrigatórioCampos
approverIdstring (uuid)obrigatórioviaTeamsstringobrigatóriodecisionstring | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nullcommentstring | nullobrigatóriopode ser null
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/absences/{id}curl "https://api.selfcare.work/v1/absences/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"absenceType": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"code": "string",
"name": "string",
"color": "string"
},
"startDate": "2026-10-16",
"endDate": "2026-10-16",
"startHalfDay": true,
"endHalfDay": true,
"workingDays": 0,
"reason": "string",
"status": "DRAFT",
"source": "string",
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"cancellationRequestedAt": "2026-10-16T09:30:00.000Z",
"approvals": [
{
"approverId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"viaTeams": "string",
"decision": "string",
"decidedAt": "2026-10-16T09:30:00.000Z",
"comment": "string"
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Corrigir um pedido pendente
/v1/absences/{id}Só enquanto ninguém decidiu nada. Valida tudo de novo e recomeça a cadeia de aprovação. Aceita If-Match.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
If-MatchstringO ETag lido; se o recurso mudou entretanto, 412.
Corpo do pedido
application/jsonabsenceTypeCodestringstartDatestring (date)endDatestring (date)startHalfDaybooleanMeio-dia no primeiro dia.
endHalfDaybooleanMeio-dia no último dia.
reasonstringforceBlockedbooleanDono e RH: marcar férias por cima de um período bloqueado (fica registado).
Respostas
200OK
dataAbsenceobrigatórioNunca leva o anexo (atestado).
Campos de Absence
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
absenceTypeAbsenceTypeRefobrigatórioPara quem não pode ver o tipo de uma ausência de saúde, sai com
idnull, códigoAUSENCIAe nomeAusência, como na app.Campos de AbsenceTypeRef
idstring (uuid) | nullobrigatóriopode ser nullcodestringobrigatórionamestringobrigatóriocolorstringobrigatório
startDatestring (date)obrigatórioendDatestring (date)obrigatóriostartHalfDaybooleanobrigatórioendHalfDaybooleanobrigatórioworkingDaysnumberobrigatórioreasonstring | nullobrigatóriopode ser nullSó para quem o vê na app: administradores, o próprio e os aprovadores.
statusstringobrigatóriosourcestringobrigatóriosubmittedAtstring (date-time) | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nullcancellationRequestedAtstring (date-time) | nullobrigatóriopode ser nullapprovalsarray<object>obrigatórioCampos
approverIdstring (uuid)obrigatórioviaTeamsstringobrigatóriodecisionstring | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nullcommentstring | nullobrigatóriopode ser null
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 412O recurso mudou (If-Match)
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/absences/{id}curl -X PATCH "https://api.selfcare.work/v1/absences/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"absenceTypeCode": "FERIAS",
"startDate": "2026-11-02",
"endDate": "2026-11-06"
}'OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"absenceType": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"code": "string",
"name": "string",
"color": "string"
},
"startDate": "2026-10-16",
"endDate": "2026-10-16",
"startHalfDay": true,
"endHalfDay": true,
"workingDays": 0,
"reason": "string",
"status": "DRAFT",
"source": "string",
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"cancellationRequestedAt": "2026-10-16T09:30:00.000Z",
"approvals": [
{
"approverId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"viaTeams": "string",
"decision": "string",
"decidedAt": "2026-10-16T09:30:00.000Z",
"comment": "string"
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Aprovar uma ausência
/v1/absences/{id}/approveA regra da app: o aprovador decide a sua linha (ALL ou ANY); RH e dono por cima, nunca as próprias (exceto o dono).
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Corpo do pedido
application/jsoncommentstring
Respostas
200OK
dataAbsenceobrigatórioNunca leva o anexo (atestado).
Campos de Absence
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
absenceTypeAbsenceTypeRefobrigatórioPara quem não pode ver o tipo de uma ausência de saúde, sai com
idnull, códigoAUSENCIAe nomeAusência, como na app.Campos de AbsenceTypeRef
idstring (uuid) | nullobrigatóriopode ser nullcodestringobrigatórionamestringobrigatóriocolorstringobrigatório
startDatestring (date)obrigatórioendDatestring (date)obrigatóriostartHalfDaybooleanobrigatórioendHalfDaybooleanobrigatórioworkingDaysnumberobrigatórioreasonstring | nullobrigatóriopode ser nullSó para quem o vê na app: administradores, o próprio e os aprovadores.
statusstringobrigatóriosourcestringobrigatóriosubmittedAtstring (date-time) | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nullcancellationRequestedAtstring (date-time) | nullobrigatóriopode ser nullapprovalsarray<object>obrigatórioCampos
approverIdstring (uuid)obrigatórioviaTeamsstringobrigatóriodecisionstring | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nullcommentstring | nullobrigatóriopode ser null
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/absences/{id}/approvecurl -X POST "https://api.selfcare.work/v1/absences/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/approve" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"comment": "string"
}'OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"absenceType": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"code": "string",
"name": "string",
"color": "string"
},
"startDate": "2026-10-16",
"endDate": "2026-10-16",
"startHalfDay": true,
"endHalfDay": true,
"workingDays": 0,
"reason": "string",
"status": "DRAFT",
"source": "string",
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"cancellationRequestedAt": "2026-10-16T09:30:00.000Z",
"approvals": [
{
"approverId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"viaTeams": "string",
"decision": "string",
"decidedAt": "2026-10-16T09:30:00.000Z",
"comment": "string"
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Rejeitar uma ausência
/v1/absences/{id}/rejectA mesma regra de aprovar.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Corpo do pedido
application/jsoncommentstring
Respostas
200OK
dataAbsenceobrigatórioNunca leva o anexo (atestado).
Campos de Absence
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
absenceTypeAbsenceTypeRefobrigatórioPara quem não pode ver o tipo de uma ausência de saúde, sai com
idnull, códigoAUSENCIAe nomeAusência, como na app.Campos de AbsenceTypeRef
idstring (uuid) | nullobrigatóriopode ser nullcodestringobrigatórionamestringobrigatóriocolorstringobrigatório
startDatestring (date)obrigatórioendDatestring (date)obrigatóriostartHalfDaybooleanobrigatórioendHalfDaybooleanobrigatórioworkingDaysnumberobrigatórioreasonstring | nullobrigatóriopode ser nullSó para quem o vê na app: administradores, o próprio e os aprovadores.
statusstringobrigatóriosourcestringobrigatóriosubmittedAtstring (date-time) | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nullcancellationRequestedAtstring (date-time) | nullobrigatóriopode ser nullapprovalsarray<object>obrigatórioCampos
approverIdstring (uuid)obrigatórioviaTeamsstringobrigatóriodecisionstring | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nullcommentstring | nullobrigatóriopode ser null
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/absences/{id}/rejectcurl -X POST "https://api.selfcare.work/v1/absences/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/reject" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"comment": "string"
}'OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"absenceType": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"code": "string",
"name": "string",
"color": "string"
},
"startDate": "2026-10-16",
"endDate": "2026-10-16",
"startHalfDay": true,
"endHalfDay": true,
"workingDays": 0,
"reason": "string",
"status": "DRAFT",
"source": "string",
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"cancellationRequestedAt": "2026-10-16T09:30:00.000Z",
"approvals": [
{
"approverId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"viaTeams": "string",
"decision": "string",
"decidedAt": "2026-10-16T09:30:00.000Z",
"comment": "string"
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Cancelar uma ausência
/v1/absences/{id}/cancelUm pedido pendente cancela-se logo. Uma ausência aprovada cancela-se logo ou fica com o cancelamento à espera de aprovação (PENDING_CANCELLATION), como na app.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Respostas
200OK
dataAbsenceobrigatórioNunca leva o anexo (atestado).
Campos de Absence
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
absenceTypeAbsenceTypeRefobrigatórioPara quem não pode ver o tipo de uma ausência de saúde, sai com
idnull, códigoAUSENCIAe nomeAusência, como na app.Campos de AbsenceTypeRef
idstring (uuid) | nullobrigatóriopode ser nullcodestringobrigatórionamestringobrigatóriocolorstringobrigatório
startDatestring (date)obrigatórioendDatestring (date)obrigatóriostartHalfDaybooleanobrigatórioendHalfDaybooleanobrigatórioworkingDaysnumberobrigatórioreasonstring | nullobrigatóriopode ser nullSó para quem o vê na app: administradores, o próprio e os aprovadores.
statusstringobrigatóriosourcestringobrigatóriosubmittedAtstring (date-time) | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nullcancellationRequestedAtstring (date-time) | nullobrigatóriopode ser nullapprovalsarray<object>obrigatórioCampos
approverIdstring (uuid)obrigatórioviaTeamsstringobrigatóriodecisionstring | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nullcommentstring | nullobrigatóriopode ser null
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/absences/{id}/cancelcurl -X POST "https://api.selfcare.work/v1/absences/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/cancel" \
-H "Authorization: Bearer sc_live_…" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"absenceType": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"code": "string",
"name": "string",
"color": "string"
},
"startDate": "2026-10-16",
"endDate": "2026-10-16",
"startHalfDay": true,
"endHalfDay": true,
"workingDays": 0,
"reason": "string",
"status": "DRAFT",
"source": "string",
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"cancellationRequestedAt": "2026-10-16T09:30:00.000Z",
"approvals": [
{
"approverId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"viaTeams": "string",
"decision": "string",
"decidedAt": "2026-10-16T09:30:00.000Z",
"comment": "string"
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Saldo de férias de um colaborador
/v1/employees/{id}/vacation-balancePara quem vê as ausências da pessoa na app.
Parâmetros do caminho
idobrigatóriostring (uuid)
Parâmetros da query
yearinteger
Respostas
200OK
dataVacationBalanceobrigatórioCampos de VacationBalance
employeeIdstring (uuid)obrigatórioyearintegerobrigatórioentitlednumberobrigatórioDireito do ano (pro-rata no ano de admissão).
carriedOvernumberobrigatórioTransitados do ano anterior.
usednumberobrigatórioGozados (aprovados e já passados).
schedulednumberobrigatórioMarcados (aprovados futuros e pendentes).
availablenumberobrigatórioPor gozar: direito + transitados − gozados − marcados.
carryRemainingnumberobrigatóriocarryWindowOpenbooleanobrigatóriocarryDeadlinestringobrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/employees/{id}/vacation-balancecurl "https://api.selfcare.work/v1/employees/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/vacation-balance" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": {
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"year": 0,
"entitled": 0,
"carriedOver": 0,
"used": 0,
"scheduled": 0,
"available": 0,
"carryRemaining": 0,
"carryWindowOpen": true,
"carryDeadline": "30/04"
},
"error": null
}Referência
Aprovações
A caixa de Aprovações do utilizador
/v1/approvalsO que o utilizador tem para decidir, como na app. Despesas, deslocações e documentos só aparecem se a credencial tiver expenses:read, trips:read e documents:read.
Parâmetros da query
limitintegerItens por página. Por omissão 50, máximo 200.
cursorstringO
meta.nextCursorda página anterior, com os mesmos filtros.
Respostas
200OK
dataarray<ApprovalItem>obrigatórioCampos de ApprovalItem
idstringobrigatório<kind>:<id do recurso>, estável.kindstringobrigatórioresourceIdstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
summarystringobrigatórioDatas, valor ou título; sem dados de saúde.
viaTeamsarray<string>obrigatóriocreatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser nullmetaobjectobrigatórioCampos
nextCursorstring | nullobrigatóriopode ser nullhasMorebooleanobrigatório
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/approvalscurl "https://api.selfcare.work/v1/approvals" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": [
{
"id": "string",
"kind": "absence",
"resourceId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"summary": "string",
"viaTeams": [
"string"
],
"createdAt": "2026-10-16T09:30:00.000Z"
}
],
"error": null,
"meta": {
"nextCursor": "string",
"hasMore": true
}
}Referência
Eu
Os meus dispositivos
/v1/me/devicesOs telefones de quem pede registados para notificações push, nesta empresa. O token de push nunca volta.
Parâmetros da query
limitintegerItens por página. Por omissão 50, máximo 200.
cursorstringO
meta.nextCursorda página anterior, com os mesmos filtros.
Respostas
200OK
dataarray<MobileDevice>obrigatórioCampos de MobileDevice
idstring (uuid)obrigatórioplatformstringobrigatóriolocalestringobrigatórioIdioma das notificações deste telefone (pt ou en).
appVersionstring | nullobrigatóriopode ser nullappobject | nullobrigatóriopode ser nullA app OAuth que registou o dispositivo.
Campos
clientIdstringobrigatórionamestringobrigatório
lastSeenAtstring (date-time)obrigatóriocreatedAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser nullmetaobjectobrigatórioCampos
nextCursorstring | nullobrigatóriopode ser nullhasMorebooleanobrigatório
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/me/devicescurl "https://api.selfcare.work/v1/me/devices" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"platform": "ios",
"locale": "pt",
"appVersion": "string",
"app": {
"clientId": "string",
"name": "string"
},
"lastSeenAt": "2026-10-16T09:30:00.000Z",
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
}
],
"error": null,
"meta": {
"nextCursor": "string",
"hasMore": true
}
}Registar um dispositivo para push
/v1/me/devicesSó com um token OAuth: o dispositivo fica preso a essa sessão, e terminar a sessão (revogar o refresh token) ou revogar a app desliga-o. Chame-o em cada arranque da app: o mesmo token de push atualiza o registo. O token guarda-se cifrado; sem cifra configurada, 503. Um token de push que passe para outra pessoa deixa de receber os avisos da anterior.
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Corpo do pedido
application/jsonplatformstringobrigatóriopushTokenstringobrigatórioO token do APNs (iOS) ou do FCM (Android). Guarda-se cifrado e nunca volta numa resposta.
localestring | nullpode ser nullappVersionstring | nullpode ser null
Respostas
201Criado
dataMobileDeviceobrigatórioCampos de MobileDevice
idstring (uuid)obrigatórioplatformstringobrigatóriolocalestringobrigatórioIdioma das notificações deste telefone (pt ou en).
appVersionstring | nullobrigatóriopode ser nullappobject | nullobrigatóriopode ser nullA app OAuth que registou o dispositivo.
Campos
clientIdstringobrigatórionamestringobrigatório
lastSeenAtstring (date-time)obrigatóriocreatedAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
- 503Serviço indisponível (por exemplo, sem a chave de cifra configurada)
https://api.selfcare.work/v1/me/devicescurl -X POST "https://api.selfcare.work/v1/me/devices" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"platform": "ios",
"pushToken": "string",
"locale": "pt-PT",
"appVersion": "1.0.0 (42)"
}'Criado
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"platform": "ios",
"locale": "pt",
"appVersion": "string",
"app": {
"clientId": "string",
"name": "string"
},
"lastSeenAt": "2026-10-16T09:30:00.000Z",
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Apagar um dispositivo
/v1/me/devices/{id}Deixa de receber push. O dispositivo de outra pessoa é 404.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
If-MatchstringO ETag lido; se o recurso mudou entretanto, 412.
Respostas
200OK
dataMobileDeviceDeletedobrigatórioCampos de MobileDeviceDeleted
idstring (uuid)obrigatóriodeletedbooleanobrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/me/devices/{id}curl -X DELETE "https://api.selfcare.work/v1/me/devices/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"deleted": true
},
"error": null
}Resumo para o ecrã inicial
/v1/me/summarySaldo de férias, próximas ausências, pedidos à espera da minha decisão, documentos para ler, IBAN por confirmar e avisos por ler, numa só chamada. Cada bloco segue o âmbito do endpoint que o lê por inteiro e vem null sem ele.
Respostas
200OK
dataMeSummaryobrigatórioCampos de MeSummary
vacationBalanceVacationBalance | nullobrigatóriopode ser nullSaldo de férias do ano corrente (âmbito absences:read).
Campos de VacationBalance
employeeIdstring (uuid)obrigatórioyearintegerobrigatórioentitlednumberobrigatórioDireito do ano (pro-rata no ano de admissão).
carriedOvernumberobrigatórioTransitados do ano anterior.
usednumberobrigatórioGozados (aprovados e já passados).
schedulednumberobrigatórioMarcados (aprovados futuros e pendentes).
availablenumberobrigatórioPor gozar: direito + transitados − gozados − marcados.
carryRemainingnumberobrigatóriocarryWindowOpenbooleanobrigatóriocarryDeadlinestringobrigatório
upcomingAbsencesarray<object> | nullobrigatóriopode ser nullAs próximas 5 ausências, pedidas ou aprovadas (âmbito absences:read).
Campos
idstring (uuid)obrigatóriostartDatestringobrigatórioendDatestringobrigatóriostatusstringobrigatórioworkingDaysnumberobrigatório
approvalsPendinginteger | nullobrigatóriopode ser nullPedidos na caixa de Aprovações à espera da minha decisão (âmbito absences:read).
documentsToAcknowledgeinteger | nullobrigatóriopode ser nullDocumentos à espera de que confirme a leitura (âmbito documents:read).
bankDetailsConfirmationPendingbooleanobrigatóriounreadNotificationsintegerobrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/me/summarycurl "https://api.selfcare.work/v1/me/summary" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": {
"vacationBalance": {
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"year": 0,
"entitled": 0,
"carriedOver": 0,
"used": 0,
"scheduled": 0,
"available": 0,
"carryRemaining": 0,
"carryWindowOpen": true,
"carryDeadline": "30/04"
},
"upcomingAbsences": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"startDate": "string",
"endDate": "string",
"status": "string",
"workingDays": 0
}
],
"approvalsPending": 0,
"documentsToAcknowledge": 0,
"bankDetailsConfirmationPending": true,
"unreadNotifications": 0
},
"error": null
}Quem é a credencial
/v1/meUtilizador, empresa (a da credencial), papel, ficha, equipas que lidera e âmbitos.
Respostas
200OK
dataMeobrigatórioCampos de Me
userobjectobrigatórioCampos
idstring (uuid)obrigatórioemailstringobrigatórionamestring | nullobrigatóriopode ser null
tenantobjectobrigatórioCampos
idstring (uuid)obrigatórionamestringobrigatórioslugstring | nullobrigatóriopode ser nulltimeZonestringobrigatóriosandboxbooleanobrigatóriodisplayNamestringobrigatórioO nome que a empresa mostra às pessoas (o do portal, ou o nome legal se não houver). É o que um seletor de contas deve mostrar.
logoUrlstring | nullobrigatóriopode ser nullO logótipo da empresa (URL público), ou null se não tiver.
brandColorstringobrigatórioA cor principal da paleta da empresa (Definições → Aparência), em #RRGGBB.
rolestringobrigatórioemployeeobject | nullobrigatóriopode ser nullCampos
idstring (uuid)obrigatóriofullNamestringobrigatóriopreferredNamestring | nullobrigatóriopode ser nullemployeeNumberstringobrigatóriojobTitlestring | nullobrigatóriopode ser nullphotoUrlstring | nullobrigatóriopode ser nullstatusstringobrigatóriokindstringobrigatórioworkEmailstring | nullobrigatóriopode ser nullteamsarray<TeamRef>obrigatórioCampos de TeamRef
idstring (uuid)obrigatórionamestringobrigatório
ledTeamsarray<TeamRef>obrigatórioCampos de TeamRef
idstring (uuid)obrigatórionamestringobrigatório
credentialobjectobrigatórioCampos
typestringobrigatórioscopesarray<string>obrigatórioenvironmentstringobrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/mecurl "https://api.selfcare.work/v1/me" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": {
"user": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"email": "string",
"name": "string"
},
"tenant": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string",
"slug": "string",
"timeZone": "string",
"sandbox": true,
"displayName": "string",
"logoUrl": "string",
"brandColor": "#EA580C"
},
"role": "HR_ADMIN",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"preferredName": "string",
"employeeNumber": "string",
"jobTitle": "string",
"photoUrl": "string",
"status": "ACTIVE",
"kind": "string",
"workEmail": "string",
"teams": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string"
}
]
},
"ledTeams": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string"
}
],
"credential": {
"type": "api_key",
"scopes": [
"me:read"
],
"environment": "LIVE"
}
},
"error": null
}Referência
Despesas
Despesas que o utilizador vê na app
/v1/expensesAs do próprio (incluindo rascunhos); as da equipa para quem lidera; as da empresa para dono, RH e contabilista. Lista vazia com o módulo desligado.
Parâmetros da query
statusstringValores separados por vírgulas.
employeeIdstring (uuid)fromstring (date)tostring (date)updatedSincestring (date-time)limitintegerItens por página. Por omissão 50, máximo 200.
cursorstringO
meta.nextCursorda página anterior, com os mesmos filtros.
Respostas
200OK
dataarray<Expense>obrigatórioCampos de Expense
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
datestring (date)obrigatóriodescriptionstringobrigatóriocategorystringobrigatórioamountCentsintegerobrigatóriocurrencystringobrigatóriostatusstringobrigatóriorejectionNotestring | nullobrigatóriopode ser nullsubmittedAtstring (date-time) | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nulldecidedByNamestring | nullobrigatóriopode ser nullpaidAtstring (date-time) | nullobrigatóriopode ser nullattachmentsarray<ExpenseAttachment>obrigatórioCampos de ExpenseAttachment
idstring (uuid)obrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatórioamountCentsintegerobrigatório
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser nullmetaobjectobrigatórioCampos
nextCursorstring | nullobrigatóriopode ser nullhasMorebooleanobrigatório
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/expensescurl "https://api.selfcare.work/v1/expenses?status=APPROVED,PAID&from=2026-10-01" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"date": "2026-10-16",
"description": "string",
"category": "MEALS",
"amountCents": 0,
"currency": "EUR",
"status": "DRAFT",
"rejectionNote": "string",
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"decidedByName": "string",
"paidAt": "2026-10-16T09:30:00.000Z",
"attachments": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fileName": "string",
"contentType": "string",
"sizeBytes": 0,
"amountCents": 0
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
}
],
"error": null,
"meta": {
"nextCursor": "string",
"hasMore": true
}
}Criar uma despesa (rascunho)
/v1/expensesDo próprio, ou em nome de alguém por quem gere as despesas. Depois juntam-se os recibos e submete-se.
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Corpo do pedido
application/jsonemployeeIdstring (uuid)Em nome de outra pessoa: só quem gere as despesas.
datestring (date)descriptionstringcategorystring
Respostas
201Criado
dataExpenseobrigatórioCampos de Expense
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
datestring (date)obrigatóriodescriptionstringobrigatóriocategorystringobrigatórioamountCentsintegerobrigatóriocurrencystringobrigatóriostatusstringobrigatóriorejectionNotestring | nullobrigatóriopode ser nullsubmittedAtstring (date-time) | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nulldecidedByNamestring | nullobrigatóriopode ser nullpaidAtstring (date-time) | nullobrigatóriopode ser nullattachmentsarray<ExpenseAttachment>obrigatórioCampos de ExpenseAttachment
idstring (uuid)obrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatórioamountCentsintegerobrigatório
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/expensescurl -X POST "https://api.selfcare.work/v1/expenses" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"date": "2026-10-15"
}'Criado
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"date": "2026-10-16",
"description": "string",
"category": "MEALS",
"amountCents": 0,
"currency": "EUR",
"status": "DRAFT",
"rejectionNote": "string",
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"decidedByName": "string",
"paidAt": "2026-10-16T09:30:00.000Z",
"attachments": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fileName": "string",
"contentType": "string",
"sizeBytes": 0,
"amountCents": 0
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Uma despesa
/v1/expenses/{id}Parâmetros do caminho
idobrigatóriostring (uuid)
Respostas
200OK
dataExpenseobrigatórioCampos de Expense
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
datestring (date)obrigatóriodescriptionstringobrigatóriocategorystringobrigatórioamountCentsintegerobrigatóriocurrencystringobrigatóriostatusstringobrigatóriorejectionNotestring | nullobrigatóriopode ser nullsubmittedAtstring (date-time) | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nulldecidedByNamestring | nullobrigatóriopode ser nullpaidAtstring (date-time) | nullobrigatóriopode ser nullattachmentsarray<ExpenseAttachment>obrigatórioCampos de ExpenseAttachment
idstring (uuid)obrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatórioamountCentsintegerobrigatório
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/expenses/{id}curl "https://api.selfcare.work/v1/expenses/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"date": "2026-10-16",
"description": "string",
"category": "MEALS",
"amountCents": 0,
"currency": "EUR",
"status": "DRAFT",
"rejectionNote": "string",
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"decidedByName": "string",
"paidAt": "2026-10-16T09:30:00.000Z",
"attachments": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fileName": "string",
"contentType": "string",
"sizeBytes": 0,
"amountCents": 0
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Editar uma despesa
/v1/expenses/{id}Rascunhos e rejeitadas. Aceita If-Match.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
If-MatchstringO ETag lido; se o recurso mudou entretanto, 412.
Corpo do pedido
application/jsondatestring (date)descriptionstringcategorystring
Respostas
200OK
dataExpenseobrigatórioCampos de Expense
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
datestring (date)obrigatóriodescriptionstringobrigatóriocategorystringobrigatórioamountCentsintegerobrigatóriocurrencystringobrigatóriostatusstringobrigatóriorejectionNotestring | nullobrigatóriopode ser nullsubmittedAtstring (date-time) | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nulldecidedByNamestring | nullobrigatóriopode ser nullpaidAtstring (date-time) | nullobrigatóriopode ser nullattachmentsarray<ExpenseAttachment>obrigatórioCampos de ExpenseAttachment
idstring (uuid)obrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatórioamountCentsintegerobrigatório
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 412O recurso mudou (If-Match)
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/expenses/{id}curl -X PATCH "https://api.selfcare.work/v1/expenses/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"date": "2026-10-15"
}'OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"date": "2026-10-16",
"description": "string",
"category": "MEALS",
"amountCents": 0,
"currency": "EUR",
"status": "DRAFT",
"rejectionNote": "string",
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"decidedByName": "string",
"paidAt": "2026-10-16T09:30:00.000Z",
"attachments": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fileName": "string",
"contentType": "string",
"sizeBytes": 0,
"amountCents": 0
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Descarregar um anexo de despesa
/v1/expenses/{id}/attachments/{attachmentId}/contentDevolve um URL pré-assinado válido durante 5 minutos, nunca um redireccionamento.
Parâmetros do caminho
idobrigatóriostring (uuid)attachmentIdobrigatóriostring (uuid)
Respostas
200OK
dataFileLinkobrigatórioCampos de FileLink
urlstring (uri)obrigatórioURL pré-assinado de GET, válido 5 minutos. Usar já; não guardar nem partilhar.
expiresAtstring (date-time)obrigatóriofileNamestringobrigatóriocontentTypestringobrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/expenses/{id}/attachments/{attachmentId}/contentcurl "https://api.selfcare.work/v1/expenses/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/attachments/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/content" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": {
"url": "https://example.com",
"expiresAt": "2026-10-16T09:30:00.000Z",
"fileName": "string",
"contentType": "string"
},
"error": null
}Categorias de despesa
/v1/expense-categoriesO nome vem na língua do Accept-Language.
Respostas
200OK
dataarray<ExpenseCategory>obrigatórioCampos de ExpenseCategory
codestringobrigatórionamestringobrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/expense-categoriescurl "https://api.selfcare.work/v1/expense-categories" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": [
{
"code": "MEALS",
"name": "string"
}
],
"error": null
}Pedir o URL para um recibo
/v1/expenses/{id}/attachments/upload-urlDevolve um URL de PUT (15 minutos) e um bilhete (30 minutos). PDF, JPEG, PNG ou WebP, até 10 MB, como na app.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Corpo do pedido
application/jsonfileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatóriosha256stringobrigatóriosha256 dos bytes, em hexadecimal; confere-se ao confirmar.
Respostas
200OK
dataUploadUrlobrigatórioCampos de UploadUrl
urlstringobrigatórioURL pré-assinado para o PUT dos bytes (15 minutos).
methodstringobrigatórioheadersobject<string, string>obrigatórioCabeçalhos que o PUT tem de levar.
ticketstringobrigatórioBilhete para confirmar o upload (30 minutos).
expiresAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/expenses/{id}/attachments/upload-urlcurl -X POST "https://api.selfcare.work/v1/expenses/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/attachments/upload-url" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"fileName": "string",
"contentType": "image/jpeg",
"sizeBytes": 0,
"sha256": "string"
}'OK
{
"data": {
"url": "string",
"method": "PUT",
"headers": {},
"ticket": "string",
"expiresAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Juntar um recibo
/v1/expenses/{id}/attachmentsDepois do PUT. Confere o sha256 declarado e o tipo real pelos bytes.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Corpo do pedido
application/jsonticketstringobrigatórioamountCentsintegerobrigatório
Respostas
201Criado
dataExpenseobrigatórioCampos de Expense
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
datestring (date)obrigatóriodescriptionstringobrigatóriocategorystringobrigatórioamountCentsintegerobrigatóriocurrencystringobrigatóriostatusstringobrigatóriorejectionNotestring | nullobrigatóriopode ser nullsubmittedAtstring (date-time) | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nulldecidedByNamestring | nullobrigatóriopode ser nullpaidAtstring (date-time) | nullobrigatóriopode ser nullattachmentsarray<ExpenseAttachment>obrigatórioCampos de ExpenseAttachment
idstring (uuid)obrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatórioamountCentsintegerobrigatório
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/expenses/{id}/attachmentscurl -X POST "https://api.selfcare.work/v1/expenses/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/attachments" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"ticket": "string",
"amountCents": 0
}'Criado
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"date": "2026-10-16",
"description": "string",
"category": "MEALS",
"amountCents": 0,
"currency": "EUR",
"status": "DRAFT",
"rejectionNote": "string",
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"decidedByName": "string",
"paidAt": "2026-10-16T09:30:00.000Z",
"attachments": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fileName": "string",
"contentType": "string",
"sizeBytes": 0,
"amountCents": 0
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Corrigir o valor de um recibo
/v1/expenses/{id}/attachments/{attachmentId}Parâmetros do caminho
idobrigatóriostring (uuid)attachmentIdobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
If-MatchstringO ETag lido; se o recurso mudou entretanto, 412.
Corpo do pedido
application/jsonamountCentsintegerobrigatório
Respostas
200OK
dataExpenseobrigatórioCampos de Expense
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
datestring (date)obrigatóriodescriptionstringobrigatóriocategorystringobrigatórioamountCentsintegerobrigatóriocurrencystringobrigatóriostatusstringobrigatóriorejectionNotestring | nullobrigatóriopode ser nullsubmittedAtstring (date-time) | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nulldecidedByNamestring | nullobrigatóriopode ser nullpaidAtstring (date-time) | nullobrigatóriopode ser nullattachmentsarray<ExpenseAttachment>obrigatórioCampos de ExpenseAttachment
idstring (uuid)obrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatórioamountCentsintegerobrigatório
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/expenses/{id}/attachments/{attachmentId}curl -X PATCH "https://api.selfcare.work/v1/expenses/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/attachments/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"amountCents": 0
}'OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"date": "2026-10-16",
"description": "string",
"category": "MEALS",
"amountCents": 0,
"currency": "EUR",
"status": "DRAFT",
"rejectionNote": "string",
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"decidedByName": "string",
"paidAt": "2026-10-16T09:30:00.000Z",
"attachments": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fileName": "string",
"contentType": "string",
"sizeBytes": 0,
"amountCents": 0
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Tirar um recibo
/v1/expenses/{id}/attachments/{attachmentId}Parâmetros do caminho
idobrigatóriostring (uuid)attachmentIdobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
If-MatchstringO ETag lido; se o recurso mudou entretanto, 412.
Respostas
200OK
dataExpenseobrigatórioCampos de Expense
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
datestring (date)obrigatóriodescriptionstringobrigatóriocategorystringobrigatórioamountCentsintegerobrigatóriocurrencystringobrigatóriostatusstringobrigatóriorejectionNotestring | nullobrigatóriopode ser nullsubmittedAtstring (date-time) | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nulldecidedByNamestring | nullobrigatóriopode ser nullpaidAtstring (date-time) | nullobrigatóriopode ser nullattachmentsarray<ExpenseAttachment>obrigatórioCampos de ExpenseAttachment
idstring (uuid)obrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatórioamountCentsintegerobrigatório
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/expenses/{id}/attachments/{attachmentId}curl -X DELETE "https://api.selfcare.work/v1/expenses/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/attachments/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"date": "2026-10-16",
"description": "string",
"category": "MEALS",
"amountCents": 0,
"currency": "EUR",
"status": "DRAFT",
"rejectionNote": "string",
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"decidedByName": "string",
"paidAt": "2026-10-16T09:30:00.000Z",
"attachments": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fileName": "string",
"contentType": "string",
"sizeBytes": 0,
"amountCents": 0
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Submeter para reembolso
/v1/expenses/{id}/submitAs mesmas verificações da app e o mesmo aviso a quem decide.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Respostas
200OK
dataExpenseobrigatórioCampos de Expense
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
datestring (date)obrigatóriodescriptionstringobrigatóriocategorystringobrigatórioamountCentsintegerobrigatóriocurrencystringobrigatóriostatusstringobrigatóriorejectionNotestring | nullobrigatóriopode ser nullsubmittedAtstring (date-time) | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nulldecidedByNamestring | nullobrigatóriopode ser nullpaidAtstring (date-time) | nullobrigatóriopode ser nullattachmentsarray<ExpenseAttachment>obrigatórioCampos de ExpenseAttachment
idstring (uuid)obrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatórioamountCentsintegerobrigatório
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/expenses/{id}/submitcurl -X POST "https://api.selfcare.work/v1/expenses/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/submit" \
-H "Authorization: Bearer sc_live_…" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"date": "2026-10-16",
"description": "string",
"category": "MEALS",
"amountCents": 0,
"currency": "EUR",
"status": "DRAFT",
"rejectionNote": "string",
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"decidedByName": "string",
"paidAt": "2026-10-16T09:30:00.000Z",
"attachments": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fileName": "string",
"contentType": "string",
"sizeBytes": 0,
"amountCents": 0
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Cancelar uma despesa
/v1/expenses/{id}/cancelEnquanto não está paga nem num lote de pagamento.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Respostas
200OK
dataExpenseobrigatórioCampos de Expense
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
datestring (date)obrigatóriodescriptionstringobrigatóriocategorystringobrigatórioamountCentsintegerobrigatóriocurrencystringobrigatóriostatusstringobrigatóriorejectionNotestring | nullobrigatóriopode ser nullsubmittedAtstring (date-time) | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nulldecidedByNamestring | nullobrigatóriopode ser nullpaidAtstring (date-time) | nullobrigatóriopode ser nullattachmentsarray<ExpenseAttachment>obrigatórioCampos de ExpenseAttachment
idstring (uuid)obrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatórioamountCentsintegerobrigatório
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/expenses/{id}/cancelcurl -X POST "https://api.selfcare.work/v1/expenses/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/cancel" \
-H "Authorization: Bearer sc_live_…" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"date": "2026-10-16",
"description": "string",
"category": "MEALS",
"amountCents": 0,
"currency": "EUR",
"status": "DRAFT",
"rejectionNote": "string",
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"decidedByName": "string",
"paidAt": "2026-10-16T09:30:00.000Z",
"attachments": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fileName": "string",
"contentType": "string",
"sizeBytes": 0,
"amountCents": 0
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Aprovar uma despesa
/v1/expenses/{id}/approveRH, dono, contabilista e líderes dos membros; as próprias, só o dono.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Respostas
200OK
dataExpenseobrigatórioCampos de Expense
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
datestring (date)obrigatóriodescriptionstringobrigatóriocategorystringobrigatórioamountCentsintegerobrigatóriocurrencystringobrigatóriostatusstringobrigatóriorejectionNotestring | nullobrigatóriopode ser nullsubmittedAtstring (date-time) | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nulldecidedByNamestring | nullobrigatóriopode ser nullpaidAtstring (date-time) | nullobrigatóriopode ser nullattachmentsarray<ExpenseAttachment>obrigatórioCampos de ExpenseAttachment
idstring (uuid)obrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatórioamountCentsintegerobrigatório
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/expenses/{id}/approvecurl -X POST "https://api.selfcare.work/v1/expenses/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/approve" \
-H "Authorization: Bearer sc_live_…" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"date": "2026-10-16",
"description": "string",
"category": "MEALS",
"amountCents": 0,
"currency": "EUR",
"status": "DRAFT",
"rejectionNote": "string",
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"decidedByName": "string",
"paidAt": "2026-10-16T09:30:00.000Z",
"attachments": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fileName": "string",
"contentType": "string",
"sizeBytes": 0,
"amountCents": 0
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Rejeitar uma despesa
/v1/expenses/{id}/rejectCom a nota obrigatória, que o colaborador vê.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Corpo do pedido
application/jsonnotestringobrigatório
Respostas
200OK
dataExpenseobrigatórioCampos de Expense
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
datestring (date)obrigatóriodescriptionstringobrigatóriocategorystringobrigatórioamountCentsintegerobrigatóriocurrencystringobrigatóriostatusstringobrigatóriorejectionNotestring | nullobrigatóriopode ser nullsubmittedAtstring (date-time) | nullobrigatóriopode ser nulldecidedAtstring (date-time) | nullobrigatóriopode ser nulldecidedByNamestring | nullobrigatóriopode ser nullpaidAtstring (date-time) | nullobrigatóriopode ser nullattachmentsarray<ExpenseAttachment>obrigatórioCampos de ExpenseAttachment
idstring (uuid)obrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatórioamountCentsintegerobrigatório
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/expenses/{id}/rejectcurl -X POST "https://api.selfcare.work/v1/expenses/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/reject" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"note": "string"
}'OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"date": "2026-10-16",
"description": "string",
"category": "MEALS",
"amountCents": 0,
"currency": "EUR",
"status": "DRAFT",
"rejectionNote": "string",
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"decidedByName": "string",
"paidAt": "2026-10-16T09:30:00.000Z",
"attachments": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fileName": "string",
"contentType": "string",
"sizeBytes": 0,
"amountCents": 0
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Referência
Ajudas de custo
Deslocações (ajudas de custo) que o utilizador vê na app
/v1/business-tripsLista vazia com o módulo desligado.
Parâmetros da query
statusstringValores separados por vírgulas.
employeeIdstring (uuid)fromstring (date)tostring (date)updatedSincestring (date-time)limitintegerItens por página. Por omissão 50, máximo 200.
cursorstringO
meta.nextCursorda página anterior, com os mesmos filtros.
Respostas
200OK
dataarray<BusinessTrip>obrigatórioCampos de BusinessTrip
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
destinationstringobrigatóriopurposestringobrigatóriodepartureAtstringobrigatórioHora local de Portugal, sem fuso.
returnAtstringobrigatórioabroadbooleanobrigatóriostatusstringobrigatóriomodestringobrigatórionightsintegerobrigatóriolegalPercentintegerobrigatóriocurrencystringobrigatórioamountCentsintegerobrigatórioexemptAmountCentsintegerobrigatóriotaxableAmountCentsintegerobrigatóriosubmittedAtstring (date-time)obrigatóriodecidedAtstring (date-time) | nullobrigatóriopode ser nulldecidedByNamestring | nullobrigatóriopode ser nullrejectionNotestring | nullobrigatóriopode ser nullpaidAtstring (date-time) | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser nullmetaobjectobrigatórioCampos
nextCursorstring | nullobrigatóriopode ser nullhasMorebooleanobrigatório
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/business-tripscurl "https://api.selfcare.work/v1/business-trips?status=APPROVED&from=2026-10-01" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"destination": "string",
"purpose": "string",
"departureAt": "2026-10-05T09:00",
"returnAt": "2026-10-06T18:30",
"abroad": true,
"status": "SUBMITTED",
"mode": "string",
"nights": 0,
"legalPercent": 0,
"currency": "EUR",
"amountCents": 0,
"exemptAmountCents": 0,
"taxableAmountCents": 0,
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"decidedByName": "string",
"rejectionNote": "string",
"paidAt": "2026-10-16T09:30:00.000Z",
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
}
],
"error": null,
"meta": {
"nextCursor": "string",
"hasMore": true
}
}Registar uma deslocação
/v1/business-tripsDo próprio. Registar é submeter; o valor sai da política da empresa ou à mão.
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Corpo do pedido
application/jsondestinationstringobrigatóriopurposestringobrigatóriodepartureAtstringobrigatórioHora local de Portugal, sem fuso.
returnAtstringobrigatórioabroadbooleanobrigatóriodistanceConfirmedbooleanobrigatórioConfirma a distância mínima da lei (20 km sem pernoita, 50 km com).
manualAmountCentsintegerValor à mão, em cêntimos; sem ele, o cálculo da política.
Respostas
201Criado
dataBusinessTripobrigatórioCampos de BusinessTrip
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
destinationstringobrigatóriopurposestringobrigatóriodepartureAtstringobrigatórioHora local de Portugal, sem fuso.
returnAtstringobrigatórioabroadbooleanobrigatóriostatusstringobrigatóriomodestringobrigatórionightsintegerobrigatóriolegalPercentintegerobrigatóriocurrencystringobrigatórioamountCentsintegerobrigatórioexemptAmountCentsintegerobrigatóriotaxableAmountCentsintegerobrigatóriosubmittedAtstring (date-time)obrigatóriodecidedAtstring (date-time) | nullobrigatóriopode ser nulldecidedByNamestring | nullobrigatóriopode ser nullrejectionNotestring | nullobrigatóriopode ser nullpaidAtstring (date-time) | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/business-tripscurl -X POST "https://api.selfcare.work/v1/business-trips" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"destination": "string",
"purpose": "string",
"departureAt": "2026-10-05T09:00",
"returnAt": "2026-10-06T18:30",
"abroad": true,
"distanceConfirmed": true
}'Criado
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"destination": "string",
"purpose": "string",
"departureAt": "2026-10-05T09:00",
"returnAt": "2026-10-06T18:30",
"abroad": true,
"status": "SUBMITTED",
"mode": "string",
"nights": 0,
"legalPercent": 0,
"currency": "EUR",
"amountCents": 0,
"exemptAmountCents": 0,
"taxableAmountCents": 0,
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"decidedByName": "string",
"rejectionNote": "string",
"paidAt": "2026-10-16T09:30:00.000Z",
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Uma deslocação
/v1/business-trips/{id}Parâmetros do caminho
idobrigatóriostring (uuid)
Respostas
200OK
dataBusinessTripobrigatórioCampos de BusinessTrip
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
destinationstringobrigatóriopurposestringobrigatóriodepartureAtstringobrigatórioHora local de Portugal, sem fuso.
returnAtstringobrigatórioabroadbooleanobrigatóriostatusstringobrigatóriomodestringobrigatórionightsintegerobrigatóriolegalPercentintegerobrigatóriocurrencystringobrigatórioamountCentsintegerobrigatórioexemptAmountCentsintegerobrigatóriotaxableAmountCentsintegerobrigatóriosubmittedAtstring (date-time)obrigatóriodecidedAtstring (date-time) | nullobrigatóriopode ser nulldecidedByNamestring | nullobrigatóriopode ser nullrejectionNotestring | nullobrigatóriopode ser nullpaidAtstring (date-time) | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/business-trips/{id}curl "https://api.selfcare.work/v1/business-trips/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"destination": "string",
"purpose": "string",
"departureAt": "2026-10-05T09:00",
"returnAt": "2026-10-06T18:30",
"abroad": true,
"status": "SUBMITTED",
"mode": "string",
"nights": 0,
"legalPercent": 0,
"currency": "EUR",
"amountCents": 0,
"exemptAmountCents": 0,
"taxableAmountCents": 0,
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"decidedByName": "string",
"rejectionNote": "string",
"paidAt": "2026-10-16T09:30:00.000Z",
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Corrigir uma deslocação
/v1/business-trips/{id}Ainda por decidir, ou rejeitada (volta a ser submetida). Aceita If-Match.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
If-MatchstringO ETag lido; se o recurso mudou entretanto, 412.
Corpo do pedido
application/jsondestinationstringobrigatóriopurposestringobrigatóriodepartureAtstringobrigatórioHora local de Portugal, sem fuso.
returnAtstringobrigatórioabroadbooleanobrigatóriodistanceConfirmedbooleanobrigatórioConfirma a distância mínima da lei (20 km sem pernoita, 50 km com).
manualAmountCentsintegerValor à mão, em cêntimos; sem ele, o cálculo da política.
Respostas
200OK
dataBusinessTripobrigatórioCampos de BusinessTrip
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
destinationstringobrigatóriopurposestringobrigatóriodepartureAtstringobrigatórioHora local de Portugal, sem fuso.
returnAtstringobrigatórioabroadbooleanobrigatóriostatusstringobrigatóriomodestringobrigatórionightsintegerobrigatóriolegalPercentintegerobrigatóriocurrencystringobrigatórioamountCentsintegerobrigatórioexemptAmountCentsintegerobrigatóriotaxableAmountCentsintegerobrigatóriosubmittedAtstring (date-time)obrigatóriodecidedAtstring (date-time) | nullobrigatóriopode ser nulldecidedByNamestring | nullobrigatóriopode ser nullrejectionNotestring | nullobrigatóriopode ser nullpaidAtstring (date-time) | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 412O recurso mudou (If-Match)
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/business-trips/{id}curl -X PATCH "https://api.selfcare.work/v1/business-trips/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"destination": "string",
"purpose": "string",
"departureAt": "2026-10-05T09:00",
"returnAt": "2026-10-06T18:30",
"abroad": true,
"distanceConfirmed": true
}'OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"destination": "string",
"purpose": "string",
"departureAt": "2026-10-05T09:00",
"returnAt": "2026-10-06T18:30",
"abroad": true,
"status": "SUBMITTED",
"mode": "string",
"nights": 0,
"legalPercent": 0,
"currency": "EUR",
"amountCents": 0,
"exemptAmountCents": 0,
"taxableAmountCents": 0,
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"decidedByName": "string",
"rejectionNote": "string",
"paidAt": "2026-10-16T09:30:00.000Z",
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Cancelar uma deslocação
/v1/business-trips/{id}/cancelParâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Respostas
200OK
dataBusinessTripobrigatórioCampos de BusinessTrip
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
destinationstringobrigatóriopurposestringobrigatóriodepartureAtstringobrigatórioHora local de Portugal, sem fuso.
returnAtstringobrigatórioabroadbooleanobrigatóriostatusstringobrigatóriomodestringobrigatórionightsintegerobrigatóriolegalPercentintegerobrigatóriocurrencystringobrigatórioamountCentsintegerobrigatórioexemptAmountCentsintegerobrigatóriotaxableAmountCentsintegerobrigatóriosubmittedAtstring (date-time)obrigatóriodecidedAtstring (date-time) | nullobrigatóriopode ser nulldecidedByNamestring | nullobrigatóriopode ser nullrejectionNotestring | nullobrigatóriopode ser nullpaidAtstring (date-time) | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/business-trips/{id}/cancelcurl -X POST "https://api.selfcare.work/v1/business-trips/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/cancel" \
-H "Authorization: Bearer sc_live_…" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"destination": "string",
"purpose": "string",
"departureAt": "2026-10-05T09:00",
"returnAt": "2026-10-06T18:30",
"abroad": true,
"status": "SUBMITTED",
"mode": "string",
"nights": 0,
"legalPercent": 0,
"currency": "EUR",
"amountCents": 0,
"exemptAmountCents": 0,
"taxableAmountCents": 0,
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"decidedByName": "string",
"rejectionNote": "string",
"paidAt": "2026-10-16T09:30:00.000Z",
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Aprovar uma deslocação
/v1/business-trips/{id}/approveParâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Respostas
200OK
dataBusinessTripobrigatórioCampos de BusinessTrip
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
destinationstringobrigatóriopurposestringobrigatóriodepartureAtstringobrigatórioHora local de Portugal, sem fuso.
returnAtstringobrigatórioabroadbooleanobrigatóriostatusstringobrigatóriomodestringobrigatórionightsintegerobrigatóriolegalPercentintegerobrigatóriocurrencystringobrigatórioamountCentsintegerobrigatórioexemptAmountCentsintegerobrigatóriotaxableAmountCentsintegerobrigatóriosubmittedAtstring (date-time)obrigatóriodecidedAtstring (date-time) | nullobrigatóriopode ser nulldecidedByNamestring | nullobrigatóriopode ser nullrejectionNotestring | nullobrigatóriopode ser nullpaidAtstring (date-time) | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/business-trips/{id}/approvecurl -X POST "https://api.selfcare.work/v1/business-trips/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/approve" \
-H "Authorization: Bearer sc_live_…" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"destination": "string",
"purpose": "string",
"departureAt": "2026-10-05T09:00",
"returnAt": "2026-10-06T18:30",
"abroad": true,
"status": "SUBMITTED",
"mode": "string",
"nights": 0,
"legalPercent": 0,
"currency": "EUR",
"amountCents": 0,
"exemptAmountCents": 0,
"taxableAmountCents": 0,
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"decidedByName": "string",
"rejectionNote": "string",
"paidAt": "2026-10-16T09:30:00.000Z",
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Rejeitar uma deslocação
/v1/business-trips/{id}/rejectCom a nota obrigatória.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Corpo do pedido
application/jsonnotestringobrigatório
Respostas
200OK
dataBusinessTripobrigatórioCampos de BusinessTrip
idstring (uuid)obrigatórioemployeeEmployeeRefobrigatórioCampos de EmployeeRef
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
destinationstringobrigatóriopurposestringobrigatóriodepartureAtstringobrigatórioHora local de Portugal, sem fuso.
returnAtstringobrigatórioabroadbooleanobrigatóriostatusstringobrigatóriomodestringobrigatórionightsintegerobrigatóriolegalPercentintegerobrigatóriocurrencystringobrigatórioamountCentsintegerobrigatórioexemptAmountCentsintegerobrigatóriotaxableAmountCentsintegerobrigatóriosubmittedAtstring (date-time)obrigatóriodecidedAtstring (date-time) | nullobrigatóriopode ser nulldecidedByNamestring | nullobrigatóriopode ser nullrejectionNotestring | nullobrigatóriopode ser nullpaidAtstring (date-time) | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/business-trips/{id}/rejectcurl -X POST "https://api.selfcare.work/v1/business-trips/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/reject" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"note": "string"
}'OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employee": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"destination": "string",
"purpose": "string",
"departureAt": "2026-10-05T09:00",
"returnAt": "2026-10-06T18:30",
"abroad": true,
"status": "SUBMITTED",
"mode": "string",
"nights": 0,
"legalPercent": 0,
"currency": "EUR",
"amountCents": 0,
"exemptAmountCents": 0,
"taxableAmountCents": 0,
"submittedAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z",
"decidedByName": "string",
"rejectionNote": "string",
"paidAt": "2026-10-16T09:30:00.000Z",
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Referência
Documentos
Tipos de documento
/v1/document-typesSem os tipos de saúde nem os disciplinares.
Parâmetros da query
limitintegerItens por página. Por omissão 50, máximo 200.
cursorstringO
meta.nextCursorda página anterior, com os mesmos filtros.
Respostas
200OK
dataarray<DocumentType>obrigatórioCampos de DocumentType
idstring (uuid)obrigatóriocodestringobrigatórionamestringobrigatórioscopestringobrigatóriohasExpirybooleanobrigatóriorequiresAckbooleanobrigatóriosystembooleanobrigatórioactivebooleanobrigatório
errorany | nullobrigatóriopode ser nullmetaobjectobrigatórioCampos
nextCursorstring | nullobrigatóriopode ser nullhasMorebooleanobrigatório
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/document-typescurl "https://api.selfcare.work/v1/document-types" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"code": "PAYSLIP",
"name": "string",
"scope": "PERSON",
"hasExpiry": true,
"requiresAck": true,
"system": true,
"active": true
}
],
"error": null,
"meta": {
"nextCursor": "string",
"hasMore": true
}
}Documentos que o utilizador vê na app
/v1/documentsCada documento passa pela mesma regra de acesso da app. Os de saúde e os disciplinares nunca aparecem.
Parâmetros da query
employeeIdstring (uuid)spaceIdstring (uuid)typeKeystringperiodstringexpiresBeforestring (date)updatedSincestring (date-time)limitintegerItens por página. Por omissão 50, máximo 200.
cursorstringO
meta.nextCursorda página anterior, com os mesmos filtros.
Respostas
200OK
dataarray<Document>obrigatórioCampos de Document
idstring (uuid)obrigatóriotitlestringobrigatóriotypeobjectobrigatórioCampos
idstring (uuid)obrigatóriocodestringobrigatórionamestringobrigatório
spaceobjectobrigatórioCampos
idstring (uuid)obrigatóriokindstringobrigatórioemployeeIdstring (uuid) | nullobrigatóriopode ser nullteamIdstring (uuid) | nullobrigatóriopode ser null
ownerEmployeeIdstring (uuid) | nullobrigatóriopode ser nullfolderobject | nullobrigatóriopode ser nullCampos
idstring (uuid)obrigatórionamestringobrigatório
visibilitystringobrigatóriostatusstringobrigatóriooriginstringobrigatórioexpiresAtstring (date) | nullobrigatóriopode ser nullperiodstring | nullobrigatóriopode ser nullRecibos de vencimento: o mês.
ackRequestedbooleanobrigatórioackDueDatestring (date) | nullobrigatóriopode ser nullcurrentVersionDocumentVersion | nullobrigatóriopode ser nullCampos de DocumentVersion
idstring (uuid)obrigatórionumberintegerobrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatóriosha256string | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatório
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser nullmetaobjectobrigatórioCampos
nextCursorstring | nullobrigatóriopode ser nullhasMorebooleanobrigatório
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/documentscurl "https://api.selfcare.work/v1/documents?typeKey=PAYSLIP&period=2026-09" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"title": "string",
"type": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"code": "string",
"name": "string"
},
"space": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"kind": "PERSON",
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"teamId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10"
},
"ownerEmployeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"folder": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string"
},
"visibility": "PRIVATE",
"status": "PENDING_REVIEW",
"origin": "string",
"expiresAt": "2026-10-16",
"period": "2026-09",
"ackRequested": true,
"ackDueDate": "2026-10-16",
"currentVersion": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"number": 0,
"fileName": "string",
"contentType": "string",
"sizeBytes": 0,
"sha256": "string",
"createdAt": "2026-10-16T09:30:00.000Z"
},
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
}
],
"error": null,
"meta": {
"nextCursor": "string",
"hasMore": true
}
}Criar um documento
/v1/documentsConfirma o upload com o bilhete, confere o sha256, o tamanho e o tipo real. Um recibo de vencimento da mesma pessoa e mês fica como versão nova.
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Corpo do pedido
application/jsonticketstringobrigatóriotitlestringexpiresAtstring | nullpode ser nullvisibilitystringrequestAckboolean
Respostas
201Criado
dataDocumentobrigatórioCampos de Document
idstring (uuid)obrigatóriotitlestringobrigatóriotypeobjectobrigatórioCampos
idstring (uuid)obrigatóriocodestringobrigatórionamestringobrigatório
spaceobjectobrigatórioCampos
idstring (uuid)obrigatóriokindstringobrigatórioemployeeIdstring (uuid) | nullobrigatóriopode ser nullteamIdstring (uuid) | nullobrigatóriopode ser null
ownerEmployeeIdstring (uuid) | nullobrigatóriopode ser nullfolderobject | nullobrigatóriopode ser nullCampos
idstring (uuid)obrigatórionamestringobrigatório
visibilitystringobrigatóriostatusstringobrigatóriooriginstringobrigatórioexpiresAtstring (date) | nullobrigatóriopode ser nullperiodstring | nullobrigatóriopode ser nullRecibos de vencimento: o mês.
ackRequestedbooleanobrigatórioackDueDatestring (date) | nullobrigatóriopode ser nullcurrentVersionDocumentVersion | nullobrigatóriopode ser nullCampos de DocumentVersion
idstring (uuid)obrigatórionumberintegerobrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatóriosha256string | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatório
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/documentscurl -X POST "https://api.selfcare.work/v1/documents" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"ticket": "string"
}'Criado
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"title": "string",
"type": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"code": "string",
"name": "string"
},
"space": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"kind": "PERSON",
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"teamId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10"
},
"ownerEmployeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"folder": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string"
},
"visibility": "PRIVATE",
"status": "PENDING_REVIEW",
"origin": "string",
"expiresAt": "2026-10-16",
"period": "2026-09",
"ackRequested": true,
"ackDueDate": "2026-10-16",
"currentVersion": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"number": 0,
"fileName": "string",
"contentType": "string",
"sizeBytes": 0,
"sha256": "string",
"createdAt": "2026-10-16T09:30:00.000Z"
},
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Um documento
/v1/documents/{id}Parâmetros do caminho
idobrigatóriostring (uuid)
Respostas
200OK
dataDocumentobrigatórioCampos de Document
idstring (uuid)obrigatóriotitlestringobrigatóriotypeobjectobrigatórioCampos
idstring (uuid)obrigatóriocodestringobrigatórionamestringobrigatório
spaceobjectobrigatórioCampos
idstring (uuid)obrigatóriokindstringobrigatórioemployeeIdstring (uuid) | nullobrigatóriopode ser nullteamIdstring (uuid) | nullobrigatóriopode ser null
ownerEmployeeIdstring (uuid) | nullobrigatóriopode ser nullfolderobject | nullobrigatóriopode ser nullCampos
idstring (uuid)obrigatórionamestringobrigatório
visibilitystringobrigatóriostatusstringobrigatóriooriginstringobrigatórioexpiresAtstring (date) | nullobrigatóriopode ser nullperiodstring | nullobrigatóriopode ser nullRecibos de vencimento: o mês.
ackRequestedbooleanobrigatórioackDueDatestring (date) | nullobrigatóriopode ser nullcurrentVersionDocumentVersion | nullobrigatóriopode ser nullCampos de DocumentVersion
idstring (uuid)obrigatórionumberintegerobrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatóriosha256string | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatório
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/documents/{id}curl "https://api.selfcare.work/v1/documents/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"title": "string",
"type": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"code": "string",
"name": "string"
},
"space": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"kind": "PERSON",
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"teamId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10"
},
"ownerEmployeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"folder": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string"
},
"visibility": "PRIVATE",
"status": "PENDING_REVIEW",
"origin": "string",
"expiresAt": "2026-10-16",
"period": "2026-09",
"ackRequested": true,
"ackDueDate": "2026-10-16",
"currentVersion": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"number": 0,
"fileName": "string",
"contentType": "string",
"sizeBytes": 0,
"sha256": "string",
"createdAt": "2026-10-16T09:30:00.000Z"
},
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Editar um documento
/v1/documents/{id}Título ou validade, quando a app o deixa. Aceita If-Match.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
If-MatchstringO ETag lido; se o recurso mudou entretanto, 412.
Corpo do pedido
application/jsontitlestringexpiresAtstring | nullpode ser null
Respostas
200OK
dataDocumentobrigatórioCampos de Document
idstring (uuid)obrigatóriotitlestringobrigatóriotypeobjectobrigatórioCampos
idstring (uuid)obrigatóriocodestringobrigatórionamestringobrigatório
spaceobjectobrigatórioCampos
idstring (uuid)obrigatóriokindstringobrigatórioemployeeIdstring (uuid) | nullobrigatóriopode ser nullteamIdstring (uuid) | nullobrigatóriopode ser null
ownerEmployeeIdstring (uuid) | nullobrigatóriopode ser nullfolderobject | nullobrigatóriopode ser nullCampos
idstring (uuid)obrigatórionamestringobrigatório
visibilitystringobrigatóriostatusstringobrigatóriooriginstringobrigatórioexpiresAtstring (date) | nullobrigatóriopode ser nullperiodstring | nullobrigatóriopode ser nullRecibos de vencimento: o mês.
ackRequestedbooleanobrigatórioackDueDatestring (date) | nullobrigatóriopode ser nullcurrentVersionDocumentVersion | nullobrigatóriopode ser nullCampos de DocumentVersion
idstring (uuid)obrigatórionumberintegerobrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatóriosha256string | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatório
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 412O recurso mudou (If-Match)
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/documents/{id}curl -X PATCH "https://api.selfcare.work/v1/documents/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"title": "string"
}'OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"title": "string",
"type": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"code": "string",
"name": "string"
},
"space": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"kind": "PERSON",
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"teamId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10"
},
"ownerEmployeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"folder": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string"
},
"visibility": "PRIVATE",
"status": "PENDING_REVIEW",
"origin": "string",
"expiresAt": "2026-10-16",
"period": "2026-09",
"ackRequested": true,
"ackDueDate": "2026-10-16",
"currentVersion": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"number": 0,
"fileName": "string",
"contentType": "string",
"sizeBytes": 0,
"sha256": "string",
"createdAt": "2026-10-16T09:30:00.000Z"
},
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Apagar um documento
/v1/documents/{id}Quando a app o deixa. Aceita If-Match.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
If-MatchstringO ETag lido; se o recurso mudou entretanto, 412.
Respostas
200OK
dataDeletedobrigatórioCampos de Deleted
idstring (uuid)obrigatóriodeletedbooleanobrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 412O recurso mudou (If-Match)
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/documents/{id}curl -X DELETE "https://api.selfcare.work/v1/documents/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"deleted": true
},
"error": null
}Versões de um documento
/v1/documents/{id}/versionsParâmetros do caminho
idobrigatóriostring (uuid)
Parâmetros da query
limitintegerItens por página. Por omissão 50, máximo 200.
cursorstringO
meta.nextCursorda página anterior, com os mesmos filtros.
Respostas
200OK
dataarray<DocumentVersion>obrigatórioCampos de DocumentVersion
idstring (uuid)obrigatórionumberintegerobrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatóriosha256string | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser nullmetaobjectobrigatórioCampos
nextCursorstring | nullobrigatóriopode ser nullhasMorebooleanobrigatório
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/documents/{id}/versionscurl "https://api.selfcare.work/v1/documents/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/versions" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"number": 0,
"fileName": "string",
"contentType": "string",
"sizeBytes": 0,
"sha256": "string",
"createdAt": "2026-10-16T09:30:00.000Z"
}
],
"error": null,
"meta": {
"nextCursor": "string",
"hasMore": true
}
}Carregar uma versão nova
/v1/documents/{id}/versionsParâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Corpo do pedido
application/jsonticketstringobrigatórioexpiresAtstring | nullpode ser null
Respostas
201Criado
dataDocumentobrigatórioCampos de Document
idstring (uuid)obrigatóriotitlestringobrigatóriotypeobjectobrigatórioCampos
idstring (uuid)obrigatóriocodestringobrigatórionamestringobrigatório
spaceobjectobrigatórioCampos
idstring (uuid)obrigatóriokindstringobrigatórioemployeeIdstring (uuid) | nullobrigatóriopode ser nullteamIdstring (uuid) | nullobrigatóriopode ser null
ownerEmployeeIdstring (uuid) | nullobrigatóriopode ser nullfolderobject | nullobrigatóriopode ser nullCampos
idstring (uuid)obrigatórionamestringobrigatório
visibilitystringobrigatóriostatusstringobrigatóriooriginstringobrigatórioexpiresAtstring (date) | nullobrigatóriopode ser nullperiodstring | nullobrigatóriopode ser nullRecibos de vencimento: o mês.
ackRequestedbooleanobrigatórioackDueDatestring (date) | nullobrigatóriopode ser nullcurrentVersionDocumentVersion | nullobrigatóriopode ser nullCampos de DocumentVersion
idstring (uuid)obrigatórionumberintegerobrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatóriosha256string | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatório
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/documents/{id}/versionscurl -X POST "https://api.selfcare.work/v1/documents/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/versions" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"ticket": "string"
}'Criado
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"title": "string",
"type": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"code": "string",
"name": "string"
},
"space": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"kind": "PERSON",
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"teamId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10"
},
"ownerEmployeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"folder": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string"
},
"visibility": "PRIVATE",
"status": "PENDING_REVIEW",
"origin": "string",
"expiresAt": "2026-10-16",
"period": "2026-09",
"ackRequested": true,
"ackDueDate": "2026-10-16",
"currentVersion": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"number": 0,
"fileName": "string",
"contentType": "string",
"sizeBytes": 0,
"sha256": "string",
"createdAt": "2026-10-16T09:30:00.000Z"
},
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Descarregar uma versão
/v1/documents/{id}/versions/{versionId}/contentDevolve um URL pré-assinado válido durante 5 minutos e regista o acesso (origem API).
Parâmetros do caminho
idobrigatóriostring (uuid)versionIdobrigatóriostring (uuid)
Respostas
200OK
dataFileLinkobrigatórioCampos de FileLink
urlstring (uri)obrigatórioURL pré-assinado de GET, válido 5 minutos. Usar já; não guardar nem partilhar.
expiresAtstring (date-time)obrigatóriofileNamestringobrigatóriocontentTypestringobrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/documents/{id}/versions/{versionId}/contentcurl "https://api.selfcare.work/v1/documents/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/versions/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/content" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": {
"url": "https://example.com",
"expiresAt": "2026-10-16T09:30:00.000Z",
"fileName": "string",
"contentType": "string"
},
"error": null
}Documentos obrigatórios da empresa
/v1/document-requirementsSem os de saúde nem os disciplinares.
Parâmetros da query
limitintegerItens por página. Por omissão 50, máximo 200.
cursorstringO
meta.nextCursorda página anterior, com os mesmos filtros.
Respostas
200OK
dataarray<DocumentRequirement>obrigatórioCampos de DocumentRequirement
idstring (uuid)obrigatóriotypeobjectobrigatórioCampos
idstring (uuid)obrigatóriocodestringobrigatórionamestringobrigatório
requiresExpirybooleanobrigatórioactivebooleanobrigatório
errorany | nullobrigatóriopode ser nullmetaobjectobrigatórioCampos
nextCursorstring | nullobrigatóriopode ser nullhasMorebooleanobrigatório
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/document-requirementscurl "https://api.selfcare.work/v1/document-requirements" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"type": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"code": "string",
"name": "string"
},
"requiresExpiry": true,
"active": true
}
],
"error": null,
"meta": {
"nextCursor": "string",
"hasMore": true
}
}Estado dos documentos obrigatórios de um colaborador
/v1/employees/{id}/document-checklistPara o próprio e para quem gere documentos (dono, RH, contabilista). Sem itens de saúde.
Parâmetros do caminho
idobrigatóriostring (uuid)
Respostas
200OK
dataarray<DocumentChecklistItem>obrigatórioCampos de DocumentChecklistItem
requirementIdstring (uuid)obrigatóriotypeobjectobrigatórioCampos
idstring (uuid)obrigatóriocodestringobrigatórionamestringobrigatório
statestringobrigatóriodocumentIdstring (uuid) | nullobrigatóriopode ser nullexpiresAtstring (date) | nullobrigatóriopode ser nulldaysLeftinteger | nullobrigatóriopode ser null
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/employees/{id}/document-checklistcurl "https://api.selfcare.work/v1/employees/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/document-checklist" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": [
{
"requirementId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"type": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"code": "string",
"name": "string"
},
"state": "MISSING",
"documentId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"expiresAt": "2026-10-16",
"daysLeft": 0
}
],
"error": null
}Pedir o URL para um documento
/v1/uploadsDocumento novo, versão nova ou recibo de vencimento (só quem gere documentos). Tipos de saúde e disciplinares são recusados.
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Corpo do pedido
application/jsontargetobjectobrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatóriosha256stringobrigatóriosha256 dos bytes, em hexadecimal; confere-se ao confirmar.
Respostas
200OK
dataUploadUrlobrigatórioCampos de UploadUrl
urlstringobrigatórioURL pré-assinado para o PUT dos bytes (15 minutos).
methodstringobrigatórioheadersobject<string, string>obrigatórioCabeçalhos que o PUT tem de levar.
ticketstringobrigatórioBilhete para confirmar o upload (30 minutos).
expiresAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/uploadscurl -X POST "https://api.selfcare.work/v1/uploads" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"target": {
"kind": "document",
"typeKey": "CONTRACT",
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"spaceId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"folderId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10"
},
"fileName": "string",
"contentType": "image/jpeg",
"sizeBytes": 0,
"sha256": "string"
}'OK
{
"data": {
"url": "string",
"method": "PUT",
"headers": {},
"ticket": "string",
"expiresAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Confirmar a leitura
/v1/documents/{id}/acknowledgeDa versão atual, quando foi pedida.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Respostas
200OK
dataDocumentobrigatórioCampos de Document
idstring (uuid)obrigatóriotitlestringobrigatóriotypeobjectobrigatórioCampos
idstring (uuid)obrigatóriocodestringobrigatórionamestringobrigatório
spaceobjectobrigatórioCampos
idstring (uuid)obrigatóriokindstringobrigatórioemployeeIdstring (uuid) | nullobrigatóriopode ser nullteamIdstring (uuid) | nullobrigatóriopode ser null
ownerEmployeeIdstring (uuid) | nullobrigatóriopode ser nullfolderobject | nullobrigatóriopode ser nullCampos
idstring (uuid)obrigatórionamestringobrigatório
visibilitystringobrigatóriostatusstringobrigatóriooriginstringobrigatórioexpiresAtstring (date) | nullobrigatóriopode ser nullperiodstring | nullobrigatóriopode ser nullRecibos de vencimento: o mês.
ackRequestedbooleanobrigatórioackDueDatestring (date) | nullobrigatóriopode ser nullcurrentVersionDocumentVersion | nullobrigatóriopode ser nullCampos de DocumentVersion
idstring (uuid)obrigatórionumberintegerobrigatóriofileNamestringobrigatóriocontentTypestringobrigatóriosizeBytesintegerobrigatóriosha256string | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatório
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/documents/{id}/acknowledgecurl -X POST "https://api.selfcare.work/v1/documents/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/acknowledge" \
-H "Authorization: Bearer sc_live_…" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"title": "string",
"type": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"code": "string",
"name": "string"
},
"space": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"kind": "PERSON",
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"teamId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10"
},
"ownerEmployeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"folder": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string"
},
"visibility": "PRIVATE",
"status": "PENDING_REVIEW",
"origin": "string",
"expiresAt": "2026-10-16",
"period": "2026-09",
"ackRequested": true,
"ackDueDate": "2026-10-16",
"currentVersion": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"number": 0,
"fileName": "string",
"contentType": "string",
"sizeBytes": 0,
"sha256": "string",
"createdAt": "2026-10-16T09:30:00.000Z"
},
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Referência
Colaboradores
Colaboradores (diretório)
/v1/employeesProcurar por nif é só para quem vê dados pessoais.
Parâmetros da query
qstringTexto a procurar no nome, nome preferido, email de trabalho e número de colaborador (e no email pessoal, para quem vê dados pessoais).
statusstringValores separados por vírgulas.
teamIdstring (uuid)employeeNumberstringnifstringupdatedSincestring (date-time)limitintegerItens por página. Por omissão 50, máximo 200.
cursorstringO
meta.nextCursorda página anterior, com os mesmos filtros.
Respostas
200OK
dataarray<Employee>obrigatórioCampos de Employee
idstring (uuid)obrigatórioemployeeNumberstringobrigatórioexternalCodestring | nullobrigatóriopode ser nullCódigo no ERP; só para quem vê dados pessoais.
fullNamestringobrigatóriopreferredNamestring | nullobrigatóriopode ser nullworkEmailstring | nullobrigatóriopode ser nullworkPhonestring | nullobrigatóriopode ser nulljobTitlestring | nullobrigatóriopode ser nullstatusstringobrigatóriokindstringobrigatóriophotoUrlstring | nullobrigatóriopode ser nullworkLocationstring | nullobrigatóriopode ser nulllocationIdstring (uuid) | nullobrigatóriopode ser nullteamsarray<TeamRef>obrigatórioCampos de TeamRef
idstring (uuid)obrigatórionamestringobrigatório
personalEmailstring | nullobrigatóriopode ser nullPara colegas, só com o consentimento da pessoa.
phonestring | nullobrigatóriopode ser nullpersonalDataobject | nullobrigatóriopode ser nullSó para dono, RH, contabilista e o próprio; null para os outros.
Campos
dateOfBirthstring (date) | nullobrigatóriopode ser nullnationalitystring | nullobrigatóriopode ser nullnifstring | nullobrigatóriopode ser nullnissstring | nullobrigatóriopode ser nullcitizenCardNumberstring | nullobrigatóriopode ser nullcitizenCardExpirystring (date) | nullobrigatóriopode ser nullibanstring | nullobrigatóriopode ser nullSempre mascarado (só os últimos 4 dígitos), nas listas e no detalhe.
swiftBicstring | nullobrigatóriopode ser nulladdressobjectobrigatórioCampos
streetstring | nullobrigatóriopode ser nullcitystring | nullobrigatóriopode ser nullpostalCodestring | nullobrigatóriopode ser nullcountrystring | nullpode ser null
fiscalAddressobjectobrigatórioCampos
streetstring | nullobrigatóriopode ser nullcitystring | nullobrigatóriopode ser nullpostalCodestring | nullobrigatóriopode ser nullcountrystring | nullpode ser null
emergencyContactobjectobrigatórioCampos
namestring | nullobrigatóriopode ser nullrelationstring | nullobrigatóriopode ser nullphonestring | nullobrigatóriopode ser null
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser nullmetaobjectobrigatórioCampos
nextCursorstring | nullobrigatóriopode ser nullhasMorebooleanobrigatório
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/employeescurl "https://api.selfcare.work/v1/employees?status=ACTIVE,ON_LEAVE&updatedSince=2026-10-01T00:00:00Z" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employeeNumber": "string",
"externalCode": "string",
"fullName": "string",
"preferredName": "string",
"workEmail": "string",
"workPhone": "string",
"jobTitle": "string",
"status": "ACTIVE",
"kind": "string",
"photoUrl": "string",
"workLocation": "string",
"locationId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"teams": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string"
}
],
"personalEmail": "string",
"phone": "string",
"personalData": {
"dateOfBirth": "2026-10-16",
"nationality": "string",
"nif": "string",
"niss": "string",
"citizenCardNumber": "string",
"citizenCardExpiry": "2026-10-16",
"iban": "string",
"swiftBic": "string",
"address": {
"street": "string",
"city": "string",
"postalCode": "string",
"country": "string"
},
"fiscalAddress": {
"street": "string",
"city": "string",
"postalCode": "string",
"country": "string"
},
"emergencyContact": {
"name": "string",
"relation": "string",
"phone": "string"
}
},
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
}
],
"error": null,
"meta": {
"nextCursor": "string",
"hasMore": true
}
}Criar um colaborador
/v1/employeesA mesma ação e a mesma validação do ecrã Novo colaborador (dono, RH ou gestor). Cria o contrato inicial com a data de entrada e, com convite, envia-o por email. O salário não se define aqui: usa POST /employees/{id}/compensation.
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Corpo do pedido
application/jsonemployeeNumberstringSem ele, o próximo número livre (EMP-0001, EMP-0002...).
fullNamestringobrigatóriopreferredNamestring | nullpode ser nullpersonalEmailstring (email) | nullpode ser nullworkEmailstring (email) | nullpode ser nullphonestring | nullpode ser nullkindstringaccessRolestringPerfil de acesso da conta. Acima de EMPLOYEE, só o dono e o RH o podem dar.
contractTypestringstartDatestring (date)obrigatóriojobTitlestring | nullpode ser nullteamIdsarray<string (uuid)>workLocationstring | nullpode ser nullexternalobjectTarifa de um prestador de serviços. É remuneração: pede também o âmbito compensation:write e só dono e RH.
Campos
rateTypestringobrigatóriorateAmountCentsintegerobrigatóriounitsPerMonthnumber | nullpode ser nullvacationPaidboolean | nullpode ser nullabsencesPaidboolean | nullpode ser nullmonthsPaidPerYearinteger | nullpode ser null
sendInvitebooleanEnvia o convite para o email pessoal; o email profissional passa a ser o de entrada na app.
Respostas
201Criado
dataEmployeeobrigatórioCampos de Employee
idstring (uuid)obrigatórioemployeeNumberstringobrigatórioexternalCodestring | nullobrigatóriopode ser nullCódigo no ERP; só para quem vê dados pessoais.
fullNamestringobrigatóriopreferredNamestring | nullobrigatóriopode ser nullworkEmailstring | nullobrigatóriopode ser nullworkPhonestring | nullobrigatóriopode ser nulljobTitlestring | nullobrigatóriopode ser nullstatusstringobrigatóriokindstringobrigatóriophotoUrlstring | nullobrigatóriopode ser nullworkLocationstring | nullobrigatóriopode ser nulllocationIdstring (uuid) | nullobrigatóriopode ser nullteamsarray<TeamRef>obrigatórioCampos de TeamRef
idstring (uuid)obrigatórionamestringobrigatório
personalEmailstring | nullobrigatóriopode ser nullPara colegas, só com o consentimento da pessoa.
phonestring | nullobrigatóriopode ser nullpersonalDataobject | nullobrigatóriopode ser nullSó para dono, RH, contabilista e o próprio; null para os outros.
Campos
dateOfBirthstring (date) | nullobrigatóriopode ser nullnationalitystring | nullobrigatóriopode ser nullnifstring | nullobrigatóriopode ser nullnissstring | nullobrigatóriopode ser nullcitizenCardNumberstring | nullobrigatóriopode ser nullcitizenCardExpirystring (date) | nullobrigatóriopode ser nullibanstring | nullobrigatóriopode ser nullSempre mascarado (só os últimos 4 dígitos), nas listas e no detalhe.
swiftBicstring | nullobrigatóriopode ser nulladdressobjectobrigatórioCampos
streetstring | nullobrigatóriopode ser nullcitystring | nullobrigatóriopode ser nullpostalCodestring | nullobrigatóriopode ser nullcountrystring | nullpode ser null
fiscalAddressobjectobrigatórioCampos
streetstring | nullobrigatóriopode ser nullcitystring | nullobrigatóriopode ser nullpostalCodestring | nullobrigatóriopode ser nullcountrystring | nullpode ser null
emergencyContactobjectobrigatórioCampos
namestring | nullobrigatóriopode ser nullrelationstring | nullobrigatóriopode ser nullphonestring | nullobrigatóriopode ser null
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/employeescurl -X POST "https://api.selfcare.work/v1/employees" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"fullName": "string",
"startDate": "2026-11-01"
}'Criado
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employeeNumber": "string",
"externalCode": "string",
"fullName": "string",
"preferredName": "string",
"workEmail": "string",
"workPhone": "string",
"jobTitle": "string",
"status": "ACTIVE",
"kind": "string",
"photoUrl": "string",
"workLocation": "string",
"locationId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"teams": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string"
}
],
"personalEmail": "string",
"phone": "string",
"personalData": {
"dateOfBirth": "2026-10-16",
"nationality": "string",
"nif": "string",
"niss": "string",
"citizenCardNumber": "string",
"citizenCardExpiry": "2026-10-16",
"iban": "string",
"swiftBic": "string",
"address": {
"street": "string",
"city": "string",
"postalCode": "string",
"country": "string"
},
"fiscalAddress": {
"street": "string",
"city": "string",
"postalCode": "string",
"country": "string"
},
"emergencyContact": {
"name": "string",
"relation": "string",
"phone": "string"
}
},
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Um colaborador
/v1/employees/{id}Parâmetros do caminho
idobrigatóriostring (uuid)
Respostas
200OK
dataEmployeeobrigatórioCampos de Employee
idstring (uuid)obrigatórioemployeeNumberstringobrigatórioexternalCodestring | nullobrigatóriopode ser nullCódigo no ERP; só para quem vê dados pessoais.
fullNamestringobrigatóriopreferredNamestring | nullobrigatóriopode ser nullworkEmailstring | nullobrigatóriopode ser nullworkPhonestring | nullobrigatóriopode ser nulljobTitlestring | nullobrigatóriopode ser nullstatusstringobrigatóriokindstringobrigatóriophotoUrlstring | nullobrigatóriopode ser nullworkLocationstring | nullobrigatóriopode ser nulllocationIdstring (uuid) | nullobrigatóriopode ser nullteamsarray<TeamRef>obrigatórioCampos de TeamRef
idstring (uuid)obrigatórionamestringobrigatório
personalEmailstring | nullobrigatóriopode ser nullPara colegas, só com o consentimento da pessoa.
phonestring | nullobrigatóriopode ser nullpersonalDataobject | nullobrigatóriopode ser nullSó para dono, RH, contabilista e o próprio; null para os outros.
Campos
dateOfBirthstring (date) | nullobrigatóriopode ser nullnationalitystring | nullobrigatóriopode ser nullnifstring | nullobrigatóriopode ser nullnissstring | nullobrigatóriopode ser nullcitizenCardNumberstring | nullobrigatóriopode ser nullcitizenCardExpirystring (date) | nullobrigatóriopode ser nullibanstring | nullobrigatóriopode ser nullSempre mascarado (só os últimos 4 dígitos), nas listas e no detalhe.
swiftBicstring | nullobrigatóriopode ser nulladdressobjectobrigatórioCampos
streetstring | nullobrigatóriopode ser nullcitystring | nullobrigatóriopode ser nullpostalCodestring | nullobrigatóriopode ser nullcountrystring | nullpode ser null
fiscalAddressobjectobrigatórioCampos
streetstring | nullobrigatóriopode ser nullcitystring | nullobrigatóriopode ser nullpostalCodestring | nullobrigatóriopode ser nullcountrystring | nullpode ser null
emergencyContactobjectobrigatórioCampos
namestring | nullobrigatóriopode ser nullrelationstring | nullobrigatóriopode ser nullphonestring | nullobrigatóriopode ser null
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/employees/{id}curl "https://api.selfcare.work/v1/employees/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employeeNumber": "string",
"externalCode": "string",
"fullName": "string",
"preferredName": "string",
"workEmail": "string",
"workPhone": "string",
"jobTitle": "string",
"status": "ACTIVE",
"kind": "string",
"photoUrl": "string",
"workLocation": "string",
"locationId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"teams": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string"
}
],
"personalEmail": "string",
"phone": "string",
"personalData": {
"dateOfBirth": "2026-10-16",
"nationality": "string",
"nif": "string",
"niss": "string",
"citizenCardNumber": "string",
"citizenCardExpiry": "2026-10-16",
"iban": "string",
"swiftBic": "string",
"address": {
"street": "string",
"city": "string",
"postalCode": "string",
"country": "string"
},
"fiscalAddress": {
"street": "string",
"city": "string",
"postalCode": "string",
"country": "string"
},
"emergencyContact": {
"name": "string",
"relation": "string",
"phone": "string"
}
},
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Editar a ficha de um colaborador
/v1/employees/{id}Muda só os campos enviados, pelas regras da ficha na app. Quem não pode escrever nada na pessoa recebe 404. If-Match opcional (412 se a ficha mudou).
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
If-MatchstringO ETag lido; se o recurso mudou entretanto, 412.
Corpo do pedido
application/jsonfullNamestringpreferredNamestring | nullpode ser nullpersonalEmailstring (email) | nullpode ser nullphonestring | nullpode ser nullgenderstring | nullpode ser nulldateOfBirthstring (date) | nullpode ser nullnationalitystring | nullpode ser nullnifstring | nullpode ser nullnissstring | nullpode ser nullcitizenCardNumberstring | nullpode ser nullcitizenCardExpirystring (date) | nullpode ser nulladdressobjectCampos
streetstring | nullpode ser nullcitystring | nullpode ser nullpostalCodestring | nullpode ser nullcountrystring | nullpode ser null
emergencyContactobjectCampos
namestring | nullpode ser nullrelationstring | nullpode ser nullphonestring | nullpode ser null
jobTitlestring | nullpode ser nullworkEmailstring (email) | nullpode ser nullworkPhonestring | nullpode ser nullexternalCodestring | nullpode ser nulllocationIdstring (uuid) | nullpode ser nullteamIdsarray<string (uuid)>
Respostas
200OK
dataEmployeeobrigatórioCampos de Employee
idstring (uuid)obrigatórioemployeeNumberstringobrigatórioexternalCodestring | nullobrigatóriopode ser nullCódigo no ERP; só para quem vê dados pessoais.
fullNamestringobrigatóriopreferredNamestring | nullobrigatóriopode ser nullworkEmailstring | nullobrigatóriopode ser nullworkPhonestring | nullobrigatóriopode ser nulljobTitlestring | nullobrigatóriopode ser nullstatusstringobrigatóriokindstringobrigatóriophotoUrlstring | nullobrigatóriopode ser nullworkLocationstring | nullobrigatóriopode ser nulllocationIdstring (uuid) | nullobrigatóriopode ser nullteamsarray<TeamRef>obrigatórioCampos de TeamRef
idstring (uuid)obrigatórionamestringobrigatório
personalEmailstring | nullobrigatóriopode ser nullPara colegas, só com o consentimento da pessoa.
phonestring | nullobrigatóriopode ser nullpersonalDataobject | nullobrigatóriopode ser nullSó para dono, RH, contabilista e o próprio; null para os outros.
Campos
dateOfBirthstring (date) | nullobrigatóriopode ser nullnationalitystring | nullobrigatóriopode ser nullnifstring | nullobrigatóriopode ser nullnissstring | nullobrigatóriopode ser nullcitizenCardNumberstring | nullobrigatóriopode ser nullcitizenCardExpirystring (date) | nullobrigatóriopode ser nullibanstring | nullobrigatóriopode ser nullSempre mascarado (só os últimos 4 dígitos), nas listas e no detalhe.
swiftBicstring | nullobrigatóriopode ser nulladdressobjectobrigatórioCampos
streetstring | nullobrigatóriopode ser nullcitystring | nullobrigatóriopode ser nullpostalCodestring | nullobrigatóriopode ser nullcountrystring | nullpode ser null
fiscalAddressobjectobrigatórioCampos
streetstring | nullobrigatóriopode ser nullcitystring | nullobrigatóriopode ser nullpostalCodestring | nullobrigatóriopode ser nullcountrystring | nullpode ser null
emergencyContactobjectobrigatórioCampos
namestring | nullobrigatóriopode ser nullrelationstring | nullobrigatóriopode ser nullphonestring | nullobrigatóriopode ser null
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 412O recurso mudou (If-Match)
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/employees/{id}curl -X PATCH "https://api.selfcare.work/v1/employees/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"dateOfBirth": "2026-11-01",
"citizenCardExpiry": "2026-11-01"
}'OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employeeNumber": "string",
"externalCode": "string",
"fullName": "string",
"preferredName": "string",
"workEmail": "string",
"workPhone": "string",
"jobTitle": "string",
"status": "ACTIVE",
"kind": "string",
"photoUrl": "string",
"workLocation": "string",
"locationId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"teams": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string"
}
],
"personalEmail": "string",
"phone": "string",
"personalData": {
"dateOfBirth": "2026-10-16",
"nationality": "string",
"nif": "string",
"niss": "string",
"citizenCardNumber": "string",
"citizenCardExpiry": "2026-10-16",
"iban": "string",
"swiftBic": "string",
"address": {
"street": "string",
"city": "string",
"postalCode": "string",
"country": "string"
},
"fiscalAddress": {
"street": "string",
"city": "string",
"postalCode": "string",
"country": "string"
},
"emergencyContact": {
"name": "string",
"relation": "string",
"phone": "string"
}
},
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Histórico de contratos de um colaborador
/v1/employees/{id}/contractsÂmbito sensível, marcado à parte. Para dono, RH, contabilista e o próprio.
Parâmetros do caminho
idobrigatóriostring (uuid)
Parâmetros da query
limitintegerItens por página. Por omissão 50, máximo 200.
cursorstringO
meta.nextCursorda página anterior, com os mesmos filtros.
Respostas
200OK
dataarray<Contract>obrigatórioCampos de Contract
idstring (uuid)obrigatórioemployeeIdstring (uuid)obrigatórioeffectiveFromstring (date)obrigatórioeffectiveTostring (date) | nullobrigatóriopode ser nullreasonstringobrigatóriocontractTypestringobrigatóriostartDatestring (date)obrigatórioendDatestring (date) | nullobrigatóriopode ser nullprobationEndDatestring (date) | nullobrigatóriopode ser nullweeklyHoursnumberobrigatóriovacationDaysPerYearintegerobrigatóriocctsstring | nullobrigatóriopode ser nullnotesstring | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser nullmetaobjectobrigatórioCampos
nextCursorstring | nullobrigatóriopode ser nullhasMorebooleanobrigatório
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/employees/{id}/contractscurl "https://api.selfcare.work/v1/employees/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/contracts" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"effectiveFrom": "2026-10-16",
"effectiveTo": "2026-10-16",
"reason": "HIRING",
"contractType": "PERMANENT",
"startDate": "2026-10-16",
"endDate": "2026-10-16",
"probationEndDate": "2026-10-16",
"weeklyHours": 0,
"vacationDaysPerYear": 0,
"ccts": "string",
"notes": "string",
"createdAt": "2026-10-16T09:30:00.000Z"
}
],
"error": null,
"meta": {
"nextCursor": "string",
"hasMore": true
}
}Registar uma alteração de contrato
/v1/employees/{id}/contractsÂmbito contracts:write, só dono e RH. Motivo obrigatório e Idempotency-Key obrigatória. A entrada vigente fecha na véspera da data de efeito, que tem de ser posterior. Fica no registo de auditoria com o antes e o depois, e o colaborador é avisado.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeyobrigatóriostringObrigatória nesta escrita (428 sem ela). Durante 24 horas, repetir com a mesma chave e o mesmo corpo devolve a mesma resposta; com outro corpo, 422.
Corpo do pedido
application/jsoneffectiveFromstring (date)obrigatórioreasonstringobrigatóriocontractTypestringobrigatóriostartDatestring (date)obrigatórioendDatestring (date) | nullpode ser nullprobationEndDatestring (date) | nullpode ser nullweeklyHoursnumberobrigatóriovacationDaysPerYearintegercctsstring | nullpode ser nullnotesstring | nullpode ser nulljustificationstringobrigatórioMotivo da alteração, obrigatório. Fica no registo de auditoria com os valores antes e depois.
Respostas
201Criado
dataContractobrigatórioCampos de Contract
idstring (uuid)obrigatórioemployeeIdstring (uuid)obrigatórioeffectiveFromstring (date)obrigatórioeffectiveTostring (date) | nullobrigatóriopode ser nullreasonstringobrigatóriocontractTypestringobrigatóriostartDatestring (date)obrigatórioendDatestring (date) | nullobrigatóriopode ser nullprobationEndDatestring (date) | nullobrigatóriopode ser nullweeklyHoursnumberobrigatóriovacationDaysPerYearintegerobrigatóriocctsstring | nullobrigatóriopode ser nullnotesstring | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 428Falta o If-Match ou a Idempotency-Key, obrigatórios nesta escrita
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/employees/{id}/contractscurl -X POST "https://api.selfcare.work/v1/employees/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/contracts" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"effectiveFrom": "2026-11-01",
"reason": "HIRING",
"contractType": "PERMANENT",
"startDate": "2026-11-01",
"endDate": "2026-11-01",
"probationEndDate": "2026-11-01",
"weeklyHours": 0,
"justification": "Revisão salarial anual aprovada pela administração"
}'Criado
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"effectiveFrom": "2026-10-16",
"effectiveTo": "2026-10-16",
"reason": "HIRING",
"contractType": "PERMANENT",
"startDate": "2026-10-16",
"endDate": "2026-10-16",
"probationEndDate": "2026-10-16",
"weeklyHours": 0,
"vacationDaysPerYear": 0,
"ccts": "string",
"notes": "string",
"createdAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Histórico de remuneração de um colaborador
/v1/employees/{id}/compensationÂmbito sensível, marcado à parte. Para dono, RH, contabilista e o próprio. Não é processamento salarial.
Parâmetros do caminho
idobrigatóriostring (uuid)
Parâmetros da query
limitintegerItens por página. Por omissão 50, máximo 200.
cursorstringO
meta.nextCursorda página anterior, com os mesmos filtros.
Respostas
200OK
dataarray<Compensation>obrigatórioCampos de Compensation
idstring (uuid)obrigatórioemployeeIdstring (uuid)obrigatórioeffectiveFromstring (date)obrigatórioeffectiveTostring (date) | nullobrigatóriopode ser nullreasonstringobrigatóriocurrencystringobrigatóriobaseSalaryMonthlyCentsintegerobrigatóriosalaryPaidMonthsintegerobrigatóriomealAllowanceDailyCentsintegerobrigatóriomealAllowanceFormstringobrigatórioseniorityBonusCentsintegerobrigatóriocoverflexMonthlyCentsinteger | nullobrigatóriopode ser nullexpenseAllowanceCentsinteger | nullobrigatóriopode ser nullworkingTimeExemptionobjectobrigatórioIsenção de horário de trabalho (CT arts. 218.º e 219.º).
Campos
enabledbooleanobrigatóriomodalitystring | nullobrigatóriopode ser nullcompensationModestring | nullobrigatóriopode ser nullcompensationValuenumber | nullobrigatóriopode ser nullPercentagem do vencimento base, horas ou euros por mês, conforme o modo de cálculo.
agreementDatestring (date) | nullobrigatóriopode ser null
externalobject | nullobrigatóriopode ser nullCampos
rateTypestring | nullobrigatóriopode ser nullrateAmountCentsinteger | nullobrigatóriopode ser nullunitsPerMonthnumber | nullobrigatóriopode ser nullvacationPaidboolean | nullobrigatóriopode ser nullabsencesPaidboolean | nullobrigatóriopode ser nullmonthsPaidPerYearinteger | nullobrigatóriopode ser null
notesstring | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser nullmetaobjectobrigatórioCampos
nextCursorstring | nullobrigatóriopode ser nullhasMorebooleanobrigatório
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/employees/{id}/compensationcurl "https://api.selfcare.work/v1/employees/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/compensation" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"effectiveFrom": "2026-10-16",
"effectiveTo": "2026-10-16",
"reason": "HIRING",
"currency": "EUR",
"baseSalaryMonthlyCents": 0,
"salaryPaidMonths": 0,
"mealAllowanceDailyCents": 0,
"mealAllowanceForm": "string",
"seniorityBonusCents": 0,
"coverflexMonthlyCents": 0,
"expenseAllowanceCents": 0,
"workingTimeExemption": {
"enabled": true,
"modality": "NOT_SUBJECT_TO_PNT_LIMITS",
"compensationMode": "PERCENT_OF_BASE",
"compensationValue": 0,
"agreementDate": "2026-10-16"
},
"external": {
"rateType": "string",
"rateAmountCents": 0,
"unitsPerMonth": 0,
"vacationPaid": true,
"absencesPaid": true,
"monthsPaidPerYear": 0
},
"notes": "string",
"createdAt": "2026-10-16T09:30:00.000Z"
}
],
"error": null,
"meta": {
"nextCursor": "string",
"hasMore": true
}
}Registar uma alteração de remuneração
/v1/employees/{id}/compensationÂmbito compensation:write, só dono e RH. Motivo obrigatório e Idempotency-Key obrigatória. O subsídio de alimentação é sempre o da empresa. Fica no registo de auditoria com o antes e o depois; o colaborador é avisado na app e por email, sem valores.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeyobrigatóriostringObrigatória nesta escrita (428 sem ela). Durante 24 horas, repetir com a mesma chave e o mesmo corpo devolve a mesma resposta; com outro corpo, 422.
Corpo do pedido
application/jsoneffectiveFromstring (date)obrigatórioreasonstringobrigatóriobaseSalaryMonthlyCentsintegerobrigatóriosalaryPaidMonthsnumberobrigatórioseniorityBonusCentsintegercoverflexMonthlyCentsinteger | nullpode ser nullexpenseAllowanceCentsinteger | nullpode ser nullworkingTimeExemptionobjectIsenção de horário de trabalho (CT arts. 218.º e 219.º).
Campos
enabledbooleanobrigatóriomodalitystring | nullpode ser nullcompensationModestring | nullpode ser nullcompensationValuenumber | nullpode ser nullPercentagem do vencimento base, horas ou euros por mês, conforme o modo de cálculo.
agreementDatestring (date) | nullpode ser null
notesstring | nullpode ser nulljustificationstringobrigatórioMotivo da alteração, obrigatório. Fica no registo de auditoria com os valores antes e depois.
Respostas
201Criado
dataCompensationobrigatórioCampos de Compensation
idstring (uuid)obrigatórioemployeeIdstring (uuid)obrigatórioeffectiveFromstring (date)obrigatórioeffectiveTostring (date) | nullobrigatóriopode ser nullreasonstringobrigatóriocurrencystringobrigatóriobaseSalaryMonthlyCentsintegerobrigatóriosalaryPaidMonthsintegerobrigatóriomealAllowanceDailyCentsintegerobrigatóriomealAllowanceFormstringobrigatórioseniorityBonusCentsintegerobrigatóriocoverflexMonthlyCentsinteger | nullobrigatóriopode ser nullexpenseAllowanceCentsinteger | nullobrigatóriopode ser nullworkingTimeExemptionobjectobrigatórioIsenção de horário de trabalho (CT arts. 218.º e 219.º).
Campos
enabledbooleanobrigatóriomodalitystring | nullobrigatóriopode ser nullcompensationModestring | nullobrigatóriopode ser nullcompensationValuenumber | nullobrigatóriopode ser nullPercentagem do vencimento base, horas ou euros por mês, conforme o modo de cálculo.
agreementDatestring (date) | nullobrigatóriopode ser null
externalobject | nullobrigatóriopode ser nullCampos
rateTypestring | nullobrigatóriopode ser nullrateAmountCentsinteger | nullobrigatóriopode ser nullunitsPerMonthnumber | nullobrigatóriopode ser nullvacationPaidboolean | nullobrigatóriopode ser nullabsencesPaidboolean | nullobrigatóriopode ser nullmonthsPaidPerYearinteger | nullobrigatóriopode ser null
notesstring | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 428Falta o If-Match ou a Idempotency-Key, obrigatórios nesta escrita
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/employees/{id}/compensationcurl -X POST "https://api.selfcare.work/v1/employees/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/compensation" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"effectiveFrom": "2026-11-01",
"reason": "HIRING",
"baseSalaryMonthlyCents": 0,
"salaryPaidMonths": 12,
"justification": "Revisão salarial anual aprovada pela administração"
}'Criado
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"effectiveFrom": "2026-10-16",
"effectiveTo": "2026-10-16",
"reason": "HIRING",
"currency": "EUR",
"baseSalaryMonthlyCents": 0,
"salaryPaidMonths": 0,
"mealAllowanceDailyCents": 0,
"mealAllowanceForm": "string",
"seniorityBonusCents": 0,
"coverflexMonthlyCents": 0,
"expenseAllowanceCents": 0,
"workingTimeExemption": {
"enabled": true,
"modality": "NOT_SUBJECT_TO_PNT_LIMITS",
"compensationMode": "PERCENT_OF_BASE",
"compensationValue": 0,
"agreementDate": "2026-10-16"
},
"external": {
"rateType": "string",
"rateAmountCents": 0,
"unitsPerMonth": 0,
"vacationPaid": true,
"absencesPaid": true,
"monthsPaidPerYear": 0
},
"notes": "string",
"createdAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Mudança de IBAN à espera de confirmação
/v1/employees/{id}/bank-details/pendingPara quem vê os dados pessoais da pessoa (dono, RH, contabilista e o próprio). A mudança só entra em vigor quando o colaborador a confirma na app. data é null quando não há nenhuma pendente.
Parâmetros do caminho
idobrigatóriostring (uuid)
Respostas
200OK
dataPendingBankDetailsChange | nullobrigatóriopode ser nullCampos de PendingBankDetailsChange
idstring (uuid)obrigatórioemployeeIdstring (uuid)obrigatóriostatusstringobrigatórioPENDING até o colaborador decidir. CONFIRMED aplica o IBAN; REJECTED, CANCELLED e EXPIRED deixam o anterior.
ibanMaskedstringobrigatórioMascarado: só os últimos 4 dígitos.
requestedAtstring (date-time)obrigatórioexpiresAtstring (date-time)obrigatórioAté quando o colaborador pode confirmar. Nunca entra em vigor sozinha.
decidedAtstring (date-time) | nullobrigatóriopode ser null
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/employees/{id}/bank-details/pendingcurl "https://api.selfcare.work/v1/employees/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/bank-details/pending" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"status": "PENDING",
"ibanMasked": "****0154",
"requestedAt": "2026-10-16T09:30:00.000Z",
"expiresAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Cancelar a mudança de IBAN pendente
/v1/employees/{id}/bank-details/pendingO próprio, o dono ou o RH. O IBAN da ficha não muda. Sem pedido pendente, 404.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
If-MatchstringO ETag lido; se o recurso mudou entretanto, 412.
Respostas
200OK
dataPendingBankDetailsChangeobrigatórioCampos de PendingBankDetailsChange
idstring (uuid)obrigatórioemployeeIdstring (uuid)obrigatóriostatusstringobrigatórioPENDING até o colaborador decidir. CONFIRMED aplica o IBAN; REJECTED, CANCELLED e EXPIRED deixam o anterior.
ibanMaskedstringobrigatórioMascarado: só os últimos 4 dígitos.
requestedAtstring (date-time)obrigatórioexpiresAtstring (date-time)obrigatórioAté quando o colaborador pode confirmar. Nunca entra em vigor sozinha.
decidedAtstring (date-time) | nullobrigatóriopode ser null
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/employees/{id}/bank-details/pendingcurl -X DELETE "https://api.selfcare.work/v1/employees/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/bank-details/pending" \
-H "Authorization: Bearer sc_live_…" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"status": "PENDING",
"ibanMasked": "****0154",
"requestedAt": "2026-10-16T09:30:00.000Z",
"expiresAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Arquivar um colaborador
/v1/employees/{id}/archiveDono e RH. Tira a pessoa das listas e dos seletores sem cessar o contrato, como na app. Um colaborador cessado ou já arquivado dá 409.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Respostas
200OK
dataEmployeeobrigatórioCampos de Employee
idstring (uuid)obrigatórioemployeeNumberstringobrigatórioexternalCodestring | nullobrigatóriopode ser nullCódigo no ERP; só para quem vê dados pessoais.
fullNamestringobrigatóriopreferredNamestring | nullobrigatóriopode ser nullworkEmailstring | nullobrigatóriopode ser nullworkPhonestring | nullobrigatóriopode ser nulljobTitlestring | nullobrigatóriopode ser nullstatusstringobrigatóriokindstringobrigatóriophotoUrlstring | nullobrigatóriopode ser nullworkLocationstring | nullobrigatóriopode ser nulllocationIdstring (uuid) | nullobrigatóriopode ser nullteamsarray<TeamRef>obrigatórioCampos de TeamRef
idstring (uuid)obrigatórionamestringobrigatório
personalEmailstring | nullobrigatóriopode ser nullPara colegas, só com o consentimento da pessoa.
phonestring | nullobrigatóriopode ser nullpersonalDataobject | nullobrigatóriopode ser nullSó para dono, RH, contabilista e o próprio; null para os outros.
Campos
dateOfBirthstring (date) | nullobrigatóriopode ser nullnationalitystring | nullobrigatóriopode ser nullnifstring | nullobrigatóriopode ser nullnissstring | nullobrigatóriopode ser nullcitizenCardNumberstring | nullobrigatóriopode ser nullcitizenCardExpirystring (date) | nullobrigatóriopode ser nullibanstring | nullobrigatóriopode ser nullSempre mascarado (só os últimos 4 dígitos), nas listas e no detalhe.
swiftBicstring | nullobrigatóriopode ser nulladdressobjectobrigatórioCampos
streetstring | nullobrigatóriopode ser nullcitystring | nullobrigatóriopode ser nullpostalCodestring | nullobrigatóriopode ser nullcountrystring | nullpode ser null
fiscalAddressobjectobrigatórioCampos
streetstring | nullobrigatóriopode ser nullcitystring | nullobrigatóriopode ser nullpostalCodestring | nullobrigatóriopode ser nullcountrystring | nullpode ser null
emergencyContactobjectobrigatórioCampos
namestring | nullobrigatóriopode ser nullrelationstring | nullobrigatóriopode ser nullphonestring | nullobrigatóriopode ser null
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/employees/{id}/archivecurl -X POST "https://api.selfcare.work/v1/employees/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/archive" \
-H "Authorization: Bearer sc_live_…" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employeeNumber": "string",
"externalCode": "string",
"fullName": "string",
"preferredName": "string",
"workEmail": "string",
"workPhone": "string",
"jobTitle": "string",
"status": "ACTIVE",
"kind": "string",
"photoUrl": "string",
"workLocation": "string",
"locationId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"teams": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string"
}
],
"personalEmail": "string",
"phone": "string",
"personalData": {
"dateOfBirth": "2026-10-16",
"nationality": "string",
"nif": "string",
"niss": "string",
"citizenCardNumber": "string",
"citizenCardExpiry": "2026-10-16",
"iban": "string",
"swiftBic": "string",
"address": {
"street": "string",
"city": "string",
"postalCode": "string",
"country": "string"
},
"fiscalAddress": {
"street": "string",
"city": "string",
"postalCode": "string",
"country": "string"
},
"emergencyContact": {
"name": "string",
"relation": "string",
"phone": "string"
}
},
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Corrigir uma entrada de contrato
/v1/employees/{id}/contracts/{contractId}Âmbito contracts:write, só dono e RH. If-Match e motivo obrigatórios. Como na app, só se corrige enquanto não há recibos emitidos (ou num prestador); depois disso regista-se uma entrada nova.
Parâmetros do caminho
idobrigatóriostring (uuid)contractIdobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
If-MatchobrigatóriostringObrigatório nesta escrita (428 sem ele): o ETag que leste no GET. Se o recurso mudou entretanto, 412. O
*não serve.
Corpo do pedido
application/jsoneffectiveFromstring (date)reasonstringcontractTypestringstartDatestring (date)endDatestring (date) | nullpode ser nullprobationEndDatestring (date) | nullpode ser nullweeklyHoursnumbervacationDaysPerYearintegercctsstring | nullpode ser nullnotesstring | nullpode ser nulljustificationstringobrigatórioMotivo da alteração, obrigatório. Fica no registo de auditoria com os valores antes e depois.
Respostas
200OK
dataContractobrigatórioCampos de Contract
idstring (uuid)obrigatórioemployeeIdstring (uuid)obrigatórioeffectiveFromstring (date)obrigatórioeffectiveTostring (date) | nullobrigatóriopode ser nullreasonstringobrigatóriocontractTypestringobrigatóriostartDatestring (date)obrigatórioendDatestring (date) | nullobrigatóriopode ser nullprobationEndDatestring (date) | nullobrigatóriopode ser nullweeklyHoursnumberobrigatóriovacationDaysPerYearintegerobrigatóriocctsstring | nullobrigatóriopode ser nullnotesstring | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 412O recurso mudou (If-Match)
- 422Campos inválidos
- 428Falta o If-Match ou a Idempotency-Key, obrigatórios nesta escrita
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/employees/{id}/contracts/{contractId}curl -X PATCH "https://api.selfcare.work/v1/employees/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/contracts/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-H 'If-Match: W/"…"' \
-d '{
"effectiveFrom": "2026-11-01",
"startDate": "2026-11-01",
"endDate": "2026-11-01",
"probationEndDate": "2026-11-01",
"justification": "Revisão salarial anual aprovada pela administração"
}'OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"effectiveFrom": "2026-10-16",
"effectiveTo": "2026-10-16",
"reason": "HIRING",
"contractType": "PERMANENT",
"startDate": "2026-10-16",
"endDate": "2026-10-16",
"probationEndDate": "2026-10-16",
"weeklyHours": 0,
"vacationDaysPerYear": 0,
"ccts": "string",
"notes": "string",
"createdAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Corrigir uma entrada de remuneração
/v1/employees/{id}/compensation/{entryId}Âmbito compensation:write, só dono e RH. If-Match e motivo obrigatórios. Muda só os campos enviados; o colaborador é avisado.
Parâmetros do caminho
idobrigatóriostring (uuid)entryIdobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
If-MatchobrigatóriostringObrigatório nesta escrita (428 sem ele): o ETag que leste no GET. Se o recurso mudou entretanto, 412. O
*não serve.
Corpo do pedido
application/jsoneffectiveFromstring (date)reasonstringbaseSalaryMonthlyCentsintegersalaryPaidMonthsnumberseniorityBonusCentsintegercoverflexMonthlyCentsinteger | nullpode ser nullexpenseAllowanceCentsinteger | nullpode ser nullworkingTimeExemptionobjectIsenção de horário de trabalho (CT arts. 218.º e 219.º).
Campos
enabledbooleanobrigatóriomodalitystring | nullpode ser nullcompensationModestring | nullpode ser nullcompensationValuenumber | nullpode ser nullPercentagem do vencimento base, horas ou euros por mês, conforme o modo de cálculo.
agreementDatestring (date) | nullpode ser null
externalobjectTarifa de um prestador de serviços. É remuneração: pede também o âmbito compensation:write e só dono e RH.
Campos
rateTypestringobrigatóriorateAmountCentsintegerobrigatóriounitsPerMonthnumber | nullpode ser nullvacationPaidboolean | nullpode ser nullabsencesPaidboolean | nullpode ser nullmonthsPaidPerYearinteger | nullpode ser null
notesstring | nullpode ser nulljustificationstringobrigatórioMotivo da alteração, obrigatório. Fica no registo de auditoria com os valores antes e depois.
Respostas
200OK
dataCompensationobrigatórioCampos de Compensation
idstring (uuid)obrigatórioemployeeIdstring (uuid)obrigatórioeffectiveFromstring (date)obrigatórioeffectiveTostring (date) | nullobrigatóriopode ser nullreasonstringobrigatóriocurrencystringobrigatóriobaseSalaryMonthlyCentsintegerobrigatóriosalaryPaidMonthsintegerobrigatóriomealAllowanceDailyCentsintegerobrigatóriomealAllowanceFormstringobrigatórioseniorityBonusCentsintegerobrigatóriocoverflexMonthlyCentsinteger | nullobrigatóriopode ser nullexpenseAllowanceCentsinteger | nullobrigatóriopode ser nullworkingTimeExemptionobjectobrigatórioIsenção de horário de trabalho (CT arts. 218.º e 219.º).
Campos
enabledbooleanobrigatóriomodalitystring | nullobrigatóriopode ser nullcompensationModestring | nullobrigatóriopode ser nullcompensationValuenumber | nullobrigatóriopode ser nullPercentagem do vencimento base, horas ou euros por mês, conforme o modo de cálculo.
agreementDatestring (date) | nullobrigatóriopode ser null
externalobject | nullobrigatóriopode ser nullCampos
rateTypestring | nullobrigatóriopode ser nullrateAmountCentsinteger | nullobrigatóriopode ser nullunitsPerMonthnumber | nullobrigatóriopode ser nullvacationPaidboolean | nullobrigatóriopode ser nullabsencesPaidboolean | nullobrigatóriopode ser nullmonthsPaidPerYearinteger | nullobrigatóriopode ser null
notesstring | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 412O recurso mudou (If-Match)
- 422Campos inválidos
- 428Falta o If-Match ou a Idempotency-Key, obrigatórios nesta escrita
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/employees/{id}/compensation/{entryId}curl -X PATCH "https://api.selfcare.work/v1/employees/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/compensation/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-H 'If-Match: W/"…"' \
-d '{
"effectiveFrom": "2026-11-01",
"justification": "Revisão salarial anual aprovada pela administração"
}'OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"effectiveFrom": "2026-10-16",
"effectiveTo": "2026-10-16",
"reason": "HIRING",
"currency": "EUR",
"baseSalaryMonthlyCents": 0,
"salaryPaidMonths": 0,
"mealAllowanceDailyCents": 0,
"mealAllowanceForm": "string",
"seniorityBonusCents": 0,
"coverflexMonthlyCents": 0,
"expenseAllowanceCents": 0,
"workingTimeExemption": {
"enabled": true,
"modality": "NOT_SUBJECT_TO_PNT_LIMITS",
"compensationMode": "PERCENT_OF_BASE",
"compensationValue": 0,
"agreementDate": "2026-10-16"
},
"external": {
"rateType": "string",
"rateAmountCents": 0,
"unitsPerMonth": 0,
"vacationPaid": true,
"absencesPaid": true,
"monthsPaidPerYear": 0
},
"notes": "string",
"createdAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Registar ou pedir a mudança do IBAN
/v1/employees/{id}/bank-detailsPode o próprio, o dono ou o RH. Sem IBAN na ficha (onboarding), o primeiro grava logo (APPLIED). A mudança de um IBAN existente nunca muda a ficha: cria um pedido pendente, cifrado, que só tem efeito quando o colaborador o confirma na app com um código (PENDING_CONFIRMATION); substitui um pedido anterior por confirmar. Para uma mudança: sem conta na app, 409; sem a cifra configurada, 503. A resposta mostra só os últimos 4 dígitos.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
If-MatchstringO ETag lido; se o recurso mudou entretanto, 412.
Corpo do pedido
application/jsonibanstringobrigatórioIBAN português (PT50...). Se a pessoa ainda não tem IBAN, grava logo; se já tem, a mudança fica pendente até o colaborador a confirmar na app.
swiftBicstring | nullpode ser null
Respostas
200OK
dataBankDetailsUpdateobrigatórioCampos de BankDetailsUpdate
employeeIdstring (uuid)obrigatóriooutcomestringobrigatórioAPPLIED: era o primeiro IBAN e ficou gravado. PENDING_CONFIRMATION: mudança de um IBAN existente, à espera do colaborador na app.
ibanMaskedstring | nullobrigatóriopode ser nullO IBAN em vigor na ficha, mascarado (só os últimos 4 dígitos).
pendingPendingBankDetailsChange | nullobrigatóriopode ser nullCampos de PendingBankDetailsChange
idstring (uuid)obrigatórioemployeeIdstring (uuid)obrigatóriostatusstringobrigatórioPENDING até o colaborador decidir. CONFIRMED aplica o IBAN; REJECTED, CANCELLED e EXPIRED deixam o anterior.
ibanMaskedstringobrigatórioMascarado: só os últimos 4 dígitos.
requestedAtstring (date-time)obrigatórioexpiresAtstring (date-time)obrigatórioAté quando o colaborador pode confirmar. Nunca entra em vigor sozinha.
decidedAtstring (date-time) | nullobrigatóriopode ser null
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
- 503Serviço indisponível (por exemplo, sem a chave de cifra configurada)
https://api.selfcare.work/v1/employees/{id}/bank-detailscurl -X PUT "https://api.selfcare.work/v1/employees/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/bank-details" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"iban": "PT50000201231234567890154"
}'OK
{
"data": {
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"outcome": "APPLIED",
"ibanMasked": "****0154",
"pending": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"status": "PENDING",
"ibanMasked": "****0154",
"requestedAt": "2026-10-16T09:30:00.000Z",
"expiresAt": "2026-10-16T09:30:00.000Z",
"decidedAt": "2026-10-16T09:30:00.000Z"
}
},
"error": null
}Referência
Equipas
Equipas
/v1/teamsParâmetros da query
updatedSincestring (date-time)limitintegerItens por página. Por omissão 50, máximo 200.
cursorstringO
meta.nextCursorda página anterior, com os mesmos filtros.
Respostas
200OK
dataarray<Team>obrigatórioCampos de Team
idstring (uuid)obrigatórionamestringobrigatóriodescriptionstring | nullobrigatóriopode ser nullcolorstringobrigatórioleaderobject | nullobrigatóriopode ser nullCampos
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
membersarray<object>obrigatórioCampos
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatóriojobTitlestring | nullobrigatóriopode ser null
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser nullmetaobjectobrigatórioCampos
nextCursorstring | nullobrigatóriopode ser nullhasMorebooleanobrigatório
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/teamscurl "https://api.selfcare.work/v1/teams?updatedSince=2026-10-01T00:00:00Z" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string",
"description": "string",
"color": "string",
"leader": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"members": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string",
"jobTitle": "string"
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
}
],
"error": null,
"meta": {
"nextCursor": "string",
"hasMore": true
}
}Criar uma equipa
/v1/teamsDono, RH ou gestor. Uma equipa tem sempre líder, que não tem de ser membro; o líder aprova as ausências de quem está na equipa.
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Corpo do pedido
application/jsonnamestringobrigatóriodescriptionstring | nullpode ser nullleaderIdstring (uuid)obrigatóriocolorstring
Respostas
201Criado
dataTeamobrigatórioCampos de Team
idstring (uuid)obrigatórionamestringobrigatóriodescriptionstring | nullobrigatóriopode ser nullcolorstringobrigatórioleaderobject | nullobrigatóriopode ser nullCampos
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
membersarray<object>obrigatórioCampos
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatóriojobTitlestring | nullobrigatóriopode ser null
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/teamscurl -X POST "https://api.selfcare.work/v1/teams" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"name": "string",
"leaderId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10"
}'Criado
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string",
"description": "string",
"color": "string",
"leader": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"members": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string",
"jobTitle": "string"
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Uma equipa
/v1/teams/{id}Parâmetros do caminho
idobrigatóriostring (uuid)
Respostas
200OK
dataTeamobrigatórioCampos de Team
idstring (uuid)obrigatórionamestringobrigatóriodescriptionstring | nullobrigatóriopode ser nullcolorstringobrigatórioleaderobject | nullobrigatóriopode ser nullCampos
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
membersarray<object>obrigatórioCampos
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatóriojobTitlestring | nullobrigatóriopode ser null
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/teams/{id}curl "https://api.selfcare.work/v1/teams/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string",
"description": "string",
"color": "string",
"leader": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"members": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string",
"jobTitle": "string"
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Editar uma equipa
/v1/teams/{id}Nome, descrição, cor ou líder. Mudar o líder muda as cadeias de aprovação. If-Match opcional.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
If-MatchstringO ETag lido; se o recurso mudou entretanto, 412.
Corpo do pedido
application/jsonnamestringdescriptionstring | nullpode ser nullleaderIdstring (uuid)colorstring
Respostas
200OK
dataTeamobrigatórioCampos de Team
idstring (uuid)obrigatórionamestringobrigatóriodescriptionstring | nullobrigatóriopode ser nullcolorstringobrigatórioleaderobject | nullobrigatóriopode ser nullCampos
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
membersarray<object>obrigatórioCampos
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatóriojobTitlestring | nullobrigatóriopode ser null
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 412O recurso mudou (If-Match)
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/teams/{id}curl -X PATCH "https://api.selfcare.work/v1/teams/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"name": "string"
}'OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string",
"description": "string",
"color": "string",
"leader": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"members": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string",
"jobTitle": "string"
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Apagar uma equipa
/v1/teams/{id}Como na app: com documentos no espaço da equipa, 409. As pessoas ficam, só deixam de pertencer à equipa.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
If-MatchstringO ETag lido; se o recurso mudou entretanto, 412.
Respostas
200OK
dataTeamDeletedobrigatórioCampos de TeamDeleted
idstring (uuid)obrigatóriodeletedbooleanobrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 412O recurso mudou (If-Match)
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/teams/{id}curl -X DELETE "https://api.selfcare.work/v1/teams/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"deleted": true
},
"error": null
}Juntar uma pessoa a uma equipa
/v1/teams/{id}/membersUma pessoa pode estar em várias equipas. Se já for membro, fica igual. Devolve a equipa.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Corpo do pedido
application/jsonemployeeIdstring (uuid)obrigatório
Respostas
200OK
dataTeamobrigatórioCampos de Team
idstring (uuid)obrigatórionamestringobrigatóriodescriptionstring | nullobrigatóriopode ser nullcolorstringobrigatórioleaderobject | nullobrigatóriopode ser nullCampos
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
membersarray<object>obrigatórioCampos
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatóriojobTitlestring | nullobrigatóriopode ser null
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/teams/{id}/memberscurl -X POST "https://api.selfcare.work/v1/teams/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/members" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"employeeId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10"
}'OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string",
"description": "string",
"color": "string",
"leader": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"members": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string",
"jobTitle": "string"
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Tirar uma pessoa de uma equipa
/v1/teams/{id}/members/{employeeId}Quem não é membro dá 404. Devolve a equipa.
Parâmetros do caminho
idobrigatóriostring (uuid)employeeIdobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
If-MatchstringO ETag lido; se o recurso mudou entretanto, 412.
Respostas
200OK
dataTeamobrigatórioCampos de Team
idstring (uuid)obrigatórionamestringobrigatóriodescriptionstring | nullobrigatóriopode ser nullcolorstringobrigatórioleaderobject | nullobrigatóriopode ser nullCampos
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatório
membersarray<object>obrigatórioCampos
idstring (uuid)obrigatóriofullNamestringobrigatórioemployeeNumberstringobrigatóriojobTitlestring | nullobrigatóriopode ser null
createdAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/teams/{id}/members/{employeeId}curl -X DELETE "https://api.selfcare.work/v1/teams/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/members/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"name": "string",
"description": "string",
"color": "string",
"leader": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string"
},
"members": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"fullName": "string",
"employeeNumber": "string",
"jobTitle": "string"
}
],
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Referência
Endpoints de webhooks
Avisos assinados quando algo muda (ausências, despesas, documentos, pessoas, equipas). Cada endpoint é de uma pessoa e só recebe o que ela vê no momento da entrega.
Listar os meus endpoints de webhooks
/v1/webhook-endpointsSó os de quem pede, nesta empresa. O segredo nunca sai aqui.
Parâmetros da query
limitintegerItens por página. Por omissão 50, máximo 200.
cursorstringO
meta.nextCursorda página anterior, com os mesmos filtros.
Respostas
200OK
dataarray<WebhookEndpoint>obrigatórioCampos de WebhookEndpoint
idstring (uuid)obrigatóriourlstringobrigatóriodescriptionstring | nullobrigatóriopode ser nulleventsarray<string>obrigatóriostatusstringobrigatóriofailingSincestring (date-time) | nullobrigatóriopode ser nullDesde quando as entregas falham sem interrupção. Ao fim de 3 dias o endpoint desliga-se e o dono é avisado.
disabledAtstring (date-time) | nullobrigatóriopode ser nulldisabledReasonstring | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser nullmetaobjectobrigatórioCampos
nextCursorstring | nullobrigatóriopode ser nullhasMorebooleanobrigatório
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/webhook-endpointscurl "https://api.selfcare.work/v1/webhook-endpoints" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"url": "https://erp.example.pt/selfcare/webhooks",
"description": "string",
"events": [
"absence.created"
],
"status": "ACTIVE",
"failingSince": "2026-10-16T09:30:00.000Z",
"disabledAt": "2026-10-16T09:30:00.000Z",
"disabledReason": "string",
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
}
],
"error": null,
"meta": {
"nextCursor": "string",
"hasMore": true
}
}Criar um endpoint de webhooks
/v1/webhook-endpointsCada entrega é um POST JSON assinado com HMAC-SHA256: Selfcare-Signature: t=<segundos>,v1=<hex de HMAC(segredo, ${t}.${corpo})>. Recusa assinaturas com mais de 5 minutos e deduplica pelo id do evento (entrega pelo menos uma vez, sem ordem garantida). Até 8 tentativas em cerca de 24 horas. O evento só leva ids, estado, datas e a empresa; o resto lê-se pela API. O segredo só aparece nesta resposta. Sem cifra configurada, 503.
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Corpo do pedido
application/jsonurlstring (uri)obrigatórioSó https, porta 443, endereço público (sem redes privadas, loopback nem metadados). Os redireccionamentos não se seguem.
eventsarray<string>obrigatórioOs tipos de evento a receber. O webhook.test chega sempre que se pede um teste.
descriptionstring | nullpode ser null
Respostas
201Criado
dataWebhookEndpointWithSecretobrigatórioerrorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
- 503Serviço indisponível (por exemplo, sem a chave de cifra configurada)
https://api.selfcare.work/v1/webhook-endpointscurl -X POST "https://api.selfcare.work/v1/webhook-endpoints" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"url": "https://example.com",
"events": [
"absence.created"
]
}'Criado
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"url": "https://erp.example.pt/selfcare/webhooks",
"description": "string",
"events": [
"absence.created"
],
"status": "ACTIVE",
"failingSince": "2026-10-16T09:30:00.000Z",
"disabledAt": "2026-10-16T09:30:00.000Z",
"disabledReason": "string",
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z",
"secret": "whsec_…"
},
"error": null
}Ver um endpoint de webhooks
/v1/webhook-endpoints/{id}Parâmetros do caminho
idobrigatóriostring (uuid)
Respostas
200OK
dataWebhookEndpointobrigatórioCampos de WebhookEndpoint
idstring (uuid)obrigatóriourlstringobrigatóriodescriptionstring | nullobrigatóriopode ser nulleventsarray<string>obrigatóriostatusstringobrigatóriofailingSincestring (date-time) | nullobrigatóriopode ser nullDesde quando as entregas falham sem interrupção. Ao fim de 3 dias o endpoint desliga-se e o dono é avisado.
disabledAtstring (date-time) | nullobrigatóriopode ser nulldisabledReasonstring | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/webhook-endpoints/{id}curl "https://api.selfcare.work/v1/webhook-endpoints/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"url": "https://erp.example.pt/selfcare/webhooks",
"description": "string",
"events": [
"absence.created"
],
"status": "ACTIVE",
"failingSince": "2026-10-16T09:30:00.000Z",
"disabledAt": "2026-10-16T09:30:00.000Z",
"disabledReason": "string",
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Alterar um endpoint de webhooks
/v1/webhook-endpoints/{id}URL, eventos, descrição, ou ligar e desligar. If-Match opcional.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
If-MatchstringO ETag lido; se o recurso mudou entretanto, 412.
Corpo do pedido
application/jsonurlstring (uri)Só https, porta 443, endereço público (sem redes privadas, loopback nem metadados). Os redireccionamentos não se seguem.
eventsarray<string>Os tipos de evento a receber. O webhook.test chega sempre que se pede um teste.
descriptionstring | nullpode ser nullenabledbooleanfalse desliga; true volta a ligar e recomeça a contagem das falhas.
Respostas
200OK
dataWebhookEndpointobrigatórioCampos de WebhookEndpoint
idstring (uuid)obrigatóriourlstringobrigatóriodescriptionstring | nullobrigatóriopode ser nulleventsarray<string>obrigatóriostatusstringobrigatóriofailingSincestring (date-time) | nullobrigatóriopode ser nullDesde quando as entregas falham sem interrupção. Ao fim de 3 dias o endpoint desliga-se e o dono é avisado.
disabledAtstring (date-time) | nullobrigatóriopode ser nulldisabledReasonstring | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 412O recurso mudou (If-Match)
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/webhook-endpoints/{id}curl -X PATCH "https://api.selfcare.work/v1/webhook-endpoints/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11" \
-d '{
"url": "https://example.com"
}'OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"url": "https://erp.example.pt/selfcare/webhooks",
"description": "string",
"events": [
"absence.created"
],
"status": "ACTIVE",
"failingSince": "2026-10-16T09:30:00.000Z",
"disabledAt": "2026-10-16T09:30:00.000Z",
"disabledReason": "string",
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Apagar um endpoint de webhooks
/v1/webhook-endpoints/{id}Apaga também o registo de entregas dele.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
If-MatchstringO ETag lido; se o recurso mudou entretanto, 412.
Respostas
200OK
dataWebhookEndpointDeletedobrigatórioCampos de WebhookEndpointDeleted
idstring (uuid)obrigatóriodeletedbooleanobrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 412O recurso mudou (If-Match)
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/webhook-endpoints/{id}curl -X DELETE "https://api.selfcare.work/v1/webhook-endpoints/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10" \
-H "Authorization: Bearer sc_live_…" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"deleted": true
},
"error": null
}Rodar o segredo
/v1/webhook-endpoints/{id}/rotate-secretDevolve o segredo novo, uma vez. Durante 24 horas cada entrega leva duas assinaturas v1 (a nova e a anterior), para trocares sem perder nada.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Respostas
200OK
dataWebhookEndpointWithSecretobrigatórioerrorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
- 503Serviço indisponível (por exemplo, sem a chave de cifra configurada)
https://api.selfcare.work/v1/webhook-endpoints/{id}/rotate-secretcurl -X POST "https://api.selfcare.work/v1/webhook-endpoints/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/rotate-secret" \
-H "Authorization: Bearer sc_live_…" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11"OK
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"url": "https://erp.example.pt/selfcare/webhooks",
"description": "string",
"events": [
"absence.created"
],
"status": "ACTIVE",
"failingSince": "2026-10-16T09:30:00.000Z",
"disabledAt": "2026-10-16T09:30:00.000Z",
"disabledReason": "string",
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z",
"secret": "whsec_…"
},
"error": null
}Enviar um evento de teste
/v1/webhook-endpoints/{id}/testManda um webhook.test só a este endpoint (tem de estar ligado; senão 409) e devolve a entrega.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Respostas
201Criado
dataWebhookDeliveryobrigatórioCampos de WebhookDelivery
idstring (uuid)obrigatórioendpointIdstring (uuid)obrigatórioeventIdstring (uuid)obrigatórioeventTypestringobrigatóriostatusstringobrigatórioPENDING (a tentar), SUCCEEDED (2xx), FAILED (8 tentativas sem 2xx) ou SKIPPED (o dono já não vê o recurso, perdeu o acesso ou o endpoint foi desligado).
attemptsintegerobrigatóriolastAttemptAtstring (date-time) | nullobrigatóriopode ser nullnextAttemptAtstring (date-time) | nullobrigatóriopode ser nullresponseStatusinteger | nullobrigatóriopode ser nullresponseBodyExcerptstring | nullobrigatóriopode ser nullOs primeiros 2 KB da resposta do teu servidor.
durationMsinteger | nullobrigatóriopode ser nullerrorstring | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/webhook-endpoints/{id}/testcurl -X POST "https://api.selfcare.work/v1/webhook-endpoints/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/test" \
-H "Authorization: Bearer sc_live_…" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11"Criado
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"endpointId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"eventId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"eventType": "absence.created",
"status": "PENDING",
"attempts": 0,
"lastAttemptAt": "2026-10-16T09:30:00.000Z",
"nextAttemptAt": "2026-10-16T09:30:00.000Z",
"responseStatus": 0,
"responseBodyExcerpt": "string",
"durationMs": 0,
"error": "string",
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Registo de entregas
/v1/webhook-endpoints/{id}/deliveriesOs últimos 30 dias: estado, tentativas, código e primeiros 2 KB da resposta, duração.
Parâmetros do caminho
idobrigatóriostring (uuid)
Parâmetros da query
limitintegerItens por página. Por omissão 50, máximo 200.
cursorstringO
meta.nextCursorda página anterior, com os mesmos filtros.
Respostas
200OK
dataarray<WebhookDelivery>obrigatórioCampos de WebhookDelivery
idstring (uuid)obrigatórioendpointIdstring (uuid)obrigatórioeventIdstring (uuid)obrigatórioeventTypestringobrigatóriostatusstringobrigatórioPENDING (a tentar), SUCCEEDED (2xx), FAILED (8 tentativas sem 2xx) ou SKIPPED (o dono já não vê o recurso, perdeu o acesso ou o endpoint foi desligado).
attemptsintegerobrigatóriolastAttemptAtstring (date-time) | nullobrigatóriopode ser nullnextAttemptAtstring (date-time) | nullobrigatóriopode ser nullresponseStatusinteger | nullobrigatóriopode ser nullresponseBodyExcerptstring | nullobrigatóriopode ser nullOs primeiros 2 KB da resposta do teu servidor.
durationMsinteger | nullobrigatóriopode ser nullerrorstring | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser nullmetaobjectobrigatórioCampos
nextCursorstring | nullobrigatóriopode ser nullhasMorebooleanobrigatório
- 400Pedido mal formado ou cursor inválido
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/webhook-endpoints/{id}/deliveriescurl "https://api.selfcare.work/v1/webhook-endpoints/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/deliveries" \
-H "Authorization: Bearer sc_live_…"OK
{
"data": [
{
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"endpointId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"eventId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"eventType": "absence.created",
"status": "PENDING",
"attempts": 0,
"lastAttemptAt": "2026-10-16T09:30:00.000Z",
"nextAttemptAt": "2026-10-16T09:30:00.000Z",
"responseStatus": 0,
"responseBodyExcerpt": "string",
"durationMs": 0,
"error": "string",
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
}
],
"error": null,
"meta": {
"nextCursor": "string",
"hasMore": true
}
}Reenviar uma entrega
/v1/webhook-deliveries/{id}/redeliverCria uma entrega nova do mesmo evento (o mesmo id: deduplica). A visibilidade volta a ser verificada.
Parâmetros do caminho
idobrigatóriostring (uuid)
Cabeçalhos
Idempotency-KeystringAté 255 caracteres. Repetir com o mesmo corpo devolve a mesma resposta durante 24 horas.
Respostas
201Criado
dataWebhookDeliveryobrigatórioCampos de WebhookDelivery
idstring (uuid)obrigatórioendpointIdstring (uuid)obrigatórioeventIdstring (uuid)obrigatórioeventTypestringobrigatóriostatusstringobrigatórioPENDING (a tentar), SUCCEEDED (2xx), FAILED (8 tentativas sem 2xx) ou SKIPPED (o dono já não vê o recurso, perdeu o acesso ou o endpoint foi desligado).
attemptsintegerobrigatóriolastAttemptAtstring (date-time) | nullobrigatóriopode ser nullnextAttemptAtstring (date-time) | nullobrigatóriopode ser nullresponseStatusinteger | nullobrigatóriopode ser nullresponseBodyExcerptstring | nullobrigatóriopode ser nullOs primeiros 2 KB da resposta do teu servidor.
durationMsinteger | nullobrigatóriopode ser nullerrorstring | nullobrigatóriopode ser nullcreatedAtstring (date-time)obrigatórioupdatedAtstring (date-time)obrigatório
errorany | nullobrigatóriopode ser null
- 401Sem credencial válida
- 402Conta da empresa bloqueada por falta de pagamento
- 403Sem âmbito, sem permissão ou API bloqueada na empresa
- 404Não existe ou o utilizador não o pode ver
- 409Estado que não permite a operação
- 422Campos inválidos
- 429Demasiados pedidos (ver Retry-After)
- 500Erro inesperado
https://api.selfcare.work/v1/webhook-deliveries/{id}/redelivercurl -X POST "https://api.selfcare.work/v1/webhook-deliveries/3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10/redeliver" \
-H "Authorization: Bearer sc_live_…" \
-H "Idempotency-Key: 2f6c1a52-1d7e-4b0c-9a51-0c3f0b5b8e11"Criado
{
"data": {
"id": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"endpointId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"eventId": "3f1c2b8e-5d0a-4c1e-9f8a-2b7d6e5c4a10",
"eventType": "absence.created",
"status": "PENDING",
"attempts": 0,
"lastAttemptAt": "2026-10-16T09:30:00.000Z",
"nextAttemptAt": "2026-10-16T09:30:00.000Z",
"responseStatus": 0,
"responseBodyExcerpt": "string",
"durationMs": 0,
"error": "string",
"createdAt": "2026-10-16T09:30:00.000Z",
"updatedAt": "2026-10-16T09:30:00.000Z"
},
"error": null
}Perguntas frequentes
- A API está incluída no meu plano?
- Sim, em todos os planos, sem custo extra. Com a conta bloqueada por falta de pagamento, a API responde 402, como o resto da app.
- Posso ler os salários ou os recibos de vencimento?
- O processamento salarial fica fora da API e do MCP. Pela API REST, os recibos de vencimento já emitidos são documentos: cada pessoa vê os seus (e o RH os de quem gere), como na app. Pelo MCP, recibos, contratos e documentos de identificação ou de IBAN nunca saem. Contratos e remuneração (âmbitos sensíveis) só para quem os vê na app.
- Porque é que recebo 404 num registo que existe?
- Porque a pessoa da credencial não o vê na app. A API responde 404 em vez de 403 para não revelar que o registo existe.
- Como vejo o IBAN de um colaborador?
- Não vês: sai sempre mascarado (
****0154). Podes registar o primeiro IBAN de uma ficha; alterar um existente fica pendente até o colaborador confirmar na app. - Uma chave serve para várias empresas?
- Não. Cada chave é de uma pessoa numa empresa. Para várias empresas, cria uma chave em cada uma ou usa OAuth, em que a pessoa escolhe a empresa ao autorizar.
- Onde ficam os dados?
- Na União Europeia. A API é servida a partir do mesmo sistema da app, com o mesmo isolamento por empresa.
- Como sei quem fez o quê pela API?
- Cada escrita fica no registo de auditoria da empresa com a origem (API ou MCP), a chave ou a app e o id do pedido. Cada pessoa vê o registo de acessos das suas chaves em Definições → API → Chaves da API.
- Os contabilistas podem usar a API?
- Podem usar chaves com o que o papel deles permite na app. O servidor MCP não está disponível para contabilistas.
- Encontrei um problema ou preciso de um endpoint novo.
- Escreve para suporte@selfcare.work com o
requestIdda resposta.
Alterações
Mudanças na API v1. Acrescentar campos, endpoints ou eventos não muda de versão; remover ou mudar o significado de algo só numa v2, com aviso prévio.
- 2026-10-19Guias completos no portal (Idempotency-Key, webhooks com verificação em código, MCP passo a passo, app móvel, perguntas frequentes). A especificação corrige os campos anuláveis que apontam para um esquema (
Document.currentVersion, o IBAN pendente e o saldo do resumo passam aanyOfcomnull) e passa noredocly lintsem erros nem avisos. - 2026-10-19Servidor MCP em
https://api.selfcare.work/mcp(Streamable HTTP), com registo dinâmico de clientes (/oauth/register, RFC 7591), metadados do recurso protegido (RFC 9728) e tokens presos ao recurso (RFC 8707).GET /v1/employeesaceitaqpara procurar por nome. - 2026-10-19OAuth 2.1 para apps usadas por várias pessoas: authorization code com PKCE S256,
/oauth/token,/oauth/revokee/.well-known/oauth-authorization-server. App móvel:GET/POST /v1/me/devices,DELETE /v1/me/devices/{id}, notificações push eGET /v1/me/summary. SDK TypeScript gerado da especificação. - 2026-10-18Webhooks assinados (
/v1/webhook-endpoints, entregas, reenvio, teste e rotação do segredo). Escritas: ausências, despesas, deslocações, documentos, colaboradores, equipas, contratos, remuneração e IBAN (a alteração fica pendente até o colaborador confirmar).Idempotency-Keyem todas as escritas eIf-Matchnas edições. - 2026-10-17Primeira versão: chaves pessoais (
sc_live_,sc_test_), âmbitos, limites, paginação por cursor, erros estáveis e leituras de ausências, aprovações, despesas, deslocações, documentos, colaboradores e equipas.