> ## Documentation Index
> Fetch the complete documentation index at: https://developers.vulcanopro.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Reservas de traslados

> Hold, confirmación (solo customer) y anulación de traslados.

## Descripción

Igual que tours, las reservas de traslado se crean en **dos pasos**:

1. **Hold** — bloquea cupo **15 minutos** y crea la orden en Vulcano (sin pago).
2. **Confirm** — envía el customer. **No hay lista de pasajeros**: se usa el comprador.

En el calendario del operador la reserva entra **Pendiente** hasta que el operador pulse Confirmar. En la API el partner ve `CONFIRMED` en cuanto cierra el hold.

> [!WARNING]
>
> Requiere **`reservations:write`** y canal Vulcano vinculado. No mezcles estos endpoints con `/reservations` de tours (`tour_id` vs `transfer_id`).

## Flujo

```
1. GET /transfers/cities → GET /transfers/places
2. GET /transfers?origin_place_id=…&destination_place_id=…&date=…&time=…&passengers=…
3. POST /transfers/reservations                 → HOLD (15 min)
4. GET /transfers/reservations/{id}             → opcional
5. POST /transfers/reservations/confirm         → CONFIRMED
6. POST /transfers/reservations/cancel          → CANCELLED
```

Si el hold **expira** antes del confirm → `409`.

## Paso 1 — Hold

`POST /transfers/reservations`

```bash theme={null}
curl -s -X POST "https://api-sandbox.vulcanopro.com/api/v1/transfers/reservations" \
  -H "X-API-KEY: TU_API_KEY" \
  -H "X-API-SECRET: TU_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "transfer_id": 14,
    "origin_place_id": 1,
    "destination_place_id": 6,
    "date": "2026-10-31",
    "time": "12:30",
    "pax": { "adult": 2, "child": 0, "senior": 0 }
  }'
```

### Body

| Campo | Tipo | Requerido | Descripción |
| - | - | - | - |
| `transfer_id` | integer | Sí | ID de `GET /transfers` |
| `origin_place_id` | integer | Sí | Origen de la búsqueda |
| `destination_place_id` | integer | Sí | Destino de la búsqueda |
| `date` | string | Sí | `YYYY-MM-DD` |
| `time` | string | Sí | `HH:mm` |
| `pax.adult` | integer | No\* | Adultos |
| `pax.child` | integer | No\* | Niños |
| `pax.senior` | integer | No\* | Adultos mayores |
| `return_date` | string | No | `YYYY-MM-DD` (ida y vuelta) |
| `return_time` | string | No | `HH:mm` (requerido con `return_date`) |

\* Al menos 1 entre adult + child + senior.

### Respuesta

```json theme={null}
{
  "status": "ok",
  "data": {
    "id": "aa1aa603-fc6e-4ec9-b44f-ca48baf8d099",
    "status": "HOLD",
    "transfer_id": 14,
    "sale_channel_id": 97,
    "origin_place_id": 1,
    "destination_place_id": 6,
    "date": "2026-10-31",
    "time": "12:30",
    "return_date": null,
    "return_time": null,
    "pax": { "adult": 2, "child": 0, "senior": 0 },
    "seats": 2,
    "expires_at": "2026-10-31T15:45:00+00:00",
    "order_id": 18580,
    "external_reference": null,
    "customer": null,
    "passengers": null,
    "additional_activities": [],
    "created_at": "2026-10-31T15:30:00+00:00"
  },
  "timestamp": "2026-10-31T15:30:00.000Z"
}
```

| HTTP | Causa |
| - | - |
| `403` | Sin `reservations:write` o sin canal |
| `409` | Sin disponibilidad |
| `422` | Traslado / fecha / hora no válidos para el canal |

## Paso 2 — Confirmar

`POST /transfers/reservations/confirm`

Solo **customer**. Los extras salen de `additional_activities` de `GET /transfers`.

```bash theme={null}
curl -s -X POST "https://api-sandbox.vulcanopro.com/api/v1/transfers/reservations/confirm" \
  -H "X-API-KEY: TU_API_KEY" \
  -H "X-API-SECRET: TU_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "aa1aa603-fc6e-4ec9-b44f-ca48baf8d099",
    "customer": {
      "name": "Jose",
      "lastname": "Pérez",
      "email": "ana@example.com",
      "phone": "912345678",
      "phone_code": "56",
      "identification": "11.111.111-1"
    },
    "additional_activities": [
      { "id": 8, "quantity": 1, "return_quantity": 0 }
    ],
    "external_reference": "OTA-1"
  }'
```

| Campo | Tipo | Requerido | Descripción |
| - | - | - | - |
| `id` | uuid | Sí | UUID del hold |
| `customer` | object | Sí | Comprador |
| `additional_activities` | array | No | `id`, `quantity`, opcional `return_quantity` |
| `external_reference` | string | No | Tu referencia |

Un confirm repetido del mismo hold es **idempotente** (`200`, sigue `CONFIRMED`).

## Consultar

`GET /transfers/reservations/{id}`

Mismo `data` que hold/confirm. Un hold vencido se marca `EXPIRED` y responde `200`.

## Anular

`POST /transfers/reservations/cancel`

```json theme={null}
{ "id": "aa1aa603-fc6e-4ec9-b44f-ca48baf8d099", "reason": "guest cancelled" }
```

| Estado actual | Resultado |
| - | - |
| `HOLD` | `CANCELLED` |
| `CONFIRMED` | `CANCELLED` (también si el operador aún no confirmó en calendario) |
| `CANCELLED` | `200` (idempotente) |
| `EXPIRED` | `409` |

## Estados (API partner)

| Estado | Significado |
| - | - |
| `HOLD` | Cupo bloqueado hasta `expires_at` |
| `EXPIRED` | Hold vencido |
| `CONFIRMED` | Hold cerrado; el operador puede seguir viéndola Pendiente en su calendario |
| `CANCELLED` | Anulada por el partner |

## Checklist

1. Permisos `transfers:read` + `reservations:write`.
2. Buscar traslado con origen, destino, fecha, hora y pasajeros.
3. `POST /transfers/reservations` → guardar `id` y `expires_at`.
4. `POST /transfers/reservations/confirm` con `customer` (sin lista de pasajeros).
5. `POST /transfers/reservations/cancel` si hay que liberar el cupo.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.