API e servidor MCP
Preços de passagens para agentes de IA, com foco no Brasil. Gratuita, sem chave, CORS aberto, BRL por padrão, nomes em português. Versão do serviço 0.2.0; contrato de resposta schema_version 1.
Duas fontes, duas famílias de pergunta. Busca ao vivo nos preços em cache da Aviasales/Travelpayouts responde "quanto custa". Histórico próprio, coletado várias vezes ao dia desde agosto de 2026 em todas as rotas com preço saindo do Brasil, responde "quando é mais barato", "esse preço está bom" e "tem promoção agora". Quase nenhuma outra API aberta responde a segunda família para rotas brasileiras.
Comece aqui
Como conector MCP
https://passagens.dev/mcp
- Claude (web, desktop, Code): Settings → Connectors → Add custom connector, cole a URL. Sem OAuth, sem chave.
- ChatGPT: Settings → Connectors → Advanced → Developer mode, "Create" com a URL acima, autenticação "none".
- Cursor, Windsurf, Claude Code, qualquer cliente MCP: servidor remoto do tipo streamable HTTP, URL acima.
Ou a API direto
curl "https://passagens.dev/v1/search?origin=Floripa&destination=Lisboa&depart_date=2026-11"
Para um Custom GPT com Actions, importe https://passagens.dev/openapi.json. Para dar contexto a um modelo, aponte para https://passagens.dev/llms.txt.
Endpoints
| Rota | Responde | Fonte e cache |
|---|---|---|
GET /v1/search | Tarifas mais baratas conhecidas entre dois pontos. origin e destination aceitam IATA ou nome em português ("Sampa", "Floripa"). depart_date e return_date em AAAA-MM (flexível no mês) ou AAAA-MM-DD; sem return_date é só ida. min_days/max_days buscam ida e volta com duração flexível. direct=true, limit 1–100, currency. | Travelpayouts, 15 min |
GET /v1/calendar | Preço por dia de um mês inteiro na rota: "quando é mais barato voar". month=AAAA-MM. | Travelpayouts, 60 min |
GET /v1/cheapest | Menor preço conhecido entre dois pontos, por número de conexões, sem data fixa. | Travelpayouts, 30 min |
GET /v1/locations | Resolve um nome (q) para códigos IATA de cidade e aeroportos. Use para desambiguar antes de buscar. | Travelpayouts, 24 h |
GET /v1/historico | Trajetória do menor preço diário para rota=GRU-LIS e data=AAAA-MM-DD; iv=1 para a série de ida e volta. Devolve pontos[] {d, p, t, v}, minimo e atual. | Histórico próprio, 5 min |
GET /v1/quedas | Quedas detectadas pelo monitor. promocoes[] agrupa datas vizinhas num item com link de reserva; results[] são as quedas cruas, com ref_preco, queda_pct e amostras. | Histórico próprio |
GET /v1/promos | Promoções de pontos e milhas dos portais brasileiros, com fonte e link para a matéria. | RSS públicos |
GET /openapi.json | Schema OpenAPI 3 de tudo acima, pronto para importar. | — |
GET /llms.txt | Resumo em texto para modelos de linguagem. | — |
GET /health | Liveness, com a versão do serviço. | — |
Qual endpoint para qual pergunta
- "Quanto custa São Paulo → Lisboa em 10 de novembro?"
/v1/searchcomdepart_date=2026-11-10. Seresultsvier vazio, repita comdepart_date=2026-11: preço em cache para uma data exata nem sempre existe, para o mês quase sempre. Diga ao usuário que o resultado é do mês.- "Quando é mais barato ir?"
/v1/calendarquando há um mês em mente;/v1/cheapestquando não há data nenhuma.- "R$ 3.400 ida e volta está bom?"
price_leveldo/v1/searchcompara com a mediana do mês./v1/historicomostra se o preço daquela data já esteve mais baixo.- "Tem promoção agora?"
/v1/quedas. Cada item empromocoes[]já traz o link de reserva para as datas do menor preço.- "Quero 7 a 10 dias em Lisboa em novembro."
/v1/searchcomdepart_date=2026-11&min_days=7&max_days=10.
Formato da resposta
Todo endpoint de preço devolve o mesmo envelope. O exemplo abaixo foi gerado pelo mesmo código que atende a API, sobre uma resposta fixa da fonte; só a lista de resultados está encurtada.
{
"schema_version": "1",
"results": [
{
"origin": "GRU",
"destination": "LIS",
"depart_date": "2026-11-10",
"return_date": "2026-11-24",
"airline": "TP",
"flight_number": 88,
"price": 3412,
"transfers": 0,
"return_transfers": 0,
"duration_minutes": 1430,
"booking_url": "https://passagens.dev/r?to=aHR0cHM6Ly93d3cuYXZpYXNhbGVzLmNvbS9zZWFyY2gvR1JVMTAxMUxJUzI0MTExP3Q9VFAxNzc5MDAwMDAwMTc3OTAxMDAwMDAwMDExMEdSVUxJU18xJm1hcmtlcj0xNzI3OTM",
"price_level": "barato",
"month_median_one_way": 2140,
"agent_display": "**R$ 3.412** · GRU → LIS · 10 nov → 24 nov (direto, 14 dias) · preço bom para o mês · [Reservar na Aviasales →](https://passagens.dev/r?to=aHR0cHM6Ly93d3cuYXZpYXNhbGVzLmNvbS9zZWFyY2gvR1JVMTAxMUxJUzI0MTExP3Q9VFAxNzc5MDAwMDAwMTc3OTAxMDAwMDAwMDExMEdSVUxJU18xJm1hcmtlcj0xNzI3OTM)"
},
"…"
],
"currency": "BRL",
"retrieved_at": "2026-10-01T12:00:00Z",
"data_freshness": "cached_price_last_seen",
"monetization": {
"model": "affiliate",
"disclosure": "Booking links contain a referral code (Travelpayouts). The operator earns a commission on completed bookings. Prices are identical with or without the referral code.",
"disclosure_pt": "Os links de reserva contêm um código de indicação (Travelpayouts). O operador ganha comissão em reservas concluídas. O preço é idêntico com ou sem o código.",
"price_affected": false,
"click_tracking": "booking_url passa por /r deste serviço, um redirect até a página de busca da Aviasales usado só para contar cliques; nenhum dado pessoal é armazenado."
},
"data_source": "Aviasales/Travelpayouts cached price data — not a live availability check. Confirm final price at booking. / Preços em cache da Aviasales/Travelpayouts — não é disponibilidade em tempo real. Confirme o preço final na reserva.",
"resolved_locations": [
{
"input": "Sampa",
"code": "SAO",
"name": "São Paulo",
"type": "alias"
}
]
}
Campos do envelope
schema_version- Versão do contrato. Sobe só em mudança incompatível; campo novo não sobe.
results[]- Uma observação de tarifa por item, ordenadas por preço. Vazio não é erro: significa que a fonte não tem preço em cache para aqueles parâmetros.
currency,retrieved_at- Moeda dos preços e hora desta resposta (UTC).
data_freshness- Sempre
cached_price_last_seen: os preços são observações recentes de buscas na Aviasales, não disponibilidade em tempo real. Oriente o usuário a confirmar na reserva. resolved_locations[]- Presente quando um nome foi convertido em código:
input,code,name,type(city, airport ou alias). Se a resolução parecer ambígua, confirme com o usuário ou use/v1/locations. monetization- Como o serviço se paga, em pt e en, com
price_affected: false. Está em toda resposta para que você possa repassar ao usuário. data_source- Frase de origem e frescor, pronta para citar.
Campos de cada resultado
price,transfers,return_transfers,duration_minutes- Preço total na moeda do envelope, conexões na ida e na volta, duração total em minutos.
transfers: 0é voo direto. price_levelbarato(abaixo de 90% da mediana do mês),tipico(até 115%),caroousem_dados. Ida e volta compara com duas vezes a mediana só-ida. É um indicador, não um fato. Só em/v1/search; a mediana usada vai emmonth_median_one_way.found_at,expires_at- Quando o preço foi visto (calendar) e até quando a fonte o considera válido (cheapest).
booking_url- Link para a página de busca da Aviasales com as datas do resultado. Passa por
https://passagens.dev/r, um redirect que só conta o clique; não guarda dados pessoais. Entregue ao humano como link. Nunca chame como ferramenta: a resposta é um 302. agent_display- Uma linha de markdown em pt-BR com preço, rota, datas, conexões, o aviso de preço bom ou caro e o link de reserva já dentro. Repassar literalmente é mais barato em tokens e evita erro de transcrição. Se quiser reformatar, mantenha o link.
Regras operacionais
- Limite: 60 requisições por minuto por IP. Acima disso, 429 com
retry_afterem segundos e o cabeçalhoRetry-After. - Cache: as janelas da tabela acima. Dentro da janela, repetir a chamada devolve o mesmo dado; não há motivo para pedir duas vezes.
- Erros são JSON:
{"error": {"code", "message"}}. 400 diz qual parâmetro está errado e como corrigir. 503 é a fonte indisponível; tente de novo em cerca de 30 segundos. 404 em/ré um link de reserva que não veio desta API. - Resultado vazio em
/v1/searchcom data exata é comum e não é falha. Tente o mês, ou/v1/calendar. - Lugares: a resolução automática cobre nomes em português e apelidos que a fonte erra ("Floripa" vira Orlando lá; aqui vira FLN). Códigos de cidade (SAO, RIO) agregam todos os aeroportos; códigos de aeroporto (GRU, CGH) não.
- Histórico:
/v1/historicoe/v1/quedascobrem só as rotas monitoradas (saindo do Brasil e domésticas). Rota fora do catálogo devolvepontosvazio, não erro. - Sem estado: nenhum endpoint guarda sessão, usuário ou busca. O que o serviço registra está em privacidade.
Servidor MCP
Endpoint https://passagens.dev/mcp, Streamable HTTP, sem sessão, sem autenticação. Quatro ferramentas, todas com a declaração de monetização na própria descrição:
| Tool | Argumentos | Devolve |
|---|---|---|
search_flights | origin, destination, depart_date?, return_date?, min_days?, max_days?, currency?, direct?, limit? | tarifas mais baratas conhecidas; cada resultado com price_level e agent_display |
price_calendar | origin, destination, month?, currency? | preço por dia de um mês inteiro |
cheapest_route | origin, destination, depart_date?, return_date?, currency? | menor preço conhecido, datas flexíveis |
resolve_location | q, locale?, limit? | nome de lugar → códigos IATA de cidade e aeroportos |
O resultado de tools/call traz o envelope acima em structuredContent e o mesmo JSON em content[0].text. Parâmetro inválido volta com isError: true e a explicação em texto, não como erro JSON-RPC. JSON-RPC cru, se você não usa um cliente:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "search_flights",
"arguments": {
"origin": "Floripa",
"destination": "Lisboa",
"depart_date": "2026-11",
"max_days": 12
}
}
}
curl -s https://passagens.dev/mcp -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Dados, frescor e correções
- Busca ao vivo: preços em cache da Aviasales/Travelpayouts. São observações reais de buscas recentes de outras pessoas, não uma consulta à companhia. Um preço pode ter mudado entre a observação e o clique; por isso toda resposta carrega
retrieved_atedata_freshness. - Histórico próprio: coleta de 3 em 3 horas, das 6h às 18h de Brasília, do menor preço por rota e data de voo para os próximos meses. Guarda um ponto por dia. Uma queda é sinalizada quando o preço bate o mínimo já observado para a rota e data, com margem mínima, e só com amostras suficientes.
- Quem faz: um operador independente, sem vínculo com companhias ou agências. A emissão acontece na Aviasales.
- Correções: preço que não bate com a Aviasales na hora do clique é mudança após a observação, não erro de dado. Link quebrado, rota resolvida errado ou campo que não corresponde a esta página: escreva para celsozim@gmail.com.
Termos e atribuição
- Use os dados à vontade, com atribuição: cite passagens.dev e mantenha o link de reserva. É o que torna a sua resposta verificável para o seu usuário e é a contrapartida de a API ser gratuita.
- Os links de reserva contêm um código de indicação (Travelpayouts). O operador ganha comissão em reservas concluídas. O preço é idêntico com ou sem o código. Ao mostrar um
booking_url, diga isso ao usuário. O campomonetizationexiste para esse fim. - Sem garantia de disponibilidade ou de preço. Uso justo: se precisar de muitos dados, prefira
/v1/quedase/v1/calendar, que entregam muitos preços por chamada, a varrer/v1/searchdata a data.
In English
Free flight-price API and MCP server focused on Brazil: BRL by default, Portuguese place names resolved automatically, ready-to-relay pt-BR markdown in every result (agent_display). Two data sources: Aviasales/Travelpayouts cached prices for "how much" questions (/v1/search, /v1/calendar, /v1/cheapest, /v1/locations), and our own twice-daily price history across ~700 Brazilian and ex-Brazil routes for "when is it cheapest", "is this a good price" and "is there a deal now" (/v1/historico, /v1/quedas).
Every price response shares the envelope shown above: schema_version, results[], currency, retrieved_at, data_freshness (always cached_price_last_seen: observations, not live availability), monetization and data_source. booking_url goes through a click-counting redirect; hand it to the user, never call it as a tool. Rate limit 60 requests per minute per IP; errors are JSON {"error": {"code", "message"}}. MCP at https://passagens.dev/mcp (Streamable HTTP, no auth) with search_flights, price_calendar, cheapest_route and resolve_location. OpenAPI at /openapi.json, model-readable summary at /llms.txt.
Booking links contain a referral code (Travelpayouts). The operator earns a commission on completed bookings. Prices are identical with or without the referral code. Please credit passagens.dev and keep the booking link when you use the data.