Ta strona nie została jeszcze przetłumaczona na Twój język. Wyświetlamy wersję angielski (Wielka Brytania).

Lead routing

Read and publish your routes, switch Smart routing, try a lead, route the waiting leads, mark people away, and read why a lead was assigned.

The lead routing API decides who owns a new lead when it arrives. Your organization has an ordered list of routes. A route has conditions (which leads), a pool of people or live teams, and options (office hours, a daily cap, a reassign timer). For each lead Fondaro walks the routes from the top and the first route that takes the lead and has someone who can get it wins. A route that takes the lead but ends with nobody (an empty pool, everyone away or at their daily cap, or the lead arriving outside office hours) falls through to the next route. When no route works, Smart routing hands the lead to the active people on your team, those who list the lead's language on their profile first, otherwise everyone in turn. With Smart routing off, the lead waits in Unassigned.

The session routes on this page take a signed-in member's session token (Authorization: Bearer <session-token>). The same operations are open to API keys under /v1/lead-routing, with the crm:read and crm:write scopes. See Authentication.

Reading Smart routing, and marking yourself away, are open to every member. Everything else under /lead-routing is for organization admins; a member gets 403.

Read the whole picture

GET /lead-routing

Admins only. Returns the routes in order, Smart routing, the problems found, who is away, and a revision you send back when you publish.

bash
curl https://api.fondaro.com/lead-routing \  -H "Authorization: Bearer $SESSION_TOKEN"
json
{  "routes": [    {      "id": "7f3c2a10-...",      "name": "Idealista sellers",      "conditions": {        "type": "group",        "combinator": "and",        "children": [          { "type": "condition", "field": "origin", "operator": "has_any_of",            "value": { "kind": "strings", "values": ["portal:idealista"] } },          { "type": "condition", "field": "leadType", "operator": "has_any_of",            "value": { "kind": "strings", "values": ["seller"] } }        ]      },      "strategy": "round_robin",      "priority": 0,      "isActive": true,      "schedule": null,      "dailyCap": 8,      "reassignAfterMinutes": 30,      "members": [        { "userId": "user_2abc...", "teamId": null, "weight": 0, "sortOrder": 0 },        { "userId": null, "teamId": "b21d94c0-...", "weight": 0, "sortOrder": 1 }      ],      "createdAt": "2026-10-08T09:00:00.000Z",      "updatedAt": "2026-10-08T09:00:00.000Z"    }  ],  "smart": { "enabled": true, "teamUserIds": ["user_2abc...", "user_2def..."] },  "problems": [],  "revision": "c4f1...",  "away": { "user_2def...": "2026-10-20T00:00:00.000Z" }}

priority is the route's place in the order, 0 first. Smart routing is not in routes.

Publish the whole set

PUT /lead-routing

Admins only. Replaces the ordered set of routes in one atomic write: routes you leave out are deleted, routes you list with their id keep it, routes without an id are created. The order of the array is the order of the routes.

ParameterTypeRequiredDescription
revisionBody, stringYesThe revision from your last read
routesBody, arrayYesUp to 200 routes, in order (see A route)
bash
curl -X PUT https://api.fondaro.com/lead-routing \  -H "Authorization: Bearer $SESSION_TOKEN" \  -H "Content-Type: application/json" \  -d '{    "revision": "c4f1...",    "routes": [      {        "id": "7f3c2a10-...",        "name": "Idealista sellers",        "strategy": "round_robin",        "members": [{ "userId": "user_2abc...", "weight": 0, "sortOrder": 0 }]      }    ]  }'

The response is the new state, in the shape of GET /lead-routing. If someone published since your read, the call answers 409 with code: "LEAD_ROUTING_REVISION_CONFLICT" and the current revision; read again and merge before you retry.

A route

Create, change and publish all use these fields.

FieldTypeDescription
namestring or nullUp to 80 characters, e.g. "Idealista sellers"
conditionsgroup or nullWhich leads. Null or an empty group takes every lead (see Conditions)
strategyround_robin, weighted or smartTake turns, split by share, or Smart routing limited to this route's people. A route of one person is "always this person"
isActivebooleanfalse pauses the route; it is skipped
scheduleobject or nullOffice hours (see below). Null means any time
dailyCapinteger or null1 to 1000. The most leads one person gets from this route in a day
reassignAfterMinutesinteger or null5 to 10080. Give the lead to the next person when nobody touched it in this long
membersarray{ userId, teamId, weight, sortOrder }. Set userId for a person or teamId for a team, not both
  • A team is read live when a lead arrives: someone joining the team joins the route. On a weighted route, members must be people (no teams) and weight is a percentage; the weights must add up to 100. On other strategies weight is 0.
  • Everyone in a pool who left the agency is skipped. Users, teams, tags and Growth areas must belong to your organization, or the write answers 400.

