Documentação da API · v1.0.0

Calendas API

Feriados e dias úteis em Portugal, por concelho, com a fonte de cada feriado.

URL base
https://api.calendas.pt
Formato
JSON (UTF-8), só GET
Especificação
https://api.calendas.pt/openapi.json (OpenAPI 3.1)

Autenticação

Cada pedido precisa de uma chave de API.

Envie-a no cabeçalho Authorization como bearer token, ou em X-Api-Key se o seu cliente não conseguir definir Authorization. Nunca a ponha no URL: os URLs acabam em registos. Guarde a chave numa variável de ambiente ou num cofre de segredos, nunca no código.

Authorization: Bearer cal_…

Sem chave, ou com uma chave desconhecida ou revogada, a API responde 401 com o código missing_api_key ou invalid_api_key. A chave mostra-se uma vez, quando é criada; para a trocar, peça uma nova e a antiga é revogada.

A API está em beta fechado: as chaves dão-se a pedido. Pedir acesso ou escreva para [email protected].

Limites

Cada chave tem um limite por minuto e uma quota diária.

Uma chave pode fazer 60 pedidos por minuto (numa janela deslizante de 60 segundos) e 1000 pedidos por dia. A quota diária repõe-se à meia-noite, hora de Lisboa; se precisar de mais, escreva-nos.

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60
X-RateLimit-Quota-Limit: 1000
X-RateLimit-Quota-Remaining: 999
X-RateLimit-Quota-Reset: 43200

Cada resposta a uma chave válida traz os dois limites: X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset para o minuto, e os mesmos com Quota para o dia. O Reset é em segundos.

Conta cada pedido com uma chave válida, também os que acabam num erro. Acima de qualquer dos limites, a API responde 429 com o código rate_limited e um cabeçalho Retry-After com os segundos a esperar; um pedido recusado não conta para a quota.

Primeiro pedido

Os feriados de um concelho num ano

O feriado municipal de 24 de junho, com a ligação para a fonte, o nível dessa fonte e a data da última verificação. A resposta abaixo é verdadeira, reduzida a dois feriados.

Pedidocurl

$ curl -G https://api.calendas.pt/v1/holidays \-H "Authorization: Bearer $CALENDAS_API_KEY" \-d year=2026 \-d municipality=guimaraes

Resposta200 · application/json

{  "data": {    "year": 2026,    "municipality": {      "ine_code": "0308",      "name": "Guimarães",      "slug": "guimaraes",      "district": "Braga",      "region": null    },    "holidays": [      {        "date": "2026-01-01",        "name": "Ano Novo",        "name_en": "New Year's Day",        "commemorates": null,        "commemorates_en": null,        "slug": "ano-novo",        "scope": "national",        "recurrence": "1 de janeiro",        "recurrence_en": "1 January",        "source_url": "https://diariodarepublica.pt/dr/legislacao-consolidada/lei/2009-34546475",        "source_kind": "legislacao",        "source_title": "Diário da República · Código do Trabalho (Lei n.º 7/2009), art. 234.º",        "source_tier": "A",        "verified_at": "2026-10-30",        "evidence": {          "confirmed_years": [],          "recurrence_confirmed": false        }      },      …,      {        "date": "2026-06-24",        "name": "Feriado municipal de Guimarães",        "name_en": "Guimarães municipal holiday",        "commemorates": "Batalha de São Mamede (1128)",        "commemorates_en": null,        "slug": "feriado-municipal-guimaraes",        "scope": "municipal",        "recurrence": "24 de junho",        "recurrence_en": "24 June",        "source_url": "https://www.visitguimaraes.travel/pages/1150/?geo_article_id=986",        "source_kind": "pagina_institucional",        "source_title": null,        "source_tier": "B",        "verified_at": "2026-11-01",        "evidence": {          "confirmed_years": [],          "recurrence_confirmed": false        }      }    ]  },  "warnings": []}

Convenções

A mesma forma em todas as respostas

  • Uma resposta com sucesso é {"data": …, "warnings": […]}. Leia os warnings: municipal_holiday_unknown quer dizer que o feriado municipal desse ano não está nos dados, por isso a resposta pode não ter um dia de folga.
  • Um erro é {"error": {"code", "message", "parameter"}}, com parameter a indicar o parâmetro em causa. Decida pelo code; a message é para pessoas e pode mudar.
  • As datas são AAAA-MM-DD. Os intervalos incluem os dois extremos.
  • Um concelho indica-se pelo slug (guimaraes) ou pelo código INE de 4 algarismos (0308); ver a lista.
  • Os feriados nunca passam para segunda-feira, e dois feriados no mesmo dia aparecem os dois.
  • recurrence descreve como o feriado se repete, para mostrar; a data a usar é date.

