Concepts and rules
What applies to every call, and the platform rules your integration needs to know.
The key and its permissions
- The key belongs to the account (the company), never to a person. It has a name, permissions, an optional expiry and, if you want, an IP allowlist.
- Each route requires a permission (
properties:read,leads:write…). Without it, scope_missing.GET /v1/meshows the key’s permissions. - Two active keys at the same time let you rotate without downtime: create the new one, switch your system, revoke the old one.
- The account owner gets an e-mail 15 days before the key expires and the day before.
Limits
- Standard tier: 10 calls per second (burst 20) and 300,000 per month. Extended tier: 20 per second (burst 40) and 1 million per month. ImobyFlow can tailor them.
- Over the per-second limit: rate_limited — wait and retry with growing intervals. Over the month: monthly_quota_exceeded — the quota resets on the 1st (UTC). The owner is warned at 80% and 100%.
- Re-reading the whole portfolio every hour wastes quota: use events to learn what changed.
Lists and pagination
- Lists come in pages:
limitsets how many items, and each response carriesnextCursor. Send it back ascursoruntil it comes back null. - A cursor is only valid for the route and account that returned it — and must not be altered. Altered or swapped: invalid_cursor.
- To sync,
updatedSincereturns only what changed since a date. Events do it better: in order, with 30 days of history.
Errors
Every error is application/problem+json (RFC 9457), with a stable code — your system should branch on it, never on the text. type is the URL of the error page, with the cause and the fix. invalidParams lists every problem in the request at once.
Include the requestId when contacting support. See every code.
How writes work
- Absent fields are kept: a request only changes what it carries. To clear a field, send
null. - Unknown fields are an error (invalid_param with
unknown_field). Abedroominstead ofbedroomsmust not slip through. - Nothing changed? The response says
UNCHANGEDand nothing is written. Re-sending the whole portfolio costs no writes. - Dashboard edits win: a field the team changed in the dashboard is not overwritten and comes back in
result.conflicts. ?dryRun=true(dry run): validates and says what would happen — create, update, nothing changed, quota exceeded — without writing anything.- Send an
Idempotency-Key(a UUID) with every write. If the network drops and you repeat the SAME request with the SAME key within 24 hours, you get the same response, with no second write (Idempotent-Replayed: true). - Two requests for the same code at once: the second gets concurrent_write. Do not send the same code in parallel.
Platform rules that apply to integrations
They are the same as in the dashboard. They protect recommendations and partners — and they are why accepted data sometimes does not show up where you expected.
- Neighborhoods are closed against the catalog. Send
neighborhoodSlugfrom the cities and neighborhoods list. Neighborhoods sent as text go through an alias dictionary; anything it does not recognize waits for ImobyFlow’s review and the property stays out of recommendations meanwhile. - No cover, no recommendations. The first photo is the cover. Photos sent by URL are downloaded after the response — follow them in
photoSync. - The 60-day rule. Properties nobody confirms go offline. Writing a property through the API confirms it; to confirm without changes, use bulk confirmation.
- One source per account. With the automatic CRM feed sync on, the API does not write properties (feed_sync_active): the feed would archive anything missing from its file.
- New properties go through ImobyFlow’s review before partners see them, same as in the dashboard.
- Plan quota. Only available properties use quota. Creating above the cap: plan_limit_reached. Updating existing ones is never blocked.
- Trash with a guard. Deleting moves to the trash for 30 days. At most 20% of the portfolio (and at least 10 items) in 24 hours — a loop in your system cannot empty the portfolio (shrink_guard).
- Clients: consent. On creation,
consentGiven: true. The agency is the data controller and declares the legal basis. - Clients: activity. Clients with no activity for 60 days are archived. Sync alone does not count: send
lastActivityAtwith your system’s date, or log interactions. - Clients: one per person. The PUT by code finds a person already here by phone or e-mail and links your code to them (
LINKED), without duplicating. - Partnerships: one funnel owner. Only the side that brought the client moves the stage (
canMoveFunnel). - Captação: accepting spends credit. Only with the
captacao:acceptpermission and the specific term accepted by the owner in the dashboard. Contact and address only appear after accepting.
Syncing the portfolio, step by step
- Initial load: send the portfolio in batches of up to 500, with your system’s code in
externalRef. First with?dryRun=true, to see what would be refused. - Then, on every change in your system:
PUT /v1/properties/by-ref/{code}. It creates or updates, and writes nothing when nothing changed. - Sold or rented:
POST /v1/properties/{id}/status. Left the portfolio:DELETE. - For the way back, read events or receive webhooks: what the team changed in the dashboard and new Radar opportunities.
Security and privacy (LGPD)
- Keep the key on your server, in a vault or environment variable. Never in your website's JavaScript, never in the end user's app.
- The key's IP allowlist closes the door to anyone who copies it: only listed servers can use it.
- The agency is the controller of its clients' data; ImobyFlow is the processor. The API Terms include the data processing agreement.
- Events and webhooks carry no personal data: only ids and the names of the changed fields.
Read the API Terms (Portuguese) before going live.