Sophia PMS – Partner API (v1)
Overview
The Sophia PMS Partner API (v1) is a read-only API that enables authorized partners to retrieve data from hotels using Sophia PMS.
The API provides access to hotel properties, reservations, revenue reports, occupancy metrics, channel mix, and room availability. It allows partners to integrate hotel operational data into their own applications, reporting platforms, and business intelligence solutions.
Key Features
- Hotel Properties: Retrieve the list of hotels accessible to the API key.
- Reservations (Bookings): Retrieve booking lists and details, including guest information, room types, reservation status, rates, and stay dates.
- Revenue and Performance Reports: Access revenue, Occupancy, Average Daily Rate (ADR), and Revenue per Available Room (RevPAR).
- Channel Mix: Analyze revenue and room-night distribution by market segment or booking source.
- Room Availability: Retrieve available room inventory by room type and date, including future dates.
1. Connection Information
| Property | Value |
|---|---|
| API Version | v1 |
| Base URL | https://app.sophiapms.com/api/partner/v1 |
| Data Format | JSON (UTF-8) |
| HTTP Method | GET only |
| Protocol | HTTPS required |
| Maximum Date Range | 30 days per request |
The API is read-only and supports GET requests only. All requests must use HTTPS.
Endpoint Reference
| Category | Endpoint | Description |
|---|---|---|
| Properties | GET /properties | Retrieve accessible hotel properties |
| Bookings | GET /bookings | Retrieve booking lists |
| Bookings | GET /bookings/{booking_id} | Retrieve booking details |
| Reports | GET /reports/summary | Revenue, Occupancy, ADR, and RevPAR |
| Reports | GET /reports/channel-mix | Revenue and distribution by booking channel |
| Inventory | GET /inventory/vacant | Available rooms by room type |
2. API Authentication
Sophia issues each partner an API key in the format spk_.... The key must be included in the user-api-key HTTP header of every request.
GET /api/partner/v1/properties Host: app.sophiapms.com user-api-key: spk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Security Requirements
- Never pass the API key through a query string.
- Each API key can access only the hotel properties explicitly assigned to it.
- API keys are stored as hashes and cannot be retrieved in their original form.
- If a key is lost, contact Sophia to request a replacement. The previous key will be deactivated immediately.
- When a key is revoked, requests using that key will be rejected within a maximum of one minute.
Partners must keep API keys confidential and must not expose them in public source code or share them with unauthorized systems.
3. Rate Limits
The API enforces rate limits per API key and hotel property.
| Limit | Default Value |
|---|---|
| Requests per minute per API key and property | 20 requests |
| Concurrent booking-list requests for the same property | 1 request |
Limits may be adjusted for individual API keys.
Successful responses include the following headers:
- X-RateLimit-Limit: Maximum number of requests allowed per minute.
- X-RateLimit-Remaining: Number of requests remaining in the current minute.
When the limit is exceeded, the API returns HTTP 429 Too Many Requests with a Retry-After header indicating how many seconds to wait before retrying.
Recommended Practices
- Synchronize data periodically, for example every 5–15 minutes, depending on business requirements.
- Process requests sequentially for each hotel property.
- Avoid concurrent requests for the same property.
- Respect the Retry-After header when receiving a 429 response.
- Use pagination to retrieve all available records.
4. Response Format and Error Codes
4.1. Successful Responses
List endpoints generally return the following structure:
{
"data": [
{
"id": "...",
"type": "...",
"attributes": {}
}
],
"meta": {
"page": 1,
"limit": 50,
"total": 120
}
}
Depending on the endpoint, data may be an array or an object containing data fields and nested collections.
4.2. Error Responses
{
"errors": {
"code": "validation_error",
"title": "property_id is required."
}
}
4.3. HTTP Error Codes
| HTTP Status | Error Code | Description |
|---|---|---|
| 400 | validation_error | Missing or invalid parameters |
| 401 | unauthorized | Missing, invalid, or revoked API key |
| 403 | forbidden | The API key does not have access to the requested property |
| 403 | https_required | The request uses HTTP instead of HTTPS |
| 404 | not_found | Booking or property not found |
| 429 | too_many_requests | Rate limit exceeded or another request is running for the same property |
| 500 | server_error | Internal server error; retry later |
| 503 | report_unavailable | The report is temporarily unavailable |
4.4. Data Conventions
- Dates use the yyyy-MM-dd format.
- Datetimes use the yyyy-MM-ddTHH:mm:ss format and the hotel's local time zone (UTC+7).
- Monetary values are numeric and use the hotel's currency, typically VND.
- Fields without available data are returned as null.
5. Hotel Properties
Endpoint: GET /properties
This endpoint returns the list of hotel properties accessible to the API key. The id field is the property_id required by the other endpoints.
Example request:
curl -H "user-api-key: spk_xxx" \ "https://app.sophiapms.com/api/partner/v1/properties"
Example response:
{
"data": [
{
"id": 10,
"type": "property",
"attributes": {
"id": 10,
"title": "Demo Sophia Hotel",
"code": "DEMO",
"address": "123 Le Loi",
"city": "Ho Chi Minh",
"country": "VN"
}
}
],
"meta": {
"total": 1
}
}
Partners should call this endpoint before requesting bookings, reports, or room inventory.
6. Booking List
Endpoint: GET /bookings
This endpoint retrieves bookings by hotel property, arrival date range or departure date range, room status, and pagination parameters.
6.1. Request Parameters
| Parameter | Required | Description |
|---|---|---|
| property_id | Yes | Hotel property ID |
| arrival_from, arrival_to | Conditional | Arrival date range; inclusive, in yyyy-MM-dd format |
| departure_from, departure_to | Conditional | Departure date range; inclusive, in yyyy-MM-dd format |
| status | No | One or more room statuses, separated by commas |
| page | No | Page number, starting at 1; defaults to 1 |
| limit | No | Number of bookings per page; defaults to 50, maximum 100 |
At least one date range—arrival or departure—must be provided. If both ranges are supplied, the results must satisfy both conditions.
- The _from and _to parameters must be supplied together.
- The end date cannot be earlier than the start date.
- Each date range is limited to 30 calendar days, inclusive.
- Each returned record represents a booking group with the same arrival and departure dates. Rooms in a group booking with different stay dates are returned as separate records sharing the same booking_id.
- Cancelled rooms are excluded. A booking with all rooms cancelled is not returned.
- When filtering by status, a booking group is returned if at least one room matches the requested status. Its rooms array contains all non-cancelled rooms in that group.
- Pagination and meta.total are based on the number of booking records, not the number of rooms.
- Results are sorted by arrival date in ascending order.
Example request:
curl -H "user-api-key: spk_xxx" \ "https://app.sophiapms.com/api/partner/v1/bookings?property_id=10&arrival_from=2026-10-01&arrival_to=2026-10-30&status=pending,checked_in&page=1&limit=50"
To retrieve all records, increment page until page * limit >= meta.total.
6.2. Group Booking Example
Suppose booking BK000123 contains four rooms:
| Room | Arrival | Departure | Status |
|---|---|---|---|
| 101 | 2026-10-05 | 2026-10-07 | pending |
| 102 | 2026-10-05 | 2026-10-07 | pending |
| 103 | 2026-10-06 | 2026-10-08 | pending |
| 104 | 2026-10-05 | 2026-10-07 | cancelled |
The API returns two records because room 103 has different stay dates and room 104 has been cancelled.
| Record ID | Arrival | Departure | Rooms |
|---|---|---|---|
| {booking_id}_20261005_20261007 | 2026-10-05 | 2026-10-07 | 101, 102 |
| {booking_id}_20261006_20261008 | 2026-10-06 | 2026-10-08 | 103 |
7. Booking Details
Endpoint: GET /bookings/{booking_id}?property_id={property_id}
| Parameter | Required | Description |
|---|---|---|
| booking_id | Yes | Booking GUID obtained from the booking list |
| property_id | Yes | Hotel property ID |
The response follows the same structure as the booking list, with data returned as an array. A group booking may contain multiple groups with different arrival and departure dates.
The API returns 404 not_found if the booking cannot be found or all its rooms have been cancelled.
7.1. Booking Fields
| Field | Description |
|---|---|
| id | Booking-group ID in the format {booking_id}_{arrival yyyyMMdd}_{departure yyyyMMdd}. Use as the partner-side group key. If stay dates change, a room may move to a group with a new ID; use rooms[].id to track individual rooms. |
| booking_id | Booking GUID in Sophia PMS, used by the details endpoint |
| property_id | Hotel property ID |
| booking_code | Booking reference in Sophia PMS |
| ota_reservation_code | OTA or Channel Manager reservation code, if available |
| is_group | Indicates whether the booking is a group booking |
| source | Booking source object containing id and name |
| arrival_date, departure_date | Arrival and departure dates for the group |
| nights | Number of nights |
| rooms_count | Number of rooms in the group |
| amount | Total room amount for the group, equal to the sum of rooms[].amount |
| notes | Booking notes |
| customer | Booking contact; if unavailable, the primary guest of the first room may be used. May be null. |
| created_at, updated_at | Creation and latest update timestamps for the booking or any room |
| rooms | Array of rooms in the booking group |
7.2. Room Fields
| Field | Description |
|---|---|
| id | Room reservation GUID |
| reservation_number | Room reservation number |
| ota_reservation_code | OTA reservation code, if available |
| status, status_code | Room status, as defined in Section 8 |
| rent_type | Rental type: day_night, monthly, or hourly |
| room_type | Room type object containing id and name |
| room | Assigned physical room; null if not yet assigned |
| occupancy | Number of adults, children, and infants |
| rate | Room rate; for monthly rentals, the rate for one month |
| discount_percent | Discount percentage |
| breakfast | Indicates whether breakfast is included |
| amount | Room amount before discount: sum of days[].rate; if days is absent, rate multiplied by the number of nights. For monthly rentals, it equals rate. |
| days | Daily rates (date, rate). For monthly rentals, each entry represents a monthly billing period starting on date. |
| guest | Primary guest for the room; may be null |
| created_at, updated_at | Room creation and update timestamps |
8. Room Statuses
Room status is defined for each rooms[].status entry, not for the booking as a whole.
| status | status_code | Description |
|---|---|---|
| pending | 0 | Reserved, not yet checked in |
| checked_in | 1 | Guest is currently staying |
| checked_out | 2 | Guest has checked out |
| cleaned | 3 | Guest has checked out and the room has been cleaned |
| no_show | 4 | Guest did not arrive |
The status filter accepts only the values listed above. Passing cancelled or another unsupported value returns 400 validation_error.
Cancelled rooms are not returned. If a room disappears from a synchronization result for the same date range, it may have been cancelled or moved to a different date group. Call the booking details endpoint to verify its current state.
9. Revenue and Performance Reports
The reporting endpoints share the following parameters:
| Parameter | Required | Description |
|---|---|---|
| property_id | Yes | Hotel property ID |
| from | Yes | Start date in yyyy-MM-dd format |
| to | Yes | End date in yyyy-MM-dd format |
The date range is inclusive and limited to 30 days per request. These endpoints use the same API key and rate limits as booking endpoints.
9.1. Revenue Calculation Rules
Revenue includes amounts already posted to the folio, such as posted room charges and entered services. Therefore, to must not be later than the hotel's current business date, returned in meta.business_date.
- revenue: Revenue including VAT and service charges.
- revenue_ex_vat: Revenue excluding VAT but including service charges.
- total: Total revenue.
- room: Room revenue.
- extra: Service revenue.
Room revenue is calculated by stay night, while service revenue is calculated by posting date.
room_nights_sold counts nights with posted room revenue greater than 10. Complimentary room nights with a rate of zero are excluded. room_nights_available is calculated from rooms in operation, excluding virtual and combined room types and subtracting OOO rooms for each date.
9.2. Revenue, Occupancy, ADR, and RevPAR
Endpoint: GET /reports/summary
Example request:
curl -H "user-api-key: spk_xxx" \ "https://app.sophiapms.com/api/partner/v1/reports/summary?property_id=10&from=2026-10-01&to=2026-10-27&group_by=week"
The optional group_by parameter supports:
| Value | Description |
|---|---|
| day | Daily grouping; default |
| week | Weekly grouping, starting Monday |
| month | Monthly grouping |
| year | Yearly grouping |
The response includes totals for the entire requested date range and periods[] for individual reporting periods. The first or last period may cover only part of a week or month.
| Field | Description |
|---|---|
| period | Period key: date (yyyy-MM-dd), Monday of the week, month (yyyy-MM), or year (yyyy); null for totals |
| from, to | Part of the period included in the requested date range |
| days | Number of days in the included period |
| revenue | Revenue including VAT and service charges: total, room, and extra |
| revenue_ex_vat | Revenue excluding VAT but including service charges: total, room, and extra |
| room_nights_sold | Sold room nights with room revenue greater than 10 |
| room_nights_available | Available room nights after subtracting OOO rooms for each date |
| out_of_order_room_nights | Number of OOO room nights |
| occupancy_percent | Occupancy percentage, or null if the denominator is zero |
| adr, adr_ex_vat | Average room rate per sold night, including or excluding VAT |
| revpar, revpar_ex_vat | Room revenue per available room night, including or excluding VAT |
Calculation formulas:
- Occupancy (%) = room_nights_sold / room_nights_available × 100.
- ADR = Room revenue / room_nights_sold.
- RevPAR = Room revenue / room_nights_available.
The corresponding excluding-VAT metrics use room revenue excluding VAT. The data object also includes property_id, from, to, group_by, currency, and sellable_rooms (rooms in operation before subtracting OOO rooms). The API returns null when a denominator is zero.
9.3. Channel Mix
Endpoint: GET /reports/channel-mix
This endpoint provides revenue and distribution by market segment or booking source.
Example request to retrieve data by booking source:
curl -H "user-api-key: spk_xxx" \ "https://app.sophiapms.com/api/partner/v1/reports/channel-mix?property_id=10&from=2026-10-01&to=2026-10-27&level=source"
The level parameter supports:
- segment (default): Groups data by market segment, such as OTA, Travel Agent, Direct, or Corporate.
- source: Groups data by individual booking source, such as Booking.com, Agoda, or a corporate account, and includes the associated market segment.
| Field | Description |
|---|---|
| id, name | Segment or source ID and name |
| segment | Associated segment; available when level=source. It is null when level=segment. |
| revenue | Revenue including VAT and service charges |
| revenue_ex_vat | Revenue excluding VAT but including service charges |
| room_nights | Sold room nights for the channel |
| adr, adr_ex_vat | Average room rate for the channel |
| share_percent | Percentage of total revenue, including VAT |
| room_nights_share_percent | Percentage of total sold room nights |
Sources without an assigned segment are grouped under Other, with id = 0. The items array is sorted by descending revenue. The totals object contains overall revenue, revenue_ex_vat, room_nights, adr, and adr_ex_vat.
10. Room Availability by Room Type
Endpoint: GET /inventory/vacant
This endpoint returns the number of rooms in operation, sold or reserved rooms, OOO rooms, and vacant rooms by date and room type.
Example request:
curl -H "user-api-key: spk_xxx" \ "https://app.sophiapms.com/api/partner/v1/inventory/vacant?property_id=10&from=2026-10-28&to=2026-11-05"
Future dates are supported. Availability is calculated based on existing bookings at the time of the request.
| Field | Description |
|---|---|
| id, name | Room type ID and name |
| total_rooms | Number of rooms in operation for the room type |
| sold | Rooms sold or reserved for the date, including reservations not yet checked in and current stays |
| out_of_order | Number of OOO rooms for the date |
| vacant | Number of vacant rooms |
Formula:
vacant = max(0, total_rooms - sold - out_of_order)
Virtual and combined room types are excluded. The days[] array contains daily availability data. Each days[].room_types[] array contains room-type details, while days[].totals provides the total for the date.
Note: Room availability changes as bookings are created or updated. Partners should retrieve this endpoint when current availability is required rather than storing results for extended periods.
11. cURL Examples
Retrieve accessible properties:
curl -H "user-api-key: spk_xxx" \ "https://app.sophiapms.com/api/partner/v1/properties"
Retrieve bookings:
curl -H "user-api-key: spk_xxx" \ "https://app.sophiapms.com/api/partner/v1/bookings?property_id=10&arrival_from=2026-10-01&arrival_to=2026-10-30"
Retrieve booking details:
curl -H "user-api-key: spk_xxx" \ "https://app.sophiapms.com/api/partner/v1/bookings/8b7d6e5f-0000-0000-0000-000000000000?property_id=10"
Retrieve weekly revenue, Occupancy, ADR, and RevPAR:
curl -H "user-api-key: spk_xxx" \ "https://app.sophiapms.com/api/partner/v1/reports/summary?property_id=10&from=2026-10-01&to=2026-10-27&group_by=week"
Retrieve channel mix by source:
curl -H "user-api-key: spk_xxx" \ "https://app.sophiapms.com/api/partner/v1/reports/channel-mix?property_id=10&from=2026-10-01&to=2026-10-27&level=source"
Retrieve room availability by room type, including future dates:
curl -H "user-api-key: spk_xxx" \ "https://app.sophiapms.com/api/partner/v1/inventory/vacant?property_id=10&from=2026-10-28&to=2026-11-05"
C# Integration Example
The following example demonstrates how to send a request using HttpClient and wait when the rate limit is reached.
using System;
using System.Net.Http;
using System.Threading.Tasks;
public class SophiaPartnerApi
{
public static async Task Main()
{
using (var http = new HttpClient
{
BaseAddress = new Uri(
"https://app.sophiapms.com/api/partner/v1/")
})
{
http.DefaultRequestHeaders.Add("user-api-key", "spk_xxx");
var res = await http.GetAsync(
"bookings?property_id=10&arrival_from=2026-10-01&arrival_to=2026-10-30");
if ((int)res.StatusCode == 429)
{
var wait = res.Headers.RetryAfter?.Delta
?? TimeSpan.FromSeconds(60);
await Task.Delay(wait);
res = await http.GetAsync(
"bookings?property_id=10&arrival_from=2026-10-01&arrival_to=2026-10-30");
}
var json = await res.Content.ReadAsStringAsync();
Console.WriteLine(json);
}
}
}
This example demonstrates basic request handling and rate-limit recovery. Production integrations should also implement HTTP status validation, error handling, pagination, and appropriate retry policies.
12. Data Synchronization Guidelines
12.1. Booking Synchronization
- Call /properties to retrieve the list of accessible properties.
- For each property, retrieve upcoming bookings using an arrival date range from today through today + 29 days.
- Retrieve current stays using status=checked_in with an appropriate departure date range.
- Process every page until all records have been retrieved.
- Compare new records with stored data using booking id, rooms[].id, and updated_at to detect changes.
If a room no longer appears in the results for the same date range, call /bookings/{booking_id} to verify its current state. If the details endpoint returns 404, the entire booking has been cancelled or no longer exists under the API's rules.
12.2. Report Synchronization
- Revenue may change when hotel staff modify folio entries. Retrieve the previous day's data after the hotel completes its night audit, for example, every morning.
- For more accurate monthly figures, periodically refresh data for the current month.
- Split date ranges longer than 30 days into multiple requests, each covering no more than 30 days.
- When consolidating multiple periods, recalculate Occupancy, ADR, and RevPAR from the corresponding totals instead of averaging individual period percentages or rates.
- Do not set to later than meta.business_date; doing so returns 400 validation_error.
12.3. Rate-Limit Handling
When receiving 429 Too Many Requests, wait for the duration specified by Retry-After before retrying. Requests for the same hotel property should be processed sequentially.
13. Support
For API key replacement, additional property access, or rate-limit adjustments, please contact the Sophia PMS team.
Sophia PMS – Hotel Management System
Website: https://sophiasolution.com/
API Base URL: https://app.sophiapms.com/api/partner/v1
This documentation applies to Sophia PMS Partner API version v1.
Category
29/10

