Bazarok Partner API — OAuth 2.0 integration
Version 1 · Base URL: https://www.bazarok.pl · Ukrainian version: partner_api_oauth_uk.md
Your CRM can publish, update and remove the real-estate listings of any number of agencies on Bazarok. Each agency connects its Bazarok account to your CRM itself, once, with one click (OAuth 2.0): there is nothing to set up on our side per agency.
| Agency action in your CRM | Bazarok endpoint |
|---|---|
| "Connect Bazarok" | GET /oauth_authorize.php → POST /oauth_token.php |
| Publish | POST /api/v1/listings |
| Update | PUT /api/v1/listings/{external_id} |
| Remove a listing | DELETE /api/v1/listings/{external_id} |
| "Disconnect Bazarok" | POST /oauth_revoke.php (or DELETE /api/v1/connection) |
What we need from you: your CRM's name, your redirect URI(s) (https). What you get from us: a client_id, a client_secret. Keep the secrets on your servers only.
1. Connecting an agency (OAuth 2.0, authorization code)
1.1 Send the agency to Bazarok
GET https://www.bazarok.pl/oauth_authorize.php
?response_type=code
&client_id=<client_id>
&redirect_uri=https://<your-crm>/oauth/bazarok/callback (exactly as registered)
&state=<random value, checked by your CRM on return>
[&code_challenge=<BASE64URL(SHA256(verifier))>&code_challenge_method=S256] (PKCE, optional)The agency logs in to Bazarok (or creates an account), sees what your CRM will be allowed to do, and clicks Allow or Deny. Bazarok then redirects to the redirect_uri:
- allowed:
?code=<code>&state=<state>— the code is valid 10 minutes and works once; - denied:
?error=access_denied&state=<state>.
1.2 Exchange the code (server to server)
POST https://www.bazarok.pl/oauth_token.php
Authorization: Basic base64(client_id:client_secret) (or client_id / client_secret in the body)
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=<code>&redirect_uri=<same redirect_uri>[&code_verifier=<verifier>]{ "access_token": "…", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "…", "account_id": 123456 }account_id is the agency's Bazarok account id: store it with the agency's tokens. Each agency has its own tokens.
1.3 Refresh
The access token lasts 1 hour, the refresh token 1 year. Refresh tokens rotate: each refresh returns a new pair and invalidates the previous refresh token — always store the new one.
POST /oauth_token.php grant_type=refresh_token&refresh_token=<refresh_token> (client authentication as above)Refresh when you get 401 token_expired, or a few minutes before expires_in.
1.4 Disconnect
POST /oauth_revoke.php token=<access or refresh token> (client authentication as above)Revokes the whole connection between this agency and your CRM (all its tokens). Reconnecting requires the agency to go through 1.1 again. Same effect: DELETE /api/v1/connection with the access token.
OAuth errors follow RFC 6749: {"error": "invalid_grant", "error_description": "…"}.
2. API conventions
- Every call:
Authorization: Bearer <access_token of the agency>; JSON bodies withContent-Type: application/json, UTF-8. Dates:YYYY-MM-DD HH:MM:SS, server time (Europe/Paris). - Errors: HTTP status + a stable machine-readable code (test the code, not the message):
{ "error": { "code": "validation_error", "message": "Some fields are missing or invalid.",
"fields": { "price": "required, number > 0", "contact.phone": "invalid phone number: 12" } } }| HTTP | error.code | Meaning / what to do |
|---|---|---|
| 401 | invalid_token | Token unknown or revoked: ask the agency to connect Bazarok again. |
| 401 | token_expired | Refresh the token and retry. |
| 422 | validation_error | Missing/invalid fields — fields lists them (show them next to the fields). |
| 422 | listing_rejected | The listing could not be saved (usually the location). |
| 403 | account_expired | The agency's trial/subscription has ended: a Bazarok subscription is needed. |
| 403 | quota_exceeded | Active listings limit of the agency reached. |
| 409 | already_exists | POST with an external_id already published: use PUT. |
| 404 | not_found | Unknown listing. |
| 429 | rate_limited | More than 120 requests in a minute for this agency: wait Retry-After seconds. |
2.1 Working with hundreds of agencies
- Throttle your calls: at most 5 requests in parallel for your whole CRM, and one at a time per agency. Publishing downloads the photos during the call (up to ~60 s), so a first import of an agency with hundreds of listings takes time: run it as a background queue.
- Retry
5xxanswers and timeouts later with an increasing delay (1 min, 5 min, 30 min…). Do not retry4xxanswers unchanged. - Only send changes:
PUTa listing when it changed in your CRM, not on every sync.
Limit: 120 requests per minute per agency (headers X-RateLimit-Limit and X-RateLimit-Remaining on every answer). Above it: 429 rate_limited with a Retry-After header (seconds).
3. Account — GET /api/v1/me
{ "account_id": 123456, "name": "ESTATYQ", "email": "…", "phone": "…",
"status": "trial", // trial | active | expired
"trial_ends_at": "2026-12-07 10:00:00",
"subscription": null, // or { "status": "active", "paid_until": "…" }
"listings": { "active": 212, "allowed": 300 },
"site": { "domain": "bazarok.pl", "country_code": "ua",
"currencies": ["uah", "usd", "eur"], // accepted by "currency" (the first one is the default)
"land_units": ["сотка", "га"] } } // accepted by "land_area_unit" (the first one is the default)The API works the same way on every site of the group (bazarok.ua, bazarok.pl, bazarok.fr, bazarok.co.uk, buenanuncios.es, bonsanuncios.pt, skelbus.lt): call it on the site where the agency publishes. site gives the currencies and land-area units that site accepts; listing titles are generated in the site's language.
4. Locations
A listing is located with a Bazarok city_id (recommended), or with city + region names (Ukrainian or Russian, exactly as in Bazarok).
GET /api/v1/locations/cities?q=Київ→{ "cities": [ { "city_id": 1, "name": "Київ", "name_ru": "Киев", "region": "Київська область", "region_ru": "…" } ] }GET /api/v1/locations/districts?city_id=1→{ "districts": [ { "district_id": 7, "name": "Печерський", "name_ru": "Печерский" } ] }
Map your own cities to city_id once and store the mapping (it is the same for all agencies).
5. Listings
external_id = the property id in your CRM (1–60 characters A-Z a-z 0-9 . _ -), unique per agency. It identifies the listing in all later calls; Bazarok's own id is returned for information.
Publish — POST /api/v1/listings → 201
{
"external_id": "CRM-48213",
"deal_type": "rent", // sale | rent
"property_type": "apartment", // apartment | room | house | land | commercial | garage
"price": 18000, "currency": "uah", // one of site.currencies (GET /me) — monthly price for rent
"description": "Світла 2-кімнатна квартира…", // 10–10000 characters
"rooms": 2, "area": 54.5, "living_area": 30, // m²
"land_area": null, "land_area_unit": "сотка", // unit: one of site.land_units (GET /me)
"floor": 5, "floors_total": 9,
"lift": true, "balcony": true, "new_building": false, "parking": false, "furnished": true,
"city_id": 1, "district": "Печерський", "address": "вул. Лесі Українки, 10",
"lat": 50.4301, "lon": 30.5402,
"photos": [ "https://cdn.example.com/1.jpg", "https://cdn.example.com/2.jpg" ], // up to 15, public http(s) URLs, first = cover
"contact": {
"name": "John",
"phone": "0671234567,0501234567"
}
}Required: external_id, deal_type, property_type, price, description, city_id (or city + region). The title is generated by Bazarok from the type, rooms, area and location.
contact (optional): the realtor of the agency in charge of this listing.
name: up to 100 characters.phone: required insidecontact; 1 to 5 numbers, comma-separated ("0671234567,0501234567") or a JSON array (["+380671234567", "0501234567"]); digits, spaces,+ ( ) -, 9 to 15 digits each.- Visitors who click "Show phone number" on the listing get the first number, with the contact's name; the other numbers are kept and returned by the API.
- Without
contact, the phone of the agency account is shown.
Response:
{ "listing": { "id": 9876543, "external_id": "CRM-48213", "status": "active",
"url": "https://www.bazarok.pl/oholoshennya/…-9876543.html",
"title": "Квартира 2-кімн. оренда Київ, Печерський – 54.5 м²", "photos_count": 2,
"contact": { "name": "John", "phone": "0671234567,0501234567" },
"updated_at": "2026-10-27 14:02:11" } }status: active (online) · expired · inactive · deleted.
Update — PUT /api/v1/listings/{external_id} → 200
Same body as publish: full replacement of price, text, photos, characteristics, location and contact (external_id may be omitted). A field you leave out is cleared — in particular, send contact again or the agency's phone will be shown. Photos are downloaded again only if the URL list changed.
Status — GET /api/v1/listings/{external_id} · Remove — DELETE /api/v1/listings/{external_id}
A removed listing can be published again with POST and the same external_id.
6. Getting started
- Send us your CRM name, redirect URI(s); we send back
client_idandclient_secret. - Add a "Connect Bazarok" button for agencies (1.1), exchange the code (1.2), store the tokens with
account_id. - Map your cities to
city_id(GET /api/v1/locations/cities). - With a test agency: publish a listing, open the returned
url, update it, remove it.
Questions: contact@bazarok.pl