Reservei Docs
Referência da API

Reservas

Criar e gerenciar reservas de voos

Reservas

Crie, gerencie e acompanhe reservas de voos. A API suporta dois modos de reserva: hold (reserva temporária) e instant (emissão imediata).

Fluxo de Reserva

Buscar Voos

Use POST /api/v1/flights/search para obter ofertas disponíveis.

Selecionar Oferta

Escolha uma oferta (offer_id) e anote os passenger_ids.

Criar Reserva

Use POST /api/v1/bookings com dados dos passageiros.

Confirmar Pagamento

Para reservas hold, confirme o pagamento antes do prazo.

Emissão de Bilhetes

Bilhetes são emitidos automaticamente após confirmação.


POST /api/v1/bookings

Cria uma nova reserva a partir de uma oferta de voo.

Validade da Oferta

As ofertas expiram rapidamente (15-30 minutos). Verifique o campo expires_at da oferta e crie a reserva antes da expiração.

Request

{
  "offerId": "off_0000GhIjKl789012",
  "type": "hold",
  "passengers": [
    {
      "id": "pas_0000YzAbCd567890",
      "given_name": "João",
      "family_name": "Silva",
      "gender": "m",
      "title": "mr",
      "born_on": "1985-06-15",
      "email": "joao.silva@email.com",
      "phone_number": "+5511999998888"
    },
    {
      "id": "pas_0000AbCdEf123456",
      "given_name": "Maria",
      "family_name": "Silva",
      "gender": "f",
      "title": "mrs",
      "born_on": "1988-03-22",
      "email": "maria.silva@email.com",
      "phone_number": "+5511999997777"
    }
  ],
  "metadata": {
    "client_reference": "PEDIDO-12345",
    "notes": "Cliente VIP - solicitar assento na janela"
  }
}

Parâmetros

CampoTipoObrigatórioDescrição
offerIdstringSimID da oferta obtida na busca de voos
typestringSimTipo de reserva: hold ou instant
passengersarraySimDados completos dos passageiros
paymentsarrayCondicionalObrigatório se type = instant
metadataobjectNãoDados adicionais da sua aplicação

Objeto Passenger (Detalhado)

CampoTipoObrigatórioDescrição
idstringSimID do passageiro da oferta (pas_xxx)
given_namestringSimPrimeiro nome (como no documento)
family_namestringSimSobrenome (como no documento)
genderstringSimGênero: m (masculino) ou f (feminino)
titlestringNãoTítulo: mr, mrs, ms, miss, dr
born_onstringSimData de nascimento (YYYY-MM-DD)
emailstringSimEmail do passageiro
phone_numberstringSimTelefone com DDI (+5511999998888)
identity_documentsarrayCondicionalDocumentos (obrigatório para voos internacionais)
loyalty_programme_accountsarrayNãoProgramas de milhagem
infant_passenger_idstringCondicionalID do bebê associado (para adultos com bebê)

Documento de Identidade

Para voos internacionais, é obrigatório informar documento:

{
  "identity_documents": [
    {
      "type": "passport",
      "unique_identifier": "BR123456789",
      "issuing_country_code": "BR",
      "expires_on": "2030-12-31"
    }
  ]
}
CampoTipoDescrição
typestringpassport, tax_id (CPF), known_traveler_number
unique_identifierstringNúmero do documento
issuing_country_codestringCódigo do país emissor (ISO 3166-1 alpha-2)
expires_onstringData de validade (YYYY-MM-DD)

Programa de Milhagem

{
  "loyalty_programme_accounts": [
    {
      "airline_iata_code": "LA",
      "account_number": "123456789"
    }
  ]
}

Tipos de Reserva

TipoDescriçãoDébito na WalletPrazo
holdReserva temporária aguardando pagamentoNão24-72h para confirmar
instantEmissão imediata do bilheteSim, imediatoInstantâneo

Use hold quando o cliente ainda não pagou. Use instant quando o pagamento já foi recebido e você quer emitir o bilhete imediatamente.

Pagamento (para type: instant)

Se type = instant, você deve incluir o objeto payments:

{
  "offerId": "off_0000GhIjKl789012",
  "type": "instant",
  "passengers": [...],
  "payments": [
    {
      "type": "balance",
      "amount": "1250.50",
      "currency": "USD"
    }
  ]
}

O valor e moeda do pagamento devem corresponder exatamente ao total_amount e total_currency da oferta original (valores originais, não os valores convertidos para BRL).

Response

