# Lookup Reservation
> Source: /api-reference/public/reservations/lookup-reservation
> Find reservation using confirmation details or reservation ID
> Endpoint: POST /public/reservations/lookup

## Overview [#overview]

Allows guests to find their reservation using confirmation code or reservation ID, guest last name, and either check-in or check-out date. Returns the external reservation ID needed to claim the reservation in the Journey loyalty program.

## Authentication [#authentication]

No authentication required. This is a public endpoint with rate limiting.

## Rate Limiting [#rate-limiting]

- **Limit**: 10 requests per minute per IP address
- **Window**: 60 seconds
- **Headers**: Rate limit information included in response headers

## Request Body [#request-body]

At least one of `confirmationCode` or `reservationId` is required.

<ParamField body="confirmationCode" type="string">
  Hotel confirmation code (required if reservationId not provided)
  <br />Maximum length: 100 characters
</ParamField>

<ParamField body="reservationId" type="string">
  Property management system reservation ID (required if confirmationCode not provided)
  <br />Maximum length: 100 characters
</ParamField>

<ParamField body="checkOutDate" type="string">
  Check-out date in YYYY-MM-DD format. Required if `checkInDate` is not provided.
</ParamField>

<ParamField body="checkInDate" type="string">
  Check-in date in YYYY-MM-DD format. Required if `checkOutDate` is not provided.
</ParamField>

<ParamField body="lastName" type="string" required>
  Guest's last name (case insensitive)
  <br />Maximum length: 200 characters
</ParamField>

<RequestExample>

```bash cURL - Using Check-in Date
curl -X POST "https://api.journey.com/v1/public/reservations/lookup" \
  -H "Content-Type: application/json" \
  -d '{
    "confirmationCode": "ABC123DEF",
    "checkInDate": "2026-05-28",
    "lastName": "Johnson"
  }'
```

```bash cURL - Using Check-out Date
curl -X POST "https://api.journey.com/v1/public/reservations/lookup" \
  -H "Content-Type: application/json" \
  -d '{
    "confirmationCode": "ABC123DEF",
    "checkOutDate": "2026-06-03",
    "lastName": "Johnson"
  }'
```

```bash cURL - Using Reservation ID
curl -X POST "https://api.journey.com/v1/public/reservations/lookup" \
  -H "Content-Type: application/json" \
  -d '{
    "reservationId": "RES-2026-001234",
    "checkInDate": "2026-05-28",
    "lastName": "Johnson"
  }'
```

```typescript TypeScript
const lookupReservation = async (lookupData) => {
  const response = await fetch('https://api.journey.com/v1/public/reservations/lookup', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      confirmationCode: 'ABC123DEF',
      checkInDate: '2026-05-28',  // or checkOutDate — either works
      lastName: 'Johnson'
    })
  });
  
  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
  }
  
  return response.json();
};
```

</RequestExample>

## Response [#response]

<ResponseField name="externalReservationId" type="string" required>
  External reservation identifier used for claiming reservation and other operations
</ResponseField>

<ResponseExample>

```json 200 Response - Reservation Found
{
  "externalReservationId": "12345678-1234-5678-9012-123456789012"
}
```

```json 404 Error - Reservation Not Found
{
  "statusCode": 404,
  "message": "Reservation not found",
  "error": "Not Found"
}
```

```json 400 Error - Validation Error
{
  "statusCode": 400,
  "message": [
    "checkOutDate must be a valid date in YYYY-MM-DD format",
    "At least one of confirmationCode or reservationId is required"
  ],
  "error": "Bad Request"
}
```

```json 400 Error - Missing Required Fields
{
  "statusCode": 400,
  "message": [
    "lastName should not be empty",
    "checkOutDate must be a valid date in YYYY-MM-DD format"
  ],
  "error": "Bad Request"
}
```

```json 429 Error - Rate Limit Exceeded
{
  "statusCode": 429,
  "message": "Too many requests",
  "error": "Too Many Requests"
}
```