Office hours are { "zone": "Europe/Madrid", "days": [{ "day": 1, "from": "09:00", "to": "17:30" }] }. day is 1 (Monday) to 7 (Sunday), times are 24-hour HH:MM, from is included and to is not. A lead that arrives outside them falls through. zone is the IANA zone the hours are read in.

Conditions

conditions is an AND/OR tree of conditions, nested up to four levels deep and holding up to 50 conditions. Each condition is { "type": "condition", "field", "operator", "value" }; a group is { "type": "group", "combinator": "and" | "or", "children": [...] }.

fieldoperatorvalue
sourcehas_any_of, has_none_of{ "kind": "strings", "values": ["zapier"] }
originhas_any_of, has_none_ofWhere the lead came from, e.g. portal:idealista, meta_lead_form, meta_ads, google_ads, organic, message:whatsapp
leadTypehas_any_of, has_none_ofbuyer, seller, tenant, collaborator
preferredLanguagehas_any_of, has_none_ofBCP 47 tags. A region (nl-BE) also matches its base language (nl)
countryhas_any_of, has_none_ofTwo-letter country of the lead's phone number
taghas_any_of, has_all_of, has_none_ofTag ids, read when the lead arrives
growthAreahas_any_of, has_none_ofGrowth area (subscription) ids
phone, emailis_present, is_missing{ "kind": "empty" }

Add, change, delete and reorder one route

These are the single-route writes. PUT /lead-routing is the better fit when you edit the whole canvas at once. All are admin-only and return the route.

Create a route

POST /lead-routing/rules

Takes a route's fields (strategy and members are required) and an optional position, the 0-based place in the order (default last, just above Smart routing).

bash
curl -X POST https://api.fondaro.com/lead-routing/rules \  -H "Authorization: Bearer $SESSION_TOKEN" \  -H "Content-Type: application/json" \  -d '{    "name": "Swedish buyers",    "strategy": "weighted",    "position": 0,    "conditions": {      "type": "group", "combinator": "and",      "children": [{ "type": "condition", "field": "preferredLanguage",        "operator": "has_any_of", "value": { "kind": "strings", "values": ["sv"] } }]    },    "members": [      { "userId": "user_2abc...", "weight": 60, "sortOrder": 0 },      { "userId": "user_2def...", "weight": 40, "sortOrder": 1 }    ]  }'

Change a route

PATCH /lead-routing/rules/:id

Takes any subset of the route's fields, plus position to move it. Sending members replaces the whole pool.

bash
curl -X PATCH https://api.fondaro.com/lead-routing/rules/7f3c2a10-... \  -H "Authorization: Bearer $SESSION_TOKEN" \  -H "Content-Type: application/json" \  -d '{ "isActive": false }'

Delete a route

DELETE /lead-routing/rules/:id

bash
curl -X DELETE https://api.fondaro.com/lead-routing/rules/7f3c2a10-... \  -H "Authorization: Bearer $SESSION_TOKEN"
json
{ "deleted": true }

Reorder the routes

PUT /lead-routing/rules/order

Send every route id in the new order. First is checked first.

bash
curl -X PUT https://api.fondaro.com/lead-routing/rules/order \  -H "Authorization: Bearer $SESSION_TOKEN" \  -H "Content-Type: application/json" \  -d '{ "ids": ["9a1c...", "7f3c2a10-..."] }'

Try a lead

POST /lead-routing/preview

Admins only. Shows which route would take a lead and who would get it, without assigning anything. Give an existing leadId, or describe a lead in facts; with both, facts override the lead's own. Send routes (and smartEnabled) to try an unpublished draft; leave them out to try what is published.

ParameterTypeRequiredDescription
leadIdBody, integerNoAn existing lead
factsBody, objectNosource, origin, leadType, language, country, tagIds, growthAreaId, hasPhone, hasEmail, arrivedAt (ISO time; office hours are read against it)
routesBody, arrayNoA draft set of routes, in the shape of a publish
smartEnabledBody, booleanNoTry with Smart routing on or off
bash
curl -X POST https://api.fondaro.com/lead-routing/preview \  -H "Authorization: Bearer $SESSION_TOKEN" \  -H "Content-Type: application/json" \  -d '{ "facts": { "origin": "portal:idealista", "leadType": "seller", "language": "es-ES" } }'
json
{  "ruleId": "7f3c2a10-...",  "smart": false,  "userId": "user_2abc...",  "reason": "next_in_turn",  "steps": [    { "ruleId": "7f3c2a10-...", "smart": false, "outcome": "assigned",      "skipped": [{ "userId": "user_2def...", "reason": "away" }],      "userId": "user_2abc...", "reason": "next_in_turn" }  ],  "facts": { "origin": "portal:idealista", "leadType": "seller", "language": "es-ES",    "source": null, "country": null, "tagIds": [], "growthAreaId": null,    "hasPhone": true, "hasEmail": true, "arrivedAt": "2026-10-08T10:00:00.000Z" }}

