Visão geral
A API tem dois endereços. O das contas, accounts.tributs.ad, indica a que empresas tem acesso. Cada empresa serve os seus dados no seu próprio endereço, e esses dados só passam por aí.
Qualquer utilizador pode criar um token, seja qual for o seu papel. Numa gestoria, um único token lê todas as empresas dos seus clientes.
| URL base | Para |
|---|---|
https://accounts.tributs.ad/api/v1 | As empresas a que o token tem acesso |
https://{slug}.tributs.ad/api/v1 | Os dados de uma empresa |
Início rápido
-
Crie um token
Na Tributs, abra o seu perfil → Ligações externas → Criar token. Dê-lhe o nome do programa que o vai usar e escolha quando expira: 30 dias, 90 dias ou 1 ano. O token (
trb_…) só é mostrado uma vez: copie-o nesse momento. -
Encontre as suas empresas
Cada empresa chega com o seu
api_base_url, que é onde vai ler os dados dela.cURLcurl https://accounts.tributs.ad/api/v1/companies \ -H "Authorization: Bearer $TRIBUTS_TOKEN"200 OK · application/json{ "data": [ { "id": "acme.tributs.ad", "name": "Acme Serveis SL", "display_name": "Acme", "role": "advisor", "status": "active", "api_base_url": "https://acme.tributs.ad/api/v1" } ], "next_cursor": null, "has_more": false } -
Leia os dados
As listas chegam por páginas. Este exemplo obtém todas as faturas de venda desde 1 de janeiro.
curl "https://acme.tributs.ad/api/v1/sales_invoices?date_from=2026-01-01&limit=200" \ -H "Authorization: Bearer $TRIBUTS_TOKEN"import os import requests BASE = "https://acme.tributs.ad/api/v1" HEADERS = {"Authorization": f"Bearer {os.environ['TRIBUTS_TOKEN']}"} params = {"date_from": "2026-01-01", "limit": 200} invoices = [] while True: response = requests.get(f"{BASE}/sales_invoices", headers=HEADERS, params=params, timeout=30) response.raise_for_status() page = response.json() invoices += page["data"] if not page["has_more"]: break params["cursor"] = page["next_cursor"]const BASE = "https://acme.tributs.ad/api/v1"; const headers = { Authorization: `Bearer ${process.env.TRIBUTS_TOKEN}` }; const invoices = []; let cursor; do { const url = new URL(`${BASE}/sales_invoices`); url.searchParams.set("date_from", "2026-01-01"); url.searchParams.set("limit", "200"); if (cursor) url.searchParams.set("cursor", cursor); const response = await fetch(url, { headers }); if (!response.ok) { const problem = await response.json().catch(() => ({})); throw new Error(problem.title ?? `HTTP ${response.status}`); } const page = await response.json(); invoices.push(...page.data); cursor = page.has_more ? page.next_cursor : undefined; } while (cursor);
Autenticação
Envie o token no cabeçalho Authorization de cada pedido, com o esquema Bearer. Todos os pedidos passam por HTTPS.
Authorization: Bearer trb_… - O token é opaco:
trb_seguido de 40 caracteres. A Tributs guarda apenas uma impressão digital (SHA-256), por isso ninguém o pode voltar a ver. - Expira sempre: ao fim de 30 dias, 90 dias ou 1 ano. Escrevemos-lhe 7 dias antes e no dia em que expira.
- Renovar gera uma chave nova para o mesmo token. A anterior deixa de funcionar em menos de um minuto; o nome e o histórico mantêm-se.
- Pode revogá-lo quando quiser. A revogação chega a todas as empresas em 60 segundos, no máximo.
- Age como si: em cada empresa tem exatamente o seu papel e as suas permissões.
- Até 10 tokens ativos por pessoa. Use um token para cada programa.
A empresa mantém o controlo
O proprietário de cada empresa vê nas definições quem a consulta pela API, com que token e quando, e pode cortar o acesso a todos ou a uma pessoa.
Paginação e sincronização
As listas devolvem data, next_cursor e has_more. Enquanto has_more for true, volte a chamar com os mesmos parâmetros e cursor=<next_cursor>. limit vai de 1 a 200 (50 por omissão, e 50 no máximo com expand=lines).
Os elementos vêm ordenados pela última alteração, do mais antigo para o mais recente. Para manter uma cópia atualizada, guarde o updated_at do último elemento e passe-o como updated_since na vez seguinte: recebe o que mudou desde então. Guarde os elementos por id, substituindo os que já tem, porque os do último segundo podem voltar a aparecer.
Um documento anulado volta a aparecer com status: "cancelled". Os rascunhos não aparecem: só há documentos emitidos. A exceção são os movimentos bancários, que não são emitidos: aparecem sempre, e um movimento manual eliminado desaparece sem aviso.
As faturas e os movimentos bancários aceitam sort: total_desc (as faturas de maior valor primeiro), issue_date_desc (as faturas mais recentes primeiro) e date_desc (os movimentos mais recentes primeiro). Um cursor só vale para a ordenação com que foi pedido. Com include=totals, a primeira página (a chamada sem cursor) traz totals: quantos elementos cumprem os filtros e quanto somam, contando todas as páginas. Os anulados contam-se à parte e não somam.
Recursos
Todos os recursos respondem a GET. O contrato completo, com cada campo e cada parâmetro, é o ficheiro OpenAPI 3.1 que cada empresa serve sem token em {api_base_url}/openapi.json. Importe-o no Postman ou gere um cliente a partir dele.
| Endpoint | Conteúdo | Filtros |
|---|---|---|
GET/companies | Empresas que o token pode ler, com o api_base_url de cada uma. Chama-se em accounts.tributs.ad. | — |
GET/contacts | Clientes e fornecedores, com NRT, país e papéis. | role |
GET/sales_invoices | Faturas de venda emitidas, notas de crédito e fechos de caixa. expand=lines acrescenta as linhas e o IGI por taxa. | date_fromdate_tostatustypecontact_idmin_totalsortinclude=totalsexpand=lines |
GET/purchase_invoices | Faturas de compra e notas de crédito, com o IGI dedutível efetivamente suportado. | date_fromdate_tostatustypecontact_idmin_totalsortinclude=totalsexpand=lines |
GET/journal_lines | Linhas do diário: data, conta, débito, crédito, terceiro e documento de origem. | date_fromdate_toaccountcontact_iddocument_id |
GET/accounts | Plano de contas (PGC de Andorra), com número, nome e conta-mãe. | — |
GET/bank_transactions | Movimentos bancários e o seu estado de reconciliação. | date_fromdate_tostatusbank_account_idmin_amountsortinclude=totals |
GET/bank_accounts | Contas bancárias da empresa com dois saldos: o dos livros (ledger_balance) e o do extrato do banco (statement_balance). | date |
GET/receivables | O que cada cliente deve à data de hoje: valor em aberto, vencido, a 30 dias e adiantamentos por aplicar. Por defeito, o maior saldo primeiro; sort=oldest_due, o vencimento mais antigo. | min_amountsortinclude=totals |
GET/payables | O que se deve a cada fornecedor, com os mesmos campos que receivables. | min_amountsortinclude=totals |
GET/obligations | Calendário fiscal: modelo, período, prazo, estado e o resultado da declaração guardada. GET /obligations/{id} acrescenta os valores campo a campo. | yearstatusdeadline_fromdeadline_to |
GET/payroll_summary | Totais de salários por mês: recibos e pessoas, bruto, líquido, CASS do trabalhador e da empresa, retenções (IRPF e IRNR) e custo total, com assalariados e sócios em separado. Sem nomes. | month_frommonth_to |
GET/payslips | Recibos de vencimento, um por pessoa e mês: bruto, líquido, CASS, retenção com a sua taxa, custo da empresa, estado e data de pagamento. include=totals acrescenta as somas. | month_frommonth_toemployee_idstatuskindsortinclude=totals |
GET/employees | Pessoas do quadro: nome, datas de entrada e de saída, tipo de contrato, categoria e residência fiscal. | statuskind |
GET/reports/profit_and_loss | Demonstração de resultados por rubrica, com o detalhe por conta. | date_fromdate_toperiodicityperiods |
GET/reports/balance_sheet | Balanço por rubrica, com o detalhe por conta. | dateperiodicityperiods |
GET/reports/trial_balance | Balancete: saldo inicial, débito, crédito e saldo final por conta. | date_fromdate_to |
As listas paginadas (todos os recursos exceto companies, bank_accounts, payroll_summary e os relatórios) aceitam também limit e cursor, e updated_since exceto receivables e payables, que são saldos à data de hoje.
Para ler um só documento: GET /sales_invoices/{id}, /purchase_invoices/{id}, /contacts/{id} e /obligations/{id} (por id ou por code, como M900-T2-2026). As faturas chegam sempre com as linhas, e a obrigação com os valores da declaração guardada (filing): resultado e detalhe por campo dos modelos 900, 910, 800, 805, 810, 700, 710, 310 e 311. As retenções saem em totais, sem a lista de beneficiários.
Fora da v1: PDF e anexos, orçamentos, guias de remessa, subscrições e projetos. Das pessoas do quadro nunca saem o NRT, o número de inscrição na CASS, o IBAN nem a data de nascimento.
Exemplo de resposta
{
"data": [
{
"id": "FV-26-00042",
"number": "FV-26-00042",
"type": "invoice",
"status": "unpaid",
"issue_date": "2026-10-02",
"due_date": "2026-11-01",
"contact_id": "Grup Ferrer SL",
"contact_name": "Grup Ferrer SL",
"contact_tax_id": "L712345A",
"currency": "EUR",
"net_amount": 1200.0,
"tax_amount": 54.0,
"total": 1254.0,
"outstanding_amount": 1254.0,
"document_currency": "EUR",
"document_total": 1254.0,
"exchange_rate": 1.0,
"credited_invoice_id": null,
"project_ids": [],
"description": "Consultoria setembre",
"disbursements_amount": 0.0,
"created_at": "2026-10-02T08:14:03Z",
"updated_at": "2026-10-02T08:14:03Z"
}
],
"next_cursor": "WyIyMDI2LTEwLTAyIDEwOjE0OjAzIiwiRlYtMjYtMDAwNDIiXQ",
"has_more": true
} Convenções
- JSON, com nomes de campo em inglês e em
snake_case. - Os estados são códigos estáveis (
paid,unpaid,cancelled…) e nunca são traduzidos. - As datas contabilísticas estão no formato
YYYY-MM-DD(calendário de Andorra). Os momentos, em RFC 3339 e UTC. - Os montantes são números com 2 casas decimais em EUR, a moeda da contabilidade. Os documentos em moeda estrangeira trazem também
document_currency,document_totaleexchange_rate. - As rubricas dos relatórios identificam-se pelo seu
code(Decret 479/2025). O texto é o oficial em catalão. - Os valores de um modelo fiscal identificam-se pelo número do campo (
box); a etiqueta está em catalão, a língua do formulário oficial.
Limites
60 pedidos por minuto por token e empresa, em rajadas de até 20. Um relatório conta como 5, tal como bank_accounts, receivables, payables e payroll_summary. Como o limite é por empresa, uma gestoria pode ler muitas empresas em paralelo; além disso, cada endereço IP tem um teto global de 600 pedidos por minuto.
| Cabeçalho | Significado |
|---|---|
RateLimit-Limit | Pedidos por minuto: 60. |
RateLimit-Remaining | Pedidos que ainda pode fazer neste momento. |
RateLimit-Reset | Segundos até o contador voltar a estar cheio. |
RateLimit-Policy | A política aplicada: 60;w=60;burst=20. |
Retry-After | Com 429 e 503: segundos a esperar antes de tentar de novo. |
Erros
Os erros seguem o RFC 9457 (application/problem+json). O campo code é estável e type liga à linha correspondente desta tabela.
HTTP/1.1 401 Unauthorized
Content-Type: application/problem+json
{
"type": "https://tributs.ad/developers#errors-expired-token",
"title": "Access token expired",
"status": 401,
"code": "expired_token",
"instance": "/api/v1/sales_invoices"
} | Estado | code | O que fazer |
|---|---|---|
| 401 | missing_token | Acrescente o cabeçalho Authorization: Bearer trb_…. |
| 401 | invalid_token | O token não existe ou foi mal copiado. Verifique-o ou crie um novo. |
| 401 | expired_token | O token expirou. Crie um novo a partir do seu perfil. |
| 401 | revoked_token | O token foi revogado. Crie um novo a partir do seu perfil. |
| 403 | no_access | Não tem acesso a esta empresa. |
| 403 | permission_denied | O seu papel nesta empresa não permite ler este recurso. |
| 403 | api_access_disabled | O proprietário desligou o acesso por API da empresa. |
| 403 | api_access_blocked | O proprietário cortou-lhe o acesso por API a esta empresa. |
| 403 | company_suspended | A subscrição da empresa não está ativa. |
| 400 | invalid_parameter | Um parâmetro não é válido. O campo detail diz qual. |
| 404 | not_found | O recurso ou o documento não existe. |
| 405 | method_not_allowed | A API só aceita GET. |
| 429 | rate_limited | Espere os segundos indicados em Retry-After. |
| 500 | internal_error | Um erro do nosso lado. Tente de novo; se persistir, escreva-nos. |
| 503 | maintenance | A empresa está em manutenção. Tente de novo depois dos segundos de Retry-After. |
| 503 | auth_unavailable | Não conseguimos verificar o token. Tente de novo dentro de alguns segundos. |
Excel e Power BI
No Excel ou no Power BI, crie primeiro um parâmetro de texto TributsToken com o token (Gerir Parâmetros). Depois abra Obter dados → Consulta em branco → Editor avançado e cole esta consulta, que percorre todas as páginas.
let
Token = TributsToken,
Base = "https://acme.tributs.ad/api/v1/sales_invoices",
GetPage = (cursor as nullable text) =>
Json.Document(Web.Contents(Base, [
Query = if cursor = null
then [limit = "200"]
else [limit = "200", cursor = cursor],
Headers = [Authorization = "Bearer " & Token]
])),
Pages = List.Generate(
() => GetPage(null),
each _ <> null,
each if _[has_more] then GetPage(_[next_cursor]) else null
),
Rows = List.Combine(List.Transform(Pages, each _[data])),
Invoices = Table.FromRecords(Rows)
in
Invoices Se pedir credenciais, escolha Anónimo: o token já segue no cabeçalho. A URL base fixa e os parâmetros em Query permitem atualizar o relatório a partir do serviço Power BI; aí, nas credenciais da origem de dados, marque «Skip test connection» (ignorar o teste de ligação), porque esse teste é feito sem token e recebe um erro 401. O token fica guardado dentro do ficheiro: use um só para este relatório e partilhe o ficheiro apenas com quem pode ver estes dados.
Assistentes de IA
Um assistente de IA (ChatGPT, Claude e outros programas compatíveis com MCP) pode ler os mesmos dados que esta API, com as mesmas consultas e as tuas permissões. Não é preciso token: entras com o teu utilizador do Tributs.
- No assistente, adiciona um conector personalizado com o endereço
https://mcp.tributs.ad/mcp, com o/mcpdo fim. - Abre-se um ecrã do Tributs: entra com o teu utilizador e carrega em Permitir.
- Em Ajustes → Perfil → Ligações externas vês a aplicação ligada e podes retirar-lhe a permissão.
- Só leitura. Cada recurso desta página é uma consulta do assistente, e os que se juntarem chegam-lhe sozinhos.
- Limite próprio: 120 pedidos por minuto por ligação, com rajadas de até 40, além do limite da API por empresa.
- O Claude Code, o Cursor ou um programa próprio que fale MCP também podem entrar com um token: envia-o como
Authorization: Bearer trb_…para o mesmo endereço. - O que o assistente lê passa pelo fornecedor que escolheste, com as condições dele.
Segurança
Como protegemos o acesso:
- Só leitura: nenhum endpoint da API altera dados.
- A Tributs só guarda uma impressão digital do token (SHA-256).
- Expiração obrigatória, com revogação e renovação a partir do perfil.
- Cada empresa vê quem a lê, e o proprietário pode cortar o acesso.
- Limites por token e empresa, e HTTPS em todos os pedidos.
Boas práticas
- Guarde o token num gestor de segredos ou numa variável de ambiente. Mantenha-o fora do código, dos repositórios e das aplicações que correm no navegador.
- Crie um token para cada programa, com a expiração mais curta que lhe sirva.
- Envie-o sempre no cabeçalho
Authorization: as URL ficam nos históricos e nos registos dos servidores. - Se achar que foi exposto, revogue-o a partir do perfil e crie um novo. O prefixo
trb_ajuda os detetores de segredos a encontrá-lo.
Para comunicar uma vulnerabilidade, escreva para security@tributs.ad.
Versões
A versão está na URL (/api/v1/). A v1 só ganha campos: uma alteração incompatível passa para a v2.