Listings API
Endpoints for browsing and retrieving accommodation listings.
List Accommodations
Retrieve a paginated list of accommodations with optional filters.
GET /api/listingsQuery Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
type | string | - | Filter by type: ACCOMMODATION, ACTIVITY, EXPERIENCE |
region | string | - | Filter by region (e.g., “Greater Accra”) |
city | string | - | Filter by city (e.g., “Accra”) |
minPrice | number | - | Minimum price in GHS |
maxPrice | number | - | Maximum price in GHS |
bedrooms | number | - | Minimum number of bedrooms |
guests | number | - | Minimum guest capacity |
amenities | string | - | Comma-separated amenity IDs |
checkIn | string | - | ISO date for availability check |
checkOut | string | - | ISO date for availability check |
sort | string | newest | Sort: price_asc, price_desc, newest, popular |
page | number | 1 | Page number |
limit | number | 20 | Items per page (max 50) |
Response
{
"data": [
{
"id": "clx123abc...",
"type": "ACCOMMODATION",
"title": "Luxury Beach Villa",
"slug": "luxury-beach-villa-accra",
"description": "A stunning beachfront property...",
"region": "Greater Accra",
"city": "Accra",
"area": "Labadi",
"priceGHS": "850.00",
"priceUnit": "PER_NIGHT",
"bedrooms": 3,
"bathrooms": 2,
"maxGuests": 6,
"featured": true,
"images": [
{
"id": "clx456...",
"url": "https://res.cloudinary.com/...",
"isPrimary": true
}
]
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 45,
"totalPages": 3,
"hasMore": true
}
}Example
# Get luxury accommodations in Accra
curl "https://y3nko.travel/api/listings?region=Greater%20Accra&minPrice=500&sort=price_desc"Get Single Listing
Retrieve complete details for a specific listing.
GET /api/listings/{slug}Path Parameters
| Parameter | Type | Description |
|---|---|---|
slug | string | Listing URL slug |
Response
{
"data": {
"id": "clx123abc...",
"type": "ACCOMMODATION",
"status": "PUBLISHED",
"title": "Luxury Beach Villa",
"slug": "luxury-beach-villa-accra",
"description": "A stunning beachfront property with panoramic ocean views...",
"highlights": [
"Private beach access",
"Infinity pool",
"24/7 security"
],
"region": "Greater Accra",
"city": "Accra",
"area": "Labadi",
"address": "123 Beach Road, Labadi",
"latitude": 5.5560,
"longitude": -0.1469,
"priceGHS": "850.00",
"priceUSD": "68.00",
"priceUnit": "PER_NIGHT",
"propertyType": "VILLA",
"bedrooms": 3,
"bathrooms": 2,
"maxGuests": 6,
"checkInTime": "14:00",
"checkOutTime": "11:00",
"viewCount": 1250,
"bookingCount": 45,
"images": [
{
"id": "clx456...",
"url": "https://res.cloudinary.com/...",
"alt": "Villa exterior",
"isPrimary": true,
"order": 0
}
],
"amenities": [
{
"amenity": {
"id": "clx789...",
"name": "WiFi",
"icon": "wifi",
"category": "Essentials"
}
},
{
"amenity": {
"id": "clx790...",
"name": "Swimming Pool",
"icon": "swimming-pool",
"category": "Comfort"
}
}
],
"createdAt": "2024-01-15T10:30:00Z",
"publishedAt": "2024-01-16T08:00:00Z"
}
}Errors
| Status | Code | Description |
|---|---|---|
| 404 | NOT_FOUND | Listing not found or not published |
Check Availability
Check if dates are available and get pricing.
GET /api/listings/{slug}/availabilityQuery Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
checkIn | string | Yes | ISO date (e.g., “2024-03-15”) |
checkOut | string | Yes | ISO date (e.g., “2024-03-18”) |
Response
{
"data": {
"available": true,
"unavailableDates": [],
"pricing": {
"nights": 3,
"pricePerNight": 850,
"subtotal": 2550,
"serviceFee": 255,
"taxes": 318.75,
"total": 3123.75,
"currency": "GHS"
}
}
}If dates are unavailable:
{
"data": {
"available": false,
"unavailableDates": ["2024-03-16", "2024-03-17"],
"pricing": null
}
}Featured Listings
Get featured listings for homepage display.
GET /api/listings/featuredQuery Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
type | string | - | Filter by type |
limit | number | 6 | Number of listings (max 12) |
Response
{
"data": [
{
"id": "clx123...",
"title": "Luxury Beach Villa",
"slug": "luxury-beach-villa-accra",
"region": "Greater Accra",
"priceGHS": "850.00",
"images": [{ "url": "...", "isPrimary": true }]
}
]
}Search Listings
Full-text search across listings.
GET /api/listings/searchQuery Parameters
| Parameter | Type | Description |
|---|---|---|
q | string | Search query |
type | string | Filter by type |
limit | number | Results limit (max 20) |
Response
{
"data": [
{
"id": "clx123...",
"title": "Beach Villa",
"slug": "beach-villa-accra",
"description": "Stunning beachfront...",
"region": "Greater Accra",
"priceGHS": "850.00"
}
]
}Implementation Notes
Server Action Alternative
For better integration with React, use the server action:
// lib/actions/listings.ts
"use server"
import { prisma } from '@/lib/db'
export async function getListings(filters: ListingFilters) {
const where: Prisma.ListingWhereInput = {
status: 'PUBLISHED',
type: filters.type || undefined,
region: filters.region || undefined,
priceGHS: {
gte: filters.minPrice,
lte: filters.maxPrice
}
}
const [listings, total] = await prisma.$transaction([
prisma.listing.findMany({
where,
include: {
images: { where: { isPrimary: true }, take: 1 }
},
orderBy: getSortOrder(filters.sort),
skip: (filters.page - 1) * filters.limit,
take: filters.limit
}),
prisma.listing.count({ where })
])
return {
listings,
pagination: {
page: filters.page,
limit: filters.limit,
total,
totalPages: Math.ceil(total / filters.limit),
hasMore: filters.page * filters.limit < total
}
}
}Usage in Server Component
// app/accommodations/page.tsx
import { getListings } from '@/lib/actions/listings'
export default async function AccommodationsPage({ searchParams }) {
const { listings, pagination } = await getListings({
region: searchParams.region,
minPrice: searchParams.minPrice,
page: searchParams.page || 1,
limit: 20
})
return <ListingGrid listings={listings} pagination={pagination} />
}