climatememory programadores

Referência da API

Começar

Três APIs, uma chave: previsões meteorológicas do ECMWF e dos modelos nacionais de alta resolução, graus-dia de aquecimento e de arrefecimento, e 87 anos de clima diário. Esta página é tudo o que precisa antes da primeira chamada. Os endpoints propriamente ditos estão nas três páginas de referência.

O que é isto#

A Climate Memory serve três produtos a partir de dois anfitriões, com uma única chave de API.

ProdutoAnfitriãoResponde aReferência
Meteorologiahttps://api.climatememory.comO que o tempo vai fazer — previsão, condições atuais, ensembles, qualidade do ar, estado do mar, riosAPI Meteorologia
Graus-diahttps://api.climatememory.comQuanto foi preciso aquecer ou arrefecer um edifício — desde 1950, em qualquer lugarAPI Graus-dia
Climahttps://api.climatememory.comO que é normal aqui — 87 anos de clima diário, normais OMM, tendênciasAPI Clima

Dois anfitriões em vez de um porque os graus-dia leem um arquivo diferente, com um perfil de custo diferente, e separá-los deixa um ser lento sem tornar o outro lento. Não tem de se preocupar com isso para lá de copiar o URL de base certo.

Todos os endpoints são GET. Não há corpo de pedido em lado nenhum desta API, não há cursor de paginação nem sessão. Uma chamada é um URL mais um cabeçalho, o que significa que pode testar qualquer uma delas na barra de endereço de um navegador com uma chave numa ferramenta sem query string como o curl, e pôr qualquer uma em cache à nossa frente sem tratamento especial.

A sua primeira chamada#

Três passos. Ao todo demora cerca de um minuto.

1. Obter uma chave

Crie uma conta em developers.climatememory.com/signin. O plano gratuito não pede cartão, dá-lhe 10 000 créditos por mês, e a sua chave aparece imediatamente no ecrã. Guarde-a numa variável de ambiente — os exemplos abaixo leem todos $API_KEY.

export API_KEY="wd_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

2. Fazer a chamada

curl -sH "X-API-Key: $API_KEY" \
  "https://api.climatememory.com/v1/forecast?lat=48.85&lon=2.35&days=3"
import os, httpx

r = httpx.get(
    "https://api.climatememory.com/v1/forecast",
    params={"lat": 48.85, "lon": 2.35, "days": 3},
    headers={"X-API-Key": os.environ["API_KEY"]},
    timeout=30,
)
r.raise_for_status()
data = r.json()
print(data["daily"]["temperature_2m_max"])
const res = await fetch(
  "https://api.climatememory.com/v1/forecast?lat=48.85&lon=2.35&days=3",
  { headers: { "X-API-Key": process.env.API_KEY } },
);
if (!res.ok) {
  const { error } = await res.json();
  throw new Error(`${error.code}: ${error.message}`);
}
const data = await res.json();
console.log(data.daily.temperature_2m_max);
req, _ := http.NewRequest("GET",
    "https://api.climatememory.com/v1/forecast?lat=48.85&lon=2.35&days=3", nil)
req.Header.Set("X-API-Key", os.Getenv("API_KEY"))

res, err := http.DefaultClient.Do(req)
if err != nil { return err }
defer res.Body.Close()

var out struct {
    Daily struct {
        TemperatureMax []float64 `json:"temperature_2m_max"`
    } `json:"daily"`
}
json.NewDecoder(res.Body).Decode(&out)

3. Ler a resposta

Todas as séries voltam orientadas por coluna — vetores paralelos que partilham um índice time, e não uma lista de objetos. Veja as convenções de resposta para saber porquê, e como as ler.

A seguir: a mesma chamada por nome de cidade costuma ser melhor — https://api.climatememory.com/v1/forecast/city/fr/paris traz a altitude real da cidade e o seu fuso horário, coisas que uma coordenada nua não pode trazer. Veja previsão por cidade.

Autenticação#

Envie a sua chave no cabeçalho X-API-Key em cada pedido. Não há fluxo OAuth, não há bearer token a renovar nem assinatura a calcular.

X-API-Key: wd_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

As chaves são guardadas em hash. Se perder uma, ela é rodada, não recuperada — não a podemos mostrar outra vez, porque não a temos. A rotação faz-se na consola e emite uma chave nova de imediato.

