{"openapi":"3.1.0","info":{"title":"The Qbox standard for management software","version":"1.0.0-beta","description":"What self-storage management software builds to publish its customers' centres on the portal (quetrastero.com, in Spain) and receive their requests (ADR-052). Each operator gives it access from Qbox (OAuth 2.0 with PKCE). The same URL for testing and production: the credential decides (`qt_test_…` or `qt_live_…`)."},"servers":[{"url":"https://api.findqbox.com/connect","description":"The same for testing and production."}],"components":{"securitySchemes":{"gestora":{"type":"oauth2","description":"Access given by an operator in Qbox.","flows":{"authorizationCode":{"authorizationUrl":"https://app.findqbox.com/oauth/authorize","tokenUrl":"https://api.findqbox.com/connect/oauth/token","refreshUrl":"https://api.findqbox.com/connect/oauth/token","scopes":{"facilities.write":"Publish the operator's centres and keep them up to date.","leads.read":"Receive their requests."}}}},"software":{"type":"oauth2","description":"Your software's token, with your credentials alone. It sees no centre.","flows":{"clientCredentials":{"tokenUrl":"https://api.findqbox.com/connect/oauth/token","scopes":{}}}}},"schemas":{"Rental":{"type":"object","properties":{"id":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"Your software's.","example":"rnt_8f2c41"},"status":{"$ref":"#/components/schemas/RentalStatus"},"heldUntil":{"type":"string","format":"date-time","description":"Until when you hold the unit: 20 minutes, and up to 30 from when they start paying."},"firstPayment":{"$ref":"#/components/schemas/RentalFirstPayment"},"monthlyPrice":{"type":"number","minimum":0,"maximum":1000000,"description":"Final, with VAT, in the centre's currency.","example":45},"nextPayments":{"$ref":"#/components/schemas/RentalNextPayments"},"minimumStayMonths":{"type":"integer","minimum":0,"maximum":120,"description":"The minimum stay, in months."},"noticeDays":{"type":"integer","minimum":0,"maximum":365,"description":"The notice period for leaving, in days."},"contractNumber":{"type":["string","null"],"minLength":1,"maxLength":60,"description":"Once paid: the contract number in your software.","example":"TS-2026-0418"},"failure":{"type":["object","null"],"properties":{"code":{"type":"string","maxLength":60},"message":{"type":"string","maxLength":500}},"required":["code"],"description":"With `payment_failed`: why. The customer doesn't see it; it goes to your area's log."}},"required":["id","status","heldUntil","firstPayment","monthlyPrice"],"description":"An online rental, as your software returns it (level 2)."},"RentalStatus":{"type":"string","enum":["held","paying","paid","payment_failed","expired","cancelled","refunded"],"description":"`held`: held · `paying`: paying on the gateway · `paid`: paid, it's theirs · `payment_failed`: the last attempt didn't go through (it stays held until `heldUntil` and can be tried again) · `expired` · `cancelled` · `refunded`: it was paid when it was no longer theirs, and refunded."},"RentalFirstPayment":{"type":"object","properties":{"lines":{"type":"array","items":{"$ref":"#/components/schemas/RentalLine"},"minItems":1,"maxItems":10},"total":{"type":"number","minimum":0,"maximum":1000000,"description":"Final, with VAT, in the centre's currency.","example":45}},"required":["lines","total"],"description":"What's paid today, line by line. The portal calculates nothing: it shows it as it is."},"RentalLine":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["rent"]},"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date"},"amount":{"type":"number","minimum":0,"maximum":1000000,"description":"Final, with VAT, in the centre's currency.","example":45}},"required":["kind","from","to","amount"],"description":"The rent for those days."},{"type":"object","properties":{"kind":{"type":"string","enum":["deposit"]},"amount":{"type":"number","minimum":0,"maximum":1000000,"description":"Final, with VAT, in the centre's currency.","example":45}},"required":["kind","amount"],"description":"The deposit."},{"type":"object","properties":{"kind":{"type":"string","enum":["extra"]},"concept":{"type":"string","minLength":1,"maxLength":80},"amount":{"type":"number","minimum":0,"maximum":1000000,"description":"Final, with VAT, in the centre's currency.","example":45}},"required":["kind","concept","amount"],"description":"Anything else charged today: a padlock, insurance…"}]},"RentalNextPayments":{"type":["object","null"],"properties":{"amount":{"type":"number","minimum":0,"maximum":1000000,"description":"Final, with VAT, in the centre's currency.","example":45},"dayOfMonth":{"type":"integer","minimum":1,"maximum":31},"from":{"type":"string","format":"date"}},"required":["amount","dayOfMonth","from"],"description":"The monthly payments, charged to the first payment's card."},"RentalCreate":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Ours: the one in `PUT /connect/v1/rentals/{rentalId}`."},"connectionId":{"type":["string","null"],"format":"uuid","description":"The operator's permission; in testing, that of the \"Test operator\"."},"facilityId":{"$ref":"#/components/schemas/ExternalId"},"unitId":{"$ref":"#/components/schemas/ExternalId"},"startDate":{"type":"string","format":"date","description":"Today or one of the next 30 days."},"locale":{"type":"string","enum":["es","en","fr","de","it","pt"],"description":"The customer's language, for your emails."}},"required":["id","connectionId","facilityId","unitId","startDate","locale"]},"ExternalId":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"An identifier from your software, opaque and stable. A GUID works.","example":"3f9c2a7e-0b1d-4c8e-9a51-2d6f0e7b4c10"},"RentalTenant":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/TenantKind"},"name":{"type":"string","description":"First name and surnames; for a company, its legal name."},"documentType":{"$ref":"#/components/schemas/TenantDocumentType"},"documentNumber":{"type":"string"},"documentCountry":{"type":"string","description":"ISO 3166-1 alpha-2."},"email":{"type":"string","format":"email","description":"Already verified with a code."},"phone":{"type":"string","description":"With its prefix: `+34 612345678`."},"address":{"$ref":"#/components/schemas/PostalAddress"},"representative":{"type":["object","null"],"properties":{"name":{"type":"string","minLength":2,"maxLength":160,"description":"First name and surnames.","example":"Marta Ruiz Pérez"},"documentType":{"$ref":"#/components/schemas/TenantDocumentType"},"documentNumber":{"type":"string","minLength":3,"maxLength":30,"example":"12345678Z"},"documentCountry":{"type":"string","pattern":"^[A-Z]{2}$","description":"The document's country; with a NIF, `ES`.","example":"ES"}},"required":["name","documentType","documentNumber","documentCountry"],"description":"For a company, whoever signs on its behalf."}},"required":["kind","name","documentType","documentNumber","documentCountry","email","phone","address","representative"],"description":"The tenant, with their email verified."},"TenantKind":{"type":"string","enum":["person","company"],"description":"`person`: individual · `company`: company, or self-employed person renting for their business."},"TenantDocumentType":{"type":"string","enum":["nif","passport","other"],"description":"`nif`: Spanish NIF (DNI, NIE or CIF), with its check digit verified · `passport`: passport · `other`: another identity document, with its country."},"PostalAddress":{"type":"object","properties":{"street":{"type":"string","minLength":3,"maxLength":200,"description":"Street, number, floor…","example":"Calle Mayor 1, 2.º B"},"postalCode":{"type":"string","minLength":3,"maxLength":12,"example":"28006"},"city":{"type":"string","minLength":2,"maxLength":120,"example":"Madrid"},"region":{"type":["string","null"],"maxLength":120,"description":"Province or region.","example":"Madrid"},"country":{"type":"string","pattern":"^[A-Z]{2}$","description":"Country, ISO 3166-1 alpha-2.","example":"ES"}},"required":["street","postalCode","city","region","country"]},"RentalContract":{"type":"object","properties":{"version":{"type":"string","minLength":1,"maxLength":60},"title":{"type":"string","minLength":1,"maxLength":160},"text":{"type":"string","minLength":200,"maxLength":200000,"description":"The full text, in Spanish, with its general terms: paragraphs separated by a blank line."}},"required":["version","title","text"],"description":"The contract with the rental's details, without a number or date, which are added on payment."},"RentalAcceptance":{"type":"object","properties":{"textSha256":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"The fingerprint of the text they read."},"version":{"type":"string"},"acceptedAt":{"type":"string","format":"date-time"},"email":{"type":"string","format":"email"},"ip":{"type":"string"},"userAgent":{"type":"string"},"earlyStart":{"type":"boolean","description":"A consumer who moves in before their 14-day withdrawal period ends: if they withdraw, they pay for the part already used."}},"required":["textSha256","version","acceptedAt","email","ip","userAgent","earlyStart"],"description":"The proof that they accepted the contract."},"RentalPayment":{"type":"object","properties":{"redirect":{"$ref":"#/components/schemas/RentalRedirect"},"heldUntil":{"type":"string","format":"date-time"}},"required":["redirect","heldUntil"],"description":"The signed order, with the amount inside."},"RentalRedirect":{"type":"object","properties":{"method":{"type":"string","enum":["POST","GET"]},"url":{"type":"string","maxLength":2000,"format":"uri","description":"The bank's payment page, over https; in a test rental, `http://localhost` too."},"fields":{"type":"object","additionalProperties":{"type":"string","maxLength":20000},"default":{},"description":"With `POST`, the form fields: with Redsys, `Ds_SignatureVersion`, `Ds_MerchantParameters` and `Ds_Signature`."}},"required":["method","url"],"description":"Where the portal takes the customer to pay."},"RentalPaymentRequest":{"type":"object","properties":{"returnUrls":{"type":"object","properties":{"ok":{"type":"string","format":"uri","description":"Where they come back to if they paid (with Redsys, `URLOK`)."},"ko":{"type":"string","format":"uri","description":"Where they come back to if they didn't pay or gave up (with Redsys, `URLKO`)."}},"required":["ok","ko"],"description":"The portal pages the customer comes back to. Put them in the signed order."}},"required":["returnUrls"]},"RentalAccess":{"type":"object","properties":{"pin":{"type":["string","null"],"pattern":"^\\d{4,12}$","description":"The PIN's digits.","example":"318604927"},"qr":{"type":["string","null"],"minLength":1,"maxLength":500,"description":"The text the QR code carries."},"app":{"type":["object","null"],"properties":{"name":{"type":"string","minLength":1,"maxLength":40},"email":{"type":["string","null"],"format":"email"}},"required":["name"],"description":"The app that opens it and the email to sign in with."},"instructions":{"type":["string","null"],"maxLength":500,"description":"How to get in on the first day, in one sentence."}},"description":"How to get in. The portal shows it and doesn't store it (ADR-005)."},"Event":{"type":"object","properties":{"id":{"type":"string","description":"To discard duplicates.","example":"evt_01JB7Q8M2Z9W"},"type":{"$ref":"#/components/schemas/EventType"},"createdAt":{"type":"string","format":"date-time"},"connectionId":{"type":["string","null"],"description":"The operator's connection; in `test.ping`, null."},"data":{"type":"object","additionalProperties":{}}},"required":["id","type","createdAt","connectionId","data"],"description":"A webhook, signed in `Qbox-Signature`."},"EventType":{"type":"string","enum":["connection.created","connection.revoked","facility.linked","facility.reviewed","facility.issues","lead.created","test.ping"]},"TokenResponse":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string","enum":["Bearer"]},"expires_in":{"type":"integer","example":3600},"refresh_token":{"type":"string","description":"With an operator's permission; not with `client_credentials`."},"scope":{"type":"string","example":"facilities.write leads.read"},"connectionId":{"type":"string"},"operator":{"$ref":"#/components/schemas/Operator"}},"required":["access_token","token_type","expires_in","scope"]},"Operator":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Trasteros Serrano"}},"required":["id","name"],"description":"The operator that gave access. In testing, your software's \"Test operator\"."},"OAuthError":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_request","invalid_client","invalid_grant","unauthorized_client","unsupported_grant_type","invalid_scope"]},"error_description":{"type":"string"}},"required":["error"],"description":"As OAuth 2.0 says (RFC 6749, 5.2)."},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Never changes: it's the one your software has to look at.","example":"invalid_facility"},"message":{"type":"string","description":"For people, in the language of `Accept-Language`."},"fields":{"type":"array","items":{"$ref":"#/components/schemas/FieldError"},"description":"When a value fails: each field, its `code` and its message."}},"required":["code","message"]}},"required":["error"]},"FieldError":{"type":"object","properties":{"path":{"type":"string","example":"address.postalCode"},"code":{"type":"string","enum":["required","invalid_format","invalid_postal_code","unknown_city","location_far","name_is_address","invalid_price","duplicate_id","unknown_unit_type","unknown_floor","invalid_svg","unknown_unit_in_plan","invalid_photo"]},"message":{"type":"string","description":"For people, in the language of `Accept-Language`."}},"required":["path","code","message"]},"TokenRequest":{"type":"object","properties":{"grant_type":{"type":"string","enum":["authorization_code","refresh_token","client_credentials"]},"code":{"type":"string","maxLength":200,"description":"For `authorization_code`."},"redirect_uri":{"type":"string","maxLength":500,"description":"For `authorization_code`: the same one it was requested with."},"code_verifier":{"type":"string","maxLength":200,"description":"For `authorization_code`: the PKCE one."},"refresh_token":{"type":"string","maxLength":200,"description":"For `refresh_token`."},"client_id":{"type":"string","maxLength":100,"description":"If it isn't sent in `Authorization: Basic`."},"client_secret":{"type":"string","maxLength":200,"description":"If it isn't sent in `Authorization: Basic`."}},"required":["grant_type"]},"FacilityListResult":{"type":"object","properties":{"retired":{"type":"array","items":{"$ref":"#/components/schemas/ExternalId"},"description":"Those that weren't in the list and have been withdrawn from the portal."},"outdated":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/ExternalId"},"resources":{"type":"array","items":{"type":"string","enum":["facility","unitTypes","units","floorPlan","photos"]}}},"required":["id","resources"]},"description":"What the portal has out of date: send it again."},"unknown":{"type":"array","items":{"$ref":"#/components/schemas/ExternalId"},"description":"Those in the list that you haven't sent yet."}},"required":["retired","outdated","unknown"]},"FacilityList":{"type":"object","properties":{"facilities":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/ExternalId"},"versions":{"type":"object","properties":{"facility":{"type":"string","maxLength":64},"unitTypes":{"type":"string","maxLength":64},"units":{"type":"string","maxLength":64},"floorPlan":{"type":"string","maxLength":64},"photos":{"type":"string","maxLength":64}},"description":"The versions of what you have of it: with them, the response says what the portal has out of date."}},"required":["id"]},"maxItems":2000}},"required":["facilities"],"description":"All the operator's centres, at least once a day."},"FacilityState":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/ExternalId"},"status":{"$ref":"#/components/schemas/FacilityStatus"},"listing":{"type":["string","null"],"format":"uri","description":"Its listing on the portal, once published."},"reasons":{"type":"array","items":{"$ref":"#/components/schemas/ReviewReason"},"description":"In `returned` and `withdrawn`, why."},"message":{"type":["string","null"],"description":"What the team wrote when returning or withdrawing it, if anything."},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/Warning"}},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","status","listing","reasons","message","warnings","updatedAt"]},"FacilityStatus":{"type":"string","enum":["pending_link","in_review","published","returned","withdrawn"],"description":"`pending_link`: it looks like one the operator already had in Qbox and waits for them to say whether it's the same · `in_review`: new, the team reviews it · `published`: on the portal · `returned`: returned, with its reasons · `withdrawn`: off the portal."},"ReviewReason":{"type":"object","properties":{"code":{"type":"string","enum":["photos","description","location","prices","access","operator"],"description":"`photos`, `description`, `location`, `prices`, `access` u `operator`."},"message":{"type":"string"}},"required":["code","message"],"description":"Why the team returned or withdrew it."},"Warning":{"type":"object","properties":{"path":{"type":"string"},"code":{"type":"string","enum":["few_photos","no_description","unit_not_in_plan"],"description":"What doesn't prevent publishing, but is worth fixing."},"message":{"type":"string"}},"required":["code","message"]},"FacilityInput":{"type":"object","properties":{"version":{"type":"string","minLength":1,"maxLength":64,"description":"Changes whenever any of this data changes (its `updatedAt` works). The daily list uses it to know what's up to date."},"name":{"type":"string","minLength":2,"maxLength":80,"description":"The trading name, the one shown on the portal: not an address nor just the city."},"address":{"$ref":"#/components/schemas/Address"},"location":{"$ref":"#/components/schemas/GeoPoint"},"openingHours":{"$ref":"#/components/schemas/OpeningHours"},"leadsEmail":{"type":"string","maxLength":254,"format":"email","description":"For the requests the operator wants by email. Never shown on the portal."},"pricesIncludeVat":{"type":"boolean","description":"Whether its unit prices include VAT. The portal always shows the final price."},"accessMethods":{"type":"array","items":{"$ref":"#/components/schemas/AccessMethod"},"maxItems":6},"amenities":{"type":"array","items":{"$ref":"#/components/schemas/Amenity"},"maxItems":8},"policies":{"$ref":"#/components/schemas/Policies"},"description":{"$ref":"#/components/schemas/LocalizedText"},"openedOn":{"type":"string","format":"date","description":"When it opened (`YYYY-MM-DD`): \"New centre\" for 180 days."},"opensOn":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$","description":"If it hasn't opened yet, the month it will open (`YYYY-MM`): \"Opens in March 2027\" and \"Notify me when it opens\".","example":"2027-03"},"onlineRental":{"type":"boolean","description":"Level 2: whether the centre takes online payments with your software, because its gateway is ready. By default, no."}},"required":["version","name","address","location","openingHours","leadsEmail","pricesIncludeVat","policies"],"description":"A centre, whole. If it already exists, it's updated; if not, it's created."},"Address":{"type":"object","properties":{"street":{"type":"string","minLength":3,"maxLength":120,"description":"The street and number.","example":"Calle de Serrano 120"},"postalCode":{"type":"string","minLength":1,"maxLength":10,"description":"In Spain, five digits.","example":"28006"},"city":{"type":"string","minLength":2,"maxLength":80,"description":"With its full name.","example":"Madrid"},"province":{"type":"string","minLength":2,"maxLength":80,"example":"Madrid"},"country":{"type":"string","pattern":"^[A-Z]{2}$","description":"ISO 3166-1. For now, only `ES`.","example":"ES"}},"required":["street","postalCode","city","province","country"]},"GeoPoint":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90,"example":40.4365},"lng":{"type":"number","minimum":-180,"maximum":180,"example":-3.6862}},"required":["lat","lng"],"description":"In WGS 84, within 1 km of where its address falls."},"OpeningHours":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["always"]}},"required":["kind"]},{"type":"object","properties":{"kind":{"type":"string","enum":["daily"]},"opens":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"closes":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"}},"required":["kind","opens","closes"]},{"type":"object","properties":{"kind":{"type":"string","enum":["weekly"]},"days":{"type":"object","properties":{"mon":{"type":"array","items":{"type":"object","properties":{"opens":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"closes":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"}},"required":["opens","closes"]},"maxItems":6},"tue":{"type":"array","items":{"type":"object","properties":{"opens":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"closes":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"}},"required":["opens","closes"]},"maxItems":6},"wed":{"type":"array","items":{"type":"object","properties":{"opens":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"closes":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"}},"required":["opens","closes"]},"maxItems":6},"thu":{"type":"array","items":{"type":"object","properties":{"opens":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"closes":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"}},"required":["opens","closes"]},"maxItems":6},"fri":{"type":"array","items":{"type":"object","properties":{"opens":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"closes":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"}},"required":["opens","closes"]},"maxItems":6},"sat":{"type":"array","items":{"type":"object","properties":{"opens":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"closes":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"}},"required":["opens","closes"]},"maxItems":6},"sun":{"type":"array","items":{"type":"object","properties":{"opens":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"closes":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"}},"required":["opens","closes"]},"maxItems":6}}}},"required":["kind","days"]}],"description":"`always`: 24 h, all 365 days · `daily`: the same hours every day · `weekly`: time slots per day (`mon`…`sun`); a day that's missing or empty is closed, and a slot that ends before it starts finishes the next day (the kind management software sends, ADR-052)."},"AccessMethod":{"type":"string","enum":["app","pin","qr","key","remote","card"],"description":"How the tenant gets into the facility: Kuartus app, PIN, QR code (ADR-005), key, remote control or card."},"Amenity":{"type":"string","enum":["cctv","alarm","trolleys","groundFloor","loadingAtDoor","lift","parking","climateControl"],"description":"The facility's amenities. The web translates them into each language."},"Policies":{"type":"object","properties":{"depositMonths":{"type":"number","minimum":0,"maximum":12,"description":"The deposit, in months' rent. 0: no deposit."},"minimumStayMonths":{"type":"integer","minimum":0,"maximum":60,"description":"The minimum stay, in months. 0: no minimum stay."}},"required":["depositMonths"]},"LocalizedText":{"type":"object","properties":{"es":{"type":"string","maxLength":2000},"en":{"type":"string","maxLength":2000},"fr":{"type":"string","maxLength":2000},"de":{"type":"string","maxLength":2000},"it":{"type":"string","maxLength":2000},"pt":{"type":"string","maxLength":2000}},"description":"In at least one language. The portal translates whatever's missing, and says so."},"Accepted":{"type":"object","properties":{"warnings":{"type":"array","items":{"$ref":"#/components/schemas/Warning"}}},"required":["warnings"]},"UnitTypeList":{"type":"object","properties":{"version":{"type":"string","minLength":1,"maxLength":64,"description":"Changes whenever any of this data changes (its `updatedAt` works). The daily list uses it to know what's up to date."},"unitTypes":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/ExternalId"},"name":{"type":"string","minLength":1,"maxLength":40,"example":"Talla M"},"color":{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$","description":"If not sent, the portal picks one.","example":"#F2B33D"}},"required":["id","name"]},"maxItems":100}},"required":["version","unitTypes"],"description":"All the centre's sizes. Those not included are removed."},"UnitsState":{"type":"object","properties":{"facilityId":{"$ref":"#/components/schemas/ExternalId"},"units":{"type":"integer","example":38},"available":{"type":"integer","example":12},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/Warning"}}},"required":["facilityId","units","available","warnings"],"description":"How many there are and how many are free."},"UnitList":{"type":"object","properties":{"version":{"type":"string","minLength":1,"maxLength":64,"description":"Changes whenever any of this data changes (its `updatedAt` works). The daily list uses it to know what's up to date."},"units":{"type":"array","items":{"$ref":"#/components/schemas/Unit"},"maxItems":3000}},"required":["version","units"],"description":"All the centre's units. Those not included are removed. It never carries tenant data."},"Unit":{"type":"object","properties":{"number":{"type":"string","minLength":1,"maxLength":20,"description":"The one the tenant sees on the door.","example":"21"},"areaM2":{"type":"number","exclusiveMinimum":0,"maximum":500,"description":"Its floor area, in m². The portal puts it in its category.","example":2.6},"status":{"$ref":"#/components/schemas/UnitStatus"},"monthlyPrice":{"type":["number","null"],"description":"Its monthly price, with or without VAT according to `pricesIncludeVat`. `null` if it isn't rented through the portal.","example":49},"unitTypeId":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"Its size, one of `unit-types`.","example":"3f9c2a7e-0b1d-4c8e-9a51-2d6f0e7b4c10"},"floorId":{"type":"string","maxLength":64,"description":"Its floor, if the floor plan has several."},"id":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"Unique in the centre: the same as its `data-unit-id` in the floor plan.","example":"3f9c2a7e-0b1d-4c8e-9a51-2d6f0e7b4c10"}},"required":["number","areaM2","status","monthlyPrice","id"]},"UnitStatus":{"type":"string","enum":["available","occupied","blocked"],"description":"`available`: free · `occupied`: rented · `blocked`: blocked, for example while someone else is paying."},"UnitFields":{"type":"object","properties":{"number":{"type":"string","minLength":1,"maxLength":20,"description":"The one the tenant sees on the door.","example":"21"},"areaM2":{"type":"number","exclusiveMinimum":0,"maximum":500,"description":"Its floor area, in m². The portal puts it in its category.","example":2.6},"status":{"$ref":"#/components/schemas/UnitStatus"},"monthlyPrice":{"type":["number","null"],"description":"Its monthly price, with or without VAT according to `pricesIncludeVat`. `null` if it isn't rented through the portal.","example":49},"unitTypeId":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"Its size, one of `unit-types`.","example":"3f9c2a7e-0b1d-4c8e-9a51-2d6f0e7b4c10"},"floorId":{"type":"string","maxLength":64,"description":"Its floor, if the floor plan has several."}},"required":["number","areaM2","status","monthlyPrice"]},"FloorPlan":{"type":"object","properties":{"version":{"type":"string","minLength":1,"maxLength":64,"description":"Changes whenever any of this data changes (its `updatedAt` works). The daily list uses it to know what's up to date."},"floors":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/ExternalId"},"name":{"type":"string","minLength":1,"maxLength":40,"example":"Planta baja"},"svg":{"type":"string","minLength":1,"description":"Up to 2 MB. Only shapes and text: no scripts, images, links or external fonts. Each unit's shape carries `data-unit-id` with its `id`."}},"required":["id","name","svg"]},"minItems":1,"maxItems":10}},"required":["version","floors"],"description":"Each floor's SVG, the same one your software's websites use (ADR-008)."},"PhotoList":{"type":"object","properties":{"version":{"type":"string","minLength":1,"maxLength":64,"description":"Changes whenever any of this data changes (its `updatedAt` works). The daily list uses it to know what's up to date."},"photos":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/ExternalId"},"caption":{"type":"string","maxLength":120,"description":"Its caption: what it shows."}},"required":["id"]},"maxItems":20}},"required":["version","photos"],"description":"The photos already uploaded, in display order. Those not included are removed."},"PhotoState":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/ExternalId"},"width":{"type":"integer"},"height":{"type":"integer"},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/Warning"}}},"required":["id","width","height","warnings"]},"LeadList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Lead"}},"nextCursor":{"type":["string","null"]}},"required":["items","nextCursor"]},"Lead":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"facilityId":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"The centre's id in your software.","example":"3f9c2a7e-0b1d-4c8e-9a51-2d6f0e7b4c10"},"kind":{"$ref":"#/components/schemas/LeadKind"},"name":{"type":"string"},"email":{"type":"string","format":"email"},"phone":{"type":["string","null"],"description":"With its international prefix. Always, except in `opening`, where it's optional.","example":"+34 612345678"},"locale":{"type":"string","enum":["es","en","fr","de","it","pt"],"description":"The language they wrote in."},"category":{"type":["string","null"],"enum":["closet","dressingRoom","room","studio","flat","house",null],"description":"The size they're interested in. In `waitlist`, always."},"unitId":{"type":["string","null"],"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"The unit they picked on the floor plan, if any.","example":"3f9c2a7e-0b1d-4c8e-9a51-2d6f0e7b4c10"},"message":{"type":["string","null"]},"status":{"type":"string","enum":["new","handled"]},"consentAt":{"type":"string","format":"date-time","description":"When they agreed to the centre contacting them."},"createdAt":{"type":"string","format":"date-time"}},"required":["id","facilityId","kind","name","email","phone","locale","category","unitId","message","status","consentAt","createdAt"],"description":"A request. Your software processes it on behalf of the operator, only to answer it."},"LeadKind":{"type":"string","enum":["contact","waitlist","opening"],"description":"`contact`: information request · `waitlist`: waiting list for a full category · `opening`: to be notified when a facility with an upcoming opening opens (ADR-039)."},"LeadStatusInput":{"type":"object","properties":{"status":{"type":"string","enum":["handled"]}},"required":["status"]},"ConnectionList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Connection"}}},"required":["items"]},"Connection":{"type":"object","properties":{"connectionId":{"type":"string"},"operator":{"$ref":"#/components/schemas/Operator"},"scopes":{"type":"array","items":{"$ref":"#/components/schemas/Scope"}},"createdAt":{"type":"string","format":"date-time"}},"required":["connectionId","operator","scopes","createdAt"]},"Scope":{"type":"string","enum":["facilities.write","leads.read"],"description":"`facilities.write`: publish the operator's centres and keep them up to date · `leads.read`: receive their requests."},"RentalState":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["open","completed","expired","cancelled","refunded"],"description":"How the portal sees it."}},"required":["id","status"]},"RentalStatusInput":{"type":"object","properties":{"status":{"type":"string","enum":["paid","payment_failed","expired","cancelled","refunded"]},"contractNumber":{"type":"string","minLength":1,"maxLength":60,"description":"With `paid`, the contract's number in your software."}},"required":["status"],"description":"Where a rental stands: your gateway's notification has already reached your server."}},"parameters":{}},"paths":{"/oauth/token":{"post":{"tags":["Access"],"summary":"The tokens","description":"- `authorization_code`: exchanges the code that reaches your `redirect_uri` for that operator's tokens, with the PKCE `code_verifier`.\n- `refresh_token`: renews the `access_token`. Each time you get a new `refresh_token` and the previous one stops working; one unused for 90 days expires.\n- `client_credentials`: your software's token, with no centre.\n\nAlways with your `client_id` and your `client_secret`, in `Authorization: Basic` or in the body.","security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/TokenRequest"}}}},"responses":{"200":{"description":"The tokens.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"`invalid_grant`, `invalid_request`… as OAuth 2.0 says.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"401":{"description":"`invalid_client`: the `client_id` or the `client_secret` isn't valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"429":{"description":"`rate_limited`: too many requests. Wait as long as `Retry-After` says.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/facilities":{"put":{"tags":["Level 1 · Centres"],"summary":"The daily list","description":"All the operator's centres, at least once a day. A centre missing from the list is withdrawn from the portal, and comes back if it reappears. With their versions, the response says what the portal has out of date.","security":[{"gestora":["facilities.write"]}],"parameters":[{"schema":{"type":"string","description":"A UUID. With the same key and the same body, for 24 hours, the same response."},"required":false,"description":"A UUID. With the same key and the same body, for 24 hours, the same response.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","description":"The language of the messages: `es` or `en` (the default)."},"required":false,"description":"The language of the messages: `es` or `en` (the default).","name":"Accept-Language","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FacilityList"}}}},"responses":{"200":{"description":"What has been withdrawn and what's out of date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FacilityListResult"}}}},"401":{"description":"`unauthorized`: no token, or an expired or invalid one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`: the token lacks this operation's scope · `connection_revoked`: the operator withdrew access · `software_suspended`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`idempotency_key_reused`: the same `Idempotency-Key` with a different body · `facility_not_ready`: the centre hasn't been sent yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`invalid_facility`, `invalid_unit_types`, `invalid_units`, `invalid_floor_plan`, `invalid_photo`… with every failing field in `fields`. Nothing from this submission is stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`: too many requests. Wait as long as `Retry-After` says.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/facilities/{facilityId}":{"put":{"tags":["Level 1 · Centres"],"summary":"A whole centre","description":"Creates the centre or updates it. It's checked on the way in: if anything fails, nothing from this submission is stored (`422 invalid_facility`, with each field), and if it was already published, it keeps its last good data. A new centre stays `in_review`: the team reviews it before publishing it. If it looks like one the operator already had in Qbox, it first stays `pending_link`. Once published, every change goes live at once.","security":[{"gestora":["facilities.write"]}],"parameters":[{"schema":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"The centre's identifier in your software.","example":"madrid-01"},"required":true,"description":"The centre's identifier in your software.","name":"facilityId","in":"path"},{"schema":{"type":"string","description":"A UUID. With the same key and the same body, for 24 hours, the same response."},"required":false,"description":"A UUID. With the same key and the same body, for 24 hours, the same response.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","description":"The language of the messages: `es` or `en` (the default)."},"required":false,"description":"The language of the messages: `es` or `en` (the default).","name":"Accept-Language","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FacilityInput"}}}},"responses":{"200":{"description":"How the centre stands now.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FacilityState"}}}},"401":{"description":"`unauthorized`: no token, or an expired or invalid one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`: the token lacks this operation's scope · `connection_revoked`: the operator withdrew access · `software_suspended`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`idempotency_key_reused`: the same `Idempotency-Key` with a different body · `facility_not_ready`: the centre hasn't been sent yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"`payload_too_large`: over 5 MB of JSON, 2 MB per floor or 15 MB per photo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`invalid_facility`, `invalid_unit_types`, `invalid_units`, `invalid_floor_plan`, `invalid_photo`… with every failing field in `fields`. Nothing from this submission is stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`: too many requests. Wait as long as `Retry-After` says.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["Level 1 · Centres"],"summary":"A centre's status on the portal","security":[{"gestora":["facilities.write"]}],"parameters":[{"schema":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"The centre's identifier in your software.","example":"madrid-01"},"required":true,"description":"The centre's identifier in your software.","name":"facilityId","in":"path"},{"schema":{"type":"string","description":"A UUID. With the same key and the same body, for 24 hours, the same response."},"required":false,"description":"A UUID. With the same key and the same body, for 24 hours, the same response.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","description":"The language of the messages: `es` or `en` (the default)."},"required":false,"description":"The language of the messages: `es` or `en` (the default).","name":"Accept-Language","in":"header"}],"responses":{"200":{"description":"Its status, its listing and what it's missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FacilityState"}}}},"401":{"description":"`unauthorized`: no token, or an expired or invalid one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`: the token lacks this operation's scope · `connection_revoked`: the operator withdrew access · `software_suspended`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`: it isn't part of this connection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`: too many requests. Wait as long as `Retry-After` says.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Level 1 · Centres"],"summary":"Remove a centre from the portal","description":"It becomes `withdrawn`. If it's sent again, it comes back.","security":[{"gestora":["facilities.write"]}],"parameters":[{"schema":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"The centre's identifier in your software.","example":"madrid-01"},"required":true,"description":"The centre's identifier in your software.","name":"facilityId","in":"path"},{"schema":{"type":"string","description":"A UUID. With the same key and the same body, for 24 hours, the same response."},"required":false,"description":"A UUID. With the same key and the same body, for 24 hours, the same response.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","description":"The language of the messages: `es` or `en` (the default)."},"required":false,"description":"The language of the messages: `es` or `en` (the default).","name":"Accept-Language","in":"header"}],"responses":{"204":{"description":"Removed."},"401":{"description":"`unauthorized`: no token, or an expired or invalid one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`: the token lacks this operation's scope · `connection_revoked`: the operator withdrew access · `software_suspended`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`: it isn't part of this connection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`: too many requests. Wait as long as `Retry-After` says.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/facilities/{facilityId}/unit-types":{"put":{"tags":["Level 1 · Centres"],"summary":"Its sizes","description":"All the centre's sizes, with their name. Those not included are removed.","security":[{"gestora":["facilities.write"]}],"parameters":[{"schema":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"The centre's identifier in your software.","example":"madrid-01"},"required":true,"description":"The centre's identifier in your software.","name":"facilityId","in":"path"},{"schema":{"type":"string","description":"A UUID. With the same key and the same body, for 24 hours, the same response."},"required":false,"description":"A UUID. With the same key and the same body, for 24 hours, the same response.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","description":"The language of the messages: `es` or `en` (the default)."},"required":false,"description":"The language of the messages: `es` or `en` (the default).","name":"Accept-Language","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnitTypeList"}}}},"responses":{"200":{"description":"Saved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Accepted"}}}},"401":{"description":"`unauthorized`: no token, or an expired or invalid one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`: the token lacks this operation's scope · `connection_revoked`: the operator withdrew access · `software_suspended`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`idempotency_key_reused`: the same `Idempotency-Key` with a different body · `facility_not_ready`: the centre hasn't been sent yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`invalid_facility`, `invalid_unit_types`, `invalid_units`, `invalid_floor_plan`, `invalid_photo`… with every failing field in `fields`. Nothing from this submission is stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`: too many requests. Wait as long as `Retry-After` says.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/facilities/{facilityId}/units":{"put":{"tags":["Level 1 · Centres"],"summary":"All its units","description":"All the centre's units, with their status and their price. Those not included are removed. It never carries tenants' data.","security":[{"gestora":["facilities.write"]}],"parameters":[{"schema":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"The centre's identifier in your software.","example":"madrid-01"},"required":true,"description":"The centre's identifier in your software.","name":"facilityId","in":"path"},{"schema":{"type":"string","description":"A UUID. With the same key and the same body, for 24 hours, the same response."},"required":false,"description":"A UUID. With the same key and the same body, for 24 hours, the same response.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","description":"The language of the messages: `es` or `en` (the default)."},"required":false,"description":"The language of the messages: `es` or `en` (the default).","name":"Accept-Language","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnitList"}}}},"responses":{"200":{"description":"How many there are and how many are free.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnitsState"}}}},"401":{"description":"`unauthorized`: no token, or an expired or invalid one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`: the token lacks this operation's scope · `connection_revoked`: the operator withdrew access · `software_suspended`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`idempotency_key_reused`: the same `Idempotency-Key` with a different body · `facility_not_ready`: the centre hasn't been sent yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"`payload_too_large`: over 5 MB of JSON, 2 MB per floor or 15 MB per photo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`invalid_facility`, `invalid_unit_types`, `invalid_units`, `invalid_floor_plan`, `invalid_photo`… with every failing field in `fields`. Nothing from this submission is stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`: too many requests. Wait as long as `Retry-After` says.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/facilities/{facilityId}/units/{unitId}":{"put":{"tags":["Level 1 · Centres"],"summary":"A unit that changes","description":"As soon as it's rented, freed or blocked, or its price changes. If it didn't exist, it's added.","security":[{"gestora":["facilities.write"]}],"parameters":[{"schema":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"The centre's identifier in your software.","example":"madrid-01"},"required":true,"description":"The centre's identifier in your software.","name":"facilityId","in":"path"},{"schema":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"The unit's id in your software, the one in its `data-unit-id` on the floor plan.","example":"u-21"},"required":true,"description":"The unit's id in your software, the one in its `data-unit-id` on the floor plan.","name":"unitId","in":"path"},{"schema":{"type":"string","description":"A UUID. With the same key and the same body, for 24 hours, the same response."},"required":false,"description":"A UUID. With the same key and the same body, for 24 hours, the same response.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","description":"The language of the messages: `es` or `en` (the default)."},"required":false,"description":"The language of the messages: `es` or `en` (the default).","name":"Accept-Language","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnitFields"}}}},"responses":{"200":{"description":"How many there are and how many are free.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnitsState"}}}},"401":{"description":"`unauthorized`: no token, or an expired or invalid one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`: the token lacks this operation's scope · `connection_revoked`: the operator withdrew access · `software_suspended`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`idempotency_key_reused`: the same `Idempotency-Key` with a different body · `facility_not_ready`: the centre hasn't been sent yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`invalid_facility`, `invalid_unit_types`, `invalid_units`, `invalid_floor_plan`, `invalid_photo`… with every failing field in `fields`. Nothing from this submission is stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`: too many requests. Wait as long as `Retry-After` says.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/facilities/{facilityId}/floor-plan":{"put":{"tags":["Level 1 · Centres"],"summary":"Its floor plan","description":"Each floor's SVG, the same one your software's websites use (ADR-008). The portal cleans it (only shapes and text) and colours it by status; it never redraws it. Each unit's shape carries `data-unit-id` with its `id`: send the units first.","security":[{"gestora":["facilities.write"]}],"parameters":[{"schema":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"The centre's identifier in your software.","example":"madrid-01"},"required":true,"description":"The centre's identifier in your software.","name":"facilityId","in":"path"},{"schema":{"type":"string","description":"A UUID. With the same key and the same body, for 24 hours, the same response."},"required":false,"description":"A UUID. With the same key and the same body, for 24 hours, the same response.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","description":"The language of the messages: `es` or `en` (the default)."},"required":false,"description":"The language of the messages: `es` or `en` (the default).","name":"Accept-Language","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FloorPlan"}}}},"responses":{"200":{"description":"Saved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Accepted"}}}},"401":{"description":"`unauthorized`: no token, or an expired or invalid one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`: the token lacks this operation's scope · `connection_revoked`: the operator withdrew access · `software_suspended`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`idempotency_key_reused`: the same `Idempotency-Key` with a different body · `facility_not_ready`: the centre hasn't been sent yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"`payload_too_large`: over 5 MB of JSON, 2 MB per floor or 15 MB per photo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`invalid_facility`, `invalid_unit_types`, `invalid_units`, `invalid_floor_plan`, `invalid_photo`… with every failing field in `fields`. Nothing from this submission is stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`: too many requests. Wait as long as `Retry-After` says.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/facilities/{facilityId}/photos":{"put":{"tags":["Level 1 · Centres"],"summary":"The order of the photos","description":"The photos already uploaded, in display order, with their caption. Those not included are removed.","security":[{"gestora":["facilities.write"]}],"parameters":[{"schema":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"The centre's identifier in your software.","example":"madrid-01"},"required":true,"description":"The centre's identifier in your software.","name":"facilityId","in":"path"},{"schema":{"type":"string","description":"A UUID. With the same key and the same body, for 24 hours, the same response."},"required":false,"description":"A UUID. With the same key and the same body, for 24 hours, the same response.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","description":"The language of the messages: `es` or `en` (the default)."},"required":false,"description":"The language of the messages: `es` or `en` (the default).","name":"Accept-Language","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhotoList"}}}},"responses":{"200":{"description":"Saved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Accepted"}}}},"401":{"description":"`unauthorized`: no token, or an expired or invalid one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`: the token lacks this operation's scope · `connection_revoked`: the operator withdrew access · `software_suspended`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`idempotency_key_reused`: the same `Idempotency-Key` with a different body · `facility_not_ready`: the centre hasn't been sent yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`invalid_facility`, `invalid_unit_types`, `invalid_units`, `invalid_floor_plan`, `invalid_photo`… with every failing field in `fields`. Nothing from this submission is stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`: too many requests. Wait as long as `Retry-After` says.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/facilities/{facilityId}/photos/{photoId}":{"put":{"tags":["Level 1 · Centres"],"summary":"Upload a photo","description":"The image as it is: JPEG, PNG or WebP, up to 15 MB and at least 800 px on the long side. The portal reworks it: straightened, resized and without metadata (ADR-015). Photos aren't downloaded from a URL.","security":[{"gestora":["facilities.write"]}],"parameters":[{"schema":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"The centre's identifier in your software.","example":"madrid-01"},"required":true,"description":"The centre's identifier in your software.","name":"facilityId","in":"path"},{"schema":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"The photo's id in your software.","example":"u-21"},"required":true,"description":"The photo's id in your software.","name":"photoId","in":"path"},{"schema":{"type":"string","description":"A UUID. With the same key and the same body, for 24 hours, the same response."},"required":false,"description":"A UUID. With the same key and the same body, for 24 hours, the same response.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","description":"The language of the messages: `es` or `en` (the default)."},"required":false,"description":"The language of the messages: `es` or `en` (the default).","name":"Accept-Language","in":"header"}],"requestBody":{"required":true,"content":{"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/png":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"Uploaded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhotoState"}}}},"401":{"description":"`unauthorized`: no token, or an expired or invalid one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`: the token lacks this operation's scope · `connection_revoked`: the operator withdrew access · `software_suspended`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`idempotency_key_reused`: the same `Idempotency-Key` with a different body · `facility_not_ready`: the centre hasn't been sent yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"`payload_too_large`: over 5 MB of JSON, 2 MB per floor or 15 MB per photo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"`unsupported_media_type`: it isn't JPEG, PNG or WebP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`invalid_facility`, `invalid_unit_types`, `invalid_units`, `invalid_floor_plan`, `invalid_photo`… with every failing field in `fields`. Nothing from this submission is stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`: too many requests. Wait as long as `Retry-After` says.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/leads":{"get":{"tags":["Requests"],"summary":"The requests","description":"Those from the last 30 days, oldest first, in case a webhook was missed. Empty if the operator only wants them by email.","security":[{"gestora":["leads.read"]}],"parameters":[{"schema":{"type":"string","format":"date-time","description":"Those sent since this moment."},"required":false,"description":"Those sent since this moment.","name":"since","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"The previous page's `nextCursor`."},"required":false,"description":"The previous page's `nextCursor`.","name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","description":"A UUID. With the same key and the same body, for 24 hours, the same response."},"required":false,"description":"A UUID. With the same key and the same body, for 24 hours, the same response.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","description":"The language of the messages: `es` or `en` (the default)."},"required":false,"description":"The language of the messages: `es` or `en` (the default).","name":"Accept-Language","in":"header"}],"responses":{"200":{"description":"The requests.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadList"}}}},"401":{"description":"`unauthorized`: no token, or an expired or invalid one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`: the token lacks this operation's scope · `connection_revoked`: the operator withdrew access · `software_suspended`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`: too many requests. Wait as long as `Retry-After` says.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/leads/{leadId}/status":{"put":{"tags":["Requests"],"summary":"Mark a request as handled","description":"It's handled in Qbox too.","security":[{"gestora":["leads.read"]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"leadId","in":"path"},{"schema":{"type":"string","description":"A UUID. With the same key and the same body, for 24 hours, the same response."},"required":false,"description":"A UUID. With the same key and the same body, for 24 hours, the same response.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","description":"The language of the messages: `es` or `en` (the default)."},"required":false,"description":"The language of the messages: `es` or `en` (the default).","name":"Accept-Language","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadStatusInput"}}}},"responses":{"200":{"description":"The request, as it now stands.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Lead"}}}},"401":{"description":"`unauthorized`: no token, or an expired or invalid one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`: the token lacks this operation's scope · `connection_revoked`: the operator withdrew access · `software_suspended`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`: it isn't part of this connection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`invalid_facility`, `invalid_unit_types`, `invalid_units`, `invalid_floor_plan`, `invalid_photo`… with every failing field in `fields`. Nothing from this submission is stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`: too many requests. Wait as long as `Retry-After` says.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/connections":{"get":{"tags":["Your software"],"summary":"The operators that have given you access","security":[{"software":[]}],"responses":{"200":{"description":"The connections.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionList"}}}},"401":{"description":"`unauthorized`: no token, or an expired or invalid one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`: too many requests. Wait as long as `Retry-After` says.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/webhooks/test":{"post":{"tags":["Your software"],"summary":"Send yourself a test webhook","description":"Sends `test.ping` to your area's webhook URL, signed like all webhooks.","security":[{"software":[]}],"responses":{"202":{"description":"Sent."},"401":{"description":"`unauthorized`: no token, or an expired or invalid one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`: too many requests. Wait as long as `Retry-After` says.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/rentals/{rentalId}":{"put":{"tags":["Level 2 · Online rental"],"summary":"An online rental's status","description":"Level 2 (ADR-053). When your gateway's notification reaches your server, you tell us how it went: `paid`, with the contract number, `payment_failed`, `expired`, `cancelled` or `refunded`. With the token of the centre's operator (in testing, that of your \"Test operator\"). The `rentalId` is ours, the one that came in `POST /rentals`.","security":[{"gestora":["facilities.write"]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Ours."},"required":true,"description":"Ours.","name":"rentalId","in":"path"},{"schema":{"type":"string","description":"A UUID. With the same key and the same body, for 24 hours, the same response."},"required":false,"description":"A UUID. With the same key and the same body, for 24 hours, the same response.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","description":"The language of the messages: `es` or `en` (the default)."},"required":false,"description":"The language of the messages: `es` or `en` (the default).","name":"Accept-Language","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RentalStatusInput"}}}},"responses":{"200":{"description":"How it now stands on the portal.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RentalState"}}}},"401":{"description":"`unauthorized`: no token, or an expired or invalid one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`: the token lacks this operation's scope · `connection_revoked`: the operator withdrew access · `software_suspended`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`: it isn't part of this connection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`invalid_facility`, `invalid_unit_types`, `invalid_units`, `invalid_floor_plan`, `invalid_photo`… with every failing field in `fields`. Nothing from this submission is stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`: too many requests. Wait as long as `Retry-After` says.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"webhooks":{"rentalCreate":{"post":{"tags":["Level 2 · Online rental"],"summary":"`POST {rentalUrl}/rentals`: hold it and say what's paid today","description":"Signed like the webhooks (`Qbox-Signature`, with an empty body for `GET` and `DELETE`), with `Qbox-Mode` (`test` or `live`) and, if it changes something, `Idempotency-Key`. The portal waits 8 seconds at most: there's a customer waiting. Your errors, like ours: `{\"error\": {\"code\", \"message\"}}`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RentalCreate"}}}},"responses":{"201":{"description":"The rental.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rental"}}}}}}},"rentalTenant":{"put":{"tags":["Level 2 · Online rental"],"summary":"`PUT {rentalUrl}/rentals/{id}/tenant`: the tenant, with their verified email","description":"Signed like the webhooks (`Qbox-Signature`, with an empty body for `GET` and `DELETE`), with `Qbox-Mode` (`test` or `live`) and, if it changes something, `Idempotency-Key`. The portal waits 8 seconds at most: there's a customer waiting. Your errors, like ours: `{\"error\": {\"code\", \"message\"}}`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RentalTenant"}}}},"responses":{"200":{"description":"The rental.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rental"}}}}}}},"rentalContract":{"get":{"tags":["Level 2 · Online rental"],"summary":"`GET {rentalUrl}/rentals/{id}/contract`: the contract, to read it","description":"Signed like the webhooks (`Qbox-Signature`, with an empty body for `GET` and `DELETE`), with `Qbox-Mode` (`test` or `live`) and, if it changes something, `Idempotency-Key`. The portal waits 8 seconds at most: there's a customer waiting. Your errors, like ours: `{\"error\": {\"code\", \"message\"}}`.","responses":{"200":{"description":"The contract.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RentalContract"}}}}}}},"rentalAcceptance":{"post":{"tags":["Level 2 · Online rental"],"summary":"`POST {rentalUrl}/rentals/{id}/acceptance`: the proof that they accepted it","description":"Signed like the webhooks (`Qbox-Signature`, with an empty body for `GET` and `DELETE`), with `Qbox-Mode` (`test` or `live`) and, if it changes something, `Idempotency-Key`. The portal waits 8 seconds at most: there's a customer waiting. Your errors, like ours: `{\"error\": {\"code\", \"message\"}}`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RentalAcceptance"}}}},"responses":{"200":{"description":"The rental.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rental"}}}}}}},"rentalPayment":{"post":{"tags":["Level 2 · Online rental"],"summary":"`POST {rentalUrl}/rentals/{id}/payment`: the signed order, to pay","description":"Signed like the webhooks (`Qbox-Signature`, with an empty body for `GET` and `DELETE`), with `Qbox-Mode` (`test` or `live`) and, if it changes something, `Idempotency-Key`. The portal waits 8 seconds at most: there's a customer waiting. Your errors, like ours: `{\"error\": {\"code\", \"message\"}}`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RentalPaymentRequest"}}}},"responses":{"200":{"description":"Where the portal takes the customer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RentalPayment"}}}}}}},"rentalStatus":{"get":{"tags":["Level 2 · Online rental"],"summary":"`GET {rentalUrl}/rentals/{id}`: where it stands","description":"Signed like the webhooks (`Qbox-Signature`, with an empty body for `GET` and `DELETE`), with `Qbox-Mode` (`test` or `live`) and, if it changes something, `Idempotency-Key`. The portal waits 8 seconds at most: there's a customer waiting. Your errors, like ours: `{\"error\": {\"code\", \"message\"}}`.","responses":{"200":{"description":"The rental.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rental"}}}}}}},"rentalAccess":{"get":{"tags":["Level 2 · Online rental"],"summary":"`GET {rentalUrl}/rentals/{id}/access`: how to get in, once paid","description":"Signed like the webhooks (`Qbox-Signature`, with an empty body for `GET` and `DELETE`), with `Qbox-Mode` (`test` or `live`) and, if it changes something, `Idempotency-Key`. The portal waits 8 seconds at most: there's a customer waiting. Your errors, like ours: `{\"error\": {\"code\", \"message\"}}`.","responses":{"200":{"description":"How to get in.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RentalAccess"}}}}}}},"rentalSignedContract":{"get":{"tags":["Level 2 · Online rental"],"summary":"`GET {rentalUrl}/rentals/{id}/signed-contract`: the signed contract","description":"Signed like the webhooks (`Qbox-Signature`, with an empty body for `GET` and `DELETE`), with `Qbox-Mode` (`test` or `live`) and, if it changes something, `Idempotency-Key`. The portal waits 8 seconds at most: there's a customer waiting. Your errors, like ours: `{\"error\": {\"code\", \"message\"}}`.","responses":{"200":{"description":"The PDF.","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}}}}},"rentalCancel":{"delete":{"tags":["Level 2 · Online rental"],"summary":"`DELETE {rentalUrl}/rentals/{id}`: abandon it","description":"Signed like the webhooks (`Qbox-Signature`, with an empty body for `GET` and `DELETE`), with `Qbox-Mode` (`test` or `live`) and, if it changes something, `Idempotency-Key`. The portal waits 8 seconds at most: there's a customer waiting. Your errors, like ours: `{\"error\": {\"code\", \"message\"}}`.","responses":{"200":{"description":"The rental.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rental"}}}}}}},"connectionCreated":{"post":{"summary":"`connection.created`","description":"Signed in the `Qbox-Signature: t=<Unix seconds>,v1=<signature>` header: the HMAC-SHA256, in hex, of `<t>.<raw body>`, with your area's webhook secret. Reject those older than 5 minutes. Reply with a 2xx within 10 seconds; otherwise it's retried after 1, 5, 15 and 60 minutes and then every hour, for a day.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Received."}}}},"connectionRevoked":{"post":{"summary":"`connection.revoked`","description":"Signed in the `Qbox-Signature: t=<Unix seconds>,v1=<signature>` header: the HMAC-SHA256, in hex, of `<t>.<raw body>`, with your area's webhook secret. Reject those older than 5 minutes. Reply with a 2xx within 10 seconds; otherwise it's retried after 1, 5, 15 and 60 minutes and then every hour, for a day.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Received."}}}},"facilityLinked":{"post":{"summary":"`facility.linked`","description":"Signed in the `Qbox-Signature: t=<Unix seconds>,v1=<signature>` header: the HMAC-SHA256, in hex, of `<t>.<raw body>`, with your area's webhook secret. Reject those older than 5 minutes. Reply with a 2xx within 10 seconds; otherwise it's retried after 1, 5, 15 and 60 minutes and then every hour, for a day.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Received."}}}},"facilityReviewed":{"post":{"summary":"`facility.reviewed`","description":"Signed in the `Qbox-Signature: t=<Unix seconds>,v1=<signature>` header: the HMAC-SHA256, in hex, of `<t>.<raw body>`, with your area's webhook secret. Reject those older than 5 minutes. Reply with a 2xx within 10 seconds; otherwise it's retried after 1, 5, 15 and 60 minutes and then every hour, for a day.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Received."}}}},"facilityIssues":{"post":{"summary":"`facility.issues`","description":"Signed in the `Qbox-Signature: t=<Unix seconds>,v1=<signature>` header: the HMAC-SHA256, in hex, of `<t>.<raw body>`, with your area's webhook secret. Reject those older than 5 minutes. Reply with a 2xx within 10 seconds; otherwise it's retried after 1, 5, 15 and 60 minutes and then every hour, for a day.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Received."}}}},"leadCreated":{"post":{"summary":"`lead.created`","description":"Signed in the `Qbox-Signature: t=<Unix seconds>,v1=<signature>` header: the HMAC-SHA256, in hex, of `<t>.<raw body>`, with your area's webhook secret. Reject those older than 5 minutes. Reply with a 2xx within 10 seconds; otherwise it's retried after 1, 5, 15 and 60 minutes and then every hour, for a day.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Received."}}}},"testPing":{"post":{"summary":"`test.ping`","description":"Signed in the `Qbox-Signature: t=<Unix seconds>,v1=<signature>` header: the HMAC-SHA256, in hex, of `<t>.<raw body>`, with your area's webhook secret. Reject those older than 5 minutes. Reply with a 2xx within 10 seconds; otherwise it's retried after 1, 5, 15 and 60 minutes and then every hour, for a day.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Received."}}}}}}