Inmobalia

Connect an Inmobalia personal access token and import contacts and activity history into the Fondaro CRM with a reversible, admin-triggered import.

The Inmobalia endpoints drive a reversible import of your Inmobalia CRM into Fondaro. Fondaro reads from the Inmobalia API directly using a per-organization personal access token (PAT). The import is read-only against Inmobalia and runs in two passes:

  • Contacts → leads (with activity logs as notes, and tasks — pending or completed — as tasks). A contact's lead status maps to a Fondaro CRM status.
  • Sales → deals (the second pass): each Inmobalia Sale becomes a Fondaro Deal attached to the buyer's (or seller's) imported lead, carrying multi-party commission (collaborators and internal agents). The sale's stage maps to a Fondaro deal stage. Run this only after the contacts pass has committed.

Every endpoint requires a valid Clerk session, an active organization, and the organization admin role. The PAT itself is managed through the standard integration credentials endpoints under the inmobalia provider (api_token key).

Connection status

GET /inmobalia/import/status

Reports whether a token is connected, whether it has expired, and a summary of the most recent import batch. Performs one live call to Inmobalia to confirm the token still works.

Response

{
  "connected": true,
  "expiresAt": "2026-12-31T00:00:00.000Z",
  "expired": false,
  "lastBatch": {
    "id": "9f1c…",
    "status": "committed",
    "counts": { "contacts": 120, "leadsCreated": 118, "leadsSkipped": 2, "notes": 540, "tasks": 33, "errors": 0 }
  }
}

User mapping

GET /inmobalia/import/user-mapping

Lists Inmobalia users and Fondaro org members, with an auto-match (autoMatch) keyed by Inmobalia username, matched case-insensitively by email. null means no match was found.

Response

{
  "inmobaliaUsers": [{ "username": "jdoe", "email": "j@agency.com", "name": "Jane Doe" }],
  "fondaroMembers": [{ "userId": "user_123", "email": "j@agency.com", "name": "Jane Doe" }],
  "autoMatch": { "jdoe": "user_123" }
}

Lead statuses

GET /inmobalia/import/lead-statuses

Returns your account's configured contact lead statuses. These drive the mandatory lead-status → CRM-status mapping (statusMapping) used by the contacts commit. Per-account, so the wizard builds the mapping table from these rather than any fixed list.

Response

{ "statuses": ["HOT", "WARM", "COLD"] }

Sale stages

GET /inmobalia/import/sale-stages

Returns your account's configured sale pipeline stages. These drive the mandatory sale-stage → deal-stage mapping (stageMapping) used by the sales commit.

Response

{ "stages": ["LEAD_CAPTURING", "OFFERING", "CLOSED"] }

Contact sources

GET /inmobalia/import/sources

Returns your account's configured contact sources (the source catalogue Inmobalia stamps on contacts). These drive the optional source → lead-source/tag mapping (sourceMapping) used by the contacts commit. Per-account, so the wizard builds the mapping table from these rather than any fixed list.

Response

{ "sources": ["PORTAL_IDEALISTA", "WALK_IN", "REFERRAL"] }

Preview (dry run)

POST /inmobalia/import/preview

Classifies the contacts that would be imported without writing anything. Does not fetch contact detail or activities, so it is cheap.

Request

{
  "fromDateModified": "2026-01-01T00:00:00.000Z",
  "includeArchived": false,
  "contactTypes": ["buyer", "owner"],
  "assignedToUser": "jdoe"
}

All fields are optional. Omitting contactTypes (or sending an empty array) imports every non-archived contact. assignedToUser is the Inmobalia username to scope the preview to a single agent, so only that agent's assigned contacts are classified. This backs the wizard's "test run, one agent" mode; omit it to preview the whole account.

Response

{
  "total": 120,
  "toCreate": 110,
  "existing": 8,
  "invalidCount": 2,
  "invalid": [{ "contactId": 42, "reasons": ["Missing phone number"] }],
  "sample": [{ "contactId": 1, "firstName": "Ada", "lastName": "Lovelace", "email": "ada@x.com", "phoneNumber": "+34…", "existing": false, "willImport": true, "missingFields": [] }],
  "typeBreakdown": { "buyer": 90, "owner": 30, "tenantLong": 0, "tenantShort": 0, "collaborator": 0, "developer": 0, "lawyer": 0, "serviceco": 0 },
  "assignmentSummary": { "inmobaliaUsers": 4, "autoMatched": 3, "unmatched": 1 }
}

Commit (background import)

POST /inmobalia/import/commit

Starts the import and returns immediately with a batch id. The work runs in the background; poll the batch endpoint for progress. Returns 202 Accepted. Blocked with 400 if the token is expired.

Request

{
  "fromDateModified": "2026-01-01T00:00:00.000Z",
  "includeArchived": false,
  "contactTypes": ["buyer"],
  "userMapping": { "jdoe": "user_123", "asmith": null },
  "missingFieldStrategy": "skip",
  "statusMapping": { "HOT": "client", "WARM": "potential", "DEFAULT": "lead" },
  "contactIds": [1, 2, 3],
  "sourceMapping": {
    "Facebook": { "leadSource": "meta", "tagName": "Facebook" },
    "Idealista": { "leadSource": "inmobalia", "tagName": "Idealista" },
    "__default__": { "leadSource": "inmobalia" }
  }
}

