# ImobyFlow API — full reference (1.0.0) Base URL: https://api.imobyflow.com.br/v1 Authentication: `Authorization: Bearer imob_live_…` — header only, never in the URL. Language: `Accept-Language: pt-BR` or `en`. ## Conventions - Adding does not break: new fields, events, routes and values can arrive at any time. Your system must tolerate fields it does not know. - Anything that breaks an existing integration ships in a new version (`/v2`). The previous version keeps working for at least 12 months after the notice, published here and e-mailed to the account owner. - Code values (`VENDA`, `ACTIVE`, the subtypes) are the same as the platform's, with no translation layer. - Errors are `application/problem+json` (RFC 9457): `type`, `title`, `status`, `code`, `requestId`, `detail` and `invalidParams` (all problems at once). - Lists: `limit` and `cursor`; follow `nextCursor` until it comes back null. - Writes: absent fields are kept; `null` clears; unknown fields are a 400 error; nothing changed = `UNCHANGED`, nothing written. - `?dryRun=true` validates and says what would happen, without writing. `Idempotency-Key` (up to 100 characters) makes retries safe for 24 h. ## Account The account that owns the key: plan, property quota, key permissions, limits and monthly usage. ### GET /me — Who am I The first call of every integration: confirms the key works and shows the account, this key's permissions, the limits and monthly usage. - Permission: any valid key Response 200: - `data` (Me): Account. Errors: common ones only ```bash curl -X GET 'https://api.imobyflow.com.br/v1/me' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ## Reference lists The accepted values for each code field: property types, purposes, statuses, stages, permissions and events. They are the SAME values stored by the platform — there is no translation layer. ### GET /reference/property-types — Property types Categories and subtypes. The subtype is what goes in the `type` field. - Permission: any valid key Response 200: - `data` (array): The list. Errors: common ones only ```bash curl -X GET 'https://api.imobyflow.com.br/v1/reference/property-types' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### GET /reference/purposes — Purposes Sale and rent. - Permission: any valid key Response 200: - `data` (array): The list. Errors: common ones only ```bash curl -X GET 'https://api.imobyflow.com.br/v1/reference/purposes' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### GET /reference/property-statuses — Property statuses The statuses a property can have. - Permission: any valid key Response 200: - `data` (array): The list. Errors: common ones only ```bash curl -X GET 'https://api.imobyflow.com.br/v1/reference/property-statuses' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### GET /reference/lead-statuses — Client stages The funnel stages. - Permission: any valid key Response 200: - `data` (array): The list. Errors: common ones only ```bash curl -X GET 'https://api.imobyflow.com.br/v1/reference/lead-statuses' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### GET /reference/partnership-statuses — Partnership stages The partnership stages. - Permission: any valid key Response 200: - `data` (array): The list. Errors: common ones only ```bash curl -X GET 'https://api.imobyflow.com.br/v1/reference/partnership-statuses' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### GET /reference/construction-stages — Construction stages The stages of a new development. - Permission: any valid key Response 200: - `data` (array): The list. Errors: common ones only ```bash curl -X GET 'https://api.imobyflow.com.br/v1/reference/construction-stages' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### GET /reference/scopes — Permissions The permissions a key can have. - Permission: any valid key Response 200: - `data` (array): The list. Errors: common ones only ```bash curl -X GET 'https://api.imobyflow.com.br/v1/reference/scopes' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### GET /reference/event-types — Event types The events, with the read permission that grants access to each. - Permission: any valid key Response 200: - `data` (array): The list. Errors: common ones only ```bash curl -X GET 'https://api.imobyflow.com.br/v1/reference/event-types' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ## Cities and neighborhoods The location catalog: city by its IBGE code and neighborhood by its catalog identifier. Neighborhoods are closed against the catalog — that is what lets a property into recommendations. ### GET /geo/cities — Cities Catalog cities, with their IBGE code. - Permission: any valid key - `uf`: Only one state (2 letters). - `q`: Part of the name (accents ignored). - `limit`: Items per page: 1 to 1000 (default 100). - `cursor`: The `nextCursor` from the previous page. The list is over when it comes back null. It is only valid for this route and this account. Response 200: - `data` (array): The cities. - `nextCursor` (string; nullable): Next page. - `total` (integer): Total in the filter. Errors: `invalid_param` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/geo/cities' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### GET /geo/cities/{cityId}/neighborhoods — A city's neighborhoods Catalog neighborhoods. The `neighborhoodSlug` from here is what guarantees the property enters recommendations. - Permission: any valid key - `cityId`: IBGE code (7 digits). - `limit`: Items per page: 1 to 1000 (default 100). - `cursor`: The `nextCursor` from the previous page. The list is over when it comes back null. It is only valid for this route and this account. Response 200: - `data` (array): The neighborhoods. - `nextCursor` (string; nullable): Next page. - `total` (integer): Total. Errors: `invalid_param`, `not_found` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/geo/cities/4106902/neighborhoods' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ## Properties The account's portfolio: read, sync by your system's code, change status, confirm availability, send photos by URL and move to the trash. ### GET /properties — List the portfolio The account's portfolio, newest first, with filters. To sync, use `updatedSince` — or the events. - Permission: `properties:read` - `limit`: Items per page: 1 to 100 (default 50). - `cursor`: The `nextCursor` from the previous page. The list is over when it comes back null. It is only valid for this route and this account. - `status`: Status (`DELETED` = trash). - `purpose`: Purpose. - `type`: Subtype. - `citySlug`: City identifier in the catalog. - `updatedSince`: Only what changed since this date/time (ISO 8601, UTC). - `radar`: `pending` = only items with recommendation pending items; `ready` = only ready items. Response 200: - `data` (array): The properties. - `nextCursor` (string; nullable): Next page cursor (null = done). Errors: `invalid_param`, `invalid_cursor`, `upstream_timeout`, `upstream_busy` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/properties' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### GET /properties/by-ref/{ref} — One property by your code The property by your system's code (`externalRef`). - Permission: `properties:read` - `ref`: The property's code in your system (up to 80 characters; encode spaces and `/`). Response 200: - `data` (Property): The property. Errors: `not_found` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/properties/by-ref/AP1234' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### GET /properties/{propertyId} — One property The property, with its recommendation, review and confirmation status. - Permission: `properties:read` - `propertyId`: Property id (`prop-…`). Response 200: - `data` (Property): The property. Errors: `not_found` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/properties/prop-3f9a1c2b7d4e' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### GET /feed — Feed sync status How the last CRM link sync ended and whether another is scheduled — to check the result after a `POST /v1/feed/sync`. Never includes the link or the token. - Permission: `properties:read` Response 200: - `data` (FeedSync): The status. Errors: common ones only ```bash curl -X GET 'https://api.imobyflow.com.br/v1/feed' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### POST /feed/sync — Sync the feed now Call it after changing the portfolio in your CRM: ImobyFlow fetches the SAME feed link, through the same 6-hourly sync — only what changed is written. The first call in each 10-minute window syncs right away; later ones leave ONE sync scheduled for the end of the window, so no change waits 6 hours and calling on every change overloads nothing. Follow it with `GET /v1/feed` or the property events. - Permission: `properties:write` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` Response 202 (200 when one was already scheduled (`ALREADY_SCHEDULED`) and on dry runs.): - `data` (FeedSync): The status. - `result` (FeedSyncResult): The outcome. Errors: `feed_not_configured`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `request_refused` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X POST 'https://api.imobyflow.com.br/v1/feed/sync?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" ``` ### PUT /properties/by-ref/{ref} — Create or update by your code The natural sync path: creates the property when the code is new (201) or updates the existing one (200). Absent fields are kept; nothing changed = `UNCHANGED`, nothing written. Edits made in the dashboard win and come back in `result.conflicts`. - Permission: `properties:write` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` - `ref`: The property's code in your system (up to 80 characters; encode spaces and `/`). Body: - `externalRef` (string): The property's code in your system (POST only; in PUT it goes in the path). - `title` (string): Title. HTML markup is stripped. - `description` (string): Description. `
` and `

` become line breaks; other markup is stripped. - `type` (string; APARTAMENTO | CASA_RUA | CASA_CONDOMINIO | CASA_VILA | STUDIO | FLAT | COBERTURA | SALA_COMERCIAL | LOJA_PONTO | GALPAO | PREDIO | TERRENO_RUA | TERRENO_CONDOMINIO | CHACARA_SITIO | FAZENDA): Subtype. - `purposes` (array): Purposes. - `salePrice` (number; nullable): Sale price, in BRL. Required with `VENDA`. - `rentPrice` (number; nullable): Rent, in BRL. Required with `LOCACAO`. - `address` (AddressInput): Address. - `bedrooms` (integer; nullable): Bedrooms. - `suites` (integer; nullable): Suites. - `bathrooms` (integer; nullable): Bathrooms. - `parkingSpots` (integer; nullable): Parking spots. - `area` (number; nullable): Total private area, in m². - `privateArea` (number; nullable): Covered area, in m². - `listingUrl` (string; nullable): Listing URL on your website (http or https). - `captadorName` (string; nullable): Listing agent name as text. - `captadorAccountId` (string; nullable): Id of the responsible broker on the team. - `partnershipTerms` (PartnershipTerms): Partner terms. - `photos` (array): Up to 30 URLs; the 1st is the cover. Downloaded after the response (see `photoSync`). Absent = gallery unchanged; empty list = remove the photos. Response 200 (201 when it creates.): - `data` (Property): The object as it now stands. - `result` (PropertyWriteResult): The outcome. Errors: `invalid_body`, `invalid_param`, `payload_too_large`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `request_refused`, `feed_sync_active`, `plan_limit_reached`, `property_in_trash`, `invalid_property`, `concurrent_write`, `upstream_timeout` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X PUT 'https://api.imobyflow.com.br/v1/properties/by-ref/AP1234?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" \ -H 'Content-Type: application/json' \ --data @- <<'JSON' { "title": "Apartamento 3 quartos no Bigorrilho", "type": "APARTAMENTO", "purposes": [ "VENDA" ], "salePrice": 890000, "address": { "cityId": "4106902", "neighborhoodSlug": "bigorrilho", "street": "Rua Padre Anchieta", "number": "1500", "complement": "Ap 82" }, "bedrooms": 3, "suites": 1, "bathrooms": 2, "parkingSpots": 2, "area": 98, "photos": [ "https://www.suaimobiliaria.com.br/fotos/AP1234/1.jpg", "https://www.suaimobiliaria.com.br/fotos/AP1234/2.jpg" ] } JSON ``` ### POST /properties — Create a property Creates a property. Minimum: `type`, `purposes`, the price for each purpose and the address with the city. An existing code → 409 with the id. - Permission: `properties:write` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` Body: - `externalRef` (string): The property's code in your system (POST only; in PUT it goes in the path). - `title` (string): Title. HTML markup is stripped. - `description` (string): Description. `
` and `

` become line breaks; other markup is stripped. - `type` (string; APARTAMENTO | CASA_RUA | CASA_CONDOMINIO | CASA_VILA | STUDIO | FLAT | COBERTURA | SALA_COMERCIAL | LOJA_PONTO | GALPAO | PREDIO | TERRENO_RUA | TERRENO_CONDOMINIO | CHACARA_SITIO | FAZENDA): Subtype. - `purposes` (array): Purposes. - `salePrice` (number; nullable): Sale price, in BRL. Required with `VENDA`. - `rentPrice` (number; nullable): Rent, in BRL. Required with `LOCACAO`. - `address` (AddressInput): Address. - `bedrooms` (integer; nullable): Bedrooms. - `suites` (integer; nullable): Suites. - `bathrooms` (integer; nullable): Bathrooms. - `parkingSpots` (integer; nullable): Parking spots. - `area` (number; nullable): Total private area, in m². - `privateArea` (number; nullable): Covered area, in m². - `listingUrl` (string; nullable): Listing URL on your website (http or https). - `captadorName` (string; nullable): Listing agent name as text. - `captadorAccountId` (string; nullable): Id of the responsible broker on the team. - `partnershipTerms` (PartnershipTerms): Partner terms. - `photos` (array): Up to 30 URLs; the 1st is the cover. Downloaded after the response (see `photoSync`). Absent = gallery unchanged; empty list = remove the photos. Response 201: - `data` (Property): The object as it now stands. - `result` (PropertyWriteResult): The outcome. Errors: `invalid_body`, `invalid_param`, `payload_too_large`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `request_refused`, `feed_sync_active`, `plan_limit_reached`, `external_ref_exists`, `invalid_property`, `concurrent_write` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X POST 'https://api.imobyflow.com.br/v1/properties?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" \ -H 'Content-Type: application/json' \ --data @- <<'JSON' { "externalRef": "AP1234", "title": "Apartamento 3 quartos no Bigorrilho", "type": "APARTAMENTO", "purposes": [ "VENDA" ], "salePrice": 890000, "address": { "cityId": "4106902", "neighborhoodSlug": "bigorrilho", "street": "Rua Padre Anchieta", "number": "1500", "complement": "Ap 82" }, "bedrooms": 3, "suites": 1, "bathrooms": 2, "parkingSpots": 2, "area": 98, "photos": [ "https://www.suaimobiliaria.com.br/fotos/AP1234/1.jpg", "https://www.suaimobiliaria.com.br/fotos/AP1234/2.jpg" ] } JSON ``` ### PATCH /properties/{propertyId} — Partially update a property Changes only what is sent. To clear a field, send `null`. - Permission: `properties:write` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` - `propertyId`: Property id (`prop-…`). Body: - `externalRef` (string): The property's code in your system (POST only; in PUT it goes in the path). - `title` (string): Title. HTML markup is stripped. - `description` (string): Description. `
` and `

