Erros

Os erros são em JSON, como todo o resto, com um status HTTP correspondente e um código que você pode usar num switch. A mensagem é uma frase destinada aos seus logs, não aos seus usuários; o texto dela pode mudar, o código nunca.

O envelope de erro

{
  "status": "error",
  "error": {
    "code": "invalid_request",
    "message": "Parameter 'lat' must be a number between -90 and 90.",
    "param": "lat"
  }
}

param aparece quando um parâmetro específico causou o problema. X-Request-Id também é definido nas respostas de erro; inclua-o se entrar em contato com o suporte.

Códigos

HTTPcodeQuandoO que fazer
400invalid_requestFalta um parâmetro obrigatório, um valor está malformado ou fora do intervalo, há mais de 100 pontos ou endereços num lote, foram pedidos mais de 10 resultados.Corrija a requisição. Não tente de novo sem alterações.
401missing_keyNenhuma chave foi enviada e o acesso sem chave está desativado neste servidor. Por padrão ele fica ativado, e uma requisição sem chave é simplesmente respondida.Envie uma chave como X-API-Key, um token bearer ou key=.
429quota_exceededO endereço já usou as suas 2.500 requisições gratuitas do dia sem chave.Aguarde o reinício (Retry-After e X-Quota-Reset dizem quando) ou envie uma chave que tenha crédito ou um pacote Unlimited.
401invalid_keyA chave não existe.Verifique se há erros de digitação ou uma cópia incompleta.
401key_revokedA chave foi revogada no painel.Use uma chave válida.
402no_creditsA cota gratuita do dia da chave foi usada e o saldo de crédito da conta está zerado.Adicione crédito no painel, com cartão ou criptomoeda, ou aguarde o reinício.
403key_ip_limitTodas as vagas de IP desta chave estão ocupadas por outros endereços por enquanto.Use uma das máquinas que ocupam as vagas, dê a esta máquina uma chave própria ou adicione um pacote. Veja vagas de IP.
403account_suspendedA conta está suspensa.Verifique o e-mail que enviamos ou abra um chamado.
404not_foundO caminho não existe. Uma consulta sem correspondências retorna 200 com resultados vazios, não 404.Verifique o caminho e o prefixo de versão.
500server_errorAlgo quebrou do nosso lado.Tente de novo uma vez depois de um segundo. O erro é registrado e nos alerta. Não é contado.
503unavailableUm backend está temporariamente indisponível.Tente de novo com backoff. Não é contado.

Coisas que não são erros

Erros nos hosts compatíveis

Os hosts de compatibilidade retornam erros no formato que o provedor original usa, então o tratamento existente funciona. Por exemplo, um saldo de crédito zerado é "status": "OVER_QUERY_LIMIT" com HTTP 200 em gapi.mygeocode.com, "statusCode": 429 no envelope do Bing em bing.mygeocode.com e {"status":"fail","message":"quota"} em ipapi.mygeocode.com; uma chave inválida é REQUEST_DENIED, 401 e invalid key, respectivamente. Os cabeçalhos X-Quota-* são enviados em todos os hosts de qualquer forma, então você pode ler o estado real nos cabeçalhos se quiser.

Uma estratégia de tratamento razoável

def call(url, params, tries=3):
    for attempt in range(tries):
        r = session.get(url, params=params, timeout=10)
        if r.status_code == 200:
            return r.json()
        body = r.json()
        code = body["error"]["code"]
        if r.status_code in (500, 503):
            time.sleep(0.2 * (2 ** attempt))
            continue
        # no_credits, key_ip_limit, invalid_request, invalid_key: retrying will not help
        raise ApiError(code, body["error"]["message"], r.headers.get("X-Request-Id"))
    raise ApiError("retries_exhausted", "Gave up after %d attempts" % tries, None)