API de Voos
API

Ofertas de Voos

Acessar ofertas destacadas e promocionais de voos

Ofertas de Voos

Acesse ofertas pré-selecionadas de voos com preços especiais. Ideal para exibir em home pages, landing pages e seções de destaques.

Ofertas Curadas

As ofertas são pré-selecionadas e otimizadas para conversão, com preços competitivos e rotas populares.


POST /api/ofertas/buscar

Busca ofertas de voos com filtros opcionais.

Request

{
  "internacional": true,
  "quantidade": 10,
  "shuffle": true,
  "page": 0,
  "pageSize": 20
}

Parâmetros

ParâmetroTipoObrigatórioDescrição
internacionalbooleanNãoFiltrar por voos internacionais (padrão: false)
quantidadenumberNãoQuantidade de ofertas a retornar (padrão: 50)
shufflebooleanNãoEmbaralhar resultados (padrão: true)
pagenumberNãoNúmero da página para paginação (padrão: 0)
pageSizenumberNãoTamanho da página (padrão: 0 = sem paginação)

Response

{
  "success": true,
  "data": [
    {
      "id": "oferta_123",
      "origem": {
        "iata": "GRU",
        "cidade": "São Paulo",
        "estado": "SP",
        "pais": "Brasil",
        "aeroporto": "Aeroporto Internacional de São Paulo/Guarulhos"
      },
      "destino": {
        "iata": "MIA",
        "cidade": "Miami",
        "estado": "FL",
        "pais": "Estados Unidos",
        "aeroporto": "Miami International Airport"
      },
      "precoMinimo": 1299.00,
      "moeda": "BRL",
      "companhiaAerea": {
        "codigo": "LA",
        "nome": "LATAM Airlines"
      },
      "tipo": "round_trip",
      "internacional": true,
      "dataInicio": "2026-03-01",
      "dataFim": "2026-06-30",
      "restricoes": [
        "Antecedência mínima de 7 dias",
        "Permanência mínima de 3 dias"
      ],
      "disponivel": true,
      "imagemDestino": "https://images.unsplash.com/..."
    }
  ],
  "totalItens": 150,
  "page": 0,
  "pageSize": 10,
  "message": "Ofertas encontradas com sucesso"
}

Campos da Resposta

CampoTipoDescrição
idstringID único da oferta
origemobjectInformações do aeroporto de origem
destinoobjectInformações do aeroporto de destino
precoMinimonumberMenor preço encontrado para esta rota
moedastringMoeda do preço (ex: BRL, USD)
companhiaAereaobjectCompanhia aérea principal (código e nome)
tipostringTipo de viagem: one_way ou round_trip
internacionalbooleanSe é um voo internacional
dataIniciostringData de início da validade da oferta
dataFimstringData de fim da validade da oferta
restricoesarrayLista de restrições da oferta
disponivelbooleanSe a oferta está disponível
imagemDestinostringURL da imagem do destino (opcional)

Exemplos de Uso

Ofertas Internacionais

curl -X POST https://api.seudominio.com/api/ofertas/buscar \
  -H "Authorization: Bearer sua_chave_aqui" \
  -H "Content-Type: application/json" \
  -d '{
    "internacional": true,
    "quantidade": 20,
    "shuffle": true
  }'

Ofertas Nacionais

curl -X POST https://api.seudominio.com/api/ofertas/buscar \
  -H "Authorization: Bearer sua_chave_aqui" \
  -H "Content-Type: application/json" \
  -d '{
    "internacional": false,
    "quantidade": 15,
    "shuffle": false
  }'

Com Paginação

curl -X POST https://api.seudominio.com/api/ofertas/buscar \
  -H "Authorization: Bearer sua_chave_aqui" \
  -H "Content-Type: application/json" \
  -d '{
    "internacional": true,
    "page": 1,
    "pageSize": 10
  }'

Implementação em React

import { useState, useEffect } from 'react';

interface Oferta {
  id: string;
  origem: {
    iata: string;
    cidade: string;
    pais: string;
  };
  destino: {
    iata: string;
    cidade: string;
    pais: string;
  };
  precoMinimo: number;
  moeda: string;
  companhiaAerea: {
    codigo: string;
    nome: string;
  };
  imagemDestino?: string;
}

function OfertasVoos() {
  const [ofertas, setOfertas] = useState<Oferta[]>([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function carregarOfertas() {
      try {
        const response = await fetch('/api/ofertas/buscar', {
          method: 'POST',
          headers: {
            'Authorization': `Bearer ${process.env.NEXT_PUBLIC_API_KEY}`,
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            internacional: true,
            quantidade: 12,
            shuffle: true
          })
        });

        const data = await response.json();
        
        if (data.success) {
          setOfertas(data.data);
        }
      } catch (error) {
        console.error('Erro ao carregar ofertas:', error);
      } finally {
        setLoading(false);
      }
    }

    carregarOfertas();
  }, []);

  if (loading) {
    return <div>Carregando ofertas...</div>;
  }

  return (
    <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
      {ofertas.map((oferta) => (
        <div key={oferta.id} className="border rounded-lg overflow-hidden shadow-lg">
          {oferta.imagemDestino && (
            <img 
              src={oferta.imagemDestino} 
              alt={oferta.destino.cidade}
              className="w-full h-48 object-cover"
            />
          )}
          
          <div className="p-4">
            <div className="text-sm text-gray-600">
              {oferta.origem.cidade} → {oferta.destino.cidade}
            </div>
            
            <div className="text-2xl font-bold mt-2">
              {oferta.moeda} {oferta.precoMinimo.toFixed(2)}
            </div>
            
            <div className="text-sm text-gray-500 mt-1">
              {oferta.companhiaAerea.nome}
            </div>
            
            <button className="mt-4 w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700">
              Ver Detalhes
            </button>
          </div>
        </div>
      ))}
    </div>
  );
}
import { useState, useEffect } from 'react';