</ResponseExample>

## Use Cases [#use-cases]

### Reservation Lookup Form [#reservation-lookup-form]
```typescript
const ReservationLookupForm = ({ onSuccess }) => {
  const [formData, setFormData] = useState({
    confirmationCode: '',
    reservationId: '',
    checkOutDate: '',
    lastName: ''
  });
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  
  const handleSubmit = async (e) => {
    e.preventDefault();
    setLoading(true);
    setError(null);
    
    try {
      // Ensure at least one identifier is provided
      if (!formData.confirmationCode && !formData.reservationId) {
        throw new Error('Please provide either a confirmation code or reservation ID');
      }
      
      const result = await lookupReservation({
        confirmationCode: formData.confirmationCode || undefined,
        reservationId: formData.reservationId || undefined,
        checkOutDate: formData.checkOutDate,
        lastName: formData.lastName.trim()
      });
      
      onSuccess(result.externalReservationId);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };
  
  return (
    <form onSubmit={handleSubmit} className="reservation-lookup">
      <div className="form-group">
        <label>Confirmation Code</label>
        <input
          type="text"
          value={formData.confirmationCode}
          onChange={(e) => setFormData(prev => ({
            ...prev, 
            confirmationCode: e.target.value.toUpperCase()
          }))}
          placeholder="ABC123DEF"
          maxLength={100}
        />
      </div>
      
      <div className="form-divider">OR</div>
      
      <div className="form-group">
        <label>Reservation ID</label>
        <input
          type="text"
          value={formData.reservationId}
          onChange={(e) => setFormData(prev => ({
            ...prev, 
            reservationId: e.target.value
          }))}
          placeholder="RES-2026-001234"
          maxLength={100}
        />
      </div>
      
      <div className="form-group">
        <label>Check-out Date *</label>
        <input
          type="date"
          value={formData.checkOutDate}
          onChange={(e) => setFormData(prev => ({
            ...prev, 
            checkOutDate: e.target.value
          }))}
          required
        />
      </div>
      
      <div className="form-group">
        <label>Last Name *</label>
        <input
          type="text"
          value={formData.lastName}
          onChange={(e) => setFormData(prev => ({
            ...prev, 
            lastName: e.target.value
          }))}
          placeholder="Johnson"
          maxLength={200}
          required
        />
      </div>
      
      {error && (
        <div className="error-message">{error}</div>
      )}
      
      <button type="submit" disabled={loading}>
        {loading ? 'Looking up...' : 'Find Reservation'}
      </button>
    </form>
  );
};
```

### Multi-Step Reservation Flow [#multi-step-reservation-flow]
```typescript
const ReservationClaimFlow = () => {
  const [step, setStep] = useState('lookup'); // 'lookup', 'preview', 'claim'
  const [externalId, setExternalId] = useState(null);
  const [reservation, setReservation] = useState(null);
  
  const handleLookupSuccess = async (foundExternalId) => {
    setExternalId(foundExternalId);
    
    // Fetch reservation preview
    try {
      const preview = await getReservationPreview(foundExternalId);
      setReservation(preview);
      setStep('preview');
    } catch (error) {
      console.error('Failed to load reservation preview:', error);
    }
  };
  
  const handleClaimReservation = () => {
    // Redirect to authentication/claim flow
    window.location.href = `/claim/${externalId}`;
  };
  
  return (
    <div className="reservation-flow">
      {step === 'lookup' && (
        <ReservationLookupForm onSuccess={handleLookupSuccess} />
      )}
      
      {step === 'preview' && reservation && (
        <div className="reservation-preview">
          <h2>Reservation Found!</h2>
          <div className="property-info">
            <h3>{reservation.property.name}</h3>
            <p>{reservation.property.address.city}, {reservation.property.address.state}</p>
          </div>
          
          <div className="guest-info">
            <h4>Guest: {reservation.guest.firstName}</h4>
            <p>Points to earn: {reservation.totalAwardedPoints.toLocaleString()}</p>
          </div>
          
          {reservation.isClaimed ? (
            <p>This reservation has already been claimed.</p>
          ) : (
            <button onClick={handleClaimReservation}>
              Claim Reservation & Earn Points
            </button>
          )}
          
          <button onClick={() => setStep('lookup')}>
            Look up different reservation
          </button>
        </div>
      )}
    </div>
  );
};
```

