Level 1 · Connected
Publish your centres
The details of each centre, what we check, the review and the daily list.
Each centre is sent whole, with its identifier in your software. If it exists, it is updated; if not, it is created. You can repeat a request as often as you need: with the same Idempotency-Key, the response is the same.
1. Send the centre
PUT /connect/v1/facilities/madrid-01
Authorization: Bearer <token>
Idempotency-Key: 5b1d0c3e-8f6a-4c2e-9d1b-7a0e2f4c6b11
Content-Type: application/json
{
"version": "2026-10-26T08:15:00Z",
"name": "Trasteros Serrano Salamanca",
"address": {
"street": "Calle de Serrano 120",
"postalCode": "28006",
"city": "Madrid",
"province": "Madrid",
"country": "ES"
},
"location": { "lat": 40.4365, "lng": -3.6862 },
"openingHours": { "kind": "daily", "opens": "07:00", "closes": "22:00" },
"leadsEmail": "avisos@trasteros-serrano.example.com",
"pricesIncludeVat": true,
"policies": { "depositMonths": 1 }
}| Field | Type | Required | Notes |
|---|---|---|---|
version | text | Yes | Changes whenever this data changes (its updatedAt works) |
name | text | Yes | The trading name: not an address nor just the city |
address | {street, postalCode, city, province, country} | Yes | City and province with their full names. country: ES |
location | {lat, lng} | Yes | In WGS 84, within 1 km of where its address falls |
openingHours | hours | Yes | {"kind": "always"}, {"kind": "daily", "opens", "closes"} or {"kind": "weekly", "days": {"mon": [{"opens", "closes"}], …}} |
leadsEmail | Yes | For the requests the operator wants by email. Never shown on the portal | |
pricesIncludeVat | yes or no | Yes | Whether its unit prices include VAT |
policies | {depositMonths, minimumStayMonths} | Yes | The deposit, in months' rent (0: none), and the minimum stay, in months |
accessMethods | list | No | app, pin, qr, key, remote or card |
amenities | list | No | cctv, alarm, trolleys, groundFloor, loadingAtDoor, lift, parking or climateControl |
description | {es, en, fr, de, it, pt} | No | In at least one language: the portal translates the rest, and says so |
openedOn | date | No | When it opened: “New centre” for 180 days |
opensOn | month | No | If it hasn't opened yet: “Opens in March 2027” and “Notify me when it opens” |
2. Look at the response
The response is how the centre stands: its status, its listing URL once published and its warnings, which don't prevent publishing but are worth fixing.
{
"id": "madrid-01",
"status": "in_review",
"listing": null,
"reasons": [],
"message": null,
"warnings": [
{ "code": "few_photos", "message": "It has 0 photos: with three or more, the listing looks much better." }
],
"updatedAt": "2026-10-26T08:15:02Z"
}status | What it means |
|---|---|
pending_link | It looks like one the operator already had in Qbox. It waits for them to say whether it's the same |
in_review | It's new: the team reviews it before publishing it, like those added in Qbox. facility.reviewed tells you |
published | It's on the portal. From now on, every change goes live at once |
returned | The team returned it, with its reasons. Fix it and send it again |
withdrawn | It's not on the portal: you removed it, it wasn't in the daily list, the operator withdrew access or the team withdrew it |
3. If something is missing
Nothing is published halfway: the response is a 422 with every failing field and why. If the centre was already published, it keeps its last good data. Everything stays in your area's log for 30 days.
{
"error": {
"code": "invalid_facility",
"message": "The centre isn't published: check these fields.",
"fields": [
{ "path": "address.postalCode", "code": "invalid_postal_code",
"message": "“03203” isn't a postal code in Madrid." },
{ "path": "name", "code": "name_is_address",
"message": "The name is an address or just the city: use the centre's trading name." }
]
}
}What we check
code | What fails |
|---|---|
required | A required field is missing |
invalid_format | A field doesn't have its format: an email, a date, a colour… |
invalid_postal_code | The postal code isn't from its country or its province |
unknown_city | The city isn't a municipality in its province |
location_far | The point is more than 1 km from where its address falls |
name_is_address | The name is an address or just the city |
invalid_price | A price below zero or not reasonable |
duplicate_id | Two sizes, units, floors or photos with the same id |
unknown_unit_type | A unit with a unitTypeId that isn't one of its sizes |
unknown_floor | A unit with a floorId that isn't in its floor plan |
invalid_svg | The floor plan doesn't pass the clean-up |
unknown_unit_in_plan | A floor plan shape with a data-unit-id that isn't any unit |
invalid_photo | The photo isn't JPEG, PNG or WebP, or is too small |
And what doesn't prevent publishing (warnings): few_photos (fewer than three), no_description and unit_not_in_plan (a unit without its shape in the floor plan).
If the operator already had it in Qbox
If the centre is less than 150 metres from one the operator already has in Qbox, or on the same street with the same postal code, it stays in pending_link. In “Connect your software”, they say whether it's the same one (it stays published, now with your data) or a different one (it's reviewed as a new one). You get the facility.linked webhook.
The daily list
At least once a day, PUT /facilities with all the operator's centres: each one's id and, if you like, its versions (facility, unitTypes, units, floorPlan and photos).
- A centre missing from the list is withdrawn from the portal. It comes back if it reappears.
- If you send the versions, the response says what we have out of date (
outdated) so you can send it again.
{
"facilities": [
{ "id": "madrid-01", "versions": { "facility": "2026-10-26T08:15:00Z", "units": "2026-10-26T09:02:11Z" } },
{ "id": "madrid-02" }
]
}Removing a centre
DELETE /facilities/{facilityId} removes it from the portal. GET /facilities/{facilityId} tells you its status at any time.