Roomly API specification: student housing data model
Author
Status: Proposed
This document defines a proposed API for exposing Roomly's student housing data and services to external applications. The API described here is a portfolio specification and does not represent a currently deployed public API.
Roomly is a student housing platform that connects students with verified accommodation and provides features including property discovery, bookings, escrow-protected payments, receipt verification, reviews, and roommate matching.
This API is designed around a longer-term vision for Roomly as a student housing data and infrastructure layer. External applications could use the API to discover properties, query availability, retrieve location information, and build housing experiences on top of Roomly's underlying data.
This document defines a proposed API specification aligned with OpenAPI 3.0 standards. It is a portfolio specification and does not represent a currently deployed public API. All endpoints, parameters, and response schemas are designed to be programmatically validatable against future implementations.
What are the API goals?
The API should allow developers to:
- Discover student accommodation
- Filter properties by location, school, price, type, availability, and verification status
- Retrieve detailed property information
- Explore supported schools and locations
- Check property availability
- Retrieve aggregated housing market data
- Build student housing applications and services using Roomly data
The API is designed to be read-oriented in its initial version. Actions involving payments, bookings, withdrawals, and account management remain controlled by Roomly's own application until corresponding public API capabilities are explicitly introduced.
What is the base URL?
The proposed production base URL is:
https://api.roomly.com.ng/v1
The "/v1" path identifies the first version of the API.
Note: This URL is proposed and is not currently presented as a live public API endpoint.
How does authentication work?
Authenticated requests use an API key supplied as a Bearer token.
Authorization: Bearer YOUR_API_KEY
Example:
curl "https://api.roomly.com.ng/v1/properties" \
-H "Authorization: Bearer YOUR_API_KEY"
API keys should be kept private and must not be exposed in client-side applications or committed to source control.
What is the response format?
Successful responses use JSON.
Collection endpoints return their results inside a "data" property:
{
"data": [
{
"id": "prop_123",
"name": "Example Lodge",
"propertyType": "self_contain",
"area": "Bosso",
"school": "FUTMINNA",
"rent": 250000,
"available": true,
"verified": true
}
]
}
Single-resource endpoints return the requested resource directly inside "data":
{
"data": {
"id": "prop_123",
"name": "Example Lodge",
"propertyType": "self_contain",
"area": "Bosso",
"school": "FUTMINNA",
"rent": 250000,
"available": true,
"verified": true
}
}
What resources does the API expose?
The initial API is organized around five primary resources:
| Resource | Purpose |
|---|---|
properties | Student accommodation listings |
schools | Schools and institutions served by Roomly |
areas | Geographic areas where properties are listed |
availability | Current availability information for properties |
market-data | Aggregated housing and pricing information |
How do you work with properties?
Properties are the primary resource in the Roomly API.
How do you list properties?
GET /v1/properties
Returns a paginated list of properties.
What query parameters are supported?
| Parameter | Type | Required | Description |
|---|---|---|---|
school | string | No | Filter by school identifier |
area | string | No | Filter by area identifier |
minPrice | integer | No | Minimum rent |
maxPrice | integer | No | Maximum rent |
propertyType | string | No | Filter by property type |
gender | string | No | Filter by gender preference |
verified | boolean | No | Return only verified properties |
available | boolean | No | Return only currently available properties |
page | integer | No | Page number. Defaults to 1. |
limit | integer | No | Number of results per page. Defaults to 20. |
What property types are supported?
The public Roomly product currently presents property types including:
- Self Contain
- One Bedroom
- Room & Parlor
- Two Bedroom
The API uses machine-readable identifiers for these values:
| Display name | API value |
|---|---|
| Self Contain | self_contain |
| One Bedroom | one_bedroom |
| Room & Parlor | room_parlor |
| Two Bedroom | two_bedroom |
What's an example request?
curl "https://api.roomly.com.ng/v1/properties?area=bosso&propertyType=self_contain&available=true" \
-H "Authorization: Bearer YOUR_API_KEY"
What's an example response?
{
"data": [
{
"id": "prop_123",
"name": "Example Lodge",
"propertyType": "self_contain",
"area": {
"id": "area_bosso",
"name": "Bosso"
},
"school": {
"id": "school_futminna",
"name": "FUTMINNA"
},
"rent": 250000,
"gender": "any",
"available": true,
"verified": true
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 1,
"totalPages": 1
}
}
How do you retrieve a single property?
GET /v1/properties/{propertyId}
Example:
curl "https://api.roomly.com.ng/v1/properties/prop_123" \
-H "Authorization: Bearer YOUR_API_KEY"
Example response:
{
"data": {
"id": "prop_123",
"name": "Example Lodge",
"description": "Student accommodation near FUTMINNA.",
"propertyType": "self_contain",
"rent": 250000,
"gender": "any",
"verified": true,
"available": true,
"area": {
"id": "area_bosso",
"name": "Bosso"
},
"school": {
"id": "school_futminna",
"name": "FUTMINNA"
},
"amenities": ["water", "electricity", "security"]
}
}
How do you work with schools?
Schools represent educational institutions associated with Roomly properties.
How do you list schools?
GET /v1/schools
Returns schools available for property discovery.
Example response:
{
"data": [
{
"id": "school_futminna",
"name": "Federal University of Technology, Minna",
"shortName": "FUTMINNA"
}
]
}
How do you retrieve a single school?
GET /v1/schools/{schoolId}
Returns information about a specific school.
How do you get properties near a school?
GET /v1/schools/{schoolId}/properties
This endpoint provides a convenient way for applications to retrieve accommodation associated with a particular institution.
Example:
curl "https://api.roomly.com.ng/v1/schools/school_futminna/properties" \
-H "Authorization: Bearer YOUR_API_KEY"
How do you work with areas?
Areas represent geographic locations used for property discovery.
How do you list areas?
GET /v1/areas
The API may return areas such as Bosso, Gidan Kwano, Gidan Mangoro, Gidan Painti, Dama, and Albishiri, which are currently presented as popular Roomly locations.
How do you retrieve a single area?
GET /v1/areas/{areaId}
How do you get properties in an area?
GET /v1/areas/{areaId}/properties
Example:
curl "https://api.roomly.com.ng/v1/areas/area_bosso/properties" \
-H "Authorization: Bearer YOUR_API_KEY"
How do you check availability?
Availability allows applications to determine whether a property currently has accommodation available.
How do you check property availability?
GET /v1/properties/{propertyId}/availability
Example response:
{
"data": {
"propertyId": "prop_123",
"available": true,
"availableUnits": 3,
"lastUpdated": "2026-09-05T12:30:00Z"
}
}
Availability data should be treated as time-sensitive. Applications should not assume that a property remains available after retrieving this response.
How do you work with market data?
The market-data resource provides aggregated information rather than individual property records.
This allows developers to build applications that answer questions such as:
- What is the average rent in an area?
- How many verified properties are available?
- Which property types are most common?
- How does pricing vary between areas?
How do you retrieve market data?
GET /v1/market-data
What query parameters are supported?
| Parameter | Type | Required | Description |
|---|---|---|---|
area | string | No | Restrict statistics to an area |
school | string | No | Restrict statistics to a school |
propertyType | string | No | Restrict statistics to a property type |
Example response:
{
"data": {
"area": "Bosso",
"propertyType": "self_contain",
"averageRent": 250000,
"medianRent": 230000,
"availableProperties": 143,
"verifiedProperties": 98
}
}
How do you get area statistics?
GET /v1/areas/{areaId}/statistics
Returns aggregated housing statistics for an area.
How does pagination work?
Collection endpoints use page-based pagination.
GET /v1/properties?page=2&limit=20
A paginated response contains:
{
"pagination": {
"page": 2,
"limit": 20,
"total": 143,
"totalPages": 8
}
}
The maximum permitted "limit" should be enforced by the API to prevent unnecessarily large responses.
How does filtering work?
Filters can be combined in a single request.
Example:
GET /v1/properties?school=school_futminna&area=area_bosso&minPrice=150000&maxPrice=300000&verified=true&available=true
Applications should treat unspecified filters as unrestricted.
If no properties match the supplied filters, the API returns an empty "data" array rather than an error:
{
"data": [],
"pagination": {
"page": 1,
"limit": 20,
"total": 0,
"totalPages": 0
}
}
How does sorting work?
Collection endpoints may support sorting using the "sort" and "order" parameters.
GET /v1/properties?sort=rent&order=asc
Supported sorting fields should be limited to fields for which predictable ordering is available:
- "rent"
- "createdAt"
- "updatedAt"
What are the error codes?
The API uses standard HTTP status codes.
| Status | Meaning |
|---|---|
200 | Request succeeded |
400 | Invalid request |
401 | Authentication required or invalid |
403 | Request not permitted |
404 | Resource not found |
429 | Rate limit exceeded |
500 | Internal server error |
Errors use a consistent response structure:
{
"error": {
"code": "PROPERTY_NOT_FOUND",
"message": "The requested property does not exist."
}
}
Example: invalid request
{
"error": {
"code": "INVALID_PARAMETER",
"message": "maxPrice must be greater than or equal to minPrice."
}
}
Applications should use the HTTP status code for broad error handling and the error code for application-specific handling.
What are the rate limits?
The proposed API should enforce rate limits to protect the service from excessive requests.
Authenticated applications may initially receive:
1,000 requests per hour
When a client exceeds its limit, the API returns:
429 Too Many Requests
Rate limits may vary by API plan and can be changed as the service scales.
Note: These limits are part of the proposed API design and are not current Roomly production limits.
How does versioning work?
The API uses URL-based versioning.
https://api.roomly.com.ng/v1/
Breaking changes should result in a new API version rather than silently changing the behaviour of an existing version.
Example:
/v1/properties
/v2/properties
Existing API versions should remain available for a defined deprecation period before removal.
How are resources related?
Roomly resources are related through stable identifiers.
A property belongs to an area and may be associated with a school.
Property
├── Area
├── School
├── Property Type
├── Amenities
└── Availability
Applications should use resource IDs when making API requests rather than relying on display names.
Example:
area_bossois preferred overBossowhen requesting a specific area.
What operations are available?
The initial proposed API focuses on read operations.
Available in the initial API design
GET /v1/properties
GET /v1/properties/{propertyId}
GET /v1/properties/{propertyId}/availability
GET /v1/schools
GET /v1/schools/{schoolId}
GET /v1/schools/{schoolId}/properties
GET /v1/areas
GET /v1/areas/{areaId}
GET /v1/areas/{areaId}/properties
GET /v1/areas/{areaId}/statistics
GET /v1/market-data
Future capabilities
Write operations could eventually expose selected Roomly functionality, including:
- Creating or updating listings
- Managing availability
- Creating reservations
- Retrieving booking information
- Managing reviews
- Receipt verification
- Partner integrations
These operations require additional authentication, authorization, validation, and security considerations and are outside the scope of this initial specification.
What are the API design principles?
The proposed API follows these principles:
- Resource-oriented URLs — URLs represent resources rather than actions.
- Predictable responses — related endpoints use consistent response structures.
- Explicit filtering — clients can narrow results without requiring separate endpoints for every use case.
- Stable identifiers — resources are referenced by IDs rather than display names.
- Versioned contracts — breaking changes are isolated behind API versions.
- Progressive capability — the initial API exposes useful read operations before introducing higher-risk write operations.
- Developer usability — endpoints, parameters, responses, and errors should be predictable enough for developers to integrate without needing access to Roomly's internal implementation.
What's the proposed API surface summary?
Properties
GET /v1/properties
GET /v1/properties/{propertyId}
GET /v1/properties/{propertyId}/availability
Schools
GET /v1/schools
GET /v1/schools/{schoolId}
GET /v1/schools/{schoolId}/properties
Areas
GET /v1/areas
GET /v1/areas/{areaId}
GET /v1/areas/{areaId}/properties
GET /v1/areas/{areaId}/statistics
Market Data
GET /v1/market-data
This specification serves as the proposed contract from which the Roomly Developer Guides can be written.
The guides will explain how to accomplish specific tasks with this API, while this specification defines what the API exposes and how its contract behaves.