{
  "id": "ord_0000AbCdEf123456",
  "booking_reference": "XJ59L2",
  "live_mode": true,
  "synced_at": "2025-01-15T10:30:00Z",
  "created_at": "2025-01-15T10:30:00Z",
  "total_amount": "1250.50",
  "total_currency": "USD",
  "tax_amount": "250.50",
  "tax_currency": "USD",
  "base_amount": "1000.00",
  "base_currency": "USD",
  "owner": {
    "iata_code": "LA",
    "name": "LATAM Airlines"
  },
  "slices": [
    {
      "id": "sli_0000MnOpQr345678",
      "origin": {
        "iata_code": "GRU",
        "name": "São Paulo-Guarulhos International Airport"
      },
      "destination": {
        "iata_code": "MIA",
        "name": "Miami International Airport"
      },
      "duration": "PT9H30M",
      "segments": [
        {
          "id": "seg_0000StUvWx901234",
          "departing_at": "2025-03-15T08:00:00",
          "arriving_at": "2025-03-15T16:30:00",
          "operating_carrier_flight_number": "8084",
          "operating_carrier": {
            "iata_code": "LA",
            "name": "LATAM Airlines"
          },
          "passengers": [
            {
              "passenger_id": "pas_0000YzAbCd567890",
              "cabin_class": "economy",
              "seat": null,
              "baggages": [
                { "type": "checked", "quantity": 1 }
              ]
            }
          ]
        }
      ]
    }
  ],
  "passengers": [
    {
      "id": "pas_0000YzAbCd567890",
      "type": "adult",
      "given_name": "João",
      "family_name": "Silva",
      "gender": "m",
      "born_on": "1985-06-15",
      "email": "joao.silva@email.com",
      "phone_number": "+5511999998888"
    }
  ],
  "documents": [],
  "conditions": {
    "refund_before_departure": {
      "allowed": false
    },
    "change_before_departure": {
      "allowed": true,
      "penalty_amount": "150.00",
      "penalty_currency": "USD"
    }
  },
  "payment_status": {
    "awaiting_payment": true,
    "payment_required_by": "2025-01-17T23:59:00Z",
    "price_guarantee_expires_at": "2025-01-16T23:59:00Z"
  },
  "metadata": {
    "client_reference": "PEDIDO-12345",
    "notes": "Cliente VIP"
  }
}

Campos da Resposta

CampoTipoDescrição
idstringID único da reserva (ord_xxx)
booking_referencestringCódigo localizador da companhia aérea
total_amountstringValor total original
total_currencystringMoeda original
ownerobjectCompanhia aérea principal
slicesarrayTrechos da viagem com detalhes
passengersarrayPassageiros com dados completos
documentsarrayBilhetes emitidos (após confirmação)
conditionsobjectCondições de alteração/cancelamento
payment_statusobjectStatus e prazos de pagamento

GET /api/v1/bookings

Lista todas as reservas do seu time.

Query Parameters

ParâmetroTipoPadrãoDescrição
pagenumber1Página atual
limitnumber20Itens por página (máx: 100)
statusstring-Filtrar por status
created_afterstring-Filtrar por data de criação (YYYY-MM-DD)
created_beforestring-Filtrar por data de criação (YYYY-MM-DD)

Response

{
  "success": true,
  "data": [
    {
      "id": "ord_0000AbCdEf123456",
      "booking_reference": "XJ59L2",
      "status": "confirmed",
      "total_amount": "7825.60",
      "currency": "BRL",
      "created_at": "2025-01-15T10:30:00Z",
      "client": {
        "id": "cli_0000...",
        "full_name": "João Silva",
        "email": "joao@email.com"
      },
      "flight_summary": {
        "origin": "GRU",
        "destination": "MIA",
        "departure_date": "2025-03-15",
        "airline": "LATAM Airlines"
      }
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 45,
    "pages": 3
  }
}

GET /api/v1/bookings/:id

Obtém detalhes completos de uma reserva específica.

Response

Retorna o objeto completo da reserva (mesmo formato do POST /bookings response), incluindo documentos emitidos se disponíveis:

{
  "id": "ord_0000AbCdEf123456",
  "booking_reference": "XJ59L2",
  "status": "ticketed",
  "documents": [
    {
      "type": "electronic_ticket",
      "unique_identifier": "001-1234567890",
      "passenger_id": "pas_0000YzAbCd567890"
    }
  ]
}

PUT /api/v1/bookings/:id/confirm

Confirma o pagamento e solicita emissão do bilhete para uma reserva hold.

Request

{
  "payment": {
    "type": "balance",
    "amount": "1250.50",
    "currency": "USD"
  }
}

Response

{
  "success": true,
  "data": {
    "id": "ord_0000AbCdEf123456",
    "booking_reference": "XJ59L2",
    "status": "confirmed",
    "documents": [
      {
        "type": "electronic_ticket",
        "unique_identifier": "001-1234567890"
      }
    ]
  }
}

Após a confirmação, os bilhetes são emitidos automaticamente. O status mudará para ticketed e os documentos serão adicionados à resposta.


DELETE /api/v1/bookings/:id

Cancela uma reserva.

Políticas de Cancelamento

O cancelamento pode estar sujeito a penalidades dependendo das condições da tarifa. Verifique o campo conditions.refund_before_departure antes de cancelar.

Comportamento por Status

Status AtualComportamento
pendingCancelamento sem custo
confirmedPode haver penalidade
ticketedSujeito a regras da tarifa
cancelledErro - já cancelado

Request

DELETE /api/v1/bookings/ord_0000AbCdEf123456

Response

{
  "success": true,
  "data": {
    "id": "ord_0000AbCdEf123456",
    "status": "cancelled",
    "refund": {
      "amount": "1100.50",
      "currency": "USD",
      "penalty_amount": "150.00",
      "penalty_currency": "USD"
    }
  }
}

Status das Reservas

StatusDescriçãoAção Esperada
pendingReserva criada, aguardando pagamentoConfirmar pagamento
confirmedPagamento recebido, aguardando emissãoAguardar bilhete
ticketedBilhetes emitidosNenhuma
cancelledReserva canceladaNenhuma
expiredPrazo de pagamento expiradoNova busca necessária
failedFalha na emissãoContatar suporte
pending → confirmed → ticketed
    ↓         ↓          ↓
cancelled  cancelled  cancelled

expired

Exemplos Completos

// 1. Buscar voos
const searchResult = await fetch('https://app.reservei.co/api/v1/flights/search', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    type: 'one_way',
    slices: [{ origin: 'GRU', destination: 'MIA', departureDate: '2025-03-15' }],
    passengers: [{ type: 'adult', count: 1 }],
    cabinClass: 'economy'
  })
});