` become line breaks; other markup is stripped. - `type` (string; APARTAMENTO | CASA_RUA | CASA_CONDOMINIO | CASA_VILA | STUDIO | FLAT | COBERTURA | SALA_COMERCIAL | LOJA_PONTO | GALPAO | PREDIO | TERRENO_RUA | TERRENO_CONDOMINIO | CHACARA_SITIO | FAZENDA): Subtype. - `purposes` (array): Purposes. - `salePrice` (number; nullable): Sale price, in BRL. Required with `VENDA`. - `rentPrice` (number; nullable): Rent, in BRL. Required with `LOCACAO`. - `address` (AddressInput): Address. - `bedrooms` (integer; nullable): Bedrooms. - `suites` (integer; nullable): Suites. - `bathrooms` (integer; nullable): Bathrooms. - `parkingSpots` (integer; nullable): Parking spots. - `area` (number; nullable): Total private area, in m². - `privateArea` (number; nullable): Covered area, in m². - `listingUrl` (string; nullable): Listing URL on your website (http or https). - `captadorName` (string; nullable): Listing agent name as text. - `captadorAccountId` (string; nullable): Id of the responsible broker on the team. - `partnershipTerms` (PartnershipTerms): Partner terms. - `photos` (array): Up to 30 URLs; the 1st is the cover. Downloaded after the response (see `photoSync`). Absent = gallery unchanged; empty list = remove the photos. Response 200: - `data` (Property): The object as it now stands. - `result` (PropertyWriteResult): The outcome. Errors: `invalid_body`, `invalid_param`, `payload_too_large`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `request_refused`, `not_found`, `feed_sync_active`, `property_in_trash`, `invalid_property` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X PATCH 'https://api.imobyflow.com.br/v1/properties/prop-3f9a1c2b7d4e?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" \ -H 'Content-Type: application/json' \ --data @- <<'JSON' { "salePrice": 870000 } JSON ``` ### POST /properties/{propertyId}/status — Change the status Available, archived, sold or rented — the same function as the dashboard: only available ones use the plan quota, and partners negotiating it are notified. Sold does not come back through the feed. - Permission: `properties:write` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` - `propertyId`: Property id (`prop-…`). Body: - `status` (string; ACTIVE | INACTIVE | SOLD | RENTED): The new status. Response 200: - `data` (Property): The object as it now stands. - `result` (PropertyWriteResult): The outcome. Errors: `invalid_body`, `invalid_param`, `payload_too_large`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `request_refused`, `not_found`, `plan_limit_reached` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X POST 'https://api.imobyflow.com.br/v1/properties/prop-3f9a1c2b7d4e/status?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" \ -H 'Content-Type: application/json' \ --data @- <<'JSON' { "status": "SOLD" } JSON ``` ### POST /properties/confirm — Confirm availability in bulk The 60-day rule takes unconfirmed properties offline. Send up to 200 `ids` and `refs`; confirmed less than 24 h ago is not rewritten (`ALREADY_CONFIRMED`). - Permission: `properties:write` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` Body: - `ids` (array): Property ids. - `refs` (array): Your system codes. Response 200: - `data` (array): Each property outcome. - `result` (object): The summary. - `result.dryRun` (boolean): Dry run. - `result.summary` (object): Count per outcome. Errors: `invalid_body`, `invalid_param`, `payload_too_large`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `request_refused` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X POST 'https://api.imobyflow.com.br/v1/properties/confirm?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" \ -H 'Content-Type: application/json' \ --data @- <<'JSON' { "refs": [ "AP1234", "CA0042" ] } JSON ``` ### DELETE /properties/{propertyId} — Move to the trash A 30-day trash (restorable in the dashboard). Shrink guard: at most 20% of the portfolio (and at least 10) in 24 hours — a loop in your system cannot empty the portfolio. With the CRM feed on, the feed is the one that takes properties offline. - Permission: `properties:write` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` - `propertyId`: Property id (`prop-…`). Response 200: - `data` (Property): The object as it now stands. - `result` (PropertyWriteResult): The outcome. Errors: `invalid_param`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `request_refused`, `not_found`, `shrink_guard`, `feed_sync_active` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X DELETE 'https://api.imobyflow.com.br/v1/properties/prop-3f9a1c2b7d4e?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" ``` ## Clients The account's clients, with the search profile that drives recommendations: read, sync by your system's code, move through the funnel, archive and log interactions. ### GET /leads — List clients The account's clients, newest first, with filters. - Permission: `leads:read` - `limit`: Items per page: 1 to 100 (default 50). - `cursor`: The `nextCursor` from the previous page. The list is over when it comes back null. It is only valid for this route and this account. - `state`: `ACTIVE` (default), `ARCHIVED` or `DELETED`. - `status`: Stage. - `ownerAccountId`: Only one broker's items. - `updatedSince`: Only what changed since this date/time (ISO 8601, UTC). - `radar`: `pending` = only items with recommendation pending items; `ready` = only ready items. Response 200: - `data` (array): The clients. - `nextCursor` (string; nullable): Next page cursor (null = done). Errors: `invalid_param`, `invalid_cursor`, `upstream_timeout`, `upstream_busy` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/leads' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### GET /leads/{leadId} — One client The client, with the search profile and recommendation status. - Permission: `leads:read` - `leadId`: Client id (`lead-…`). Response 200: - `data` (Lead): The client. Errors: `not_found` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/leads/lead-7c2e9a1b3d5f' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### GET /leads/by-ref/{ref} — One client by your code The client by your system's code. - Permission: `leads:read` - `ref`: The client's code in your system (up to 80 characters). Response 200: - `data` (Lead): The client. Errors: `not_found` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/leads/by-ref/CLI-889' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### PUT /leads/by-ref/{ref} — Create, update or link by your code Creates the client (201), updates it (200) — or LINKS it: the code is new but the person is already here by phone or e-mail (from a portal, a spreadsheet); the code now points to them (`LINKED`), without a second client. On creation, `consentGiven: true` is required. - Permission: `leads:write` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` - `ref`: The client's code in your system (up to 80 characters). Body: - `externalRef` (string): The client's code in your system (POST only). - `name` (string): Name. Required on creation. - `phones` (array): Up to 5 phones. On creation, a phone or an e-mail. - `email` (string; nullable): E-mail. - `status` (string; NEW | ATTENDING | PROPOSAL | WON | LOST): Funnel stage. - `notes` (string): Notes. - `preApproved` (boolean): Pre-approved credit. - `sharedToNetwork` (boolean): The profile may receive partner properties. - `interest` (InterestInput): Search profile. - `ownerAccountId` (string): The responsible broker, by id. - `ownerEmail` (string): The responsible broker, by e-mail — the way your system knows them. Without one, the agency's distribution rule applies. - `lastActivityAt` (string): The last activity in YOUR system. It only moves forward. More than 60 days ago on creation = the client is created archived (historical base). - `consentGiven` (boolean): Must be `true` on creation: the agency declares it has the legal basis to process the data (API Terms). Response 200 (201 when it creates.): - `data` (Lead): The object as it now stands. - `result` (LeadWriteResult): The outcome. Errors: `invalid_body`, `invalid_param`, `payload_too_large`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `request_refused`, `consent_required`, `lead_linked_to_other_ref`, `lead_in_trash`, `external_ref_exists`, `concurrent_write` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X PUT 'https://api.imobyflow.com.br/v1/leads/by-ref/CLI-889?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" \ -H 'Content-Type: application/json' \ --data @- <<'JSON' { "name": "Carlos Pereira", "phones": [ { "number": "(41) 99999-8888", "isWhatsApp": true } ], "email": "carlos@example.com", "status": "ATTENDING", "ownerEmail": "marina@suaimobiliaria.com.br", "interest": { "purposes": [ "VENDA" ], "propertyTypes": [ "APARTAMENTO" ], "locations": [ { "cityId": "4106902", "neighborhoodSlug": "bigorrilho" } ], "salePriceMax": 950000, "bedrooms": 3 }, "lastActivityAt": "2026-10-02T15:00:00Z", "consentGiven": true } JSON ``` ### POST /leads — Create a client Creates a client. Minimum: `name`, a phone or e-mail and `consentGiven: true`. An existing contact → 409 with the id. Without an owner, the agency's distribution rule applies. - Permission: `leads:write` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` Body: - `externalRef` (string): The client's code in your system (POST only). - `name` (string): Name. Required on creation. - `phones` (array): Up to 5 phones. On creation, a phone or an e-mail. - `email` (string; nullable): E-mail. - `status` (string; NEW | ATTENDING | PROPOSAL | WON | LOST): Funnel stage. - `notes` (string): Notes. - `preApproved` (boolean): Pre-approved credit. - `sharedToNetwork` (boolean): The profile may receive partner properties. - `interest` (InterestInput): Search profile. - `ownerAccountId` (string): The responsible broker, by id. - `ownerEmail` (string): The responsible broker, by e-mail — the way your system knows them. Without one, the agency's distribution rule applies. - `lastActivityAt` (string): The last activity in YOUR system. It only moves forward. More than 60 days ago on creation = the client is created archived (historical base). - `consentGiven` (boolean): Must be `true` on creation: the agency declares it has the legal basis to process the data (API Terms). Response 201: - `data` (Lead): The object as it now stands. - `result` (LeadWriteResult): The outcome. Errors: `invalid_body`, `invalid_param`, `payload_too_large`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `request_refused`, `consent_required`, `lead_exists`, `external_ref_exists`, `concurrent_write` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X POST 'https://api.imobyflow.com.br/v1/leads?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" \ -H 'Content-Type: application/json' \ --data @- <<'JSON' { "externalRef": "CLI-889", "name": "Carlos Pereira", "phones": [ { "number": "(41) 99999-8888", "isWhatsApp": true } ], "email": "carlos@example.com", "status": "ATTENDING", "ownerEmail": "marina@suaimobiliaria.com.br", "interest": { "purposes": [ "VENDA" ], "propertyTypes": [ "APARTAMENTO" ], "locations": [ { "cityId": "4106902", "neighborhoodSlug": "bigorrilho" } ], "salePriceMax": 950000, "bedrooms": 3 }, "lastActivityAt": "2026-10-02T15:00:00Z", "consentGiven": true } JSON ``` ### PATCH /leads/{leadId} — Partially update a client Changes only what is sent. Changing the stage is logged but does not count as activity — for that send `lastActivityAt` or log an interaction. - Permission: `leads:write` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` - `leadId`: Client id (`lead-…`). Body: - `externalRef` (string): The client's code in your system (POST only). - `name` (string): Name. Required on creation. - `phones` (array): Up to 5 phones. On creation, a phone or an e-mail. - `email` (string; nullable): E-mail. - `status` (string; NEW | ATTENDING | PROPOSAL | WON | LOST): Funnel stage. - `notes` (string): Notes. - `preApproved` (boolean): Pre-approved credit. - `sharedToNetwork` (boolean): The profile may receive partner properties. - `interest` (InterestInput): Search profile. - `ownerAccountId` (string): The responsible broker, by id. - `ownerEmail` (string): The responsible broker, by e-mail — the way your system knows them. Without one, the agency's distribution rule applies. - `lastActivityAt` (string): The last activity in YOUR system. It only moves forward. More than 60 days ago on creation = the client is created archived (historical base). - `consentGiven` (boolean): Must be `true` on creation: the agency declares it has the legal basis to process the data (API Terms). Response 200: - `data` (Lead): The object as it now stands. - `result` (LeadWriteResult): The outcome. Errors: `invalid_body`, `invalid_param`, `payload_too_large`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `request_refused`, `not_found`, `lead_in_trash` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X PATCH 'https://api.imobyflow.com.br/v1/leads/lead-7c2e9a1b3d5f?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" \ -H 'Content-Type: application/json' \ --data @- <<'JSON' { "status": "PROPOSAL", "lastActivityAt": "2026-10-02T15:00:00Z" } JSON ``` ### POST /leads/{leadId}/state — Archive or reactivate `ARCHIVED` archives; `ACTIVE` reactivates. The same function as the dashboard. - Permission: `leads:write` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` - `leadId`: Client id (`lead-…`). Body: - `state` (string; ACTIVE | ARCHIVED): The state. Response 200: - `data` (Lead): The object as it now stands. - `result` (LeadWriteResult): The outcome. Errors: `invalid_body`, `invalid_param`, `payload_too_large`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `request_refused`, `not_found`, `lead_in_trash` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X POST 'https://api.imobyflow.com.br/v1/leads/lead-7c2e9a1b3d5f/state?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" \ -H 'Content-Type: application/json' \ --data @- <<'JSON' { "state": "ARCHIVED" } JSON ``` ### POST /leads/{leadId}/interactions — Log an interaction A contact, visit, proposal or note made in YOUR system, with its date. It counts as activity (the client is not archived for inactivity). - Permission: `leads:write` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` - `leadId`: Client id (`lead-…`). Body: - `type` (string; CONTACT | VISIT | PROPOSAL | NOTE): `CONTACT`, `VISIT`, `PROPOSAL` or `NOTE`. - `note` (string): Note. - `at` (string): When it happened (default: now). Response 200: - `data` (Lead): The object as it now stands. - `result` (LeadWriteResult): The outcome. Errors: `invalid_body`, `invalid_param`, `payload_too_large`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `request_refused`, `not_found` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X POST 'https://api.imobyflow.com.br/v1/leads/lead-7c2e9a1b3d5f/interactions?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" \ -H 'Content-Type: application/json' \ --data @- <<'JSON' { "type": "VISIT", "note": "Visitou o AP1234 com a esposa.", "at": "2026-10-02T15:00:00Z" } JSON ``` ### DELETE /leads/{leadId} — Move to the trash A 30-day trash; cancels the client's open partnerships, as the dashboard does. The same shrink guard as properties. - Permission: `leads:write` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` - `leadId`: Client id (`lead-…`). Response 200: - `data` (Lead): The object as it now stands. - `result` (LeadWriteResult): The outcome. Errors: `invalid_param`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `request_refused`, `not_found`, `shrink_guard` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X DELETE 'https://api.imobyflow.com.br/v1/leads/lead-7c2e9a1b3d5f?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" ``` ## Opportunities (Radar) The opportunities Radar finds between properties and clients — in the account itself and with partners — under the same display rules as the dashboard. ### GET /properties/{propertyId}/matches — A property's opportunities The clients that fit the property. Only the account's own clients — partner clients never show up on your property. - Permission: `radar:read` - `propertyId`: Property id (`prop-…`). Response 200: - `data` (array): The opportunities. - `nextCursor` (string; nullable): Next page cursor (null = done). Errors: `not_found` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/properties/prop-3f9a1c2b7d4e/matches' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### GET /leads/{leadId}/matches — A client's opportunities The properties that fit the client — own and from partners. - Permission: `radar:read` - `leadId`: Client id (`lead-…`). Response 200: - `data` (array): The opportunities. - `nextCursor` (string; nullable): Next page cursor (null = done). Errors: `not_found` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/leads/lead-7c2e9a1b3d5f/matches' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### GET /matches — The account's opportunities The opportunities, newest first. Partner ones follow the dashboard display rule: without an active subscription the partner stays hidden (`locked`). The client's name only comes with `leads:read` on the key. - Permission: `radar:read` - `limit`: Items per page: 1 to 100 (default 50). - `cursor`: The `nextCursor` from the previous page. The list is over when it comes back null. It is only valid for this route and this account. - `status`: Status. - `scope`: Origin. - `ownerAccountId`: Only one broker's items. Response 200: - `data` (array): The opportunities. - `nextCursor` (string; nullable): Next page cursor (null = done). Errors: `invalid_param`, `invalid_cursor`, `upstream_timeout`, `upstream_busy` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/matches' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### POST /matches/{matchId}/dismiss — Dismiss an opportunity The broker's decision, made in your system. A favorited opportunity cannot be dismissed. - Permission: `radar:write` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` - `matchId`: Opportunity id. It contains `#`: send it URL-encoded (`%23`). Response 200: - `data` (Match): The object as it now stands. - `result` (MatchWriteResult): The outcome. Errors: `invalid_param`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `request_refused`, `not_found` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X POST 'https://api.imobyflow.com.br/v1/matches/m%23prop-3f9a1c2b7d4e%23lead-7c2e9a1b3d5f%23L/dismiss?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" ``` ### POST /matches/{matchId}/restore — Restore an opportunity Brings a dismissed opportunity back to new. - Permission: `radar:write` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` - `matchId`: Opportunity id. It contains `#`: send it URL-encoded (`%23`). Response 200: - `data` (Match): The object as it now stands. - `result` (MatchWriteResult): The outcome. Errors: `invalid_param`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `request_refused`, `not_found` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X POST 'https://api.imobyflow.com.br/v1/matches/m%23prop-3f9a1c2b7d4e%23lead-7c2e9a1b3d5f%23L/restore?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" ``` ## Partnerships The team's partnerships, with the stage and both sides. Only the side that brought the client moves the funnel. ### GET /partnerships — The team's partnerships All partnerships in one response. `nextCursor` exists in the contract for when it paginates — follow it from day one. - Permission: `partnerships:read` - `status`: Stage. - `updatedSince`: Only what changed since this date/time (ISO 8601, UTC). Response 200: - `data` (array): The partnerships. - `nextCursor` (string; nullable): Next page cursor (null = done). Errors: `invalid_param`, `upstream_timeout` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/partnerships' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### GET /partnerships/{partnershipId} — One partnership The partnership, with both sides and who can move the funnel. - Permission: `partnerships:read` - `partnershipId`: Partnership id (`pship-…`). Response 200: - `data` (Partnership): The partnership. Errors: `not_found` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/partnerships/pship-5b8d2f1e9a3c' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### POST /partnerships/{partnershipId}/status — Move the partnership stage Only the side that brought the client moves the funnel (`canMoveFunnel`). The other side can only close it after asking for an update and waiting 15 days without an answer — the dashboard rule. - Permission: `partnerships:write` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` - `partnershipId`: Partnership id (`pship-…`). Body: - `status` (string; PENDING | ACCEPTED | DECLINED | CANCELLED | LEAD_REGISTERED | CONTACTED | NEGOTIATING | PROPOSAL | WON | LOST): The new stage. Response 200: - `data` (Partnership): The object as it now stands. - `result` (PartnershipWriteResult): The outcome. Errors: `invalid_body`, `invalid_param`, `payload_too_large`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `request_refused`, `not_found` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X POST 'https://api.imobyflow.com.br/v1/partnerships/pship-5b8d2f1e9a3c/status?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" \ -H 'Content-Type: application/json' \ --data @- <<'JSON' { "status": "PROPOSAL" } JSON ``` ## Team Who is on the team: name, e-mail, role and broker license. Your system matches the broker by e-mail. ### GET /team — The team Who is on the team, including suspended members. - Permission: `team:read` Response 200: - `data` (array): The team. - `nextCursor` (string; nullable): Next page cursor (null = done). Errors: `not_available` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/team' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ## Launches The city's new-development catalog: development, unit types, price list and construction stage. ### GET /launches — The city's new developments The new-development catalog, with unit types. - Permission: `launches:read` - `limit`: Items per page: 1 to 50 (default 20). - `cursor`: The `nextCursor` from the previous page. The list is over when it comes back null. It is only valid for this route and this account. - `citySlug`: City identifier in the catalog. - `neighborhood`: Neighborhood (name). - `type`: Subtype. - `stage`: Construction stage. - `priceMin`: Minimum price. - `priceMax`: Maximum price. - `q`: Search in the name. Response 200: - `data` (array): The developments. - `nextCursor` (string; nullable): Next page cursor (null = done). Errors: `invalid_param`, `invalid_cursor`, `upstream_timeout`, `upstream_busy` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/launches' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ## Captação (owner leads) Property owners offered to the account and the acceptance, which debits credit and reveals the contact. Accepting requires its own permission and the specific term accepted in the dashboard. ### GET /captacao/offers — Owners offered to the account The owners offered to the account right now, with the deadline running — the same cards as the desk — plus a summary (credit, pause, module status). Before accepting, contact and address do not exist in the response. - Permission: `captacao:read` Response 200: - `data` (array): The owners. - `summary` (CaptacaoSummary): Desk summary. - `nextCursor` (string; nullable): Always null today. Errors: `captacao_not_active`, `not_available` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/captacao/offers' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### GET /captacao/offers/{offerId} — One owner Offered to the account (no contact) or already accepted by it (with contact). - Permission: `captacao:read` - `offerId`: The owner's id on the desk (`cap-…`). Response 200: - `data` (CaptacaoOffer): The owner. Errors: `not_found`, `captacao_not_active` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/captacao/offers/cap-8e7d6c5b4a39' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### GET /captacao/owners — Accepted owners Accepted owners, by desk tab, in pages of 10, with the count of the three tabs. - Permission: `captacao:read` - `tab`: The tab (default `ACTIVE`). - `cursor`: The `nextCursor` from the previous page. The list is over when it comes back null. It is only valid for this route and this account. Response 200: - `data` (array): The accepted owners. - `nextCursor` (string; nullable): Next page. - `total` (integer; nullable): Total in the tab. - `counts` (object; nullable): How many in each tab. Errors: `invalid_param`, `invalid_cursor`, `captacao_not_active` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/captacao/owners' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### POST /captacao/offers/{offerId}/accept — Accept an owner The only API path that spends money: it debits credit and reveals the contact. Requires the `captacao:accept` permission and item 13 of the API Terms accepted by the owner in the dashboard. Each acceptance records the key, the IP and the terms version. A dry run returns `WOULD_ACCEPT` with the price; retrying the same acceptance returns `ALREADY_ACCEPTED`, with no second debit. - Permission: `captacao:accept` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` - `offerId`: The owner's id on the desk (`cap-…`). Response 200: - `data` (CaptacaoOffer): The owner (with contact). - `result` (CaptacaoAcceptResult): The outcome. Errors: `invalid_param`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `request_refused`, `not_found`, `captacao_not_active`, `captacao_terms_required`, `offer_unavailable`, `captacao_insufficient_credit` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X POST 'https://api.imobyflow.com.br/v1/captacao/offers/cap-8e7d6c5b4a39/accept?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" ``` ## Events What changed in the account, in order, with 30 days of history — incremental sync. Events are lean: ids and the names of the changed fields; the detail comes from reading the resource. ### GET /events — What changed The account's events in order, with 30 days of history. Keep `nextCursor` and send it back next time — it always comes, even when there is nothing new. Each type also requires the resource's read permission. An event takes from seconds to over a minute to show up: follow the CURSOR, never the clock. - Permission: `events:read` - `limit`: Items per page: 1 to 500 (default 100). - `cursor`: The `nextCursor` from the previous page. The list is over when it comes back null. It is only valid for this route and this account. - `since`: Start from this date/time (only without a cursor). - `types`: Only these types, comma-separated. Response 200: - `data` (array): The events, in order. - `nextCursor` (string): Where to continue (always present). - `hasMore` (boolean): There is more to read right now. Errors: `invalid_param`, `invalid_cursor` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/events' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ## Webhooks The endpoints that receive events right away, signed with the Standard Webhooks spec, with retries, automatic disabling, redelivery and a test event. ### GET /webhooks — Registered endpoints The account's webhook endpoints. - Permission: `webhooks:manage` Response 200: - `data` (array): The endpoints. Errors: common ones only ```bash curl -X GET 'https://api.imobyflow.com.br/v1/webhooks' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### POST /webhooks — Register an endpoint HTTPS and public hosts only. The response carries the `secret` (`whsec_…`) ONCE — keep it: it is what you verify the signature with. This route does not accept `Idempotency-Key` (a stored response would keep the secret in plain text); repeating creates another endpoint. - Permission: `webhooks:manage` Body: - `url` (string): The URL, HTTPS and public only. Credentials in the URL are refused. - `types` (array): The types (absent = all the account can read). - `description` (string; nullable): Description. Response 201: - `data` (Webhook): The endpoint. - `secret` (string): The secret, only in this response. Errors: `invalid_body`, `invalid_param`, `payload_too_large`, `webhook_url_refused`, `webhook_limit_reached` ```bash curl -X POST 'https://api.imobyflow.com.br/v1/webhooks' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H 'Content-Type: application/json' \ --data @- <<'JSON' { "url": "https://crm.suaimobiliaria.com.br/imobyflow/eventos", "types": [ "property.updated", "lead.created" ], "description": "CRM — produção" } JSON ``` ### PATCH /webhooks/{webhookId} — Update an endpoint Changes the URL, the types, the description — or disables and re-enables it (re-enabling clears the disable reason). - Permission: `webhooks:manage` - Accepts `Idempotency-Key` - `webhookId`: Endpoint id (`wh_…`). Body: - `url` (string): The URL. - `types` (array): The types. - `description` (string; nullable): Description. - `status` (string; ACTIVE | DISABLED): `ACTIVE` re-enables (clears the disable reason) and `DISABLED` disables. Response 200: - `data` (Webhook): The endpoint. Errors: `invalid_body`, `invalid_param`, `payload_too_large`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `not_found`, `webhook_url_refused` ```bash curl -X PATCH 'https://api.imobyflow.com.br/v1/webhooks/wh_9c8b7a6f5e4d3c2b' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" \ -H 'Content-Type: application/json' \ --data @- <<'JSON' { "status": "ACTIVE" } JSON ``` ### DELETE /webhooks/{webhookId} — Delete an endpoint Stops delivering and deletes the endpoint. - Permission: `webhooks:manage` - Accepts `Idempotency-Key` - `webhookId`: Endpoint id (`wh_…`). Response 200: - `data` (Webhook): The deleted endpoint. - `result` (object): The outcome. - `result.outcome` (string): `DELETED`. Errors: `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `not_found` ```bash curl -X DELETE 'https://api.imobyflow.com.br/v1/webhooks/wh_9c8b7a6f5e4d3c2b' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" ``` ### POST /webhooks/{webhookId}/rotate-secret — Rotate the secret Generates a new secret, returned ONCE. The previous one keeps signing alongside for 24 hours — time to switch it in your system without losing events. No `Idempotency-Key`. - Permission: `webhooks:manage` - `webhookId`: Endpoint id (`wh_…`). Response 200: - `data` (Webhook): The endpoint. - `secret` (string): The new secret. Errors: `not_found` ```bash curl -X POST 'https://api.imobyflow.com.br/v1/webhooks/wh_9c8b7a6f5e4d3c2b/rotate-secret' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### POST /webhooks/{webhookId}/test — Send a test event Delivers a `webhook.test` NOW, signed, and returns what your system answered. - Permission: `webhooks:manage` - Accepts `Idempotency-Key` - `webhookId`: Endpoint id (`wh_…`). Response 200: - `data` (WebhookTestResult): The result. Errors: `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `not_found` ```bash curl -X POST 'https://api.imobyflow.com.br/v1/webhooks/wh_9c8b7a6f5e4d3c2b/test' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" ``` ### GET /webhooks/{webhookId}/deliveries — An endpoint's deliveries The deliveries, newest first, with status, attempts and the last status code. - Permission: `webhooks:manage` - `webhookId`: Endpoint id (`wh_…`). - `limit`: Items per page: 1 to 200 (default 50). - `cursor`: The `nextCursor` from the previous page. The list is over when it comes back null. It is only valid for this route and this account. Response 200: - `data` (array): The deliveries. - `nextCursor` (string; nullable): Next page cursor (null = done). Errors: `invalid_param`, `invalid_cursor`, `not_found` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/webhooks/wh_9c8b7a6f5e4d3c2b/deliveries' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### POST /webhooks/{webhookId}/deliveries/{deliveryId}/retry — Redeliver A new round of attempts for the same delivery — with the SAME `webhook-id`, so your system recognizes the repeat. One already scheduled returns `ALREADY_SCHEDULED`. - Permission: `webhooks:manage` - Accepts `Idempotency-Key` - `webhookId`: Endpoint id (`wh_…`). - `deliveryId`: Delivery id (`dlv_…`). Response 200: - `data` (Delivery): The delivery. - `result` (object): The outcome. - `result.outcome` (string; SCHEDULED | ALREADY_SCHEDULED): `SCHEDULED` or `ALREADY_SCHEDULED`. Errors: `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress`, `not_found` ```bash curl -X POST 'https://api.imobyflow.com.br/v1/webhooks/wh_9c8b7a6f5e4d3c2b/deliveries/dlv_20261002164512000_evt_4f1c9a7e2b3d8c6a5e4f1b2c/retry' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" ``` ## Batches Up to 500 properties or clients in one call, processed at the platform pace, with the outcome of each item. ### POST /properties/batch — Batch of properties Up to 500 properties and 4 MB in one call. Each item is the PUT by code (`externalRef` required) — same rules, same outcomes. A malformed item comes back `REJECTED` and does not block the others; the same code twice in a batch is refused. Answers 202 right away and processes at the platform pace (4 items per second): 500 items take 2 to 3 minutes. - Permission: `properties:write` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` Body: - `items` (array): The items (1 to 500). Response 202: - `data` (BatchCreated): The received batch. Errors: `invalid_body`, `invalid_param`, `payload_too_large`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X POST 'https://api.imobyflow.com.br/v1/properties/batch?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" \ -H 'Content-Type: application/json' \ --data @- <<'JSON' { "items": [ { "externalRef": "AP1234", "title": "Apartamento 3 quartos no Bigorrilho", "type": "APARTAMENTO", "purposes": [ "VENDA" ], "salePrice": 890000, "address": { "cityId": "4106902", "neighborhoodSlug": "bigorrilho", "street": "Rua Padre Anchieta", "number": "1500", "complement": "Ap 82" }, "bedrooms": 3, "suites": 1, "bathrooms": 2, "parkingSpots": 2, "area": 98, "photos": [ "https://www.suaimobiliaria.com.br/fotos/AP1234/1.jpg", "https://www.suaimobiliaria.com.br/fotos/AP1234/2.jpg" ] } ] } JSON ``` ### GET /properties/batch/{batchId} — Track the batch The status, counts and each item outcome, in request order. The batch is available for 7 days. - Permission: `properties:read` - `batchId`: Batch id (`b-…`). Response 200: - `data` (Batch): The batch. Errors: `not_found` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/properties/batch/b-4c1d9e2f7a3b8c6d' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ### POST /leads/batch — Batch of clients Up to 500 clients and 4 MB in one call. Each item is the PUT by code (`externalRef` required) — same rules, same outcomes. A malformed item comes back `REJECTED` and does not block the others; the same code twice in a batch is refused. Answers 202 right away and processes at the platform pace (4 items per second): 500 items take 2 to 3 minutes. - Permission: `leads:write` - Accepts `?dryRun=true` - Accepts `Idempotency-Key` Body: - `items` (array): The items (1 to 500). Response 202: - `data` (BatchCreated): The received batch. Errors: `invalid_body`, `invalid_param`, `payload_too_large`, `invalid_idempotency_key`, `idempotency_key_reused`, `idempotency_in_progress` ```bash # Dry run: nothing is written. Remove ?dryRun=true to write for real. curl -X POST 'https://api.imobyflow.com.br/v1/leads/batch?dryRun=true' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' \ -H "Idempotency-Key: $(uuidgen)" \ -H 'Content-Type: application/json' \ --data @- <<'JSON' { "items": [ { "externalRef": "CLI-889", "name": "Carlos Pereira", "phones": [ { "number": "(41) 99999-8888", "isWhatsApp": true } ], "email": "carlos@example.com", "status": "ATTENDING", "ownerEmail": "marina@suaimobiliaria.com.br", "interest": { "purposes": [ "VENDA" ], "propertyTypes": [ "APARTAMENTO" ], "locations": [ { "cityId": "4106902", "neighborhoodSlug": "bigorrilho" } ], "salePriceMax": 950000, "bedrooms": 3 }, "lastActivityAt": "2026-10-02T15:00:00Z", "consentGiven": true } ] } JSON ``` ### GET /leads/batch/{batchId} — Track the batch The status, counts and each item outcome, in request order. The batch is available for 7 days. - Permission: `leads:read` - `batchId`: Batch id (`b-…`). Response 200: - `data` (Batch): The batch. Errors: `not_found` ```bash curl -X GET 'https://api.imobyflow.com.br/v1/leads/batch/b-4c1d9e2f7a3b8c6d' \ -H "Authorization: Bearer $IMOBYFLOW_API_KEY" \ -H 'Accept-Language: en' ``` ## Objects ### Problem Error in RFC 9457 format (`application/problem+json`). - `type` (string): URL of this error page, with the cause and the fix. - `title` (string): Error name, in the `Accept-Language` language. - `status` (integer): The HTTP status code. - `code` (string): Stable code — your system should branch on it. - `requestId` (string): Request id. Include it when contacting support. - `detail` (string): Explanation of this case (when available). - `invalidParams` (array): All problems in the request at once — not just the first one. ### Limits The account's usage tier limits. - `ratePerSecond` (integer): Calls per second. - `burst` (integer): Short burst allowed. - `monthlyQuota` (integer): Calls per month (calendar month, UTC). - `maxKeys` (integer): Active keys at the same time. - `maxWebhooks` (integer): Webhook endpoints. ### Me Who the account is, what the key can do and how much of the quota is used. - `account` (object): The account that owns the key. - `account.id` (string): Account id. - `account.name` (string; nullable): Company name. - `account.type` (string; nullable): `IMOBILIARIA` (agency) or `CONSTRUTORA` (developer). - `account.plan` (string; nullable): Plan code. - `access` (object): API access. - `access.status` (string; nullable): Access status (`APPROVED` when valid). - `access.tier` (string): Usage tier: `PADRAO` (standard) or `AMPLIADA` (extended). - `access.pilotUntil` (string; nullable): End of the pilot period, if any. - `access.limits` (Limits): The limits that apply to the account. - `key` (object): The key used in this call. - `key.id` (string; nullable): Key id (not the secret). - `key.name` (string; nullable): Name given in the dashboard. - `key.scopes` (array): The permissions that apply to THIS key. - `key.expiresAt` (string; nullable): When the key expires (null = no expiry). - `usage` (object): Monthly usage. - `usage.month` (string): The month (`YYYY-MM`, UTC). - `usage.calls` (integer): Calls made this month. - `usage.monthlyQuota` (integer): The monthly quota. - `usage.remaining` (integer): What is left. - `properties` (object): The plan's property quota. - `properties.active` (integer): Active properties right now. - `properties.limit` (integer; nullable): The plan's active-property cap. ### ValueLabel An accepted value and its label. - `value` (string): The value to send in the field. - `label` (string): The label, in the `Accept-Language` language. ### PropertyTypeGroup A property category and its subtypes. - `category` (string; RESIDENCIAL | COMERCIAL | TERRENO | RURAL): The category. - `label` (string): Category label. - `types` (array): The subtypes in the category — the subtype is what goes in `type`. ### ScopeInfo A permission a key can have. - `id` (string; properties:read | properties:write | leads:read | leads:write | radar:read | radar:write | partnerships:read | partnerships:write | team:read | launches:read | launches:write | captacao:read | captacao:accept | events:read | webhooks:manage): The permission. - `group` (string): The group, for display. - `label` (string): The name, for display. - `description` (string): What it allows. ### EventTypeInfo An event type. - `type` (string; property.created | property.updated | property.deleted | property.restored | property.purged | lead.created | lead.updated | lead.deleted | lead.restored | lead.purged | radar.client_summary | partnership.created | partnership.updated | captacao.offer_received | captacao.offer_accepted | captacao.offer_withdrawn): The event type. - `scope` (string; properties:read | properties:write | leads:read | leads:write | radar:read | radar:write | partnerships:read | partnerships:write | team:read | launches:read | launches:write | captacao:read | captacao:accept | events:read | webhooks:manage): The read permission that grants access to it. - `description` (string): What it signals. ### City A catalog city. - `cityId` (string): IBGE code, 7 digits — the safest way to send the city. - `name` (string): City name. - `uf` (string): State (UF). - `citySlug` (string): City identifier in the catalog. ### Neighborhood A catalog neighborhood. - `neighborhoodSlug` (string): The neighborhood identifier — the `neighborhoodSlug` value for writes. - `name` (string): Neighborhood name. ### Address The full address — the property belongs to the account itself. - `neighborhood` (string; nullable): Neighborhood name. - `neighborhoodSlug` (string; nullable): Catalog neighborhood. Null when the neighborhood is not recognized yet — the property stays out of recommendations until curation decides. - `city` (string; nullable): City name. - `cityId` (string; nullable): IBGE code. - `citySlug` (string; nullable): City identifier in the catalog. - `state` (string; nullable): State (UF). - `street` (string; nullable): Street. - `number` (string; nullable): Number. - `complement` (string; nullable): Complement. ### AddressArea The address down to the neighborhood. - `neighborhood` (string; nullable): Neighborhood name. - `neighborhoodSlug` (string; nullable): Catalog neighborhood. - `city` (string; nullable): City name. - `cityId` (string; nullable): IBGE code. - `citySlug` (string; nullable): City identifier in the catalog. - `state` (string; nullable): State (UF). ### PartnershipTerms Terms for partners. - `commissionPercent` (number; nullable): Sale commission offered to partners, in %. - `rentCommissionMonths` (number; nullable): Rent commission, in months of rent. - `splitListingPercent` (number; nullable): Share of the commission kept by the listing side, in %. ### PropertyRadar The property's status in recommendations (Radar). - `eligible` (boolean): Is in recommendations right now (active and with no pending item). - `pending` (array): What is missing to enter recommendations. A cover photo is required. - `labels` (array): The same pending items, spelled out. ### Curation ImobyFlow's review before the property is shown to partners. New properties from the API start under review. - `status` (string; nullable): `PENDING`, `APPROVED` or `REJECTED`. - `reason` (string; nullable; LANCAMENTO | SEM_VALOR | QUALIDADE_BAIXA | NAO_ANGARIACAO | MARCA_DAGUA | FOTOS_INSUFICIENTES | DADOS_INCOERENTES | OUTRO): The rejection reason, as a code. - `label` (string; nullable): The reason, spelled out. ### Confirmation The 60-day rule: unconfirmed properties go offline. Writing the property through the API (or confirming it) renews the date. - `lastConfirmedAt` (string; nullable): Last confirmation that it is still available. - `dueAt` (string; nullable): When the confirmation is due (every 60 days). - `noticeAt` (string; nullable): When the confirmation notice was sent. - `offlineAt` (string; nullable): When it goes offline without an answer (7 days after the notice). ### LaunchBlock New-development data (development and unit type). - `constructionStage` (string; nullable; LAUNCH | OFF_PLAN | NEW | READY): Construction stage. - `deliveryDate` (string; nullable): Expected delivery. - `constructionProgress` (integer; nullable): Construction progress, in %. - `unitsTotal` (integer; nullable): Total units. - `unitsAvailable` (integer; nullable): Available units. - `unitsReserved` (integer; nullable): Reserved units. - `unitsSold` (integer; nullable): Sold units. - `floorPlans` (array): The floor plans. ### PhotoSync Download of the photos sent by URL. It happens after the response — this is where you see whether the gallery made it. - `state` (string): `QUEUED`, `DONE`, `PARTIAL` (some failed), `FAILED` or `NOT_QUEUED` (the queue refused — the next request retries). - `requested` (integer; nullable): Photos requested. - `ingested` (integer; nullable): Photos downloaded and stored. - `failed` (integer; nullable): Photos that failed. - `queuedAt` (string; nullable): When it was queued. - `finishedAt` (string; nullable): When it finished. ### Property A property in the account's portfolio. - `id` (string): Property id. - `externalRef` (string; nullable): The property's code in YOUR system. - `kind` (string; PROPERTY | DEVELOPMENT | TYPOLOGY): `PROPERTY` (standalone), `DEVELOPMENT` (new development) or `TYPOLOGY` (unit type of a development). - `developmentId` (string; nullable): The development of this unit type. - `status` (string; ACTIVE | INACTIVE | SOLD | RENTED | DELETED): Status. `DELETED` = in the trash (30 days). - `type` (string; nullable; APARTAMENTO | CASA_RUA | CASA_CONDOMINIO | CASA_VILA | STUDIO | FLAT | COBERTURA | SALA_COMERCIAL | LOJA_PONTO | GALPAO | PREDIO | TERRENO_RUA | TERRENO_CONDOMINIO | CHACARA_SITIO | FAZENDA): Subtype (see the reference lists). - `category` (string; nullable; RESIDENCIAL | COMERCIAL | TERRENO | RURAL): The subtype's category. - `purposes` (array): Purposes: `VENDA` (sale), `LOCACAO` (rent) or both. - `salePrice` (number; nullable): Sale price, in BRL. - `rentPrice` (number; nullable): Monthly rent, in BRL. - `title` (string; nullable): Listing title. - `description` (string; nullable): Description, as plain text. - `address` (Address): Address. - `bedrooms` (integer; nullable): Bedrooms. - `suites` (integer; nullable): Suites. - `bathrooms` (integer; nullable): Bathrooms. - `parkingSpots` (integer; nullable): Parking spots. - `area` (number; nullable): Total private area, in m² — the comparable one. - `privateArea` (number; nullable): Covered area, in m² (display only). - `amenities` (array): Property and building amenities. - `coverPhoto` (string; nullable): The cover (1st photo). Without a cover the property is left out of recommendations. - `photos` (array): The gallery, in order. - `listingUrl` (string; nullable): Listing URL on your website. - `captador` (object; nullable): The responsible broker on the team. - `captador.accountId` (string): Broker id. - `captador.name` (string; nullable): Name. - `captadorName` (string; nullable): Listing agent name as text (someone not on the team). - `sharedToNetwork` (boolean): Shared with partners. - `partnershipTerms` (PartnershipTerms): Partner terms. - `radar` (PropertyRadar): Recommendation status. - `curation` (Curation): ImobyFlow's review. - `confirmation` (Confirmation): Availability confirmation. - `inactiveReason` (string; nullable): Why it is archived (only when `status` = `INACTIVE`). - `deletedAt` (string; nullable): When it was moved to the trash. - `launch` (LaunchBlock; nullable): New-development data (development and unit type only). - `photoSync` (PhotoSync; nullable): Download of the photos sent by URL. - `createdAt` (string): When it was created (UTC). - `updatedAt` (string): Last change (UTC). ### AddressInput The address. Send it whole when you send it. - `cityId` (string): IBGE code (7 digits). With it, `city` and `state` are not needed. - `city` (string): City name (with `state`). An unknown name returns 400 with suggestions. - `state` (string): State (UF), 2 letters. - `neighborhoodSlug` (string): Neighborhood by catalog identifier — the guaranteed path. - `neighborhood` (string): Neighborhood as text. It goes through the alias dictionary; anything unrecognized waits for curation and never becomes a made-up neighborhood. - `street` (string): Street. - `number` (string): Number. - `complement` (string): Complement. ### PropertyInput The fields the API accepts for a property. Unknown fields are an error (400). Absent fields are kept; to clear one, send `null`. - `externalRef` (string): The property's code in your system (POST only; in PUT it goes in the path). - `title` (string): Title. HTML markup is stripped. - `description` (string): Description. `
` and `