Scopes

Uma chave leva scopes, e é o plano que decide quais. Chamar um endpoint fora dos seus scopes devolve 403 scope_denied — o que é um problema de plano e não um problema de chave, e a mensagem di-lo.

ScopeDá acesso a
meteoToda a API Meteorologia, incluindo os extras
djuOs graus-dia e o histórico horário
climateO arquivo climático diário e os seus agregados
normalsAs normais OMM e a comparação de normais

Os endpoints de geocodificação não exigem nenhum deles. Qualquer chave válida resolve um nome de lugar, em qualquer plano, porque todos os produtos aqui precisam de uma coordenada antes de poderem responder o que quer que seja. Veja geocodificação.

Nunca ponha a sua chave num navegador. Chame a API a partir do seu servidor e passe o resultado ao cliente. Uma chave em JavaScript de front-end é uma chave que qualquer pessoa lê no separador de rede e gasta contra a sua quota — e, como é a sua chave, esse uso é indistinguível do seu.

Se precisa de meteorologia numa aplicação móvel, os endpoints móveis existem exatamente para isso: emitem um token por instalação em vez de embeberem a sua chave.

Geocodificação#

GEThttps://api.climatememory.com/v1/geocodequalquer chave0 créditos

Resolve um nome de lugar em coordenadas, altitude e fuso horário.

Parâmetros

ParâmetroTipoPor omissãoDescrição
qstringNome do lugar, em qualquer língua. Acentos opcionais. Obrigatório.
langISO-639-1enApenas apresentação e ordenação — nunca o que é elegível. Um código desconhecido cai para os nomes locais em vez de falhar.
nearlat,lonA posição de quem chama. O critério de desempate mais forte que existe.
countryISO-3166-1 alpha-2Restringir a um só país.
limitint101–50.

O catálogo é a classe de entidades P do GeoNames por inteiro — todos os lugares habitados da Terra, até aldeias de algumas dezenas de pessoas, e não um extrato filtrado por população. Uma aldeia de 528 habitantes está lá.

Não custa créditos, em plano nenhum, e não exige scope. Uma chave vendida para graus-dia também resolve nomes, porque não se podem pedir graus-dia sem uma coordenada. Em vez disso tem um teto próprio — cinco pedidos de geocodificação por cada crédito do seu plano — deliberadamente generoso o bastante para que uma caixa de pesquisa com sugestões e debounce seja o uso previsto. Veja limites de ritmo e quota.

A correspondência nunca é restringida pela língua

A consulta é testada contra o nome local, a sua transliteração ASCII e todos os apelidos localizados, diga o que disser lang. Isso importa mais do que parece: 98 % dos lugares não têm nome localizado nenhum — o francês cobre 1,84 % do catálogo — pelo que uma pesquisa filtrada por língua encontra capitais e mais nada. lang escolhe que nome volta e influencia a ordenação; nunca decide o que é elegível.

GET /v1/geocode?q=ramillies&lang=fr
GET /v1/geocode?q=ramillies&lang=fr&near=50.63,3.06   # a partir de Lille
GET /v1/geocode?q=bruxelles&lang=fr                     # exónimo, pelo índice de apelidos
GET /v1/geocode?q=zuesch&lang=de                        # tremas escritos por extenso

Como os resultados são ordenados

Cada resultado traz um score e, quando foi dado near, uma distance_km. A ordenação combina quatro sinais: quão bem o nome coincidiu, quão importante é o lugar, quão perto está de near, e se o nome que coincidiu estava na língua pedida.

Porque é que near existe. Há duas Ramillies — 5 749 habitantes no Brabante Valão, 528 nos Altos de França, a 126 km uma da outra. Nenhuma é a resposta certa em abstrato. Sem near devolve-se a maior; a partir de Lille, devolve-se a francesa.

A importância não é só a população. 90,7 % do catálogo não tem população registada — o GeoNames não publica nenhuma para certos países — pelo que é o tipo de lugar (capital nacional, sede de divisão administrativa, lugar comum, bairro) que carrega a ordenação onde a população falta.