Endpoints

5 endpoints

GET /v1/municipalities

Todos os concelhos (308), por nome.

$ curl -G https://api.calendas.pt/v1/municipalities \-H "Authorization: Bearer $CALENDAS_API_KEY"
200
Concelhos.
401
Sem chave de API, ou com uma desconhecida ou revogada (missing_api_key, invalid_api_key). A resposta traz WWW-Authenticate: Bearer.
429
Acima de um limite da chave (rate_limited): os pedidos por minuto ou a quota diária. Espere os segundos de Retry-After. Um pedido recusado não conta para a quota.
500
Erro.

GET /v1/holidays

Todos os feriados de um concelho num ano.

Todos os âmbitos (nacional, regional, municipal, facultativo), cada um com a sua fonte. Dois feriados no mesmo dia aparecem os dois. Os feriados nunca passam para segunda-feira.

ParâmetroTipoDescrição
year obrigatório integer Um ano da cobertura (2000 a 2050).
municipality obrigatório string Slug do concelho (ex.: guimaraes) ou código INE de 4 algarismos (ex.: 0308).
$ curl -G https://api.calendas.pt/v1/holidays \-H "Authorization: Bearer $CALENDAS_API_KEY" \-d year=2026 \-d municipality=guimaraes
200
Feriados do ano.
401
Sem chave de API, ou com uma desconhecida ou revogada (missing_api_key, invalid_api_key). A resposta traz WWW-Authenticate: Bearer.
400
Erro.
404
Erro.
422
Erro.
429
Acima de um limite da chave (rate_limited): os pedidos por minuto ou a quota diária. Espere os segundos de Retry-After. Um pedido recusado não conta para a quota.
500
Erro.

GET /v1/holidays/check

Os feriados de um dia, e se é feriado e dia útil.

holidays lista todos os feriados do dia, sejam quais forem as opções; is_holiday e is_business_day seguem municipal, carnival e rest_days.

ParâmetroTipoDescrição
date obrigatório string (date)
municipality obrigatório string Slug do concelho (ex.: guimaraes) ou código INE de 4 algarismos (ex.: 0308).
municipal boolean Se o feriado municipal conta.
carnival boolean Se o Carnaval (um feriado facultativo) conta.
rest_days string Dias da semana ISO separados por vírgulas (1 = segunda-feira … 7 = domingo). Presente e vazio: sem dias de descanso.
$ curl -G https://api.calendas.pt/v1/holidays/check \-H "Authorization: Bearer $CALENDAS_API_KEY" \-d date=2026-06-24 \-d municipality=guimaraes
200
O dia.
401
Sem chave de API, ou com uma desconhecida ou revogada (missing_api_key, invalid_api_key). A resposta traz WWW-Authenticate: Bearer.
400
Erro.
404
Erro.
422
Erro.
429
Acima de um limite da chave (rate_limited): os pedidos por minuto ou a quota diária. Espere os segundos de Retry-After. Um pedido recusado não conta para a quota.
500
Erro.

GET /v1/business-days/count

Dias úteis entre dois dias, ambos incluídos.

ParâmetroTipoDescrição
from obrigatório string (date)
to obrigatório string (date) O mesmo dia que from ou posterior.
municipality obrigatório string Slug do concelho (ex.: guimaraes) ou código INE de 4 algarismos (ex.: 0308).
rest_days string Dias da semana ISO separados por vírgulas (1 = segunda-feira … 7 = domingo). Presente e vazio: sem dias de descanso.
municipal boolean Se o feriado municipal conta.
carnival boolean Se o Carnaval (um feriado facultativo) conta.
$ curl -G https://api.calendas.pt/v1/business-days/count \-H "Authorization: Bearer $CALENDAS_API_KEY" \-d from=2026-06-01 \-d to=2026-06-30 \-d municipality=guimaraes
200
Contagem.
401
Sem chave de API, ou com uma desconhecida ou revogada (missing_api_key, invalid_api_key). A resposta traz WWW-Authenticate: Bearer.
400
Erro.
404
Erro.
422
Erro.
429
Acima de um limite da chave (rate_limited): os pedidos por minuto ou a quota diária. Espere os segundos de Retry-After. Um pedido recusado não conta para a quota.
500
Erro.

GET /v1/business-days/add

O dia n dias úteis depois de um dia (ou antes, com dias negativos).

O dia de partida não conta: days=0 devolve o próprio dia se for útil, senão o seguinte.

