# 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