### Form Validation [#form-validation]
```typescript
const validateLookupForm = (formData) => {
  const errors = [];
  
  // Check for at least one identifier
  if (!formData.confirmationCode && !formData.reservationId) {
    errors.push('Please provide either a confirmation code or reservation ID');
  }
  
  // Validate date format
  const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
  if (!dateRegex.test(formData.checkOutDate)) {
    errors.push('Check-out date must be in YYYY-MM-DD format');
  }
  
  // Validate date is not in future (reasonable booking window)
  const checkOutDate = new Date(formData.checkOutDate);
  const maxFutureDate = new Date();
  maxFutureDate.setFullYear(maxFutureDate.getFullYear() + 2);
  
  if (checkOutDate > maxFutureDate) {
    errors.push('Check-out date seems too far in the future');
  }
  
  // Validate last name
  if (!formData.lastName.trim()) {
    errors.push('Last name is required');
  }
  
  if (formData.lastName.length > 200) {
    errors.push('Last name is too long');
  }
  
  return errors;
};
```

## Lookup Strategies [#lookup-strategies]

### Search Priority [#search-priority]
1. **Exact Match**: Direct lookup by confirmation code or reservation ID
2. **Fuzzy Matching**: Handle common typos in names (implementation dependent)
3. **Case Insensitive**: Last name matching ignores case differences

### Data Sources [#data-sources]
- **Hotel PMS Systems**: Primary reservation data source
- **Booking Platforms**: OTA and direct booking confirmations  
- **Legacy Systems**: Historical reservation data

### Matching Criteria [#matching-criteria]
- **Confirmation Code/Reservation ID**: Exact match required
- **Check-out Date**: Must match exactly
- **Last Name**: Case-insensitive match
- **Additional Validation**: May include room type, dates, etc.

## Error Handling [#error-handling]

### Common Issues [#common-issues]
- **Multiple Identifiers**: Don't provide both confirmationCode and reservationId
- **Date Format**: Use YYYY-MM-DD format only
- **Name Variations**: Try exact name as on reservation
- **Recent Bookings**: May take time to sync from PMS

### Troubleshooting Tips [#troubleshooting-tips]
```typescript
const troubleshootingMessages = {
  notFound: {
    title: "Reservation not found",
    suggestions: [
      "Double-check your confirmation code or reservation ID",
      "Verify the check-out date is correct",
      "Ensure the last name matches the reservation exactly",
      "Try using the other identifier (confirmation code vs reservation ID)",
      "Recent bookings may take up to 24 hours to sync"
    ]
  },
  validation: {
    title: "Invalid information provided",
    suggestions: [
      "Use YYYY-MM-DD format for dates (e.g., 2026-06-03)",
      "Provide either confirmation code OR reservation ID",
      "Enter the full last name as shown on the reservation"
    ]
  }
};
```

## Security Considerations [#security-considerations]

### Rate Limiting [#rate-limiting-1]
- Prevents brute force attempts
- IP-based tracking across all public endpoints
- Exponential backoff recommended for retries

### Data Privacy [#data-privacy]
- Only returns external reservation ID
- No sensitive guest information exposed
- Lookup requires multiple verification points

### Input Sanitization [#input-sanitization]
- All inputs validated and sanitized
- SQL injection prevention
- XSS protection for all text fields

## Related Endpoints [#related-endpoints]

- [Get Reservation Preview](/api-reference/public/reservations/get-reservation-preview) - View reservation details
- [Resolve Legacy Booking](/api-reference/public/reservations/resolve-legacy-booking) - Convert legacy bookings