Os tremas escrevem-se por extenso, não se deitam fora. Um teclado alemão ou dinamarquês sem diacríticos escreve Zuesch para Züsch e Koeln para Köln. O GeoNames não tem essa grafia — a sua forma ASCII é Zusch, com o trema removido em vez de expandido — por isso é gerada aqui. Ambas as grafias chegam ao lugar, e o resultado mostra o nome verdadeiro nos dois casos.

Consulta de cidades#

GEThttps://api.climatememory.com/v1/cities/searchqualquer chave0 créditos

Pesquisa de nomes antiga. Corresponde apenas ao nome ASCII e ordena por população.

GEThttps://api.climatememory.com/v1/cities/nearestqualquer chave0 créditos

A cidade catalogada mais próxima de uma coordenada.

/v1/cities/search é anterior a /v1/geocode e mantém o seu contrato para quem já construiu em cima dele: corresponde apenas ao nome ASCII e ordena por população.

Prefira /v1/geocode para tudo o que o utilizador vê. A rota antiga não consegue corresponder a um exónimo — Bruxelles não encontra Brussel — e a sua ordenação é indefinida para os nove em cada dez lugares que não têm população registada.

/v1/cities/nearest é o sentido inverso, e é o que transforma uma posição GPS num slug de cidade que pode depois passar aos endpoints por cidade. Recebe lat, lon e um max_km opcional.

Ambos contam para o mesmo teto de geocodificação que /v1/geocode, e nenhum custa créditos.

Convenções de resposta#

Seis regras valem para todos os endpoints. Aprenda-as uma vez e o resto desta documentação são só nomes de campos.

1. As séries são colunas, não linhas

Cada série temporal é um conjunto de vetores paralelos que partilham um índice time, em vez de um vetor de objetos:

"hourly": {
  "time":           ["2026-08-01T00:00:00+00:00", "2026-08-01T01:00:00+00:00"],
  "temperature_2m": [18.4, 18.1],
  "precipitation":  [0.0, 0.2]
}

O índice i de cada vetor descreve o mesmo instante. Isto é três a cinco vezes mais pequeno na rede do que a forma por linhas, entra diretamente num dataframe ou numa biblioteca de gráficos sem transformação, e é o que os clientes feitos à medida do Open-Meteo já esperam. Para percorrer por linhas:

rows = zip(h["time"], h["temperature_2m"], h["precipitation"])

2. As horas são ISO 8601 com desfasamento explícito

Sempre. 2026-08-01T00:00:00+00:00, nunca uma string local nua nem um inteiro Unix. Quando passa um timezone, o desfasamento na resposta é o dessa zona — por isso a string sozinha é inequívoca e nunca tem de saber o que assumimos.

3. As unidades são SI, fixas, e nunca negociadas

°C, mm, m/s, hPa, W/m², metros. Não há parâmetro units=imperial, e é de propósito: um interruptor de unidades é um campo cujo significado depende de outro campo, e é assim que quem chama acaba a traçar Fahrenheit num eixo em Celsius depois de uma alteração de configuração que ninguém reviu. Converta na sua fronteira, onde está o leitor.

Os endpoints que trazem unidades invulgares incluem na resposta um bloco units que as nomeia explicitamente, em vez de contarem com a sua memória.

4. null quer dizer «não se sabe», nunca «zero»

Uma hora em falta é null no vetor, guardando o seu lugar para que os índices continuem alinhados. Nunca é preenchida em silêncio com 0 — para a precipitação são duas afirmações opostas, e uma delas é uma mentira sobre uma seca.

5. Cada resposta diz de onde veio

Um bloco source (meteorologia) ou um bloco quality (arquivos) viaja com os dados: que modelo ou run respondeu, que idade tem, quão completo era o período. Nunca tem de deduzir a frescura pelo relógio.

6. Antigo é melhor do que nada

Se o nosso run mais recente for mais velho do que o esperado, respondemos na mesma — com "stale": true e data_age_hours no bloco source — em vez de devolver 503. Uma previsão com oito horas é mais útil do que um erro. Verifique a marca se a frescura for determinante para si; ignore-a se não for.

Não há paginação em lado nenhum. Um pedido devolve a sua resposta inteira ou falha com um erro de intervalo que lhe diz o máximo. Em vez disso, os intervalos são limitados por endpoint — o que significa que a lógica de repetição nunca tem de lidar com um conjunto de resultados lido pela metade.

Limites de ritmo, créditos e quota#

