Get Reservation Preview
Get basic reservation information for claiming by guests
/public/reservations/{externalId}/previewOverview
Returns basic reservation information including guest name, property details, and points earned. Used by guests to preview their reservation before claiming it in the Journey loyalty program.
Authentication
No authentication required. This is a public endpoint with rate limiting.
Rate Limiting
- Limit: 10 requests per minute per IP address
- Window: 60 seconds
- Headers: Rate limit information included in response headers
Path Parameters
externalIdpathstringrequiredExternal reservation ID (UUID format)
Request
curl -X GET "https://api.journey.com/v1/public/reservations/12345678-1234-5678-9012-123456789012/preview"Response
externalIdstringrequiredExternal reservation identifier
isClaimedbooleanrequiredWhether the reservation has been claimed by a Journey member
totalAwardedPointsnumberrequiredTotal loyalty points that will be awarded for this stay
guestobjectrequiredGuest information
guest object
firstNamestringrequiredPrimary guest's first name
propertyobjectrequiredProperty information
property object
namestringrequiredProperty name
allianceMemberbooleanrequiredWhether the property is part of the Journey alliance
mediaarrayrequiredProperty images
media items
urlstringrequiredFull resolution image URL
thumbnailUrlstringrequiredThumbnail image URL
addressobjectrequiredProperty location
address object
citystringrequiredCity name
statestringrequiredState or province
latitudenumberrequiredLatitude coordinate
longitudenumberrequiredLongitude coordinate
brandobjectrequiredBrand information
brand object
namestringrequiredBrand name
logostringrequiredBrand logo URL
Response
{
"externalId": "12345678-1234-5678-9012-123456789012",
"isClaimed": false,
"totalAwardedPoints": 2500,
"guest": {
"firstName": "Sarah"
},
"property": {
"name": "Journey Beach Resort & Spa",
"allianceMember": true,
"media": [
{
"url": "https://cdn.journey.com/properties/beach-resort-hero.jpg",
"thumbnailUrl": "https://cdn.journey.com/properties/beach-resort-hero-thumb.jpg"
},
{
"url": "https://cdn.journey.com/properties/beach-resort-pool.jpg",
"thumbnailUrl": "https://cdn.journey.com/properties/beach-resort-pool-thumb.jpg"
}
],
"address": {
"city": "Cancun",
"state": "Quintana Roo",
"latitude": 21.1619,
"longitude": -86.8515
},
"brand": {
"name": "Journey Resorts",
"logo": "https://cdn.journey.com/brands/journey-resorts-logo.svg"
}
}
}Use Cases
Reservation Claim Flow
const ReservationClaimPreview = ({ externalId }) => {
const [reservation, setReservation] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchReservation = async () => {
try {
const data = await getReservationPreview(externalId);
setReservation(data);
} catch (error) {
console.error('Failed to fetch reservation:', error);
} finally {
setLoading(false);
}
};
fetchReservation();
}, [externalId]);
if (loading) return <div>Loading reservation...</div>;
if (!reservation) return <div>Reservation not found</div>;
return (
<div className="reservation-preview">
<div className="property-info">
<img
src={reservation.property.media[0]?.thumbnailUrl}
alt={reservation.property.name}
/>
<h2>{reservation.property.name}</h2>
<p>{reservation.property.address.city}, {reservation.property.address.state}</p>
</div>
<div className="guest-info">
<h3>Welcome, {reservation.guest.firstName}!</h3>
{reservation.isClaimed ? (
<p>This reservation has already been claimed.</p>
) : (
<div>
<p>Earn {reservation.totalAwardedPoints.toLocaleString()} points for this stay!</p>
<button onClick={() => claimReservation(externalId)}>
Claim Reservation
</button>
</div>
)}
</div>
</div>
);
};Points Display
const formatPointsEarned = (points) => {
if (points === 0) return 'No points available';
if (points < 1000) return `${points} points`;
if (points < 10000) return `${(points / 1000).toFixed(1)}K points`;
return `${Math.round(points / 1000)}K points`;
};
const PointsEarnedBadge = ({ points, isClaimed }) => {
const formattedPoints = formatPointsEarned(points);
return (
<div className={`points-badge ${isClaimed ? 'claimed' : 'available'}`}>
<span className="points-amount">{formattedPoints}</span>
<span className="points-status">
{isClaimed ? 'Earned' : 'Available to Earn'}
</span>
</div>
);
};Property Location Display
const PropertyLocation = ({ property }) => {
const { address, brand } = property;
const openInMaps = () => {
const url = `https://maps.google.com/?q=${address.latitude},${address.longitude}`;
window.open(url, '_blank');
};
return (
<div className="property-location">
<div className="brand-info">
<img src={brand.logo} alt={brand.name} className="brand-logo" />
<span className="brand-name">{brand.name}</span>
</div>
<div className="location-info">
<span className="location">{address.city}, {address.state}</span>
<button onClick={openInMaps} className="map-link">
View on Map
</button>
</div>
{property.allianceMember && (
<span className="alliance-badge">Journey Alliance Member</span>
)}
</div>
);
};Error Handling
Common Error Scenarios
- Invalid UUID Format: Ensure external ID is valid UUID
- Reservation Not Found: Handle gracefully with user-friendly message
- Rate Limiting: Implement retry logic with exponential backoff
- Network Errors: Show offline/error states
Retry Logic
const fetchWithRetry = async (url, options = {}, maxRetries = 3) => {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(url, options);
if (response.status === 429) {
// Rate limited, wait and retry
const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
return response;
} catch (error) {
if (attempt === maxRetries) throw error;
// Wait before retry
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
};Security Considerations
Rate Limiting
- Implemented to prevent abuse
- IP-based tracking
- Headers indicate remaining requests
Data Privacy
- Only returns basic guest first name
- No sensitive personal information exposed
- External ID acts as secure token
Input Validation
- External ID must be valid UUID format
- Malformed requests return 400 error
Related Endpoints
- Lookup Reservation - Find reservation by details
- Resolve Legacy Booking - Convert legacy bookings