Primi passi
Tutte le chiamate provengono dallo stesso database e restituiscono JSON. Gli endpoint pubblici non richiedono l'autenticazione; quelli privati richiedono la tua chiave di accesso.
Indirizzo di base
/it-ch/api Il prefisso della lingua fa parte dell'URL (it-ch), ma ciò non modifica i dati restituiti: i record provengono dalla banca esattamente come sono stati registrati sul campo.
curl -G -d "municipality=Ponta Pora" --data-urlencode "country=Brasil" \
/it-ch/api/lastcountingpublic Se la risposta è un elenco JSON, l'integrazione sta già funzionando.
key viene letto dalla stringa di query (?key=SUA_CHAVE). L'invio solo nel corpo del modulo restituisce 404 "Wrong key". Gli altri campi continuano ad apparire nel corpo della richiesta. Consulta i dati pubblici
Il punto finale /api/lastcountingpublic restituisce gli ultimi conteggi delle uova con latitudine, longitudine, settimana e anno epidemiologici. È il punto di partenza per mappe, pannelli e studi.
/api/lastcountingpublicPubblicocurl -G \
--data-urlencode "municipality=Ponta Pora" \
--data-urlencode "date_start=2025-01-01" \
--data-urlencode "date_end=2025-12-31" \
/it-ch/api/lastcountingpublic import requests
BASE = "/it-ch/api"
resposta = requests.get(
BASE + "/lastcountingpublic",
params={
"municipality": "Ponta Pora",
"date_start": "2025-01-01",
"date_end": "2025-12-31",
},
timeout=60,
)
resposta.raise_for_status()
for contagem in resposta.json():
print(contagem["date"], contagem["ovitrap_id"], contagem["eggs"]) const BASE = "/it-ch/api";
const params = new URLSearchParams({
state: "MS",
date_start: "2025-01-01",
});
const resposta = await fetch(BASE + "/lastcountingpublic?" + params);
const contagens = await resposta.json();
console.log(contagens.length, "contagens"); Gli stessi parametri di posizione (country, state, municipality) Si applicano ad altri endpoint pubblici: ovitrap, isolati, EDL, manutenzione EDL e punti strategici. La semplice modifica del percorso dell'endpoint modifica già il set di dati.
Sfoglia tutte le pagine
Supporto per endpoint impaginati page da 1 a 100. Al di sopra di questo, l'API risponde con il testo "Maximum pagination is 100" e lo stato 200, ovvero il corpo non è più un elenco. Controlla sempre il tipo prima di ripetere.
import requests
BASE = "/it-ch/api"
def baixar_tudo(endpoint, **filtros):
"""Percorre as paginas ate a API devolver uma pagina vazia."""
registros = []
for pagina in range(1, 101):
resposta = requests.get(
BASE + endpoint,
params=dict(filtros, page=pagina),
timeout=60,
)
resposta.raise_for_status()
dados = resposta.json()
# limite de paginacao atingido: a API devolve uma string, nao uma lista
if not isinstance(dados, list):
print("Aviso:", dados)
break
if not dados:
break
registros.extend(dados)
return registros
ovitrampas = baixar_tudo("/getmunicipalityovitrapspublic", municipality="Ponta Pora")
print(len(ovitrampas), "ovitrampas") date_start e date_end dividere il periodo in intervalli più piccoli. Sincronizzazione incrementale
Per mantenere una base con mirroring, non scaricare nuovamente tutto ad ogni esecuzione. Il punto finale /api/lastcountingpublic accettato id, che restituisce solo i conteggi da quell'identificatore e anche date (data di inclusione) e date_collect (data de coleta).
import json
import os
import requests
BASE = "/it-ch/api"
ESTADO = "ultimo_id.json"
def ultimo_id_lido():
if os.path.exists(ESTADO):
with open(ESTADO) as arquivo:
return json.load(arquivo)["counting_id"]
return 0
def sincronizar():
ultimo = ultimo_id_lido()
novas = []
for pagina in range(1, 101):
resposta = requests.get(
BASE + "/lastcountingpublic",
params={"municipality": "Ponta Pora", "id": ultimo, "page": pagina},
timeout=60,
)
resposta.raise_for_status()
dados = resposta.json()
if not isinstance(dados, list) or not dados:
break
novas.extend(dados)
if novas:
maior = max(item["counting_id"] for item in novas)
with open(ESTADO, "w") as arquivo:
json.dump({"counting_id": maior}, arquivo)
return novas
print(len(sincronizar()), "contagens novas") Conserva sempre il più grande counting_id ricevuti, non la data di esecuzione: un conteggio inserito nel campo oggi può riferirsi ad una settimana precedente, e il filtro per id non lascia sfuggire questi record.
Esporta in CSV
I conteggi pubblici sono già dotati di coordinate, quindi puoi generare un foglio di calcolo o alimentare una mappa senza ulteriori unizioni.
import csv
import requests
BASE = "/it-ch/api"
COLUNAS = [
"counting_id",
"municipality",
"state_code",
"ovitrap_id",
"latitude",
"longitude",
"week",
"year",
"eggs",
"date",
"date_collect",
]
resposta = requests.get(
BASE + "/lastcountingpublic",
params={"state": "MS", "date_start": "2025-01-01"},
timeout=60,
)
contagens = resposta.json()
with open("contagens.csv", "w", newline="", encoding="utf-8") as arquivo:
escritor = csv.DictWriter(arquivo, fieldnames=COLUNAS, extrasaction="ignore")
escritor.writeheader()
escritor.writerows(contagens)
print("Arquivo contagens.csv gerado com", len(contagens), "linhas") Invio dati
Gli esempi seguenti utilizzano l'API privata e richiedono una chiave. L'ambito geografico della chiave definisce ciò che può registrare: una chiave municipale registra solo nel comune stesso.
/api/postcountingPrivatoInvia la lettura di una ovitrappola esistente
Invia il conteggio delle uova di un ovitrap già registrato. L'ovitrappola si trova vicino al ovitrap_group_id all'interno del comune di Key e la settimana epidemiologica viene calcolata dal campo date.
curl -X POST \
-d "ovitrap_group_id=97" \
-d "ovitrap_lat=-7.000000" \
-d "ovitrap_lng=-8.000000" \
-d "date=2025-01-20" \
-d "counting_observation_id=1" \
-d "counting_eggs=5" \
"/it-ch/api/postcounting?key=SUA_CHAVE" import requests
BASE = "/it-ch/api"
CHAVE = "SUA_CHAVE"
resposta = requests.post(
BASE + "/postcounting",
params={"key": CHAVE}, # a chave vai na URL
data={ # os dados vao no corpo
"ovitrap_group_id": 97,
"ovitrap_lat": -7.000000,
"ovitrap_lng": -8.000000,
"date": "2025-01-20",
"counting_observation_id": 1,
"counting_eggs": 5,
},
timeout=60,
)
print(resposta.status_code, resposta.json())
# 200 "Contagem registrada" /api/postcountingPrivatoInstalla una nuova ovitrappola accanto alla lettura
Se il ovitrap_group_id non esiste ancora nel comune, nella stessa richiesta viene creata l'ovitrappola. Inviare anche l'indirizzo e, se applicabile, il tipo (ovitrap_type_id: 1 urbano, modello; 2 rural).
import requests
BASE = "/it-ch/api"
CHAVE = "SUA_CHAVE"
resposta = requests.post(
BASE + "/postcounting",
params={"key": CHAVE},
data={
"ovitrap_group_id": 96,
"ovitrap_address_district": "Centro",
"ovitrap_address_street": "Rua das Flores",
"ovitrap_address_number": "123",
"ovitrap_address_complement": "",
"ovitrap_address_sector": "Setor 04",
"ovitrap_responsable": "Maria Souza",
"ovitrap_block_id": "12",
"ovitrap_type_id": 2, # 1 = urbana (padrao), 2 = rural
"ovitrap_lat": -7.000000,
"ovitrap_lng": -8.000000,
"date": "2025-01-20",
"counting_date_collect": "2025-01-27",
"counting_observation_id": 1,
"counting_eggs": 5,
},
timeout=60,
)
print(resposta.status_code, resposta.json()) 400— mancanzaovitrap_lat,ovitrap_lngouovitrap_group_id.400—ovitrap_type_iddiverso da 1 o 2.404— C'è già un conteggio per questa ovitrappola, anno e settimana.500— la data inviata rientra in una settimana epidemiologica futura o non valida.
/api/postactionPrivatoRegistra una visita in isolato
Utilizzo block_id per avviare la visita in un isolato già registrato. Se l'isolato non esiste ancora, invia block_group_id con i dati dell'isolato e viene creato automaticamente all'interno del comune chiave.
import requests
BASE = "/it-ch/api"
CHAVE = "SUA_CHAVE"
visita = {
"block_id": 97,
"date": "2025-01-20",
"block_land_residence": 10,
"action_land_residence_out": 2,
"action_land_residence_breedings": 1,
"action_land_residence_treated": 1,
"action_deposit_a1_quantity": 4,
"action_deposit_a1_eliminated": 2,
"action_deposit_a1_treated": 1,
"action_deposit_a1_larvicid": 10,
"action_observation": "Foco encontrado em pneus nos fundos do imovel.",
}
resposta = requests.post(
BASE + "/postaction", params={"key": CHAVE}, data=visita, timeout=60
)
if resposta.status_code == 409:
print("Ja existe visita para esse quarteirao nessa semana")
else:
print(resposta.status_code, resposta.json()) visita = {
"block_group_id": 97,
"date": "2025-01-20",
"block_address_district": "Centro Historico",
"block_address_sector": "Setor 04 - Norte",
"block_coordinates": "[[-7.123, -34.845], [-7.124, -34.846]]",
"block_lat": -7.123456,
"block_lng": -34.845678,
"block_responsable": "Joao da Silva",
"block_land_residence": 10,
"action_land_residence_out": 2,
"action_land_residence_breedings": 1,
"action_land_residence_treated": 1,
"action_observation": "Area com alta densidade de recipientes descartaveis.",
}
resposta = requests.post(
BASE + "/postaction", params={"key": CHAVE}, data=visita, timeout=60
)
print(resposta.status_code, resposta.json()) L'elenco completo dei campi immobiliari e di deposito (a1, a2, b, c, d1, d2, e) è dentro riferimento all'endpoint. I campi numerici non inviati presuppongono zero, ma qualsiasi valore che non sia un numero restituisce 400.
Rimuovi i record
Gli spostamenti sono definitivi e sempre limitati al comune di riferimento.
# leitura de uma ovitrampa (identificada pela ovitrampa + data)
curl -X POST -d "ovitrap_group_id=97" -d "date=2025-01-20" \
"/it-ch/api/postdeletecounting?key=SUA_CHAVE"
# a ovitrampa inteira
curl -X POST -d "ovitrap_group_id=97" \
"/it-ch/api/postdeleteovitrap?key=SUA_CHAVE"
# visita de um quarteirao (quarteirao + data)
curl -X POST -d "block_group_id=97" -d "date=2025-01-20" \
"/it-ch/api/postdeleteaction?key=SUA_CHAVE"
# o quarteirao inteiro
curl -X POST -d "block_group_id=97" \
"/it-ch/api/postdeleteblock?key=SUA_CHAVE" /api/postdeletecounting e inviarlo di nuovo con /api/postcounting — il nuovo invio restituisce un errore di duplicazione.Gestione degli errori
Il corpo della risposta è sempre una stringa JSON con il messaggio. Vale la pena affrontare ogni caso, perché non tutti gli errori meritano un altro tentativo:
| Situazione | Codice | Cosa fare |
|---|---|---|
"Wrong key" | 404 | Controlla che la chiave sia nella stringa di query e non nel corpo. |
| Doppio conteggio | 404 | Questa settimana si sta già leggendo per l'ovitrappola; si prega di rimuovere prima di inviare nuovamente. |
| Visita duplicata | 409 | C'è già una visita all'isolato questa settimana. |
| Fuori portata | 403 | L'isolato non appartiene al comune di Chave. Non ripetere. |
| Campo obbligatorio mancante | 400 | Correggere l'invio; la ripetizione restituisce lo stesso errore. |
| Settimana o anno non valido | 500 | La data non rientra nella settimana epidemiologica accettata. Correggere il campo date. |
import time
import requests
NAO_REPETIR = {400, 403, 404, 409}
def enviar(url, chave, dados, tentativas=3):
for tentativa in range(tentativas):
try:
resposta = requests.post(
url, params={"key": chave}, data=dados, timeout=60
)
except requests.RequestException as erro:
print("Falha de rede:", erro)
time.sleep(5 * (tentativa + 1))
continue
if resposta.status_code in NAO_REPETIR:
print("Erro definitivo:", resposta.status_code, resposta.json())
return None
if resposta.ok:
return resposta.json()
# 500 e demais erros de servidor: espera progressiva e tenta de novo
time.sleep(5 * (tentativa + 1))
return None Buone pratiche
- Filtra per comune o stato quando possibile: senza filtrare, la query esegue la scansione dell'intero paese.
- Preferisci la sincronizzazione incrementale tramite
idabbassando l'intera base ogni giorno. - Invia richieste in serie. L'API non è progettata per decine di chiamate simultanee per client.
- Verificare che la risposta sia un elenco prima di ripetere: i messaggi sul limite di paging hanno lo stato 200.
- Salva il
counting_ide ilblock_idricevuti: sono ciò che ti consente di abbinare i record di Conta Ovos con quelli del tuo sistema. - Considerate la settimana epidemiologica come campo determinante: Conta Ovos accetta solo una lettura per ovitrap a settimana e una visita per isolato a settimana.
- Segui la pagina mudanças prima di aggiornare l'integrazione.