Aplicam-se três limites independentes, e falham de maneiras diferentes de propósito. Cada resposta bem-sucedida diz onde está:

CabeçalhoSignificado
X-RateLimit-RemainingPedidos que restam no minuto deslizante em curso
X-Quota-RemainingCréditos que restam este mês
X-Quota-Resets-AtData ISO da próxima reposição mensal
X-Geocode-RemainingPedidos de geocodificação que restam este mês. Só nos endpoints de catálogo, que são os únicos que limita.

Créditos, não pedidos

Uma previsão de cidade em cache é uma leitura de 3 ms. Dez anos de graus-dia horários em quinhentos sítios não é. Cobrar por pedido deixaria quem chama manter-se dentro da quota e custar mais do que paga, de forma inteiramente legítima — por isso o que uma chamada custa depende de quanto arquivo ela move.

EndpointCréditos
/v1/forecast, /v1/current, e as formas por cidade1
/v1/probability, /v1/air-quality, /v1/marine, /v1/hydrology1
/v1/cells/resolve, /v1/climate/cells/resolve1
/v1/climate/normals3
/v1/climate/normals/compare6 — responde sobre dois períodos
/v1/climate/daily, /v1/climate/monthly2, +1 por cada período completo de 365,25 dias do intervalo
/v1/climate/summary3, +1 por cada período completo de 365,25 dias do intervalo — cerca de 89 sobre o arquivo completo
/v1/degree-days e as suas formas por cidade e por célula2, +1 por cada período completo de 365,25 dias do intervalo
/v1/degree-days/monthly2
/v1/historical(anos + 1) × (variáveis ÷ 2), arredondado por defeito, mínimo 1
Qualquer um dos anteriores com format=csv4× o custo do JSON
/v1/geocode, /v1/cities/search, /v1/cities/nearest0 — limitado à parte
/v1/models, /v1/methods, /v1/coverage, /v1/climate/coverage, /v1/climate/fields, /v1/historical/variables, /v1/attribution, /v1/licensing1, e sem chave nenhuma

A geocodificação não custa créditos. Todos os produtos aqui precisam de uma coordenada antes de poderem responder, por isso resolver um nome está incluído em vez de ser vendido. Uma caixa de pesquisa com sugestões é o uso previsto: ponha-lhe debounce e deixe-a correr.

Tem limite, isso sim, e por um teto próprio em vez de pelos seus créditos: cinco pedidos de geocodificação por cada crédito do seu plano. No plano de 50 000 créditos são 250 000 pesquisas por mês, e uma caixa de pesquisa com debounce gasta cerca de seis por cada lugar encontrado. Esgotá-lo devolve 429 geocode_quota_exceeded e deixa os seus créditos intactos — que é também a razão de serem dois códigos separados.

O que fazer quando bate em cada um

LimiteRespostaTratamento
Ritmo (por minuto)429 rate_limited + Retry-AfterEspere os segundos de Retry-After e repita. Este é transitório por construção.
Créditos (por período)429 quota_exceeded + X-Quota-Resets-AtRepetir não ajuda até à reposição. Faça upgrade, ou degrade a funcionalidade.
Teto de geocodificação429 geocode_quota_exceededOs seus créditos estão intactos e todos os outros endpoints continuam a funcionar. Reforce o debounce.

O seu período de quota vai da data da subscrição ao mesmo dia do mês seguinte — o período que a Stripe fatura — e o contador recomeça inteiro de cada vez. X-Quota-Resets-At traz essa data em cada resposta, por isso leia-a em vez de assumir o dia 1. As contas sem subscrição seguem o mês de calendário.

Faça cache com vontade — não nos incomoda, e é quota grátis. Um run de previsão muda 2 a 4 vezes por dia; um total de graus-dia de um mês passado não muda nunca. Nada aqui é específico de um utilizador, por isso uma cache HTTP comum à nossa frente é segura. Os endpoints de arquivo, em particular, vale a pena guardar para sempre abaixo dos últimos cinco dias.

Erros#

Todos os erros têm a mesma forma, em ambos os anfitriões:

{
  "error": {
    "code": "range_too_long",
    "message": "Requested span is 14.0 years; the maximum per request is 10.",
    "max_years": 10
  }
}

