Joivy API Documentation GUIDE
Open Reference

Getting started with the Joivy Partner API

This guide explains how to authenticate and call the Joivy Partner API endpoints documented at xfeedreference.joivy.com. The reference is built on Scalar and exposes two OpenAPI specs: one for OAuth2 authentication and one for the main API.

1
Get your client credentials
You need a client_id and client_secret issued by Joivy. These are used to obtain a bearer token from the identity provider.
2
Request an access token
Call the OAuth2 POST /token endpoint on the Authentication – OAuth2 spec. You'll receive a Bearer token valid for 3600 seconds.
3
Query availability & commercial conditions
Use GET /api/Availability/{bedCode} to check if a bed is bookable, and GET /CommercialCondition/v2 to retrieve pricing, deposit, and discount details.
4
Create a booking
Optionally validate the tenant's tax code first with POST /Booking/ValidateTaxCode, then submit the booking with POST /Booking.

The OpenAPI specs #

The reference loads three distinct specs. Switch between them using the dropdown at the very top of the sidebar — it currently reads Main API, Authentication – OAuth2, or Authentication – API Key.

Spec 1 — Business logic
Main API
OpenAPI 3.0.1 · v1.0.0
All partner endpoints: availability, bookings, commercial conditions, rentables, and more.
Spec 2 — Authentication (OAuth2)
Authentication – OAuth2
OpenAPI 3.0.3 · v1.0.0
Single endpoint: POST /token
Used to obtain bearer tokens.
Spec 3 — Authentication (API Key)
Authentication – API Key
OpenAPI 3.0.3 · v1.0.0
Endpoints: POST /apikey/generate and a sample protected resource.
Describes the X-API-KEY header scheme.
Pick the authentication method required by the endpoint you need to call: most Main API endpoints use OAuth2 bearer tokens, while a few (such as GET /api/Ubiflow/Beds) require an API Key sent in the X-API-KEY header. Each spec has a Download OpenAPI Document link at the top of its page (JSON and YAML).

OAuth2 Client Credentials flow #

The API uses OAuth2 Client Credentials. There is no user login — your application authenticates directly using its own client_id and client_secret.

🔑
client_id
client_secret
POST /token
ciamlogin
🎟
access_token
3600 s
Authorization:
Bearer …

The identity provider is Microsoft Entra ID (Azure AD) hosted on Joivy's tenant. The token endpoint is:

URL
https://joivysuppliers.ciamlogin.com/0d098523-a320-480a-b0fb-21dedf5231fd/oauth2/v2.0/token

Getting a token #

In the reference, open the Authentication – OAuth2 spec and click Get access token (Client Credentials). The body must be sent as application/x-www-form-urlencoded with the four required fields below.

client_idstringrequiredYour application client ID
client_secretstringrequiredYour application client secret
grant_typestringrequiredMust be client_credentials
scopestringrequiredapi://43869ec9-dd76-46ef-84c9-6de401dafd27/.default
cURL
curl https://joivysuppliers.ciamlogin.com/0d098523-a320-480a-b0fb-21dedf5231fd/oauth2/v2.0/token \
  --request POST \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=client_credentials' \
  --data-urlencode 'client_id=<your-client-id>' \
  --data-urlencode 'client_secret=<your-client-secret>' \
  --data-urlencode 'scope=api://43869ec9-dd76-46ef-84c9-6de401dafd27/.default'
Response 200
{
  "token_type":     "Bearer",
  "expires_in":     3600,
  "ext_expires_in": 3600,
  "access_token":   "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Token expiry: tokens are valid for exactly 3600 seconds (1 hour). Build token caching into your integration and re-request before expiry to avoid 401 Unauthorized errors on API calls.

Using the token #

Most Main API endpoints are marked Auth Required and use OAuth2. Pass the token in every request via the Authorization header:

JavaScript
// 1. Obtain token
const tokenRes = await fetch(
  'https://joivysuppliers.ciamlogin.com/0d098523-a320-480a-b0fb-21dedf5231fd/oauth2/v2.0/token',
  {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type:    'client_credentials',
      client_id:     CLIENT_ID,
      client_secret: CLIENT_SECRET,
      scope:         'api://43869ec9-dd76-46ef-84c9-6de401dafd27/.default'
    })
  }
);
const { access_token } = await tokenRes.json();

