Conventions that apply to every endpoint — the URL structure, headers, response shape, pagination, errors, retries and rate limits. Read this once and every endpoint page will make sense.
Base URL and versioning#
{base_url}/api/v1/{resource}
{base_url} is the Standard Interface base URL for your environment. The UAT and production values are listed once, under Standard Interface Endpoints on the Introduction page.The /stdinterface segment is part of the base URL, not the resource path. A full URL looks like:{base_url}/api/v1/companies?page=1&pageSize=10
The API version lives in the path. Anything published under /api/v1/ keeps its current behaviour — a future /api/v2/ will be introduced alongside it rather than replacing it, so your integration will not break underneath you.
Always use HTTPS. Plain HTTP is not supported.
| Header | When | Value |
|---|
Authorization | Every authenticated request | Bearer {access_token} |
Accept | Always | application/json |
Content-Type | POST and PUT requests | application/json |
X-Region-Identifier | Region-routed endpoints only — see below | e.g. mumbai |
A small number of endpoints are region-routed rather than token-scoped, because they are used before you have a token — to discover which region and property you should be working with.| Endpoint | Token required | X-Region-Identifier required |
|---|
GET /api/v1/regions | No | No |
GET /api/v1/properties | No | Yes |
GET /api/v1/properties/licenses | No | Yes |
| Everything else | Yes | No |
Call GET /api/v1/regions first to get the list of valid region identifiers, then pass the one you want in the header.A missing or unknown X-Region-Identifier is rejected with 400 Bad Request. The value is validated against the active region list rather than being used directly, so a typo fails loudly instead of silently returning another region's data.
Tenancy and the companyId#
Almost every endpoint takes a companyId query parameter identifying the property (hotel) you are working with. Get it from GET /api/v1/companies — see Quick Start, step 3.Your credentials are bound to one customer and one product. You cannot reach another customer's data by guessing an ID: a companyId outside your grant returns 404 Not Found, not 403. So if you get a 404 for a record you know exists, check that it belongs to your customer before assuming the record is missing.
The response envelope#
Every Standard Interface endpoint returns the same JSON envelope. The payload is always in data; the fields around it are the same shape whether the call succeeded or failed.| Field | Type | What it is |
|---|
success | boolean | true if the call succeeded |
message | string | null | Human-readable message. Populated on errors, usually null on success |
errorCode | string | null | Machine-readable error identifier. null on success |
statusCode | integer | null | The HTTP status code, repeated in the body |
data | object | array | null | The payload. null on errors |
timestamp | string (ISO 8601) | When the response was generated, in UTC |
Success#
{
"success": true,
"message": null,
"errorCode": null,
"statusCode": 200,
"data": { },
"timestamp": "2026-08-27T09:14:22.481Z"
}
Error#
{
"success": false,
"message": "companyId is required",
"errorCode": "VALIDATION_ERROR",
"statusCode": 400,
"data": null,
"timestamp": "2026-08-27T09:14:22.481Z"
}
Branch on errorCode where you need to handle a specific condition, and on success or the HTTP status otherwise.if (body.errorCode === "VALIDATION_ERROR")
if (body.message === "companyId is required") — the wording can change.
List endpoints are paginated with two query parameters.| Parameter | Default | Maximum |
|---|
page | 1 | — |
pageSize | 10 | 100 (reservation endpoints allow up to 500) |
Reservation endpoints allow a larger page size so that bulk or first-time loads need fewer calls.pageSize is capped silently, not rejected. Ask for pageSize=1000 and you get 100 (or 500 on reservation endpoints) with a 200, not a 400. Always read pageSize back from the response rather than assuming you got what you asked for — otherwise your paging arithmetic will be wrong and will quietly skip records.
page below 1 is rejected with 400 Bad Request.The data object on a paginated response carries the page metadata alongside the items:{
"success": true,
"statusCode": 200,
"data": {
"items": [ ],
"pageNumber": 1,
"pageSize": 10,
"totalCount": 137,
"totalPages": 14,
"hasPrevious": false,
"hasNext": true
},
"timestamp": "2026-08-27T09:14:22.481Z"
}
Always page to the end. Use hasNext rather than comparing counts yourself:Do not assume a single page holds everything, even in testing — a UAT property with three reservations becomes a production property with three thousand.
HTTP status codes#
| Code | Meaning | What it usually means for you |
|---|
| 200 | Success | — |
| 201 | Resource created | — |
| 204 | No content | The call succeeded and there is nothing to return |
| 400 | Bad request | A parameter is missing or invalid. Fix the request; retrying will not help |
| 401 | Unauthorized | Token missing, expired or invalid. Get one fresh token and retry once |
| 403 | Forbidden | Your token lacks the required permission. Refreshing will not help — see Authentication |
| 404 | Not found | The record does not exist, or it belongs to another customer |
| 409 | Conflict | The request conflicts with the current state, e.g. a duplicate |
| 422 | Validation failed | The body was well-formed but failed business validation |
| 429 | Too many requests | Back off and retry later. Never treat this as token expiry |
| 500 | Internal server error | Transient. Retry with exponential backoff; if it persists, contact support with the request details |
One important exception#
401 responses do not use the standard envelope. They return an RFC 7807 ProblemDetails body instead. Your error handling must cope with both shapes — a parser that assumes success and errorCode are always present will throw on a 401, which is exactly the moment you most need a clear error message.
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.2",
"title": "Unauthorized",
"status": 401,
"detail": null,
"instance": "/api/v1/companies"
}
Token endpoint errors use a third shape again (error_code / error_description / error_uri). Those are covered on Authentication.
Retries and backoff#
Retrying the wrong status code is the fastest way to turn a small problem into an outage.Retry 429 and 5xx with exponential backoff and jitter. Retry a 401 exactly once, after refreshing the token.
Retry a 400, 403, 404, 409 or 422 — each will fail identically the second time.
Jitter matters. Without it, every one of your workers retries at the same instant and you re-create the spike you were backing off from.
Never treat 429 as token expiry. 429 means slow down; 401 means get a new token.
Never refresh a token on 403. A new token carries the same permissions and fails the same way.
Set request timeouts and a cap on total retries, so a slow dependency degrades your integration rather than hanging it.
Caching#
Cache reference data. Countries, currencies, payment methods, room types and reservation statuses change rarely. Fetch them at startup, not per request.
Cache the companyId list. Call GET /api/v1/companies once at startup rather than hardcoding IDs or re-fetching them.
Rate limits#
Today, only the token endpoint is rate limited. Exceeding it returns 429 with error_code RATE_LIMITED, and no Retry-After header is sent — you must choose your own back-off.When you get a 429 on the token endpoint, back off and then reuse the token you already hold rather than requesting another one. Requesting a token per API call is the usual cause.Standard Interface business endpoints are not throttled at present.Coming soon. Per-feature rate limits based on subscription tiers, with independent read and write limits for Reservations, Rates and Inventory. This is not applied to live traffic yet and must not be built against as though it were.Build your client to handle 429 from any endpoint now, so that enforcement going live is not a breaking change for you. See Retries and backoff above. Exact limits are environment settings and can change without a code release. Ask the WinCloud Support Team for the figures that apply to your environment.
Support#
Contact the WinCloud Support Team for API behaviour, and for credentials, access and token problems.When you raise an issue, include:the errorCode or error_code, and the HTTP status
the environment (UAT or production) and the full URL you called
the time of the request, with timezone
Never send your client secret, in a ticket, a screenshot, a chat message or a log extract. If a secret has been shared by accident, ask your administrator to rotate it immediately.