userMapping maps each Inmobalia username to a Fondaro userId (or null to import that user's contacts unassigned). missingFieldStrategy is skip (drop contacts missing a required field) or placeholder (import them with placeholder values). statusMapping is mandatory: it maps each Inmobalia contact lead status (from Lead statuses) plus a DEFAULT catch-all to a Fondaro CRM status. The commit re-validates it and rejects (400) an incomplete or invalid mapping before writing anything.

contactIds is optional. When present, the import is restricted to exactly those Inmobalia contact ids (everything else is ignored), which is how the wizard's "test run, one agent" mode imports just one agent's capped slice. Omit it to import the full classified set.

sourceMapping is optional. It maps an Inmobalia contact source name (from Contact sources) to a Fondaro leadSource — one of the existing values meta, google, client_web, manual, csv_import, zapier, james_edition, inmobalia (the source enum is not expanded) — and, optionally, a tagName (a plain string; the tag is found-or-created by name, so you don't pre-create it). The special __default__ key covers contacts with no source. Any source you don't map defaults to a Lead.source of INMOBALIA; mapping a source overrides that with your chosen leadSource, and the mapped tag (if any) is attached to every lead that source brings in. Only the tags you reference are applied; no tags are created from Inmobalia's own source details or free-form tags. Regardless of mapping, each contact's original source, source details, and tags are preserved in the lead's metadata.

Response

{ "batchId": "9f1c…" }

The import is idempotent: every created lead carries externalId = "inmobalia:<contactId>", so re-running skips contacts that already exist.

Sales preview (dry run)

POST /inmobalia/import/sales/preview

Classifies the Sales that would import as Deals, list-only (no per-sale calls). A Sale attaches to the buyer's (fallback seller's) imported lead, so run this after the contacts pass has committed.

Request

{ "fromDateModified": "2026-01-01T00:00:00.000Z", "status": "WON", "forContactIds": [1, 2, 3] }

All fields optional (status is one of IN_PROGRESS, WON, LOST). forContactIds restricts the preview to sales whose buyer or seller is one of those Inmobalia contact ids. Pass the ids from a "test run" contacts import so the Deals pass follows only those contacts; omit it to consider every sale.

Response

{
  "totalSales": 60,
  "toCreate": 52,
  "existing": 3,
  "skippedNoLead": 5,
  "unlinkedParties": 7,
  "byStage": { "CLOSED": 40, "OFFERING": 12 },
  "byStatus": { "WON": 40, "IN_PROGRESS": 20 },
  "sample": [{ "saleId": 81, "code": 81, "title": "CL Postigo de Arance 14", "stage": "CLOSED", "status": "WON", "amount": 655000, "primaryLeadLinked": true }]
}

skippedNoLead counts sales whose buyer and seller are both un-imported (no deal can attach). unlinkedParties counts buyer/seller references that won't resolve to a lead among the importable sales.

Sales commit (background import)

POST /inmobalia/import/sales/commit

Starts the Sales → Deals pass and returns a batch id (202). Poll the batch endpoint for progress.

Request

{
  "fromDateModified": "2026-01-01T00:00:00.000Z",
  "stageMapping": { "CLOSED": "under_contract", "OFFERING": "offer", "DEFAULT": "qualified" },
  "userMapping": { "jdoe": "user_123" },
  "forContactIds": [1, 2, 3]
}

stageMapping is mandatory: it maps each Inmobalia sale stage (from Sale stages) plus a DEFAULT catch-all to a Fondaro deal stage (qualified, viewing, offer, reserved, under_contract). userMapping is reused from the contacts pass. forContactIds is optional and matches the sales preview: pass the contact ids from a "test run" contacts import to commit only those contacts' deals; omit it to import every eligible sale. Each created deal carries externalId = "inmobalia:sale:<id>" (idempotent re-runs) and connects buyer, seller, lawyers, collaborators, and internal agents as deal participants with their commission shares.

Response

{ "batchId": "a2d7…" }

A sales batch's counts are { totalSales, dealsCreated, dealsSkipped, participants, notes, errors }.

Batch status

GET /inmobalia/import/batches/:id GET /inmobalia/import/batches

Poll a single batch (or list the 20 most recent). status moves through committing → committed (or failed), and rolling_back → rolled_back on undo.

Response

{
  "id": "9f1c…",
  "status": "committing",
  "counts": { "contacts": 40, "leadsCreated": 39, "leadsSkipped": 1, "notes": 180, "tasks": 12, "errors": 0 },
  "committedAt": null,
  "rolledBackAt": null,
  "error": null
}

Rollback (undo)

POST /inmobalia/import/batches/:id/rollback

Undoes a batch in one transaction, and writes assignment-audit reversals. Generic over both passes: a contacts batch hard-deletes the leads, notes, and tasks it created; a sales batch hard-deletes only the deals it created (which cascades their participants and stage history) plus any folded notes, and never touches contacts-batch leads. Refused with 400 if the batch is already rolled back or still running. The deletion is exact (only what the batch created) but permanent.

Response

{ "status": "rolled_back", "deleted": { "leads": 118, "notes": 540, "tasks": 33, "deals": 0, "participants": 0 } }

A sales-batch undo zero-fills leads/tasks and reports deals and participants instead.

Fondaro Help

Docs & support

Hi there, how can we help?

Browse popular articles or ask a question below.

Popular articles

Or ask a question