Construa a sua lógica de repetição sobre error.code, e não sobre o estado HTTP. Três condições diferentes devolvem 429 e pedem três reações diferentes: uma quer uma espera curta, outra quer uma mudança de plano, e outra não devia parar a sua aplicação de todo. O estado sozinho não as distingue. As chaves extra — max_years acima — trazem o limite que ultrapassou, para que o seu cliente se adapte em vez de adivinhar.

EstadoCódigoO que fazer
400invalid_latitude, invalid_longitudeCorrija as coordenadas. A latitude vai de −90 a 90, a longitude de −180 a 180.
400range_too_longDivida em vários pedidos. max_years diz o limite.
400bad_requestA forma genérica, quando uma verificação não tem código próprio mais específico. Trate-o como permanente — o pedido não fica válido por ser repetido.
400invalid_coordinatesO par está fora de alcance ou não é um ponto da Terra.
400invalid_method, invalid_baseVeja métodos de cálculo.
400invalid_breakdownNão é daily, weekly, monthly nem yearly.
400invalid_dateUma data que não é ISO YYYY-MM-DD.
400invalid_rangeend vem antes de start.
400invalid_nearnear não é lat,lon.
400unknown_field, unknown_variablePergunte a /v1/fields, /v1/climate/fields ou /v1/historical/variables o que esse produto tem — nenhum dos três precisa de chave. Em /v1/forecast a mensagem nomeia a correspondência mais próxima do que pediu.
400unknown_periodNão é um período de referência da OMM. Veja normais.
400period_not_coveredO arquivo não abrange esse período de referência neste ponto.
401missing_api_keyFaltava o cabeçalho X-API-Key.
401invalid_api_keyA chave é desconhecida ou foi rodada.
401unauthorizedA forma genérica, quando nada de mais específico se aplica.
402export_not_in_planA exportação CSV é uma funcionalidade dos planos pagos.
403scope_deniedO seu plano não inclui esta API. Veja scopes.
403key_inactiveA chave existe mas foi revogada ou desativada. Rodar uma chave faz isto à antiga — verifique a consola antes de assumir uma avaria.
404city_not_foundA resposta inclui um vetor suggestions — mostre-o.
404cell_not_foundUma célula fixada que já não existe. Veja fixar uma célula.
404not_at_seaUm pedido marinho sobre terra. O modelo de ondas não tem valor aí.
404not_foundA forma genérica. Como acima: permanente.
404no_city_nearbyNada catalogado a menos de max_km desse ponto.
404outside_archiveAs datas estão fora do que o arquivo tem. /v1/climate/coverage diz o que ele tem, e não precisa de chave.
429rate_limitedRecue durante os segundos de Retry-After.
429quota_exceededEspere pela reposição ou faça upgrade. Repetir mais cedo não pode resultar.
429geocode_quota_exceededSó o teto de geocodificação. Os seus créditos estão intactos; ponha debounce na caixa de pesquisa.
503data_unavailableTransitório. Repita com recuo exponencial.
503load_shedRecusado de propósito para proteger o serviço sob carga. A criticidade do seu plano decide quem é largado primeiro. Repita com recuo; passa em segundos.
503catalogue_unavailableO catálogo de cidades está por instantes inacessível. As coordenadas continuam a funcionar — recorra a elas em vez de falhar o pedido.

É esta a lista toda, e é confrontada com o código-fonte em cada construção: um código publicado aqui que nenhum handler levanta faz falhar os testes, e um handler que levante um que esta tabela não traga também. Se encontrar um código que não esteja acima, é um defeito desta página e não um valor que deva tratar à parte.

Uma política de repetição que funciona

RETRY = {"rate_limited", "data_unavailable"}

def should_retry(status, code, attempt):
    if code == "quota_exceeded":
        return False              # nada muda até à reposição
    if code == "geocode_quota_exceeded":
        return False              # e não pare: os créditos continuam a valer
    if code in RETRY:
        return attempt < 5
    return status >= 500

Precisão — o que esperar#

Preferimos definir bem as expectativas a que descubra os limites em produção.

Onde a previsão é forte

Temperatura, pressão, vento sinótico, humidade, insolação. O erro típico da temperatura a 2 m às 24 horas anda pelos 1–1,5 °C. O ECMWF é o melhor modelo global determinístico do mundo, e é o que está a receber.