ParâmetroTipoDescrição
date obrigatório string (date)
days obrigatório integer
municipality obrigatório string Slug do concelho (ex.: guimaraes) ou código INE de 4 algarismos (ex.: 0308).
rest_days string Dias da semana ISO separados por vírgulas (1 = segunda-feira … 7 = domingo). Presente e vazio: sem dias de descanso.
municipal boolean Se o feriado municipal conta.
carnival boolean Se o Carnaval (um feriado facultativo) conta.
$ curl -G https://api.calendas.pt/v1/business-days/add \-H "Authorization: Bearer $CALENDAS_API_KEY" \-d date=2026-06-24 \-d days=10 \-d municipality=guimaraes
200
Resultado.
401
Sem chave de API, ou com uma desconhecida ou revogada (missing_api_key, invalid_api_key). A resposta traz WWW-Authenticate: Bearer.
400
Erro.
404
Erro.
422
Erro.
429
Acima de um limite da chave (rate_limited): os pedidos por minuto ou a quota diária. Espere os segundos de Retry-After. Um pedido recusado não conta para a quota.
500
Erro.

Fontes e fiabilidade

Cada feriado diz de onde vem

Cada feriado traz a fonte em que assenta e o nível dessa fonte. Use o nível para decidir quanto confiar numa data: por exemplo, mostre as datas de nível C como provisórias, ou peça aos seus utilizadores que as confirmem.

O nível diz que prova temos de cada data, não se a data está certa. Uma data de nível C vem de fontes públicas e é comparada regularmente com outras fontes; pode perfeitamente estar certa, mas ainda não a confirmámos numa fonte oficial. B já é uma página oficial que afirma o feriado; A é o próprio ato publicado.

Nível A · ato publicado
O ato que fixa o feriado, tal como foi publicado: uma lei no Diário da República, uma deliberação ou um edital do município. verified_at é o dia em que o lemos pela última vez.
Nível B · página oficial
Uma página oficial de uma entidade pública (o município, um serviço do governo regional ou da administração central) que indica o feriado, sem o próprio ato.
Nível C · fonte secundária
Uma enciclopédia, a imprensa ou um agregador. Nunca conta como verificada: verified_at é sempre null. Estamos a substituí-las por fontes oficiais.

O objeto feriado

CampoTipoDescrição
date string (date)
name string Nome em português, sempre. O feriado municipal tem o nome do concelho (Feriado municipal de Guimarães); o que comemora está em commemorates.
name_en string | null Nome em inglês, ou null enquanto não houver tradução (nunca o nome em português).
commemorates string | null O que o feriado comemora, em português (ex.: Batalha de São Mamede (1128)), ou null quando o nome já o diz.
commemorates_en string | null commemorates em inglês, ou null enquanto não houver tradução (nunca o texto em português).
slug string
scope string Um de: national, regional, municipal, optional.
recurrence string Como o feriado se repete, em português, para mostrar. Use date: isto é uma descrição, não uma fórmula.
recurrence_en string recurrence em inglês.
source_url string | null (uri) A fonte oficial (o Diário da República nas leis; a deliberação ou o edital da câmara nos feriados municipais), ou a fonte secundária no nível C.
source_kind string | null Tipo de documento da fonte: deliberação, edital, página institucional, notícia, agenda, legislação ou outra (ex.: uma enciclopédia). Descreve o documento; a força da fonte é o source_tier. Um de: deliberacao, edital, pagina_institucional, noticia, agenda, legislacao, outra.
source_title string | null Título curto e legível da fonte, para mostrar.
source_tier string A: o ato publicado (lei, decreto, deliberação). B: uma página oficial que indica o feriado, sem o ato. C: uma fonte secundária (imprensa, Wikipédia), nunca verificada. Um de: A, B, C.
verified_at string | null (date) Dia em que a fonte foi verificada pela última vez; sempre null no nível C.
evidence object Evidências de uso: páginas oficiais (um aviso de serviços, o programa do dia do município) que dizem em que dia o feriado foi gozado num ano. Confirmam o uso nesses anos, nunca o ato: não mudam o source_tier (A é só o ato).

Erros

Códigos de erro

EstadoCódigoSignificado
401 missing_api_key Não foi enviada nenhuma chave de API.
401 invalid_api_key A chave é desconhecida, está mal formada ou foi revogada.
400 invalid_parameter Um parâmetro falta, está repetido ou não é válido; parameter indica qual.
404 municipality_not_found Nenhum concelho tem esse slug ou código INE.
404 not_found Esse endpoint não existe.
422 out_of_coverage Uma data ou um ano fora dos anos a que a API responde.
429 rate_limited Acima de um limite da chave, por minuto ou por dia; espere os segundos de Retry-After.
500 internal_error Erro nosso: fica registado e somos alertados.