lalafo Python SDK
A typed Python client for lalafo.az. Sign in, read categories and their params, post an ad with photos, edit, deactivate, activate and delete it, and list your own ads. Sync and async.
$ pip install lalafo-python-sdk
lalafo.az is one of the big classifieds sites in Azerbaijan, with a large real estate section. lalafo has no public API, so this SDK talks to the same endpoints the lalafo.az website uses, with the same headers. It sends no device fingerprint and no mobile app identity.
Posting an ad, the way the website does
Posting on lalafo is not one request. The website loads the form for the category and city, makes a draft, clears photos left in an old draft, uploads the new photos, saves the draft and publishes it. ads.create() does all of that in one call, and every step is also there on its own.
lalafo writes the title itself, something like “Bakı, 2 otaqlı, Köhnə tikili, 42 kv. m”. The ad then goes to moderation, and ads.wait() waits until moderation is over. An ad over the free limit comes back waiting for payment. The client never pays.
Before the draft is even made, the params are checked against the form: unknown fields, unknown options, two values for a single choice field, missing required fields. Nothing is sent until the form is right. Photos are checked too, from 1 to 20, each between 20 KB and 20 MB.
Sessions that renew themselves
Sign in with a phone number or an email. The token is renewed with the refresh token once 75% of its lifetime has passed, or once after a 401, and every new session is handed to your code so you can store it. If lalafo starts asking for a captcha after failed sign ins, the client stops and tells you. It never solves captchas.
Managing ads
Edit, deactivate, activate and delete. List ads by status: active, in moderation, rejected, deactivated or waiting for payment. The README lists the lalafo.az real estate category ids, so posting a flat or a plot does not start with a search.
Never twice
lalafo.az is sometimes slow and sometimes answers with a short Cloudflare check page. Reads ride over that with retries. A write that timed out may still have gone through, so it is never sent again on its own: the client raises OutcomeUnknownError and you check the ad list first.
Built with Python, httpx and Pydantic, sync and async, typed with mypy and covered by 55 tests. MIT licensed.