Pinitos
Todas las llamadas provienen de la misma base de datos y devuelven JSON. Los puntos finales públicos no requieren autenticación; los privados requieren su clave de acceso.
dirección base
/es-cl/api El prefijo de idioma es parte de la URL (es-cl), pero no cambia los datos devueltos: los registros provienen del banco exactamente como fueron registrados en el campo.
curl -G -d "municipality=Ponta Pora" --data-urlencode "country=Brasil" \
/es-cl/api/lastcountingpublic Si la respuesta es una lista JSON, la integración ya está funcionando.
key se lee de la cadena de consulta (?key=SUA_CHAVE). Enviándolo solo en el cuerpo del formulario devuelve 404 "Wrong key". Los demás campos siguen apareciendo en el cuerpo de la solicitud. Consultar datos públicos
El punto final /api/lastcountingpublic devuelve los últimos recuentos de huevos con latitud, longitud, semana y año epidemiológicos. Es el punto de partida de mapas, paneles y estudios.
/api/lastcountingpublicPúblicocurl -G \
--data-urlencode "municipality=Ponta Pora" \
--data-urlencode "date_start=2025-01-01" \
--data-urlencode "date_end=2025-12-31" \
/es-cl/api/lastcountingpublic import requests
BASE = "/es-cl/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 = "/es-cl/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"); Los mismos parámetros de ubicación. (country, state, municipality) Se aplican a otros puntos finales públicos: ovitrampas, manzanas, EDL, mantenimiento de EDL y puntos estratégicos. Simplemente cambiar la ruta del punto final ya cambia el conjunto de datos.
Explorar todas las páginas
Compatibilidad con puntos finales paginados page del 1 al 100. Por encima de eso, la API responde con el texto "Maximum pagination is 100" y estado 200, es decir, el cuerpo ya no es una lista. Siempre verifique el tipo antes de iterar.
import requests
BASE = "/es-cl/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 dividir el período en intervalos más pequeños. Sincronización incremental
Para mantener una base reflejada, no descargue todo nuevamente con cada ejecución. El punto final /api/lastcountingpublic aceptado id, que devuelve sólo los recuentos de ese identificador, y también date (fecha de inclusión) e date_collect (data de coleta).
import json
import os
import requests
BASE = "/es-cl/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") Mantenga siempre el más grande counting_id recibido, no la fecha de ejecución: un conteo ingresado en el campo hoy puede referirse a una semana anterior, y el filtro por id no deja escapar estos registros.
Exportar a CSV
Los recuentos públicos ya vienen con coordenadas, por lo que puedes generar una hoja de cálculo o alimentar un mapa sin ningún tipo de unión adicional.
import csv
import requests
BASE = "/es-cl/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") Enviando datos
Los siguientes ejemplos utilizan la API privada y requieren una clave. El alcance geográfico de la clave define lo que puede registrar: una clave municipal solo registra en el propio municipio.
/api/postcountingPrivadoEnviar la lectura de una ovitrampa existente
Envía el recuento de huevos de una ovitrampa ya registrada. La ovitrampa está situada junto al ovitrap_group_id dentro del municipio del cayo, y la semana epidemiológica se calcula a partir del 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" \
"/es-cl/api/postcounting?key=SUA_CHAVE" import requests
BASE = "/es-cl/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/postcountingPrivadoInstale una nueva ovitrampa al lado de la lectura.
si el ovitrap_group_id aún no existe en el municipio, en la misma solicitud se crea la ovitrampa. Enviar también la dirección y, en su caso, el tipo (ovitrap_type_id: 1 urbano, patrón; 2 rural).
import requests
BASE = "/es-cl/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— faltaovitrap_lat,ovitrap_lngouovitrap_group_id.400—ovitrap_type_iddiferente de 1 o 2.404— Ya hay un recuento para esta ovitrampa, año y semana.500— la fecha de envío cae en una semana epidemiológica futura o inválida.
/api/postactionPrivadoRegistrar una visita de manzana
Usar block_id para registrar la visita en una manzana ya registrado. Si la manzana aún no existe, envíe block_group_id con los datos de la manzana y se crea automáticamente dentro del municipio clave.
import requests
BASE = "/es-cl/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 lista completa de campos inmobiliarios y de depósitos. (a1, a2, b, c, d1, d2, e) esta en referencia de punto final. Los campos numéricos no enviados suponen cero, pero cualquier valor que no sea un número devuelve 400.
Eliminar registros
Las mudanzas son definitivas y siempre restringidas al municipio clave.
# leitura de uma ovitrampa (identificada pela ovitrampa + data)
curl -X POST -d "ovitrap_group_id=97" -d "date=2025-01-20" \
"/es-cl/api/postdeletecounting?key=SUA_CHAVE"
# a ovitrampa inteira
curl -X POST -d "ovitrap_group_id=97" \
"/es-cl/api/postdeleteovitrap?key=SUA_CHAVE"
# visita de um quarteirao (quarteirao + data)
curl -X POST -d "block_group_id=97" -d "date=2025-01-20" \
"/es-cl/api/postdeleteaction?key=SUA_CHAVE"
# o quarteirao inteiro
curl -X POST -d "block_group_id=97" \
"/es-cl/api/postdeleteblock?key=SUA_CHAVE" /api/postdeletecounting y enviarlo de nuevo con /api/postcounting — reenviarlo devuelve un error de duplicación.Manejo de errores
El cuerpo de la respuesta es siempre una cadena JSON con el mensaje. Vale la pena analizar cada caso, porque no todos los errores merecen otro intento:
| Situación | Código | que hacer |
|---|---|---|
"Wrong key" | 404 | Compruebe que la clave esté en la cadena de consulta y no en el cuerpo. |
| Conteo duplicado | 404 | Ya hay lectura para la ovitrampa esta semana; quítelo antes de reenviarlo. |
| Visita duplicada | 409 | Ya hay visita a la manzana esta semana. |
| Fuera de alcance | 403 | La manzana no pertenece al municipio de Chave. No repitas. |
| Falta campo obligatorio | 400 | Corregir la presentación; repetir devuelve el mismo error. |
| Semana o año no válido | 500 | La fecha cae fuera de la semana epidemiológica aceptada. Corregir el 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 Buenas prácticas
- Filtre por municipio o estado siempre que sea posible; sin filtrar, la consulta analiza todo el país.
- Prefiere la sincronización incremental mediante
idbajando toda la base todos los días. - Enviar solicitudes en serie. La API no está diseñada para decenas de llamadas simultáneas por cliente.
- Verifique que la respuesta sea una lista antes de iterar: los mensajes de límite de paginación vienen con el estado 200.
- guardar el
counting_idy elblock_idrecibidos: son los que le permiten comparar los registros de Conta Ovos con los de su sistema. - Trate la semana epidemiológica como campo determinante: Conta Ovos solo acepta una lectura por ovitrampa por semana y una visita por manzana por semana.
- sigue la pagina mudanças antes de actualizar su integración.