Get Signature Stays
Get premium curated properties hand-picked by Journey
/members/me/features/discover/galleries/signature-staysOverview
Returns premium/curated properties hand-picked by Journey for the Signature Stays gallery. These are high-quality, vetted properties that showcase the best of what Journey has to offer.
Authentication
Requires a valid Clerk JWT token in the Authorization header.
Query Parameters
limitquerynumberMaximum number of items to return
offsetquerynumberNumber of items to skip for pagination
Request
curl -X GET "http://localhost:3000/v1/members/me/features/discover/galleries/signature-stays" \
-H "Authorization: Bearer YOUR_CLERK_JWT"Response
itemsarrayrequiredArray of curated property groups
array items
idnumberrequiredGroup ID
documentIdstringGroup document identifier
titlestringGallery group title
contextstringAdditional context about the group
prioritynumberDisplay priority order
isActivebooleanWhether the group is currently active
createdAtstringISO 8601 creation timestamp
updatedAtstringISO 8601 last update timestamp
groupMediaobjectGroup-level media (header image/video)
propertiesarrayrequiredProperties in this group
properties items
propertyobjectrequiredProperty summary information
property object
idnumberrequiredProperty ID
documentIdstringProperty document identifier
namestringProperty name
brandNamestringBrand name
typestringProperty type (Hotel, Resort, etc.)
baseRoomCategorystringBase room category
nightlyCostnumberNightly cost in cents
guestRatingnumberAverage guest rating
maxGuestsnumberMaximum guests allowed
amenitiesarrayArray of amenity names
addressobjectProperty address information
heroImageobjectHero image for the property
galleryarrayArray of property images
mediaobjectProperty-specific media for this gallery context
totalnumberrequiredTotal number of groups available
Response
{
"items": [
{
"id": 1,
"documentId": "gallery_luxury_escapes",
"title": "Luxury Escapes",
"context": "Premium properties in exotic destinations",
"priority": 1,
"isActive": true,
"createdAt": "2024-01-15T10:00:00Z",
"updatedAt": "2024-04-20T12:00:00Z",
"groupMedia": {
"url": "https://cdn.example.com/galleries/luxury-escapes-header.mp4",
"alt": "Luxury properties compilation video"
},
"properties": [
{
"property": {
"id": 123,
"documentId": "prop_maldives_resort",
"name": "Overwater Villa Resort",
"brandName": "Journey Signature",
"type": "Resort",
"baseRoomCategory": "Overwater Villa",
"nightlyCost": 120000,
"guestRating": 4.9,
"maxGuests": 4,
"amenities": ["Private Pool", "Butler Service", "Spa", "Fine Dining"],
"address": {
"city": "Male",
"state": "Male Atoll",
"country": "Maldives",
"latitude": 4.1755,
"longitude": 73.5093
},
"heroImage": {
"url": "https://cdn.example.com/properties/maldives-resort-hero.jpg",
"alt": "Overwater villa with crystal clear water"
},
"gallery": [
{
"url": "https://cdn.example.com/properties/maldives-resort-1.jpg",
"alt": "Villa interior"
},
{
"url": "https://cdn.example.com/properties/maldives-resort-2.jpg",
"alt": "Sunset view from deck"
}
]
},
"media": {
"url": "https://cdn.example.com/galleries/maldives-feature.jpg",
"alt": "Featured view of Maldives resort"
}
},
{
"property": {
"id": 124,
"documentId": "prop_santorini_villa",
"name": "Cliffside Villa Santorini",
"brandName": "Journey Collection",
"type": "Villa",
"baseRoomCategory": "Private Villa",
"nightlyCost": 85000,
"guestRating": 4.8,
"maxGuests": 6,
"amenities": ["Infinity Pool", "Private Terrace", "Concierge", "Ocean View"],
"address": {
"city": "Oia",
"state": "Santorini",
"country": "Greece",
"latitude": 36.4618,
"longitude": 25.3753
},
"heroImage": {
"url": "https://cdn.example.com/properties/santorini-villa-hero.jpg",
"alt": "White villa overlooking Aegean Sea"
},
"gallery": [
{
"url": "https://cdn.example.com/properties/santorini-villa-1.jpg",
"alt": "Villa terrace with sunset view"
}
]
},
"media": {
"url": "https://cdn.example.com/galleries/santorini-feature.jpg",
"alt": "Featured view of Santorini villa"
}
}
]
},
{
"id": 2,
"documentId": "gallery_urban_retreats",
"title": "Urban Retreats",
"context": "Sophisticated city properties with exceptional service",
"priority": 2,
"isActive": true,
"createdAt": "2024-02-01T10:00:00Z",
"updatedAt": "2024-04-18T14:30:00Z",
"groupMedia": {
"url": "https://cdn.example.com/galleries/urban-retreats-header.jpg",
"alt": "City skyline with luxury hotel"
},
"properties": [
{
"property": {
"id": 125,
"documentId": "prop_tokyo_tower_hotel",
"name": "Tokyo Tower Luxury Hotel",
"brandName": "Journey Premier",
"type": "Hotel",
"baseRoomCategory": "Executive Suite",
"nightlyCost": 75000,
"guestRating": 4.7,
"maxGuests": 3,
"amenities": ["Rooftop Bar", "Michelin Star Restaurant", "Spa", "City Views"],
"address": {
"city": "Tokyo",
"state": "Tokyo",
"country": "Japan",
"latitude": 35.6762,
"longitude": 139.6503
},
"heroImage": {
"url": "https://cdn.example.com/properties/tokyo-hotel-hero.jpg",
"alt": "Modern hotel with Tokyo Tower view"
},
"gallery": [
{
"url": "https://cdn.example.com/properties/tokyo-hotel-1.jpg",
"alt": "Suite interior with city view"
}
]
},
"media": null
}
]
}
],
"total": 8
}Use Cases
Gallery Display
const SignatureStaysGallery = () => {
const [galleries, setGalleries] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const loadSignatureStays = async () => {
try {
const response = await fetch('/api/members/me/features/discover/galleries/signature-stays');
const data = await response.json();
setGalleries(data.items);
} catch (error) {
console.error('Failed to load signature stays:', error);
} finally {
setLoading(false);
}
};
loadSignatureStays();
}, []);
if (loading) return <GalleryLoadingSkeleton />;
return (
<div className="signature-stays">
<h2>Signature Stays</h2>
{galleries.map(gallery => (
<PropertyGallery key={gallery.id} gallery={gallery} />
))}
</div>
);
};Property Card Rendering
const PropertyCard = ({ propertyItem }) => {
const { property, media } = propertyItem;
return (
<div className="property-card">
<img
src={media?.url || property.heroImage?.url}
alt={media?.alt || property.heroImage?.alt}
className="property-image"
/>
<div className="property-info">
<h3>{property.name}</h3>
<p className="brand">{property.brandName}</p>
<p className="location">{property.address?.city}, {property.address?.country}</p>
<div className="details">
<span className="rating">★ {property.guestRating}</span>
<span className="price">From ${property.nightlyCost / 100}/night</span>
<span className="guests">Up to {property.maxGuests} guests</span>
</div>
<div className="amenities">
{property.amenities?.slice(0, 3).map(amenity => (
<span key={amenity} className="amenity">{amenity}</span>
))}
{property.amenities?.length > 3 && (
<span className="more">+{property.amenities.length - 3} more</span>
)}
</div>
</div>
</div>
);
};Infinite Scroll Implementation
const useInfiniteSignatureStays = () => {
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(false);
const [hasMore, setHasMore] = useState(true);
const [offset, setOffset] = useState(0);
const loadMore = useCallback(async () => {
if (loading || !hasMore) return;
setLoading(true);
try {
const response = await fetch(`/api/members/me/features/discover/galleries/signature-stays?limit=5&offset=${offset}`);
const data = await response.json();
setItems(prev => [...prev, ...data.items]);
setOffset(prev => prev + data.items.length);
setHasMore(offset + data.items.length < data.total);
} catch (error) {
console.error('Failed to load more signature stays:', error);
} finally {
setLoading(false);
}
}, [offset, loading, hasMore]);
return { items, loading, hasMore, loadMore };
};Gallery Features
Curation Quality
- Hand-picked: Properties selected by Journey travel experts
- Quality Assurance: High standards for amenities and service
- Exclusive Access: Some properties may be exclusive to Journey members
- Premium Experience: Focus on luxury and unique experiences
Visual Presentation
- Group Media: Video or hero images for each gallery section
- Property Media: Curated images optimized for gallery display
- Contextual Grouping: Properties grouped by theme or destination type
- Priority Ordering: Groups displayed in priority order
Content Management
- Dynamic Updates: Gallery content updated regularly
- Seasonal Rotation: Properties may rotate based on seasonality
- Member Feedback: Curation influenced by member preferences and reviews
- Performance Tracking: Popular properties highlighted
Related Endpoints
- Get Featured Content - Main discover screen content
- Get New to Journey - Recently added properties
- Get Inspiring Stays - Themed property collections
- Get Earn More Gallery - Properties with bonus campaigns