` become line breaks; other markup is stripped. - `type` (string; APARTAMENTO | CASA_RUA | CASA_CONDOMINIO | CASA_VILA | STUDIO | FLAT | COBERTURA | SALA_COMERCIAL | LOJA_PONTO | GALPAO | PREDIO | TERRENO_RUA | TERRENO_CONDOMINIO | CHACARA_SITIO | FAZENDA): Subtype. - `purposes` (array): Purposes. - `salePrice` (number; nullable): Sale price, in BRL. Required with `VENDA`. - `rentPrice` (number; nullable): Rent, in BRL. Required with `LOCACAO`. - `address` (AddressInput): Address. - `bedrooms` (integer; nullable): Bedrooms. - `suites` (integer; nullable): Suites. - `bathrooms` (integer; nullable): Bathrooms. - `parkingSpots` (integer; nullable): Parking spots. - `area` (number; nullable): Total private area, in m². - `privateArea` (number; nullable): Covered area, in m². - `listingUrl` (string; nullable): Listing URL on your website (http or https). - `captadorName` (string; nullable): Listing agent name as text. - `captadorAccountId` (string; nullable): Id of the responsible broker on the team. - `partnershipTerms` (PartnershipTerms): Partner terms. - `photos` (array): Up to 30 URLs; the 1st is the cover. Downloaded after the response (see `photoSync`). Absent = gallery unchanged; empty list = remove the photos. ### PropertyWriteResult The write outcome. - `outcome` (string): What happened: `CREATED`, `UPDATED`, `UNCHANGED` (nothing changed, nothing written), `CONFIRMED` (only the availability date), `STATUS_SET`, `DELETED`, `ALREADY_DELETED`… - `dryRun` (boolean): It was a dry run — nothing was written. - `conflicts` (array): Fields the team edited in the dashboard, so they were not overwritten — dashboard edits win. - `photos` (string; nullable): The gallery: `UNCHANGED`, `QUEUED`, `ALREADY_QUEUED` or `CLEARED`. Null when the request did not mention photos. ### Phone A phone number. - `number` (string): Digits only, with area code (10 to 13). - `isWhatsApp` (boolean): Is WhatsApp. - `label` (string; nullable): Free label (`mobile`, `work`…). ### Location A region of interest. - `cityId` (string; nullable): IBGE code. - `citySlug` (string; nullable): City identifier. - `cityName` (string; nullable): City name. - `uf` (string; nullable): State. - `neighborhoodSlug` (string; nullable): Catalog neighborhood (null = the whole city). - `neighborhoodName` (string; nullable): Neighborhood name. - `preference` (string; PREFERRED | ACCEPTABLE): `PREFERRED` or `ACCEPTABLE` — it weighs on the recommendation score. ### Interest The search profile — it is what drives recommendations. - `purposes` (array): Purposes: `VENDA` (sale), `LOCACAO` (rent) or both. - `propertyTypes` (array): Property types wanted. - `locations` (array): Regions of interest. - `similarNeighborhoods` (boolean): Accepts neighborhoods similar to the chosen ones. - `salePriceMin` (number; nullable): Purchase: minimum, in BRL. - `salePriceMax` (number; nullable): Purchase: maximum, in BRL. - `rentPriceMin` (number; nullable): Rent: minimum, in BRL. - `rentPriceMax` (number; nullable): Rent: maximum, in BRL. - `bedrooms` (integer; nullable): Minimum bedrooms. - `bathrooms` (integer; nullable): Minimum bathrooms. - `parkingSpots` (integer; nullable): Minimum parking spots. - `areaMin` (number; nullable): Minimum area, in m². ### LeadRadar The client's status in recommendations. - `eligible` (boolean): Receives recommendations right now (active and with no pending item). - `pending` (array): What is missing in the search profile. - `labels` (array): The same pending items, spelled out. ### Lead A client of the account. Name, phone and e-mail are personal data — the agency is the controller. - `id` (string): Client id. - `externalRef` (string; nullable): The client's code in YOUR system. - `ownerAccountId` (string; nullable): The responsible broker (or the agency itself). - `state` (string; ACTIVE | ARCHIVED | DELETED): `ACTIVE`, `ARCHIVED` or `DELETED` (trash). - `status` (string; nullable; NEW | ATTENDING | PROPOSAL | WON | LOST): Funnel stage. - `name` (string; nullable): Name. - `phones` (array): Phones. - `email` (string; nullable): E-mail. - `source` (string): Where it came from: `MANUAL`, `IMPORT_CSV`, `EMAIL`, `WEBHOOK`, `META_ADS`, `PORTAL_API`, `CRM_API` (through the API)… - `sourceDetail` (string; nullable): Source detail (the portal, the system name). - `sourcePropertyId` (string; nullable): The property that brought the client, if any. - `preApproved` (boolean): Pre-approved credit. - `sharedToNetwork` (boolean): The profile (without name or contact) may receive partner properties. - `notes` (string; nullable): Notes. - `interest` (Interest): Search profile. - `radar` (LeadRadar): Recommendation status. - `lastActivityAt` (string; nullable): Last activity — moves with the date your system sends and with interactions, never with sync itself. - `archivedAt` (string; nullable): When it was archived. - `archivedReason` (string; nullable): Why it was archived (`MANUAL`, `INACTIVITY`, `IMPORT`…). - `deletedAt` (string; nullable): When it was moved to the trash. - `createdAt` (string): When it was created (UTC). - `updatedAt` (string): Last change (UTC). ### PhoneInput A phone. A plain string with the number is also accepted. - `number` (string): With area code; only digits count. - `isWhatsApp` (boolean): Is WhatsApp (default: yes). - `label` (string): Free label. ### LocationInput A region of interest. - `cityId` (string): IBGE code. - `cityName` (string): City name (with `uf`). - `uf` (string): State. - `neighborhoodSlug` (string): Catalog neighborhood. - `neighborhoodName` (string): Neighborhood as text. Market areas ("Ecoville") expand into the catalog neighborhoods they cover. - `preference` (string; PREFERRED | ACCEPTABLE): `PREFERRED` (default) or `ACCEPTABLE`. ### InterestInput The search profile. Merged field by field: sending only the maximum does not erase the regions. - `purposes` (array): Purposes. - `propertyTypes` (array): Types wanted. - `locations` (array): Regions (up to 20). Send the whole list when you send it. - `similarNeighborhoods` (boolean): Accepts similar neighborhoods. - `salePriceMin` (number; nullable): Purchase: minimum. - `salePriceMax` (number; nullable): Purchase: maximum. Below the minimum is refused. - `rentPriceMin` (number; nullable): Rent: minimum. - `rentPriceMax` (number; nullable): Rent: maximum. Below the minimum is refused. - `bedrooms` (integer; nullable): Minimum bedrooms. - `bathrooms` (integer; nullable): Minimum bathrooms. - `parkingSpots` (integer; nullable): Minimum parking spots. - `areaMin` (number; nullable): Minimum area, in m². ### LeadInput The fields the API accepts for a client. Unknown fields are an error; absent fields are kept. - `externalRef` (string): The client's code in your system (POST only). - `name` (string): Name. Required on creation. - `phones` (array): Up to 5 phones. On creation, a phone or an e-mail. - `email` (string; nullable): E-mail. - `status` (string; NEW | ATTENDING | PROPOSAL | WON | LOST): Funnel stage. - `notes` (string): Notes. - `preApproved` (boolean): Pre-approved credit. - `sharedToNetwork` (boolean): The profile may receive partner properties. - `interest` (InterestInput): Search profile. - `ownerAccountId` (string): The responsible broker, by id. - `ownerEmail` (string): The responsible broker, by e-mail — the way your system knows them. Without one, the agency's distribution rule applies. - `lastActivityAt` (string): The last activity in YOUR system. It only moves forward. More than 60 days ago on creation = the client is created archived (historical base). - `consentGiven` (boolean): Must be `true` on creation: the agency declares it has the legal basis to process the data (API Terms). ### LeadWriteResult The write outcome. - `outcome` (string): What happened: `CREATED`, `UPDATED`, `UNCHANGED`, `LINKED` (the code now points to a client that already existed by contact), `ARCHIVED` (created archived, historical base), `STATE_SET` (archived or reactivated), `ADDED` (interaction logged), `DELETED`, `ALREADY_DELETED`. - `dryRun` (boolean): It was a dry run — nothing was written. - `interaction` (object): The logged interaction (only in `POST /leads/{leadId}/interactions`). - `interaction.id` (string): Record id. - `interaction.type` (string): Type. - `interaction.note` (string; nullable): Note. - `interaction.at` (string; nullable): When it happened. ### PropertySnapshot The property snapshot in the pair — the same as the card. Fields the dashboard hides come back null. - `title` (string; nullable): Title. - `type` (string; nullable): Subtype. - `purpose` (string; nullable): Purpose of the pair. - `purposes` (array): The property's purposes. - `price` (number; nullable): Price (sale, or rent when the pair is a rental). - `priceFrom` (boolean): The price is a "starting at" price (new development). - `rentPrice` (number; nullable): Rent. - `city` (string; nullable): City. - `neighborhood` (string; nullable): Neighborhood. - `bedrooms` (integer; nullable): Bedrooms. - `bathrooms` (integer; nullable): Bathrooms. - `parkingSpots` (integer; nullable): Parking spots. - `area` (number; nullable): Area, in m². - `coverPhoto` (string; nullable): Cover photo. - `listingUrl` (string; nullable): Listing URL (null when the dashboard hides it too). - `commissionPercent` (number; nullable): Sale commission, in %. - `rentCommissionMonths` (number; nullable): Rent commission, in months. - `splitListingPercent` (number; nullable): Listing side share, in %. - `lastConfirmedAt` (string; nullable): Last availability confirmation. - `deliveryDate` (string; nullable): Delivery (new development). - `developmentId` (string; nullable): Development. - `developmentName` (string; nullable): Development name. ### ClientSnapshot The client snapshot in the pair. - `masked` (boolean): The client belongs to a partner and is masked. - `status` (string; nullable): Funnel stage. - `preApproved` (boolean): Pre-approved credit. - `purposes` (array): Purposes wanted. - `propertyTypes` (array): Types wanted. - `regions` (array): Regions, spelled out. - `priceMin` (number; nullable): Minimum. - `priceMax` (number; nullable): Maximum. - `bedrooms` (integer; nullable): Bedrooms. - `parkingSpots` (integer; nullable): Parking spots. - `areaMin` (number; nullable): Minimum area. - `name` (string; nullable): Name — only with the `leads:read` permission on the key and only when the dashboard shows it too. Phone, never. ### Counterpart The partner on the other side. - `accountId` (string): Partner's account id. - `name` (string; nullable): Name. - `type` (string; nullable): Account type. - `organization` (string; nullable): Partner's agency. - `creci` (string; nullable): Broker license (CRECI). - `creciVerified` (boolean): License verified. - `phone` (string; nullable): Phone. ### Match An opportunity: a property that fits a client. - `id` (string): Opportunity id (`m#{property}#{client}#{side}`). It contains `#`: URL-encode it (`%23`) in the path. - `scope` (string; INTERNAL | NETWORK | LAUNCH): `INTERNAL` (own portfolio), `NETWORK` (with partners) or `LAUNCH` (new development). - `status` (string): `NEW`, `FAVORITED`, `ARCHIVED` or `REQUESTED` (became a partnership request). - `score` (integer): Score from 0 to 100. - `reasons` (array): Why it matches. - `gaps` (array): What doesn't match. - `propertyId` (string; nullable): Property. - `leadId` (string; nullable): Client. - `ownerAccountId` (string; nullable): The in-house broker who gets the opportunity. - `ownerName` (string; nullable): Their name. - `locked` (boolean): Partner opportunity without an active subscription — the partner stays hidden, as in the dashboard. - `lostRelevance` (boolean): No longer matches after a change. - `property` (PropertySnapshot; nullable): The property. - `client` (ClientSnapshot; nullable): The client. - `counterpart` (Counterpart; nullable): The partner (null when in-house or hidden). - `createdAt` (string): When it was created (UTC). - `updatedAt` (string): Last change (UTC). ### MatchWriteResult The outcome. - `outcome` (string): `APPLIED`; in a dry run, `WOULD_APPLY`. - `dryRun` (boolean): It was a dry run. ### Party One side of the partnership. - `accountId` (string; nullable): Account id. - `name` (string; nullable): Name. - `type` (string; nullable): Account type. ### Partnership A partnership. - `id` (string): Partnership id. - `status` (string; PENDING | ACCEPTED | DECLINED | CANCELLED | LEAD_REGISTERED | CONTACTED | NEGOTIATING | PROPOSAL | WON | LOST): Stage. - `kind` (string; nullable): `CLIENT_FOR_PROPERTY` or `PROPERTY_FOR_CLIENT`. - `propertyId` (string; nullable): Property. - `leadId` (string; nullable): Client. - `matchId` (string; nullable): The originating opportunity. - `developmentId` (string; nullable): Development (new-development registration). - `developmentTitle` (string; nullable): Development name. - `score` (integer; nullable): Opportunity score. - `summary` (string; nullable): Summary. - `reasons` (array): Why it matches. - `message` (string; nullable): Request message. - `ourSide` (string; nullable): The account's side: `REQUESTER` or `ADDRESSEE`. - `ourBrokerId` (string; nullable): The in-house broker in the partnership. - `canMoveFunnel` (boolean): The account can move the stage — only the side that brought the client can. - `requester` (Party; nullable): Requester. - `addressee` (Party; nullable): Addressee. - `counterpart` (object): The partner on the other side. - `counterpart.name` (string; nullable): Name. - `counterpart.type` (string; nullable): Account type. - `counterpart.organization` (string; nullable): Agency. - `counterpart.contactName` (string; nullable): Contact. - `counterpart.phone` (string; nullable): Phone. - `counterpart.email` (string; nullable): E-mail. - `counterpart.creci` (string; nullable): Broker license. - `counterpart.creciVerified` (boolean): License verified. - `property` (PropertySnapshot; nullable): The property. - `client` (ClientSnapshot; nullable): The client. - `lastProgressAt` (string; nullable): Last stage move. - `protectedUntil` (string; nullable): Until when the client is protected (new development). - `propertyOffMarketAt` (string; nullable): When the property went off the market. - `createdAt` (string): When it was created (UTC). - `updatedAt` (string): Last change (UTC). ### PartnershipWriteResult The outcome. - `outcome` (string): What happened. - `dryRun` (boolean): It was a dry run. ### Member A team member. - `accountId` (string): The person's platform id. - `name` (string; nullable): Name. - `email` (string; nullable): E-mail — your system matches the broker by it. - `phone` (string; nullable): Phone. - `photoUrl` (string; nullable): Photo. - `creci` (string; nullable): Broker license (if any — the team also has interns and office staff). - `creciVerified` (boolean): License verified. - `status` (string): `active` or `suspended`. - `canCaptureProperties` (boolean): Can register properties and be responsible for them. - `isSupervisor` (boolean): Supervises part of the team. - `supervisorId` (string; nullable): This person's supervisor. - `receivesLeadDistribution` (boolean): Takes part in client distribution. - `firstAccessAt` (string; nullable): First access. ### FeedSync The CRM feed sync. Never includes the link or the token. - `configured` (boolean): The CRM feed link is set up on the account. - `connector` (string; nullable): The CRM behind the link (the feed format). - `autoSync` (boolean): The 6-hourly sync is on. - `status` (string; nullable): How the last sync ended (the same status as the dashboard) — `QUEUED` while it runs. - `message` (string; nullable): The last sync message, the same as in the dashboard. - `lastSyncAt` (string; nullable): When the last one finished. - `feedCount` (integer; nullable): Properties in the feed at the last read. - `counts` (object): What the last sync did. - `counts.created` (integer; nullable): Created. - `counts.updated` (integer; nullable): Updated. - `counts.archived` (integer; nullable): Archived (left the feed and passed the grace period). - `counts.skipped` (integer; nullable): Skipped (incomplete or over quota). - `counts.unchanged` (integer; nullable): Checked with no change (nothing written). - `counts.confirmed` (integer; nullable): Confirmed (only the availability date renewed). - `conflicts` (integer): Properties with a field edited in the dashboard that the feed tried to change — awaiting a decision under Properties › Import. - `scheduledFor` (string; nullable): The sync scheduled by `POST /v1/feed/sync` for the end of the window (null = none). ### FeedSyncResult The outcome. - `outcome` (string; QUEUED | SCHEDULED | ALREADY_SCHEDULED): `QUEUED` (syncs now) · `SCHEDULED` (scheduled for the end of the 10-minute window) · `ALREADY_SCHEDULED` (one was already scheduled — nothing new). - `dryRun` (boolean): It was a dry run (nothing queued). ### Typology A unit type of the development. - `id` (string): Unit type id. - `title` (string; nullable): Name. - `type` (string; nullable): Subtype. - `status` (string): Status. - `salePrice` (number; nullable): Price. - `bedrooms` (integer; nullable): Bedrooms. - `suites` (integer; nullable): Suites. - `bathrooms` (integer; nullable): Bathrooms. - `parkingSpots` (integer; nullable): Parking spots. - `area` (number; nullable): Private area, in m². - `privateArea` (number; nullable): Covered area, in m². - `coverPhoto` (string; nullable): Cover photo. - `floorPlans` (array): Floor plans. - `unitFeatures` (array): Unit features. - `unitsAvailable` (integer; nullable): Available units. - `unitsTotal` (integer; nullable): Total units. ### Launch A development in the new-development catalog. - `id` (string): Development id. - `title` (string; nullable): Name. - `developer` (string; nullable): Developer. - `address` (AddressArea): Address down to the neighborhood (the street is not in the catalog). - `constructionStage` (string; nullable; LAUNCH | OFF_PLAN | NEW | READY): Construction stage. - `deliveryDate` (string; nullable): Expected delivery. - `constructionProgress` (integer; nullable): Construction progress, in %. - `coverPhoto` (string; nullable): Cover photo. - `amenities` (array): Development amenities. - `commissionPercent` (number; nullable): Broker commission, in %. - `priceMin` (number; nullable): Lowest unit-type price. - `priceMax` (number; nullable): Highest price. - `typologyCount` (integer): How many unit types. - `typologies` (array): The unit types. ### CaptacaoOffer A Captação owner. The fields after `createdAt` only exist after accepting. - `id` (string): The owner's id on the desk. - `status` (string; nullable): Status. - `purpose` (string; nullable): Sale or rent. - `propertyType` (string; nullable): Subtype. - `city` (string; nullable): City. - `citySlug` (string; nullable): City identifier. - `neighborhood` (string; nullable): Neighborhood. - `bedrooms` (integer; nullable): Bedrooms. - `suites` (integer; nullable): Suites. - `bathrooms` (integer; nullable): Bathrooms. - `parkingSpots` (integer; nullable): Parking spots. - `usableAreaDeclared` (number; nullable): Usable area declared by the owner. - `areaDeclared` (number; nullable): Total area declared by the owner. - `priceExpected` (number; nullable): Price the owner expects. - `sellTimeframe` (string; nullable): Time frame to sell: `AGORA` (now), `TRES_MESES` (3 months), `SEIS_MESES` (6 months) or `PESQUISANDO` (just researching). - `occupancy` (string; nullable): Occupancy: `PROPRIO` (owner lives there), `ALUGADO` (rented) or `VAZIO` (empty). - `ownerRelation` (string; nullable): Who registered: `DONO` (owner), `COPROPRIETARIO` (co-owner), `REPRESENTANTE` (legal representative) or `OUTRO` (not the owner). - `exclusivityOpenness` (string; nullable): Accepts exclusivity: `SIM` (yes) or `NAO` (no). - `alreadyListedDeclared` (boolean): Said it is already listed elsewhere. - `priceCents` (integer; nullable): The contact price, in cents — what accepting debits. - `deadline` (string; nullable): Accept deadline (the clock runs only 9am–5pm on service days). - `matchingClients` (object): How many account clients match. - `matchingClients.city` (integer; nullable): Account clients looking for something like this in the city (null = could not compute). - `matchingClients.neighborhood` (integer; nullable): The same, in the neighborhood. - `demand` (object; nullable): Demand measured by the platform. - `demand.available` (boolean): Demand was measured. - `demand.people` (integer; nullable): People looking. - `demand.scope` (string; nullable): Scope. - `demand.scopeName` (string; nullable): Scope name. - `demand.asOf` (string; nullable): Measurement date. - `demand.label` (string; nullable): What was measured, spelled out. - `stockNeighborhood` (integer; nullable): Similar properties for sale in the neighborhood. - `ownerNameMasked` (string; nullable): Masked name (before accepting). - `ownerPhoneVerifiedVia` (string; nullable): How the owner's phone was verified. - `ownerPhoneVerifiedAt` (string; nullable): When. - `revealed` (boolean): The contact was released to the account (accepted). Before that, `owner` and `address` do NOT exist in the response. - `createdAt` (string): When it was created (UTC). - `owner` (object): The owner (only after accepting). - `owner.name` (string; nullable): Name. - `owner.phone` (string; nullable): Phone. - `owner.email` (string; nullable): E-mail. - `address` (object): The address (only after accepting). - `address.street` (string; nullable): Street. - `address.number` (string; nullable): Number. - `address.complement` (string; nullable): Complement. - `address.neighborhood` (string; nullable): Neighborhood. - `address.city` (string; nullable): City. - `acceptedAt` (string; nullable): When it was accepted. - `acceptedVia` (object; nullable): How it was accepted: in the dashboard or through the API (with the key, the IP and the terms version). - `refundUntil` (string; nullable): Refund request deadline. - `refundedAt` (string; nullable): When it was refunded. - `soldAt` (string; nullable): When the property was sold. - `stage` (string; nullable): Stage on the desk. - `stageLabel` (string; nullable): Stage, spelled out. - `lostReason` (string; nullable): Lost reason. - `note` (string; nullable): Note. - `tab` (string; nullable): Desk tab: `ACTIVE`, `CAPTURED` or `ARCHIVED`. ### CaptacaoSummary Desk summary. - `pendingCount` (integer): Owners offered to the account right now. - `balanceCents` (integer): Credit, in cents. - `subscriptionActive` (boolean): Module subscription active. - `platformActive` (boolean): The module is on for the platform. - `paused` (boolean): The account paused receiving owners. - `pausedAuto` (boolean): Automatic pause (deadlines missed in a row). - `expiredStreak` (integer): Deadlines missed in a row. - `autoPauseAfter` (integer; nullable): Automatic pause after how many. - `inActivation` (boolean): In activation (before the first top-up). - `leadsToFirstCharge` (integer; nullable): Accepts until the first top-up. - `rechargePending` (boolean): Top-up in progress. - `operatingCities` (array): Cities served. - `purposes` (array): Purposes served. - `serviceDays` (array): Service days. ### CaptacaoAcceptResult The accept outcome. - `outcome` (string): `ACCEPTED`, `ALREADY_ACCEPTED` (no second debit) or, in a dry run, `WOULD_ACCEPT`. - `dryRun` (boolean): It was a dry run — nothing was debited. - `priceCents` (integer; nullable): The amount debited (or that would be), in cents. ### Event An event. - `id` (string): Event id (`evt_…`) — the same `webhook-id` as the delivery. Use it to avoid processing twice. - `type` (string; property.created | property.updated | property.deleted | property.restored | property.purged | lead.created | lead.updated | lead.deleted | lead.restored | lead.purged | radar.client_summary | partnership.created | partnership.updated | captacao.offer_received | captacao.offer_accepted | captacao.offer_withdrawn): Type. - `createdAt` (string): When it was recorded (UTC). - `data` (object): What changed, lean: ids, state and `changedFields` (the NAMES of the changed fields). Never name, phone, e-mail or address — fetch the detail by reading the resource. ### Webhook A webhook endpoint. The secret never comes back here. - `id` (string): Endpoint id (`wh_…`). - `url` (string): The URL (HTTPS only). - `types` (array): The types it receives (empty = all the account can read). - `description` (string; nullable): Description. - `status` (string; ACTIVE | DISABLED): `ACTIVE` or `DISABLED`. - `disabledAt` (string; nullable): When it was disabled. - `disabledReason` (string; nullable): `GONE_410` (your system answered 410), `FAILURE_RATE` (half or more of the deliveries failed in 48 h) or `MANUAL`. - `secretRotatedAt` (string; nullable): Last secret rotation. - `previousSecretValidUntil` (string; nullable): Until when the previous secret still signs alongside (24 h after rotation). - `createdAt` (string): When it was created (UTC). - `updatedAt` (string): Last change (UTC). ### WebhookCreate A new endpoint. - `url` (string): The URL, HTTPS and public only. Credentials in the URL are refused. - `types` (array): The types (absent = all the account can read). - `description` (string; nullable): Description. ### WebhookUpdate What to change on the endpoint. - `url` (string): The URL. - `types` (array): The types. - `description` (string; nullable): Description. - `status` (string; ACTIVE | DISABLED): `ACTIVE` re-enables (clears the disable reason) and `DISABLED` disables. ### Delivery One event delivery to an endpoint. - `id` (string): Delivery id (`dlv_…`). - `eventId` (string; nullable): The delivered event. - `type` (string; nullable): Event type. - `status` (string): `PENDING`, `RETRYING`, `DELIVERED`, `FAILED` (out of retries) or `SKIPPED` (the endpoint was disabled). - `attempts` (integer): Attempts made. - `lastStatusCode` (integer; nullable): Last HTTP status from your system. - `lastError` (string; nullable): Last error. - `lastAttemptAt` (string; nullable): Last attempt. - `nextAttemptAt` (string; nullable): Next attempt (1 min, 5 min, 30 min, 2 h, 6 h and 12 h). - `deliveredAt` (string; nullable): When it was delivered. - `createdAt` (string; nullable): When the delivery was opened. ### WebhookTestResult The test event result (`webhook.test`). - `delivered` (boolean): Your system answered 2xx. - `statusCode` (integer; nullable): The status it answered. - `error` (string; nullable): The failure reason. - `ms` (integer; nullable): Delivery time, in ms. ### BatchCreated The received batch. - `id` (string): Batch id (`b-…`). - `type` (string; properties | leads): `properties` or `leads`. - `status` (string; QUEUED | RUNNING | DONE): `QUEUED`, or `DONE` when no item was valid. - `total` (integer): Items received. - `accepted` (integer): Items queued for processing. - `rejected` (integer): Items rejected on shape (see the result). - `dryRun` (boolean): The whole batch is a dry run. ### BatchItem One item result. - `index` (integer): Position in the request. - `externalRef` (string; nullable): The item's code. - `outcome` (string): The item's outcome — the same as the PUT by code, plus `PENDING` (still queued) and `REJECTED`. - `id` (string; nullable): The property or client id. - `code` (string; nullable): The error code, when refused. - `detail` (string; nullable): Detail. - `invalidParams` (array; nullable): Shape problems. - `photos` (string; nullable): The gallery (properties). ### Batch A batch, with each item outcome. - `id` (string): Batch id. - `type` (string; properties | leads): `properties` or `leads`. - `status` (string; QUEUED | RUNNING | DONE): `QUEUED`, `RUNNING` or `DONE`. - `dryRun` (boolean): Dry run. - `total` (integer; nullable): Items. - `processed` (integer; nullable): Items with an outcome. - `counts` (object): Count per outcome (`CREATED`, `UPDATED`, `REJECTED`…). - `createdAt` (string; nullable): When it was received. - `startedAt` (string; nullable): When it started. - `finishedAt` (string; nullable): When it finished. - `results` (array): Each item outcome, in request order. ### ConfirmItem One property outcome in the confirmation. - `id` (string): The requested id (when the request used `ids`). - `ref` (string): The requested code (when the request used `refs`). - `propertyId` (string; nullable): The property found (null when not found). - `outcome` (string; CONFIRMED | ALREADY_CONFIRMED | NOT_FOUND): `CONFIRMED`, `ALREADY_CONFIRMED` (less than 24 h ago — not rewritten) or `NOT_FOUND`. ## Events `GET /v1/events`: in order, 30 days of history; keep `nextCursor` (always present) and follow the cursor, never the clock. Events are lean: ids, state and `changedFields` (field NAMES), never personal data — read the resource for the new value. Each type also requires the resource's read permission. - `property.created` (`properties:read`): Property created. data: `id`, `externalRef`, `status`, `updatedAt` - `property.updated` (`properties:read`): Property updated (fields in changedFields). data: `id`, `externalRef`, `status`, `changedFields`, `updatedAt` - `property.deleted` (`properties:read`): Property moved to the trash. data: `id`, `externalRef`, `status`, `updatedAt` - `property.restored` (`properties:read`): Property restored. data: `id`, `externalRef`, `status`, `updatedAt` - `property.purged` (`properties:read`): Property permanently deleted. data: `id`, `externalRef`, `status`, `updatedAt` - `lead.created` (`leads:read`): Client created. data: `id`, `externalRef`, `state`, `status`, `ownerAccountId`, `updatedAt` - `lead.updated` (`leads:read`): Client updated (fields in changedFields). data: `id`, `externalRef`, `state`, `status`, `ownerAccountId`, `changedFields`, `updatedAt` - `lead.deleted` (`leads:read`): Client moved to the trash. data: `id`, `externalRef`, `state`, `status`, `ownerAccountId`, `updatedAt` - `lead.restored` (`leads:read`): Client restored. data: `id`, `externalRef`, `state`, `status`, `ownerAccountId`, `updatedAt` - `lead.purged` (`leads:read`): Client permanently deleted. data: `id`, `externalRef`, `state`, `status`, `ownerAccountId`, `updatedAt` - `radar.client_summary` (`radar:read`): New opportunities for a client, batched over a few minutes. data: `leadId`, `newMatches`, `topScore`, `since`, `until` - `partnership.created` (`partnerships:read`): Partnership created. data: `id`, `status`, `kind` - `partnership.updated` (`partnerships:read`): Partnership stage or deadline changed. data: `id`, `status`, `previousStatus`, `changedFields` - `captacao.offer_received` (`captacao:read`): An owner is now offered to the account, with the deadline. data: `id`, `deadline` - `captacao.offer_accepted` (`captacao:read`): Owner accepted by the account. data: `id`, `acceptedAt`, `via` - `captacao.offer_withdrawn` (`captacao:read`): Owner no longer offered to the account (deadline passed or taken). data: `id` ## Webhooks - Each delivery: JSON `POST` `{type, timestamp, data}` with the headers `webhook-id` (the event id — the same on every attempt; use it to deduplicate), `webhook-timestamp` (seconds since 1970) and `webhook-signature`. - Signature (Standard Webhooks): `v1,` + base64 of HMAC-SHA256 over `{webhook-id}.{webhook-timestamp}.{raw body}`, keyed with the secret after `whsec_`, base64-decoded. There may be several, space-separated (secret rotation): accept if any matches. Compare in constant time. - Reject messages more than 5 minutes off the clock. Answer 2xx within 10 s (process later, from a queue). - Without a 2xx, retries after 1 min, 5 min, 30 min, 2 h, 6 h, 12 h. Order is not guaranteed. `410` disables the endpoint; it is also disabled with 5+ finished deliveries in 48 h and 50% or more failing after every attempt. - Rotating the secret: the previous one keeps signing alongside for 24 h. ## Errors - `unauthorized` (401) — Key missing, invalid, revoked or expired. The request came without a key, with a key that does not exist, was revoked in the dashboard or has expired. Send the key in the `Authorization: Bearer imob_live_…` header. Never in the URL. If it expired or was revoked, create another in the dashboard (My account › API integration). - `access_not_active` (403) — This account's API is not active. The key exists, but the account's access is not valid right now. The account owner sees the reason in the dashboard, under API integration. - `access_denied` (403) — Access denied. The edge refused the request before it reached the API. Check the key and the path. If it persists, contact ImobyFlow with the `requestId`. - `IP_NOT_ALLOWED` (403) — Source IP not allowed for this key. The key has an IP allowlist and the request came from an address outside it. Add the address to the key's allowlist in the dashboard — or call the API from a server already on it. - `ACCOUNT_INACTIVE` (403) — Account inactive. The account that owns the key is not active on the platform. Contact ImobyFlow. - `NOT_REQUESTED` (403) — API not requested for this account. The account never requested API access. The owner requests it under My account › API integration. Access is granted account by account by ImobyFlow. - `PENDING` (403) — Access request under review. The access request is still under review. Wait for approval. The owner gets an e-mail when it happens. - `INFO_REQUESTED` (403) — Access request awaiting information. ImobyFlow asked for more information about the request. The owner answers in the dashboard, under API integration. - `DENIED` (403) — Access request denied. The access request was denied. The reason is shown in the dashboard. You can request again after addressing it. - `SUSPENDED` (403) — API access suspended. ImobyFlow suspended this account's access. Nothing was deleted. The reason is shown in the dashboard. Contact ImobyFlow to reactivate. - `REVOKED` (403) — API access revoked. Access was revoked and all keys were revoked with it. Contact ImobyFlow. - `PLAN_NOT_ELIGIBLE` (403) — Plan not eligible for the API. The current plan does not include the API (agencies from 2,000 properties up, or any developer plan). Change plans under My account › Subscription. Keys work again right away, with nothing deleted. - `SUBSCRIPTION_INACTIVE` (403) — Subscription not active. The subscription is not up to date. The API requires an active subscription (the trial counts). Settle it under My account › Subscription. Keys work again right away. - `PILOT_EXPIRED` (403) — Pilot period ended. The account was granted a pilot period and it ended. Contact ImobyFlow to continue. - `scope_missing` (403) — The key lacks the permission for this route. The route requires a permission this key does not have. `invalidParams` says which. Create a key with that permission in the dashboard. If it is not offered, the account's access does not include it — contact ImobyFlow. - `rate_limited` (429) — Per-second call limit reached. Too many calls per second for the account's tier. Wait and retry with growing intervals (1 s, 2 s, 4 s…). For many items, use batches. - `monthly_quota_exceeded` (429) — Monthly quota exhausted. The account used all calls for the month. The owner was warned at 80%. The quota resets on the 1st (UTC). To raise it, contact ImobyFlow. Syncing through events instead of re-reading the whole portfolio uses far less. - `route_not_found` (404) — Route not found. The path does not exist. Check the path: routes start with `/v1/`. The reference lists them all. - `method_not_allowed` (405) — Method not allowed. The path exists, but not with this method. Check the method in the reference. - `bad_request` (400) — Request refused. The edge refused the request before it reached the API (malformed request). Check the method, path and headers. - `invalid_param` (400) — Invalid parameter. One or more request fields are wrong. `invalidParams` lists ALL of them at once, with the path and the reason (`required`, `unknown_field`, `one_of` with the `allowed` list, `not_in_catalog` with `suggestions`…). Fix each `invalidParams` item. Unknown fields are an error on purpose: a `bedroom` instead of `bedrooms` must not slip through. - `invalid_cursor` (400) — Invalid cursor — restart the listing without it. The cursor was altered, belongs to another route or another account. Restart the listing without `cursor` and follow each response's `nextCursor` untouched. - `invalid_body` (400) — Invalid body — send a JSON object. The body was empty or is not JSON. Send a JSON object with `Content-Type: application/json`. - `payload_too_large` (413) — Payload too large. The body exceeded the cap: 256 KB per request, 4 MB per batch. Split the batch into smaller parts. - `not_found` (404) — Not found. The id or code does not exist in this account. Items from other accounts also return 404 — not even their existence is confirmed. Check the id. To look up by your system's code, use the `by-ref` routes. - `not_available` (403) — Resource not available for this account type. The resource does not exist for this account type (for example: team and clients do not exist for developers). Use only the resources for the account type — `GET /v1/me` shows the type and permissions. - `invalid_idempotency_key` (400) — Invalid Idempotency-Key (up to 100 visible characters). The idempotency key has spaces, characters outside visible ASCII or more than 100 characters. Use an identifier such as a UUID. - `idempotency_key_reused` (422) — Idempotency-Key already used with a different request. The same key was used in the last 24 hours with another body, method or path. Generate a new key for each different request. Reuse the SAME key only when retrying the same request. - `idempotency_in_progress` (409) — A request with this Idempotency-Key is still in progress. The retry arrived before the original request finished. Wait a few seconds and repeat — you will get the original response, with `Idempotent-Replayed: true`. - `concurrent_write` (409) — Another write for this code is in progress — retry. Two requests for the SAME code arrived together. The lock exists so the property is not created twice. Retry in a few seconds. Avoid sending the same code in parallel. - `feed_sync_active` (409) — Automatic CRM feed sync is on for this account. One source per account: with the feed on, it is the source of properties, and anything not in the XML would be archived on the next cycle. Status and confirmation remain allowed. Turn the feed off under Properties › Import for the API to take over — or keep using the feed. - `feed_not_configured` (409) — The CRM feed link is not set up for this account. `POST /v1/feed/sync` fetches the feed link the account set up — and this account has none. Set up the link under Properties › Import › CRM sync, or write properties through the API (`PUT /v1/properties/by-ref/{code}`). - `plan_limit_reached` (409) — Plan limit of active properties reached. Creating or activating this property would exceed the plan's active-property cap. Updating existing ones is never blocked. Archive the ones that are gone (`SOLD`, `RENTED`, `INACTIVE` do not use quota) or change plans. - `property_in_trash` (409) — Property is in the trash. This code's property is in the trash. Re-creating it would make two properties with the same code. Restore it in the dashboard to update it again. - `external_ref_exists` (409) — A property with this code already exists. The code (`externalRef`) already belongs to another property — or, for clients, to another client. `invalidParams` carries the id. Use the PUT by code (`/by-ref/{code}`) to update. - `invalid_property` (422) — Incomplete or inconsistent property. After merging the request with what was stored, the minimum was missing: type, purpose, the price for each purpose and the city. Fill in the fields indicated in `detail`. - `shrink_guard` (409) — Shrink guard: too many deletions in 24 hours. The API already trashed 20% of the portfolio (and at least 10 items) in the last 24 hours. The guard exists so a loop or an inverted filter in your system cannot empty the portfolio. Check the integration. If the deletion is intentional, do it in the dashboard, where a person is watching. - `consent_required` (422) — Client consent not declared. On creation, the agency must declare its legal basis to process the client's data (it is the controller). Send `consentGiven: true`. The platform records the date, the Terms version and the channel. - `lead_exists` (409) — A client with this phone or e-mail already exists. The contact already belongs to one of the account's clients (from a portal, a spreadsheet). `invalidParams` carries the id. Use the PUT by code: it LINKS your code to the existing client (`LINKED`), without duplicating. - `lead_linked_to_other_ref` (409) — The client with this contact already has another CRM code. The contact belongs to a client already linked to ANOTHER code in your system. Check whether they are the same person in your system and use a single code. - `lead_in_trash` (409) — Client is in the trash. The client is in the trash. Restore it in the dashboard to update it again. - `captacao_not_active` (409) — Captação is not active for this account. Captação is a module for agencies and is enabled by ImobyFlow. Contact ImobyFlow to join. - `captacao_terms_required` (403) — Accepting via the API requires the specific term accepted in the dashboard. Accepting through the API spends credit and requires item 13 of the API Terms, accepted by the owner in the dashboard. The owner accepts it under My account › API integration. - `offer_unavailable` (409) — This owner is no longer available to your account. The deadline passed or the owner moved on. Who took it is not disclosed — it is another account's information. Nothing was charged. Move on to the next ones on the desk. - `captacao_insufficient_credit` (409) — Not enough Captação credit. The credit does not cover this contact's price. `invalidParams` carries the price and balance, in cents. Top up under My account › Subscription. - `webhook_url_refused` (422) — Webhook URL refused. The URL is not HTTPS, has embedded credentials, does not resolve, or resolves to an internal IP. Use a public HTTPS URL, without user and password in it. - `webhook_limit_reached` (409) — Account webhook limit reached. The account already has the maximum number of endpoints for its tier. Delete an unused endpoint — one endpoint can receive every type. - `request_refused` (422) — The platform refused the request. A platform rule refused the request — the same the dashboard would apply. `detail` carries the dashboard message (in Portuguese). Read `detail`: it says what to adjust. - `upstream_busy` (503) — Too many concurrent requests — retry shortly. The platform is serving too many requests from this and other accounts. Retry with growing intervals. Send fewer requests in parallel. - `upstream_timeout` (504) — The query took too long — try a smaller page. The read took too long. Use a smaller `limit` or a narrower filter. - `upstream_unavailable` (503) — Service temporarily unavailable. A platform component did not respond. Retry shortly. With `Idempotency-Key`, retrying a write is safe. - `authorizer_failure` (500) — Temporary failure validating the key. Key validation failed on our side. Retry shortly. If it persists, contact ImobyFlow with the `requestId`. - `internal` (500) — Internal error. Our failure. It has been logged. Retry shortly. If it persists, contact ImobyFlow with the `requestId`. ## Changelog ### 2026-10-04 - Official SDKs in TypeScript, Python and PHP, generated from this contract: one method per route, pages walked for you, retries that never duplicate a write, and webhook signature verification. - Response examples (success and errors) in the Postman collection and in the OpenAPI. The public Postman collection follows every release. - `POST /v1/feed/sync`: your system says the portfolio changed and ImobyFlow fetches the feed link right away, without waiting 6 hours; `GET /v1/feed` shows the result. - MCP server at `https://api.imobyflow.com.br/mcp`: AI agents read and update the account with the same key. Every write runs as a dry run and is only saved after confirmation. ### 2026-10-03 — 1.0.0 - Developer portal in Portuguese and English, generated from the OpenAPI 3.1 contract. - One page per error code — the URL in each error's `type`. - Postman collection, OpenAPI in JSON and YAML, and `llms.txt` for AI assistants. - A "Try it" button on every route: calls the API from the browser with your key (real reads, writes always as a dry run) and explains every field of the response — annotated JSON. ### 2026-10-02 - Signed webhooks (Standard Webhooks), with retries for about 21 hours, automatic disabling, redelivery and a test event. - Events (`GET /v1/events`): what changed in the account, in order, with 30 days of history. - E-mail notices: key expiring, monthly quota at 80% and 100%, webhook endpoint disabled. - Batches of up to 500 properties or clients. - Captação: the desk, accepted owners and acceptance, with its own permission and term. - Actions: dismiss and restore opportunities, move partnerships and the trash with the shrink guard. - Client writes (your system's code, linking by contact, consent) and property writes (photos by URL, dry run, `Idempotency-Key`). - Reads: properties, clients, opportunities, partnerships, team and new developments. ### 2026-10-01 - The foundation: per-account keys, account-by-account access, `GET /v1/me`, reference lists and the city and neighborhood catalog.