const { offers } = await searchResult.json();
const selectedOffer = offers[0];

// 2. Criar reserva hold
const bookingResult = await fetch('https://app.reservei.co/api/v1/bookings', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    offerId: selectedOffer.id,
    type: 'hold',
    passengers: [{
      id: selectedOffer.passengers[0].id,
      given_name: 'João',
      family_name: 'Silva',
      gender: 'm',
      born_on: '1985-06-15',
      email: 'joao@email.com',
      phone_number: '+5511999998888'
    }]
  })
});

const booking = await bookingResult.json();
console.log(`Reserva criada: ${booking.booking_reference}`);
console.log(`Pagar até: ${booking.payment_status.payment_required_by}`);

// 3. Após cliente pagar, confirmar reserva
const confirmResult = await fetch(`https://app.reservei.co/api/v1/bookings/${booking.id}/confirm`, {
  method: 'PUT',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    payment: {
      type: 'balance',
      amount: selectedOffer.total_amount,
      currency: selectedOffer.total_currency
    }
  })
});

const confirmed = await confirmResult.json();
console.log(`Bilhete emitido: ${confirmed.documents[0].unique_identifier}`);
// Emissão instantânea (pagamento já recebido)
const bookingResult = await fetch('https://app.reservei.co/api/v1/bookings', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    offerId: selectedOffer.id,
    type: 'instant',
    passengers: [{
      id: selectedOffer.passengers[0].id,
      given_name: 'João',
      family_name: 'Silva',
      gender: 'm',
      born_on: '1985-06-15',
      email: 'joao@email.com',
      phone_number: '+5511999998888'
    }],
    payments: [{
      type: 'balance',
      amount: selectedOffer.total_amount,
      currency: selectedOffer.total_currency
    }]
  })
});

const booking = await bookingResult.json();
// Bilhete já emitido!
console.log(`Código: ${booking.booking_reference}`);
console.log(`Bilhete: ${booking.documents[0].unique_identifier}`);
// Voo internacional requer passaporte
const bookingResult = await fetch('https://app.reservei.co/api/v1/bookings', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    offerId: selectedOffer.id,
    type: 'hold',
    passengers: [{
      id: selectedOffer.passengers[0].id,
      given_name: 'João',
      family_name: 'Silva',
      gender: 'm',
      title: 'mr',
      born_on: '1985-06-15',
      email: 'joao@email.com',
      phone_number: '+5511999998888',
      identity_documents: [{
        type: 'passport',
        unique_identifier: 'BR123456789',
        issuing_country_code: 'BR',
        expires_on: '2030-12-31'
      }],
      loyalty_programme_accounts: [{
        airline_iata_code: 'LA',
        account_number: 'LATAM123456'
      }]
    }]
  })
});

Erros Comuns

CódigoErroCausaSolução
400Offer expiredOferta expirouBusque novamente
400Invalid passenger dataDados incompletosVerifique campos obrigatórios
400Passport requiredVoo internacional sem documentoAdicione identity_documents
400Payment amount mismatchValor incorretoUse valores da oferta original
409Booking already confirmedJá confirmadaNenhuma ação necessária
409Booking already cancelledJá canceladaNão pode ser revertido
422Insufficient balanceSaldo insuficiente na walletRecarregue a wallet

Emails Automáticos

Após criar uma reserva, emails são enviados automaticamente:

TipoDestinatárioQuando
Confirmação de reservaCliente + AgênciaReserva criada
Bilhete emitidoCliente + AgênciaApós emissão
Lembrete de pagamentoCliente12h antes do prazo
Reserva canceladaCliente + AgênciaApós cancelamento