// 2. Call any Main API endpoint
const res = await fetch('/api/Availability/BED001', {
  headers: { 'Authorization': `Bearer ${access_token}` }
});

API Key authentication #

In addition to OAuth2, a subset of endpoints accept an API Key as their authentication scheme. The full spec is documented under Authentication – API Key in the spec switcher.

The API Key must be sent on every request in the X-API-KEY HTTP header. Endpoints currently protected by this scheme include:

GET/api/Ubiflow/BedsUbiflow feed — requires X-API-KEY
POST/apikey/generateGenerate a new API key (auth-apikey spec)
GET/protected/resourceSample protected endpoint (auth-apikey spec)

Security scheme

typeapiKeyOpenAPI apiKey security scheme
inheaderThe key is transported in an HTTP header
nameX-API-KEYExact header name expected by the API
cURL
curl '/api/Ubiflow/Beds' \
  -H 'X-API-KEY: <your-api-key>'

Obtaining an API Key

An API Key can be generated through the POST /apikey/generate endpoint described in the Authentication – API Key spec. This endpoint is itself protected and typically requires a valid OAuth2 bearer token to be called.

Response 200
{
  "apiKey":    "sk_live_1234567890abcdef",
  "createdAt": "2026-01-01T12:00:00Z"
}

Trying it from the reference

To call an API Key protected endpoint via Try it out:

1
Open the endpoint in the reference
For example, GET /api/Ubiflow/Beds in the Main API spec, or any endpoint in the Authentication – API Key spec.
2
Click the 🔒 lock icon and pick apiKeyHeader
In the authorization dialog, paste your key into the X-API-KEY value field. Scalar will inject the header on every subsequent request in the session.
3
Send the request
If the key is invalid or missing, the API responds with 401 Unauthorized.
Never embed an API Key in client-side code. The key grants direct access to protected endpoints without a user context — keep it on the server side and rotate it via POST /apikey/generate if it is ever exposed.

Availability #

Check whether a specific bed can be booked and retrieve its available check-in/check-out windows before presenting options to a tenant.

GET/api/Availability/{bedCode}Gets availability by bed code

Query parameters

bedCodestring · pathrequiredThe bed code identifier
checkInDatestring · date-timeRFC 3339, e.g. 2025-09-01T00:00:00Z
checkOutDatestring · date-timeRFC 3339 checkout date
commercialConditionsIdstringOptional — filter to a specific commercial condition
cURL
curl '/api/Availability/BED001?checkInDate=2025-09-01T00:00:00Z&checkOutDate=2026-06-30T00:00:00Z' \
  -H 'Authorization: Bearer <access_token>'

The response includes status (Occupied / Available), arrays of valid checkInDates and validCheckoutDates, and evaluedExitWindows with pricing per exit window. Use salableOnline to check if the bed can be booked through your portal.

CommercialCondition #

Retrieve the full pricing and contractual conditions for a bed before creating a booking. The values returned here must be forwarded directly into the booking request body.

GET/CommercialCondition/v2Gets commercial conditions (reads from units collection)

Query parameters

bedCodestringThe unit/bed code
datestring · date-timeThe target check-in date
commercialConditionsIdstringCommercial condition ID for private sales
couponCodestringOptional coupon code
checkoutDatestring · date-timeThe target checkout date
Key fields to carry forward into POST /Booking: priceprice, discountedPricediscountedPrice, discountUntildiscountUntil, depositAmountdeposit, confirmationDepositdownPayment.

Booking #

Two endpoints handle the booking lifecycle. Validate the tenant's tax code first when required by Italian law, then create the booking.

POST/Booking/ValidateTaxCodeValidate tenant's tax code before booking
POST/BookingCreate the booking

POST /Booking — key request fields

