Submitting applications
POST /units/{id}/applications is the only write operation in the Catalogue API. It turns an end client’s enquiry about a specific unit into records in the CRM of the company that owns the key: the client, their interests (an opportunity), a draft offer for the selected unit, and the link between the offer and the opportunity. All four are written in a single transaction — either everything is created or nothing is.
How it works
Section titled “How it works”There is no signed-in user behind the request, so ownership and authorship are taken from the key: the agency that owns the key receives the application, and the user who issued the key is recorded as its author. A unit of a draft or deleted project, or of a developer without an approved contract, is treated as not found (404).
The operation is not idempotent: each call creates a new opportunity and a new offer. An existing client is reused if the company already has one with the same email address or the same mobile number (compared by digits only); in that case client.created is false and the client’s fields are left unchanged.
Request body
Section titled “Request body”| Field | Notes |
|---|---|
client.first_name |
Required, up to 255 characters. |
client.email / client.mobile_number |
At least one is required. Email is lower-cased and must contain @; the mobile number is stored as given, including the country code. |
client.last_name, landline_number, address_line1/2, city, country, postcode |
Optional. |
client.social_links |
Handles only (instagram, tiktok, facebook, x), without URLs. |
preferences.based_on_unit |
Adds the project’s property type and area, the unit’s tags, the project’s features and amenities, and the unit price as budget bounds. |
preferences.property_types, preferred_area_ids, property_features, preference_ids, project_preference_ids |
Explicit interests, up to 100 items each. Unknown reference IDs return 400. |
preferences.investment_type, min_budget, max_budget |
Optional. An explicit budget bound takes precedence over the unit price. |
message |
The client’s own message, up to 5000 characters; stored in the opportunity notes. |
language |
Offer language, en by default. |
currency |
AED or USD; defaults to the project currency if it is one of those, otherwise AED. |
Example
Section titled “Example”curl https://agent-dev.azizdubai.com/units/123/applications \ -H "X-API-Key: $AZIZ_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "client": { "first_name": "Ivan", "last_name": "Petrov", "email": "ivan.petrov@example.com", "mobile_number": "+971 50 111 22 33" }, "preferences": { "based_on_unit": true }, "message": "Please call me after 6 pm" }'A successful call returns 201 with the created (or reused) client, the opportunity with its board stage, and the draft offer including its public uuid. The offer PDF is generated and sent by the main Aziz backend, so offer.is_sent is always false here.
Errors
Section titled “Errors”400 covers a body that is not JSON or exceeds 64 KiB, a missing first name, no contact channel (client.email or client.mobile_number is required), an unknown reference ID, an inverted budget range, or a value over its maximum length. 401 additionally covers a key whose company or author has been removed (api key author is gone). 500 offer status catalogue is empty means reference data is not configured on the server and cannot be fixed by the caller.