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
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
offerId | string | Sim | ID da oferta obtida na busca de voos |
type | string | Sim | Tipo de reserva: hold ou instant |
passengers | array | Sim | Dados completos dos passageiros |
payments | array | Condicional | Obrigatório se type = instant |
metadata | object | Não | Dados adicionais da sua aplicação |
Objeto Passenger (Detalhado)
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | string | Sim | ID do passageiro da oferta (pas_xxx) |
given_name | string | Sim | Primeiro nome (como no documento) |
family_name | string | Sim | Sobrenome (como no documento) |
gender | string | Sim | Gênero: m (masculino) ou f (feminino) |
title | string | Não | Título: mr, mrs, ms, miss, dr |
born_on | string | Sim | Data de nascimento (YYYY-MM-DD) |
email | string | Sim | Email do passageiro |
phone_number | string | Sim | Telefone com DDI (+5511999998888) |
identity_documents | array | Condicional | Documentos (obrigatório para voos internacionais) |
loyalty_programme_accounts | array | Não | Programas de milhagem |
infant_passenger_id | string | Condicional | ID 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"
}
]
}| Campo | Tipo | Descrição |
|---|---|---|
type | string | passport, tax_id (CPF), known_traveler_number |
unique_identifier | string | Número do documento |
issuing_country_code | string | Código do país emissor (ISO 3166-1 alpha-2) |
expires_on | string | Data de validade (YYYY-MM-DD) |
Programa de Milhagem
{
"loyalty_programme_accounts": [
{
"airline_iata_code": "LA",
"account_number": "123456789"
}
]
}Tipos de Reserva
| Tipo | Descrição | Débito na Wallet | Prazo |
|---|---|---|---|
hold | Reserva temporária aguardando pagamento | Não | 24-72h para confirmar |
instant | Emissão imediata do bilhete | Sim, imediato | Instantâ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
| Campo | Tipo | Descrição |
|---|---|---|
id | string | ID único da reserva (ord_xxx) |
booking_reference | string | Código localizador da companhia aérea |
total_amount | string | Valor total original |
total_currency | string | Moeda original |
owner | object | Companhia aérea principal |
slices | array | Trechos da viagem com detalhes |
passengers | array | Passageiros com dados completos |
documents | array | Bilhetes emitidos (após confirmação) |
conditions | object | Condições de alteração/cancelamento |
payment_status | object | Status e prazos de pagamento |
GET /api/v1/bookings
Lista todas as reservas do seu time.
Query Parameters
| Parâmetro | Tipo | Padrão | Descrição |
|---|---|---|---|
page | number | 1 | Página atual |
limit | number | 20 | Itens por página (máx: 100) |
status | string | - | Filtrar por status |
created_after | string | - | Filtrar por data de criação (YYYY-MM-DD) |
created_before | string | - | 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 Atual | Comportamento |
|---|---|
pending | Cancelamento sem custo |
confirmed | Pode haver penalidade |
ticketed | Sujeito a regras da tarifa |
cancelled | Erro - já cancelado |
Request
DELETE /api/v1/bookings/ord_0000AbCdEf123456Response
{
"success": true,
"data": {
"id": "ord_0000AbCdEf123456",
"status": "cancelled",
"refund": {
"amount": "1100.50",
"currency": "USD",
"penalty_amount": "150.00",
"penalty_currency": "USD"
}
}
}Status das Reservas
| Status | Descrição | Ação Esperada |
|---|---|---|
pending | Reserva criada, aguardando pagamento | Confirmar pagamento |
confirmed | Pagamento recebido, aguardando emissão | Aguardar bilhete |
ticketed | Bilhetes emitidos | Nenhuma |
cancelled | Reserva cancelada | Nenhuma |
expired | Prazo de pagamento expirado | Nova busca necessária |
failed | Falha na emissão | Contatar suporte |
pending → confirmed → ticketed
↓ ↓ ↓
cancelled cancelled cancelled
↓
expiredExemplos 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ódigo | Erro | Causa | Solução |
|---|---|---|---|
400 | Offer expired | Oferta expirou | Busque novamente |
400 | Invalid passenger data | Dados incompletos | Verifique campos obrigatórios |
400 | Passport required | Voo internacional sem documento | Adicione identity_documents |
400 | Payment amount mismatch | Valor incorreto | Use valores da oferta original |
409 | Booking already confirmed | Já confirmada | Nenhuma ação necessária |
409 | Booking already cancelled | Já cancelada | Não pode ser revertido |
422 | Insufficient balance | Saldo insuficiente na wallet | Recarregue a wallet |
Emails Automáticos
Após criar uma reserva, emails são enviados automaticamente:
| Tipo | Destinatário | Quando |
|---|---|---|
| Confirmação de reserva | Cliente + Agência | Reserva criada |
| Bilhete emitido | Cliente + Agência | Após emissão |
| Lembrete de pagamento | Cliente | 12h antes do prazo |
| Reserva cancelada | Cliente + Agência | Após cancelamento |