externalReferencestring · min 1requiredYour invoice number or unique booking ID
bedCodestringBed code identifier
checkinDatedate-timeCheck-in date (RFC 3339)
checkoutDatedate-timeCheck-out date (RFC 3339)
pricenumberFrom commercialConditions.price
discountedPricenumberFrom commercialConditions.discountedPrice
discountUntildate-timePair with discountedPrice
depositnumberFrom commercialConditions.depositAmount
downPaymentnumberFrom commercialConditions.confirmationDeposit
guarantorTypeenumOneGuarantor · NoGuarantor · OwnGuarantor · Garantme · Studapart · Smartgarant · None
feeTaxIncludednumberPortal fee including VAT
userDataobjectFull tenant data (name, email, birthDate, taxCode, address…)
Booking response 200/201
{
  "tenantId":      "123e4567-e89b-12d3-a456-426614174000",
  "contractId":    "123e4567-e89b-12d3-a456-426614174000",
  "company":       null,
  "paymentIntent": null
}
Price fields are mandatory in practice: even though they are typed number | null, omitting price, deposit, and downPayment when they have values from commercial conditions will result in a 400 Bad request or 406 Not Acceptable.

Beds #

Retrieve the legal entity associated with a bed — useful for understanding which Joivy company entity is the contract counterpart for invoicing and compliance purposes.

GET/Beds/{bedCode}/LegalEntityGets the legal entity for a bed

The response returns id and code of the legal entity. This data typically drives the portal's invoice generation logic and determines the correct VAT number to display to the tenant.

Rentables #

Search and list available rental units. This is the main catalogue endpoint — use it to power listing pages with filters, sorting, and pagination.

POST/Rentables/Search rentable units with filters and pagination

Request body (RentablesSearchRequest)

querystringFree-text search query
maxItemsPerPageintegerPage size
pageIndexintegerZero-based page index
sorting.orderByenumPricing and other values
sorting.ascOrderbooleantrue = ascending
languagestring · queryLocale for localized content (e.g. it, en)

Each item in the response includes the full unit descriptor: bed type, room type, accommodation type, address, geo-coordinates, building amenities, flat features, room features, media gallery, localized descriptions, availability windows, and commercial condition summary. This is the richest payload in the API.

The /Rentables/ endpoint does not require authentication. It's the only endpoint in the Main API spec that can be called without a bearer token.

Portals & Ubiflow #

GET/BedsPortals — list all beds visible to this portal (no response body)
GET/api/Ubiflow/BedsUbiflow — structured bed data for the Ubiflow real-estate feed

Portals / GET /Beds returns a 200 with no body — it's used as a health/sync check to confirm which beds are associated with your portal credentials.

Ubiflow / GET /api/Ubiflow/Beds returns a rich JSON map keyed by bed identifier, containing room dimensions, energy ratings (DPE), geo-address, pricing, gallery URLs, and amenity counts. This feed is intended for syndication to the Ubiflow real-estate aggregator.


Try it out #

Every endpoint has an interactive Open API Client button at the bottom of the sidebar (or use the inline send panel on each endpoint). To test authenticated endpoints:

1
Switch to Authentication – OAuth2
Use the spec switcher, open the Get access token (Client Credentials) endpoint, fill in your client_id, client_secret, grant_type=client_credentials, and scope. Click Send and copy the access_token from the response.
2
Switch to Main API and authorize
Click the 🔒 lock icon on any endpoint marked Auth Required. In the authorization dialog, paste your token in the Bearer field. It will be applied to all subsequent requests in this session.
3
Fill parameters and send
Path parameters (like bedCode) are editable inline. Query parameters and body fields appear in the form below the endpoint description. Hit Send and inspect the response status, headers, and JSON body.
!
Live endpoints: the reference points at production. POST /Booking sent via "Try it out" will create a real booking. Always use test credentials and a test externalReference when experimenting.

Error handling #

StatusMeaningLikely cause
200OKSuccess
201AcceptedBooking created (async processing)
400Bad requestMissing required field or malformed body (e.g. missing externalReference)
401UnauthorizedToken missing, expired, or wrong scope
404Not FoundbedCode does not exist or not visible to your portal
406Not AcceptablePricing mismatch — price fields don't match current commercial conditions
500Server ErrorRetry with exponential back-off
Availability and Beds endpoints return text/plain on error (not JSON). Parse accordingly — check Content-Type before calling .json().