Build your own website
Changelog
Every change to the Wzgate public API — what was added, what is deprecated and when it goes, and what has been removed.
The public API is a contract. A breaking change is announced here first, the old behaviour keeps working for a stated period, and only then is it removed. Nothing is withdrawn without appearing on this page with a date.
Watch this page — it is the only place a removal is announced.
2026-09-19
Changed — owner listings
POST /public/owner-listingsneeds a signed-in, verified visitor. Send the visitor's token asAuthorization: Bearer <token>. An anonymous call is a401; only a verified account can sign in, so a token is proof enough. The listing is filed under that account — the API no longer matches owners by a typed phone or email.nameandphoneare optional; the account's own name labels the owner when they are missing.emailis accepted and ignored — the account's address is already known. It will be removed from the body with notice here.mediaUrlsis removed. A body that still sends it is a400. Photos are uploaded to the listing itself, so the flow is now three calls:POST /public/owner-listingswithdraft: true— creates a draft.POST /public/owner-listings/:id/media— upload photos (multipart, up to 20, 8 MB each, JPEG/PNG/WebP).POST /public/owner-listings/:id/submit— sends it for review.
- Submit needs at least five photos. Submit, resubmit and a non-draft create
answer
400 PHOTOS_TOO_FEWwithdetails: { min, count }below that. Drafts andPATCHare never blocked by it. PATCH /public/owner-listings/:idacceptsnameandphone, andGET /public/owner-listings/:idreturns them, so an edit form can prefill what was saved rather than the profile.mineand:idreturnlisting: { slug, status }once staff approve the request and a property exists.slugis present only while the listing is public — link to it when it is there, and not otherwise.- Owner-listing routes require the
realestate.secondarymodule. An organization without it answers403 MODULE_NOT_ENABLEDon every/public/owner-listings/*route. Readfeatures.ownerListings(below) and hide your "sell" entry points when it isfalse.
Changed — visitor sessions
- Tokens can be revoked. Logout, a password change, a password reset,
account deletion and staff disabling the account all end every session the
account holds. A revoked token is a
401 VISITOR_SESSION_EXPIRED: clear it and send the visitor to sign in. A disabled account is403 VISITOR_DISABLEDon sign-in and on any signed-in call. POST /public/me/passwordreturns a freshtoken. The change revokes the token that made the call, so store the new one or the next request is a401 VISITOR_SESSION_EXPIRED. A wrong current password is a401that does not end the session.- Logout reads the Bearer token from
Authorization, like every other signed-in call — no body needed. resend-otpis bot-checked and rate-limited per account. SendX-Turnstile-Tokenas on the other protected writes; a resend inside the cooldown is429 RESEND_TOO_SOONwithdetails.retryAfterSeconds— show a countdown instead of retrying.- An unverified sign-in returns
details.visitorIdwith401 VISITOR_EMAIL_NOT_VERIFIED, so you can go straight to the OTP screen and callresend-otpwithout asking the visitor to register again. - Reset links carry
<visitorId>.<secret>as the token. Pass it through unchanged. A malformed, old-format, used or expired token is400 RESET_TOKEN_INVALID.
Added
- Register takes
intentandacceptTerms.intentis optional,BUYERorSELLER— a hint recorded for the CRM that grants nothing.acceptTermsis optional but must betruewhen sent; send it when your form has a terms checkbox. GET /public/company-profilegainsfeatures.ownerListings(boolean — whether owner listings are open on this site) andsite.ownerReviewSlaHours(number ornull— how long staff aim to take over a review, for "we reply within …" copy).- A registered domain alone identifies the site on every public route. A
browser call from one of the site's domains needs no header: the
Originis enough, including on module-gated routes, which previously still demandedX-Subdomain.X-SiteandX-Subdomainkeep working. See Identify your site.
Error codes
| Code | Status | Meaning | المعنى |
|---|---|---|---|
VISITOR_TOKEN_REQUIRED | 401 | A signed-in route (now including POST /public/owner-listings) was called with no token. | استُدعي مسار يتطلّب تسجيل الدخول بلا رمز. |
VISITOR_SESSION_EXPIRED | 401 | The token was revoked by logout, a password change or reset, or account deletion. | أُلغي الرمز بتسجيل الخروج أو تغيير كلمة المرور أو استعادتها أو حذف الحساب. |
VISITOR_DISABLED | 403 | Staff disabled the account. | عطّل فريق العمل الحساب. |
VISITOR_EMAIL_NOT_VERIFIED | 401 | Sign-in before the email is verified; details.visitorId is set. | تسجيل دخول قبل تأكيد البريد؛ ويأتي details.visitorId. |
RESEND_TOO_SOON | 429 | resend-otp inside the cooldown; wait details.retryAfterSeconds. | إعادة إرسال الرمز خلال مهلة الانتظار؛ انتظر details.retryAfterSeconds. |
RESET_TOKEN_INVALID | 400 | The reset token is malformed, old-format, used or expired. | رمز الاستعادة مشوّه أو بالصيغة القديمة أو مستخدم أو منتهٍ. |
PHOTOS_TOO_FEW | 400 | Submitting a listing with fewer than five photos; details: { min, count }. | إرسال عرض بأقل من خمس صور؛ ويأتي details: { min, count }. |
MODULE_NOT_ENABLED | 403 | The organization does not have realestate.secondary, so owner listings are closed. | المؤسّسة لا تملك realestate.secondary، فعروض المُلّاك مغلقة. |
2026-09-14
Added
X-Site— identify a site by its key instead of by its organization. An organization can now run several public websites (real estate, stays, company profile) and a request resolves a site, not just a tenant. A verified domain resolves the site with no header at all. See Identify your site.X-Api-Key— per-site publishable (pk_…) and secret (sk_…) keys, created in the CRM under Settings → Websites → Connect your website. A publishable key is only valid from the site's own domains; a secret key is for your server and gets five times the rate limits. Currently in monitor mode: a call without a key is served and the refusal is logged. Enforcement will be announced here before it is switched on. See Keys and CORS.X-Turnstile-Token— a Cloudflare Turnstile token on the five writes bots abuse: leads, viewing requests, visitor register, forgot-password and newsletter. Required with a publishable key, skipped for secret-key calls, inactive where the site has no Turnstile configured. See Bot protection.GET /public-openapi.json— a machine-readable OpenAPI 3 document containing only/api/public/*, with the headers above declared on every operation. It is the source of the API reference in these docs, and the thing to point a client generator at.- Legal text on the company profile —
legal.privacyandlegal.termsarrive as{ en, ar }rich text beside the existingprivacyUrl/termsUrl. A site can now render its own/privacy-policyand/termsfrom the CRM instead of hard-coding copy: if a URL is set, redirect to it; else if text is set, render it; else fall back to your own page. - Viewing validation errors —
VIEWING_SLOT_INVALID,VIEWING_DAY_CLOSED,VIEWING_SLOT_TOO_SOON(400) andVIEWING_SLOT_TAKEN(409). Booking now respects the site's working days, slot list, time zone and minimum notice, and a slot can be held by only one live request. Previously a booking outside the rules was accepted and two visitors could take the same slot. See Errors.
Deprecated
X-Subdomain— still honoured, and still resolves an organization's default site, so existing websites keep working unchanged. It cannot name one site among several, which is whyX-Sitereplaces it. Removal date: to be announced here, with notice, once live sites have moved. Migration is one line: sendX-Site: <site key>(from the Connect tab) instead of, or alongside,X-Subdomain.
Removed
/api/public/promotion/*— the owner "promote your listing" flow and its plans are gone from the API and from the CRM. Nothing replaces it. A website still calling those paths gets a404; remove the calls and any UI that offered promotion.