function OfertasVoos() {
  const [ofertas, setOfertas] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function carregarOfertas() {
      try {
        const response = await fetch('/api/ofertas/buscar', {
          method: 'POST',
          headers: {
            'Authorization': `Bearer ${process.env.NEXT_PUBLIC_API_KEY}`,
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            internacional: true,
            quantidade: 12,
            shuffle: true
          })
        });

        const data = await response.json();
        
        if (data.success) {
          setOfertas(data.data);
        }
      } catch (error) {
        console.error('Erro ao carregar ofertas:', error);
      } finally {
        setLoading(false);
      }
    }

    carregarOfertas();
  }, []);

  if (loading) {
    return <div>Carregando ofertas...</div>;
  }

  return (
    <div className="ofertas-grid">
      {ofertas.map((oferta) => (
        <div key={oferta.id} className="oferta-card">
          {oferta.imagemDestino && (
            <img src={oferta.imagemDestino} alt={oferta.destino.cidade} />
          )}
          
          <div className="oferta-content">
            <div className="rota">
              {oferta.origem.cidade} → {oferta.destino.cidade}
            </div>
            
            <div className="preco">
              {oferta.moeda} {oferta.precoMinimo.toFixed(2)}
            </div>
            
            <div className="companhia">
              {oferta.companhiaAerea.nome}
            </div>
            
            <button>Ver Detalhes</button>
          </div>
        </div>
      ))}
    </div>
  );
}

Casos de Uso

1. Home Page - Destaques

Exiba ofertas em destaque na página inicial:

// Buscar 6 ofertas internacionais aleatórias
const response = await fetch('/api/ofertas/buscar', {
  method: 'POST',
  body: JSON.stringify({
    internacional: true,
    quantidade: 6,
    shuffle: true
  })
});

2. Landing Page - Destino Específico

Filtre ofertas por destino usando os dados retornados:

const ofertas = await buscarOfertas({ quantidade: 50 });
const ofertasParaMiami = ofertas.data.filter(
  oferta => oferta.destino.iata === 'MIA'
);

3. Newsletter - Ofertas Semanais

Envie ofertas diferentes a cada semana:

// Sem shuffle para manter consistência
const response = await fetch('/api/ofertas/buscar', {
  method: 'POST',
  body: JSON.stringify({
    internacional: true,
    quantidade: 10,
    shuffle: false
  })
});

4. Comparador de Preços

Mostre as melhores ofertas por região:

const [nacionais, internacionais] = await Promise.all([
  fetch('/api/ofertas/buscar', {
    method: 'POST',
    body: JSON.stringify({ internacional: false, quantidade: 20 })
  }).then(r => r.json()),
  
  fetch('/api/ofertas/buscar', {
    method: 'POST',
    body: JSON.stringify({ internacional: true, quantidade: 20 })
  }).then(r => r.json())
]);

Integração com Busca de Voos

Quando um usuário clicar em uma oferta, redirecione para a busca de voos:

function handleOfertaClick(oferta) {
  // Calcular data de partida (ex: 30 dias à frente)
  const departureDate = new Date();
  departureDate.setDate(departureDate.getDate() + 30);
  
  // Calcular data de retorno (ex: 7 dias depois)
  const returnDate = new Date(departureDate);
  returnDate.setDate(returnDate.getDate() + 7);
  
  // Redirecionar para busca
  const searchParams = new URLSearchParams({
    origin: oferta.origem.iata,
    destination: oferta.destino.iata,
    departureDate: departureDate.toISOString().split('T')[0],
    returnDate: returnDate.toISOString().split('T')[0],
    passengers: '1',
    cabinClass: 'economy'
  });
  
  window.location.href = `/voos/buscar?${searchParams.toString()}`;
}

Dicas de UX

Melhores Práticas

  • Embaralhe ofertas para evitar repetição visual
  • Exiba imagens atraentes dos destinos
  • Destaque o preço como elemento principal
  • Adicione CTAs claros como "Ver Voos" ou "Buscar"
  • Mostre restrições de forma clara mas não intrusiva
  • Use cache de 1-4 horas (ofertas mudam pouco)

Layout Sugerido

┌───────────────────────────────────┐
│     [Imagem do Destino]           │
│                                   │
├───────────────────────────────────┤
│ São Paulo → Miami                 │
│                                   │
│ R$ 1.299,00                       │
│ LATAM Airlines                    │
│                                   │
│ [ Ver Voos ]                      │
└───────────────────────────────────┘

Cache e Performance

Recomendações de Cache

// Próximo.js - Cache de 2 horas
export const revalidate = 7200;

// Ou usar SWR
import useSWR from 'swr';

function OfertasVoos() {
  const { data, error } = useSWR(
    'ofertas',
    () => fetch('/api/ofertas/buscar', { 
      method: 'POST',
      body: JSON.stringify({ internacional: true, quantidade: 12 })
    }).then(r => r.json()),
    {
      refreshInterval: 7200000, // 2 horas
      revalidateOnFocus: false
    }
  );
}

Performance

  • Latência típica: 200-500ms
  • Cache recomendado: 1-4 horas
  • Refresh: A cada 2-4 horas para manter ofertas atualizadas

Erros Comuns

CódigoErroSolução
401UnauthorizedVerifique sua API key
400Invalid parametersVerifique tipos dos parâmetros
429Rate limit exceededReduza frequência ou implemente cache
500Internal server errorTente novamente ou contate suporte

Próximos Passos

Após exibir ofertas, integre com:

On this page