Onde é mais fraca

Trovoadas convectivas — uma célula de 28 km não resolve uma trovoada, e nem sequer 3 km fazem mais do que sugeri-la. A localização e o momento exatos dos aguaceiros. O microclima costeiro e de montanha abaixo da resolução do modelo. As brisas marítimas e as bolsas de ar frio nos vales, que a correção de relevo não modela.

Honestidade geográfica

Em França, na Alemanha, nos EUA e no Canadá servimos modelos nacionais de 1,3–3 km, e uma aldeia pequena tem mesmo a sua própria célula de grelha. No resto da Europa recebe 6,5 km. Em África, no Médio Oriente e na maior parte da Ásia, o melhor modelo público disponível é de 13–28 km, pelo que recebe o tempo da zona e não o da rua. A correção de relevo estreita essa distância mas não a fecha.

Graus-dia

A reanálise em grelha cobre tudo, incluindo sítios sem estação meteorológica num raio de 60 km — é essa a sua vantagem sobre os fornecedores baseados em estações. A sua fraqueza são os centros urbanos, que a reanálise subestima; os endpoints por cidade aplicam uma correção calibrada, os endpoints por coordenada não.

Dois campos são estimativas, e preferimos dizê-lo

O uv_index é derivado da elevação solar e da radiação de banda larga, não de uma coluna de ozono — exato até cerca de ±1 unidade. O precipitation_probability_proxy é uma estimativa, não uma probabilidade; a verdadeira está em /v1/probability. Ambos são explicados por inteiro na referência dos campos.

Planos#

PlanoPreçoCréditos / mêsRitmoChavesScopes
Gratuito0 €10 00020 / min1meteorologia, mais graus-dia e clima durante 30 dias
Starter19 € / mês50 00060 / min3meteorologia + graus-dia + clima
Pro79 € / mês400 000300 / min10meteorologia + graus-dia + clima + normais
Businessa partir de 299 € / mêsAcordado por contratoAcordado por contrato50meteorologia + graus-dia + clima + normais

A geocodificação fica fora desta tabela: não custa créditos em plano nenhum, e tem um teto próprio de cinco pedidos por crédito. Veja limites de ritmo e quota.

A faturação anual dá dois meses grátis. O catálogo em direto está em developers.climatememory.com/pricing — essa página lê diretamente o sistema de faturação, por isso se alguma vez as duas discordarem, é ela que vale.

Não há endpoint de exportação em massa em plano nenhum. A exportação CSV existe nos arquivos de graus-dia e de clima, está limitada ao mesmo intervalo que a chamada JSON equivalente, e devolve apenas linhas agregadas — nunca a série horária.

Atribuição e licenciamento#

GEThttps://api.climatememory.com/v1/attributionsem chave0 créditos

A formulação exigida, exata e legível por máquina. Sem chave.

GEThttps://api.climatememory.com/v1/licensingsem chave0 créditos

A tabela de licenças por trás de cada conjunto de dados. Sem chave.

A atribuição é uma condição de uso, não uma cortesia. Os dados subjacentes estão-nos licenciados em termos que a exigem, e esses termos passam para si. Mostre um aviso onde quer que os dados apareçam, incluindo em produtos derivados. Uma linha de rodapé basta:

Weather data: ECMWF, DWD, NOAA, Météo-France · Climate data: Copernicus/ERA5-Land · Places: GeoNames

Ambos os endpoints acima não precisam de chave, por isso pode desenhar o aviso a partir da API em vez de fixar no código uma string que envelhece quando uma fonte muda. A atribuição do run concreto que respondeu também viaja em cada resposta de dados, em source.attribution e no cabeçalho X-Data-Attribution.

Pode dizer que usa estes dados. Não pode dar a entender que alguma destas organizações produziu, aprovou ou apoia o seu produto.

Isenção de responsabilidade

As previsões são fornecidas sem garantia. Nem a Comissão Europeia, nem o ECMWF, nem o DWD, nem a NOAA, nem a Météo-France são responsáveis por qualquer uso feito desta informação. Não a use como base única de decisões em que a vida, a segurança ou o património estejam em risco.

Uma restrição não é nossa para dispensar: a licença Copernicus reserva os avisos de cheias às autoridades nacionais e regionais. Veja rios.