steps lists every route checked, in order. A step's outcome is assigned, no_match, paused, outside_hours or empty_pool. skipped[].reason is departed, away or capped. reason is why the person was picked: next_in_turn, share, speaks_language, least_recent or only_person. With no person, userId is null and the lead would wait in Unassigned.

Last 30 days

GET /lead-routing/stats?days=30

Admins only. days is 1 to 90 (default 30). Counts the leads each route and Smart routing assigned, and each person's share.

json
{  "days": 30,  "byRoute": [{ "ruleId": "7f3c2a10-...", "count": 41, "lastAt": "2026-10-08T08:12:00.000Z", "lastUserId": "user_2abc..." }],  "byUser": [{ "userId": "user_2abc...", "count": 24 }]}

Route the waiting leads

POST /lead-routing/route-unassigned

Admins only. Sends the leads waiting in Unassigned through your routes now: up to 500, oldest first, within a 25 second limit. A lead someone assigns meanwhile is left alone. Takes no body.

bash
curl -X POST https://api.fondaro.com/lead-routing/route-unassigned \  -H "Authorization: Bearer $SESSION_TOKEN"
json
{ "considered": 37, "assigned": 31, "leftWaiting": 6 }

Mark someone away

PUT /lead-routing/away

Every route, and Smart routing, skip a person until the date. A member may set their own; setting someone else's is for admins.

ParameterTypeRequiredDescription
userIdBody, stringNoWhose away date. Default: the caller
untilBody, ISO date or nullYesWhen they are back. null means back now
bash
curl -X PUT https://api.fondaro.com/lead-routing/away \  -H "Authorization: Bearer $SESSION_TOKEN" \  -H "Content-Type: application/json" \  -d '{ "userId": "user_2def...", "until": "2026-10-20" }'

Smart routing

Read Smart routing

GET /lead-routing/smart

Open to every member. Returns whether Smart routing is on and who it hands leads to, in turn order.

bash
curl https://api.fondaro.com/lead-routing/smart \  -H "Authorization: Bearer $SESSION_TOKEN"
json
{ "enabled": true, "teamUserIds": ["user_2abc...", "user_2def..."] }

Switch Smart routing on or off

PUT /lead-routing/smart

Admins only. Idempotent. Fondaro never switches it back on after you switch it off.

ParameterTypeRequiredDescription
enabledBody, booleanYestrue to switch on, false to switch off
bash
curl -X PUT https://api.fondaro.com/lead-routing/smart \  -H "Authorization: Bearer $SESSION_TOKEN" \  -H "Content-Type: application/json" \  -d '{ "enabled": false }'
json
{ "enabled": false }

Smart routing always sits after your own routes. It is changed only through this switch: it is not in routes, and PATCH or DELETE on its id returns 404.

Problems

problems in GET /lead-routing lists what is wrong with a route. Each has a code and the ruleId it concerns.

codeMeaning
unreachableAn earlier route takes every lead this one would (byRuleId names it)
empty_poolNobody is left in the route
departed_memberSomeone in the route left the agency (userId); they are skipped
everyone_awayEveryone in the route is away
missing_tagThe conditions name a deleted tag (tagId); the route is paused
ended_growth_areaThe conditions name a Growth area that ended (growthAreaId)
weights_not_100A split by share whose shares do not add up to 100
schedule_no_daysOffice hours with no day in them, so the route never runs
archived_teamA team in the route was archived (teamId)

Read why a lead was assigned

GET /crm/leads/:id returns lead.assignmentReason to every member who can see the lead.

bash
curl https://api.fondaro.com/crm/leads/12345 \  -H "Authorization: Bearer $SESSION_TOKEN"
json
{  "lead": {    "id": 12345,    "assignmentReason": {      "assigneeIds": ["user_2abc..."],      "at": "2026-10-08T10:14:03.000Z",      "route": { "id": "7f3c2a10-...", "name": "Idealista sellers" },      "smart": false    }  },  "origin": {}}

It is set when the newest change to the lead's owners was Fondaro routing it, and null once a person has changed the owners since, or when nothing routed it. assigneeIds are the user ids routing added. route names the route that assigned the lead, or is null for an older assignment or a route since deleted. smart is true when Smart routing assigned it.

Errors

StatusWhen
400Validation failed: bad conditions, a person, team, tag or Growth area outside your organization, shares that do not add up to 100, or a cap or timer out of range
401No valid session token
403A member called an admin-only endpoint
404The route does not exist in your organization, or it is the Smart routing rule
409LEAD_ROUTING_REVISION_CONFLICT: someone published since your read. Read again and retry