Premiers pas
Tous les appels proviennent de la même base de données et renvoient du JSON. Les points de terminaison publics ne nécessitent pas d'authentification ; les privés nécessitent votre clé d’accès.
Adresse de base
/fr-lu/api Le préfixe de langue fait partie de l'URL (fr-lu), mais cela ne change pas les données renvoyées : les enregistrements proviennent de la banque exactement tels qu'ils ont été enregistrés sur le terrain.
curl -G -d "municipality=Ponta Pora" --data-urlencode "country=Brasil" \
/fr-lu/api/lastcountingpublic Si la réponse est une liste JSON, l'intégration fonctionne déjà.
key est lu à partir de la chaîne de requête (?key=SUA_CHAVE). L'envoyer uniquement dans le corps du formulaire renvoie 404 "Wrong key". Les autres champs continuent d'apparaître dans le corps de la requête. Consulter les données publiques
Le point final /api/lastcountingpublic renvoie le dernier nombre d’œufs avec la latitude épidémiologique, la longitude, la semaine et l’année. C'est le point de départ de cartes, panneaux et études.
/api/lastcountingpublicPubliquecurl -G \
--data-urlencode "municipality=Ponta Pora" \
--data-urlencode "date_start=2025-01-01" \
--data-urlencode "date_end=2025-12-31" \
/fr-lu/api/lastcountingpublic import requests
BASE = "/fr-lu/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 = "/fr-lu/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"); Les mêmes paramètres de localisation (country, state, municipality) Ils s'appliquent à d'autres points de terminaison publics : ovitraps, îlots, EDL, maintenance EDL et points stratégiques. Le simple fait de changer le chemin du point de terminaison modifie déjà l'ensemble de données.
Parcourir toutes les pages
Prise en charge des points de terminaison paginés page de 1 à 100. Au-dessus, l'API répond avec le texte "Maximum pagination is 100" et le statut 200 — c'est-à-dire que le corps n'est plus une liste. Vérifiez toujours le type avant de répéter.
import requests
BASE = "/fr-lu/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 pour diviser la période en intervalles plus petits. Synchronisation incrémentielle
Pour conserver une base en miroir, ne téléchargez pas tout à nouveau à chaque exécution. Le point final /api/lastcountingpublic accepté id, qui renvoie uniquement les décomptes de cet identifiant, et également date (date d'inclusion) e date_collect (data de coleta).
import json
import os
import requests
BASE = "/fr-lu/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") Gardez toujours le plus grand counting_id reçu, pas la date d'exécution : un décompte saisi dans le champ aujourd'hui peut faire référence à une semaine précédente, et le filtre par identifiant ne laisse pas échapper ces enregistrements.
Exporter au format CSV
Les décomptes publics sont déjà accompagnés de coordonnées, vous pouvez donc générer une feuille de calcul ou alimenter une carte sans aucune jointure supplémentaire.
import csv
import requests
BASE = "/fr-lu/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") Envoi de données
Les exemples suivants utilisent l'API privée et nécessitent une clé. La portée géographique de la clé définit ce qu'elle peut enregistrer : une clé municipale n'enregistre que dans la municipalité elle-même.
/api/postcountingPrivéEnvoyer la lecture d'un ovitrap existant
Envoie le nombre d’œufs d’un ovitrap déjà enregistré. L'ovitrap est localisé près du ovitrap_group_id au sein de la commune de la clé, et la semaine épidémiologique est calculée à partir du terrain 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" \
"/fr-lu/api/postcounting?key=SUA_CHAVE" import requests
BASE = "/fr-lu/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/postcountingPrivéInstallez un nouvel ovitrap à côté de la lecture
Si le ovitrap_group_id n'existe pas encore sur la commune, l'ovitrap est créé dans la même demande. Envoyez également l'adresse et, le cas échéant, le type (ovitrap_type_id: 1 urbain, modèle; 2 rural).
import requests
BASE = "/fr-lu/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— manqueovitrap_lat,ovitrap_lngouovitrap_group_id.400—ovitrap_type_iddifférent de 1 ou 2.404— Il existe déjà un décompte pour cet ovitrap, année et semaine.500— la date d'envoi tombe dans une semaine épidémiologique future ou invalide.
/api/postactionPrivéEnregistrez une visite en îlot
Utiliser block_id pour lancer la visite dans un îlot déjà enregistré. Si l'îlot n'existe pas encore, envoyez block_group_id avec les données de l'îlot et il est automatiquement créé au sein de la commune clé.
import requests
BASE = "/fr-lu/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()) La liste complète des domaines immobiliers et dépôts (a1, a2, b, c, d1, d2, e) est dans référence du point de terminaison. Les champs numériques non envoyés supposent zéro, mais toute valeur qui n'est pas un nombre renvoie 400.
Supprimer des enregistrements
Les déménagements sont définitifs et toujours limités à la commune clé.
# leitura de uma ovitrampa (identificada pela ovitrampa + data)
curl -X POST -d "ovitrap_group_id=97" -d "date=2025-01-20" \
"/fr-lu/api/postdeletecounting?key=SUA_CHAVE"
# a ovitrampa inteira
curl -X POST -d "ovitrap_group_id=97" \
"/fr-lu/api/postdeleteovitrap?key=SUA_CHAVE"
# visita de um quarteirao (quarteirao + data)
curl -X POST -d "block_group_id=97" -d "date=2025-01-20" \
"/fr-lu/api/postdeleteaction?key=SUA_CHAVE"
# o quarteirao inteiro
curl -X POST -d "block_group_id=97" \
"/fr-lu/api/postdeleteblock?key=SUA_CHAVE" /api/postdeletecounting et renvoyez-le à nouveau avec /api/postcounting — le renvoyer renvoie une erreur de duplication.Gestion des erreurs
Le corps de la réponse est toujours une chaîne JSON avec le message. Cela vaut la peine de traiter chaque cas, car toutes les erreurs ne méritent pas une nouvelle tentative :
| Situation | Code | Ce qu'il faut faire |
|---|---|---|
"Wrong key" | 404 | Vérifiez que la clé est dans la chaîne de requête et non dans le corps. |
| Double comptage | 404 | Il y a déjà de la lecture pour l'ovitrap cette semaine ; veuillez le retirer avant de renvoyer. |
| Visite en double | 409 | Il y a déjà une visite à l'îlot cette semaine. |
| Hors de portée | 403 | L'îlot n'appartient pas à la commune de Chave. Ne répétez pas. |
| Champ obligatoire manquant | 400 | Corriger la soumission ; répéter renvoie la même erreur. |
| Semaine ou année invalide | 500 | La date tombe en dehors de la semaine épidémiologique acceptée. Corriger le champ 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 Bonnes pratiques
- Filtrez par municipalité ou par État chaque fois que cela est possible : sans filtrage, la requête analyse l'ensemble du pays.
- Préférez la synchronisation incrémentielle par
idabaisser toute la base chaque jour. - Envoyez des demandes en série. L'API n'est pas conçue pour des dizaines d'appels simultanés par client.
- Vérifiez que la réponse est une liste avant de procéder à une itération : les messages de limite de pagination ont le statut 200.
- Enregistrez le
counting_idet leblock_idreçus — ce sont eux qui vous permettent de faire correspondre les enregistrements Conta Ovos avec ceux de votre système. - Considérez la semaine épidémiologique comme le champ déterminant : Conta Ovos n'accepte qu'une seule lecture par ovitrap par semaine, et une visite par îlot et par semaine.
- Suivez la page mudanças avant de mettre à jour votre intégration.