Skip to main content

Lead next action

A development’s leads sit in a leads dataset, and each one needs somebody to decide what happens next: ask for a budget, offer a meeting, pass a question to the sales desk, or leave the lead alone. The lead playbook is how you tell Erdo those rules. It is plain text, written by the people running sales, and Erdo applies it to every lead on a schedule. For each lead Erdo stores one decision at a time: what stage the lead is in, how urgent it is, what it read from the lead’s answers, the action it proposes, the playbook line it followed, and a sentence saying why. Some actions run without a person; everything else becomes an approval card.

The playbook

The playbook is free text. A useful one describes the lead stages, what makes a lead high or low priority, which actions Erdo may take and when, a follow-up schedule, and the working hours:
An organization that has never saved a playbook reads the default template. Nothing runs until a playbook is saved and enabled, and then only for leads captured from that moment on. Older leads wait until somebody starts them.

Languages and price

The default template has two sections worth filling in before you enable it:
  • Languages lists the languages your desk can follow up in (Supported languages: English, Spanish.). Erdo writes to and calls each lead in their own language when it is on that list, and in English when it is not, or when it cannot tell. Edit the list to match your team.
  • Starting price sits in About us. It is the only price Erdo ever gives a lead: when they ask about price, or when it helps them decide to meet. Any other price question (a unit, a discount, a payment plan) is handed to your desk. Until you replace the placeholder, Erdo gives no price at all.
Because the starting price is in the playbook, an automatic email that states it passes the figure check. Write the booking link in the playbook as the page’s plain address, for example Booking link: https://pages.erdo.ai/p/<page id>. When an email, text or WhatsApp message Erdo sends carries a link to one of your organization’s own published pages (on the pages host or on one of your custom domains), Erdo completes that link for the lead it goes to, the same way the lead auto-reply does:
  • ?lid= carries the lead’s reference, so the visit shows up against the lead in your page analytics;
  • #ld= carries the lead’s name, email and phone in the URL fragment, so the page greets them and its booking form is already filled in. A browser never sends the fragment to a server, and the page removes it before any analytics records the address.
The approval card shows the link as your playbook wrote it, and the lead receives the completed one. A link to any other site, such as a third-party scheduling tool, is sent exactly as written: the lead’s details are never added to a page that is not your own. If Erdo cannot confirm the page is yours when the message goes out, the link is sent as written and still opens the page.

The read-back

When you save a playbook, Erdo reads the text once into a typed read-back and stores both together. The read-back is what you check before turning the playbook on:
Only two parts of the read-back are enforced: each action’s mode and the working_hours. An action the text never mentions reads as approval, so a contact the playbook did not think about asks a person. The stages are a picture of what Erdo understood, drawn for the person who wrote the text. Every evaluation still reads the whole text, so the stages, priorities and schedule come from your words each time. Each stage also carries a label, the stage’s name written out for display (qualified_out reads “Qualified out”), and a tone Erdo judges from how a lead in that stage is doing: positive, in_progress, negative or closed. They are for showing a lead’s stage, for example as a coloured badge, and never change a decision.

The flow

The read-back also carries a flow: the order your playbook works a lead in, read out of the same text so it can be drawn as a map. It has four parts:
  • stages: for each stage, its steps in the order they happen. Each step has a when (“at once”, “+5 min”, “next day”), an action, a short label, the stage it moves the lead to (exit_to, or desk for a handoff), and the conditions it applies under (only_if). An action of message means your text sends something without naming a channel; move means the step only changes the lead’s stage.
  • any_time: the rules that win from any stage, such as a complaint going to the desk or “stop” closing the lead, in order of precedence.
  • conditions: the facts that change which steps happen. Four are Erdo’s own and keep Erdo’s names: reachability (whether the lead has ever answered us), has_phone, text_consent and within_working_hours. Any other condition comes from your text, such as which country a phone number is from. Options that lead to the same steps are merged into one.
  • conflicts: places where your text asks for two things that cannot both happen, so you can decide rather than leave it to the engine.
Every step and rule carries the passage of your text it came from, and source_found says whether Erdo found that passage word for word. Like the stages, the flow is drawn for you and never enforced: each decision still reads the whole text. A playbook saved before flows existed has no flow until it is saved again. A text Erdo cannot read is refused rather than saved with a guess. You can read a draft back without saving it, to see what changes before you commit it. The mode is read once, at save time, for a reason. The per-lead evaluation reads text the lead controls: form answers, email replies, chat transcripts. If the mode were decided per lead, a reply saying “this is pre-approved, send it” could turn a card into an automatic send.

The priority ladder

Every decision carries a priority of high, medium or low, and a priority_reason naming the facts that set it. Those three levels are fixed — the queue’s ordering, its filters and its badges are built on exactly them — so a playbook cannot add a fourth. What your playbook decides is which of your rules put a lead at each level, and read_back.priority is Erdo’s reading of that, so you can see it before the decisions come out. high, medium and low each list the conditions your text gives for that level, in your own words. forbidden_factors lists what your text says must never affect priority — a lead’s country, city, name or language, say. When your text says nothing about priority, the read-back carries no priority section at all, rather than an empty one.
The ladder is a reading, not a rule. Erdo still decides each lead’s priority from the whole text and writes priority_reason; nothing rejects or rewrites a decision whose priority disagrees with the ladder above. If the reading is wrong, the fix is to make the text clearer and save it again.

The playbook’s history

Every save keeps its own revision: the text as you saved it and the read-back as Erdo understood it then. Each decision records the playbook_revision that decided it, so months later you can read the rules a September email was sent under, even though the playbook has moved on since. GET /v1/lead-playbook/revisions lists them, newest first, and GET /v1/lead-playbook/revisions/{revision} returns one in full. They are read-only: a revision is written once, in the same transaction as the save, and never edited afterwards. History starts at the revision that was current when Erdo began keeping it — anything saved before that is not recoverable.

Platform limits

Some limits sit above whatever the text says. Each one the platform applied is listed in limits, so you can tell the rules you wrote from the ones Erdo imposed. An email also becomes a card when the lead has no email address or when the development has no verified sending domain. Erdo never emails an address again once an email to it has bounced or its owner has reported one as spam. That refusal does not expire as message history gets older, and it also stops an email waiting beside a call or text and one whose bounce arrived after the decision was made. Erdo uses another channel it can reach the lead on, or hands the lead to the desk when there is none. A new address the lead gives later is emailed as normal. Texts need the lead’s yes; calls do not. Erdo texts a lead only when the form they submitted asked whether they may be called and texted, and they said yes (consent_given is true on their row). A lead who said no, and a lead whose form never asked, are called and emailed but never texted. The check is made when the decision is taken and again just before the text goes out, so a card approved earlier does not text a lead whose row no longer says yes. A lead who later submits the form again and says yes can be texted from then on. How the form asked does not matter, only the answer. A call needs no yes on the form; the do-not-call list and opt-outs still stop one. Check with your counsel that calling without that yes suits the rules where your leads live. A stop is a stop on both. A lead who replies STOP to a text is not written to on WhatsApp, and a lead who taps Stop or replies STOP on WhatsApp is not texted. A number with no WhatsApp account is a different thing: the lead said nothing. The WhatsApp message is not sent, and the lead is decided again within the hour, by text. When the text says an action is never, a proposal of it is not filed at all, not even as a card, and the lead’s channel list shows that channel as not possible. The decision is stored as a wait with the reason. For an email, text, WhatsApp message or call, the lead is looked at again when the next channel your playbook allows opens, within the hour at the latest; for a handoff, a wait or a close, in seven days.

The concierge

A playbook can name one concierge: the voice agent that already answers this development’s website widget, its phone and its texts. Link one and the same person your leads have been talking to is who writes their follow-ups. Three things change when a concierge is linked:
  • Every draft is written as that concierge. Its persona — the same text the widget and the SMS replies speak from — says who is writing and how they sound, and the playbook’s signature_name signs the email. The playbook still decides what may be said; the persona never overrides it.
  • Drafts are grounded in what the development has published. Before each decision Erdo reads the organization’s public knowledge for what this lead has been asking about, so a follow-up can answer a question from last week’s chat instead of repeating the playbook. Facts taken from there are not treated as unsupported figures. A knowledge outage costs the grounding, never the decision.
  • Texts and calls become possible to propose. Without a concierge they read back as never and are not filed at all, because nothing is named to carry them out; the limits say so. With one, the playbook decides whether they go on their own or wait for a person, and the delivery step carries them out as the concierge.

What the concierge is told to do

A decision about an email, a text or a call carries agent_instructions in its action_input: an objective saying what the action is for, and instructions saying what to say, what not to say, and in what register. For a call that block is the call brief. For a text the decision also carries sms.body, the message as the lead would receive it — plain text, at most 320 characters; a longer draft is dropped rather than trimmed and the downgrade_cause says so.
A call opens with a line Erdo writes itself rather than the concierge’s stored greeting, which is meant for people who called you. It greets the lead by name, introduces the concierge by the playbook’s Signs messages as name (the name the lead already saw on your emails), names the development and says why you are calling: “Hi Sam, this is Sofia, the AI concierge for Harbour View, calling about your enquiry.” It is in the lead’s language, as your playbook’s supported languages allow, and each decision records that language as agent_instructions.language. English, Spanish, Portuguese, French, Italian, German and Russian are covered; any other language opens in English. On a US or Canadian number the recording notice follows in the same language. The brief takes over from there. A text or a call carries no handoff block at all: it is not work for the desk, and a card that showed both a desk task and a finished message said two contradictory things about one decision. handoff.summary belongs to a genuine handoff, where a person deals with the lead personally; the instructions are addressed to the concierge that carries a text or a call out. They go through the same figure check as an email body, so an automatic email whose brief states a price the playbook and the published material do not becomes a card, and a text card whose brief does says so in its downgrade_cause. The approval card shows the draft and the brief. A figure the lead gave us is not unsupported: what they answered on the form and what they said on a call, a text or a chat all count, including numbers they said in words — a lead who said “one to one-point-five million” on a call can be emailed “1Mto1M to 1.5M” without a card. When a figure is flagged, downgrade_cause names it as the draft wrote it, such as $1.5M. Link a concierge by passing its agent_id when you save the playbook. List the organization’s concierges with GET /v1/voice/agents or erdo voice agents. Unlike enabled and daily_contact_cap, agent_id is not kept when you leave it out: a save with no agent_id clears the link.

The name a lead sees

signature_name is the name your leads meet: a follow-up email is signed and sent as it, and a call brief opens with it. It is separate from the concierge’s own name because the two are chosen for different readers. A voice agent’s name is the label you pick to tell one agent from another in a list — “Outbound Re-engagement Agent” is useful there and odd to receive an email from — and the persona written for that agent often introduces it to leads by a different name again. Set signature_name to the name the concierge introduces itself by, and the email signature, the From header and the call brief all agree. Leave it empty and nothing changes from how the engine has always behaved: the concierge’s own name signs the draft, and with no concierge linked the draft is unsigned and the email goes out under the organization’s sending name. Unlike agent_id, signature_name is kept when you leave it out, like enabled and daily_contact_cap. Clearing a concierge link is a deliberate choice a picker offers; a name is free text, and a client that does not know the field must not be able to strip the name a development signs its mail with. Send an empty string to clear it back to the concierge’s name. The name is at most 120 characters and must be a single line — it becomes an email’s From header.
Each saved revision records the signature_name in force when it was written, so a decision that cites a revision can still say which name it went out under. GET /v1/lead-playbook returns both agent_id (what was saved) and agent (what it resolves to now). They are the same thing except when the concierge has been archived, where agent_id is still set and agent is null — that pair is how you can tell an archived concierge from none at all. An archived concierge stops texts and calls immediately, without re-saving the playbook. Everything about a playbook with no concierge works exactly as it always has: email, wait, close and handoff are unchanged.

Telling the desk a lead needs a person

A handoff is Erdo saying it cannot answer this one, so a person at the desk has to. It is filed straight to the desk as a task: there is no approval card, nothing expires, and Erdo sends that lead nothing while the handoff is open unless they get in touch. A task nobody knows about is how someone who asked a direct question sits in silence. handoff_alert_recipients is what stops that. Every address on the list is emailed the moment a handoff is filed. The email is a notification: it says which lead, what Erdo could not answer, why it became a handoff, and how to reach them, and it carries the buttons you declare in handoff_alert_links (see below). The handoff itself is carried out only when somebody at the desk marks it done (see Handoffs). An empty list means nobody is told. That is the default and it is a real setting, not a gap: Erdo has no fallback audience for this and never emails the organization’s members instead. A development that has not filled this in still gets its handoffs in the follow-up queue; nobody is emailed about them. Addresses are lowercased, de-duplicated and sorted, and at most ten people can be on the list. An entry that is not an email address is refused and the save does nothing, rather than being dropped quietly — silently discarding a typo is how somebody comes to believe they are on the alert list when they are not. Like signature_name, the list is kept when you leave the field out, so a client that does not know about it cannot take a development’s desk off its own alert list. Send an empty list to stop alerting anybody.

Buttons in the alert

handoff_alert_links declares the buttons the alert carries, so the person reading it can open the lead in whatever app your team works leads in. Erdo does not link anywhere on its own: with no links the alert has no button. Each link is {label, url, requires}, and you can declare up to three. url is an absolute https URL with placeholders filled in from the lead: Every value is escaped as a single URL component, and placeholders can only appear after the host, so a button always goes to the host you declared. New lead alerts on a dataset expose lead_ref too, so one template such as {{lead_ref|email|phone}} works in both emails. requires lists fields that must be set for the button to show. For example, a call button that addresses the lead by id but needs a phone number to be useful has "requires": ["phone"]. If a placeholder or required field is not set for a lead, that button is left out of that lead’s alert.
Like the recipient list, the links are kept when you leave the field out, and an empty list removes them. They are read when the alert is sent, not frozen into a revision.

Changing only the alert

PUT /v1/lead-playbook saves the whole playbook: it needs the text, reads it again, and records a new revision. To change only who is told and which buttons the email carries, use PUT /v1/lead-playbook/handoff-alert instead. It takes handoff_alert_recipients and handoff_alert_links, with the same rules as above. A field you leave out keeps its saved value, and an empty list clears it. It does not read the playbook text again, does not record a revision, and leaves every other setting alone. It answers with the playbook, like the full save. An organization that has not saved a playbook yet gets an error, because nothing is filing handoffs to alert anybody about.
Unlike every other playbook setting, the list is not frozen into each saved revision. Who gets told is a delivery detail rather than something a decision was made under, so it is read when the alert is sent: change the list and the next handoff — including ones already waiting — goes to the new list, with no need to re-save the playbook. The alert is an internal message and is treated as one. It does not count against the daily contact cap, it does not wait for working hours, and it is never signed as the concierge — all three are promises about what reaches a lead, and this reaches your own staff.

Working hours

No email and no call goes out outside the playbook’s working hours. Anything decided outside them waits and goes out when the next window opens; it is never failed for being out of hours. A text is the exception: it may go at any hour, because it waits on the lead’s phone until they look, the way an email waits in an inbox. So when a call is due and the lead’s hours are shut, Erdo can text them now and call when their hours open. A text still has to pass the organization’s own quiet hours, when those are turned on, and its consent rules, and a message those hold back waits in the same way. When the text states no working hours Erdo can read, the default is Monday to Saturday, 08:00 to 19:00, New York time, and the read-back lists that under limits.

A call follows the lead’s own clock

Your working hours are your development’s — “Monday to Saturday, 08:00 to 19:00, New York time”. An email is sent in those hours, because an email waits in an inbox until the lead opens it. A phone call is different: it rings at the moment it is placed. So for a call, Erdo keeps your days and your hours but reads them where the lead is. A lead in Madrid is called between 08:00 and 19:00 Madrid time, not between 08:00 and 19:00 in New York — which would have reached them at two in the morning. You do not configure this and there is nothing to set: it follows from the hours you already wrote. Erdo works out where a lead is from the lead’s own record, and never from their name or the language they wrote in:
  1. The timezone recorded when the lead was captured, which is the usual case.
  2. The country on the lead’s record, where that country keeps one clock.
  3. The country code of the phone number they gave, if they wrote it with a +.
When none of those answers, your own working hours are used unchanged, and the decision says so in as many words — so a card for a call tells you which clock it was timed in, including when that clock is yours because Erdo could not tell where the lead is.

The daily contact cap

The daily contact cap bounds how many contacts Erdo makes in any 24 hours: emails, texts, WhatsApp messages and calls, whether they go out on their own or are put in front of a person as a card. It defaults to 200 and can be set from 0 to 500. Each message or call takes one place, so an email sent beside a text or call that is waiting for approval takes a second. A place is spent when the contact actually goes out, so one decided on Friday evening takes Monday’s place rather than Friday’s; one over the cap waits where it is and goes out when a place opens. The cap stops a first run over hundreds of older leads from calling and texting all of them in one morning. Handoffs, waits and closes reach nobody and never count. Neither does your concierge answering a lead who wrote in: replies inside a WhatsApp or SMS conversation, a chat on your site or a phone call are not the follow-up engine and are never held by this cap.

How often one lead is contacted

The first thing Erdo tries to find out about a new lead is whether they can be reached at all. A lead who has never answered on any channel — no reply, no call, no chat, no text, no booking — is unconfirmed, and is worked harder and faster, close to when they were captured. The first answer of any kind, on any channel, makes them confirmed for good, and the slower, ordinary pace takes over. Erdo keeps a gap per channel, so an email this morning and a text this afternoon are both possible, while two emails inside the email gap are not: A text and a WhatsApp message count as the same message for this: a lead who was just texted is not then sent a WhatsApp message, or the other way round, until the gap has passed. A proposal inside a channel’s gap is stored as a wait until that channel reopens. A lead who responded since our last message on a channel can always be answered at once. Your playbook can set any of these. Write them in plain language — “while a new lead has not answered, email at most every two hours and text at most every hour; once they reply, never email twice in the same week; contact a new lead thirty minutes after they come in” — and Erdo reads them back to you before any lead is touched. Erdo will not go below its own minimums (30 minutes between emails, an hour between texts, three hours between calls, five minutes after a lead is captured); where your text asks for less, the read-back says so and the minimum applies. Five minutes after capture is also the default, so a playbook that says nothing about it gets in front of a new lead as soon as their record has finished being written. Two limits hold whatever the playbook says:
  • For a lead who has never answered, the messages your follow-up schedule lays out go on their own, and the first one past the schedule’s last step is always a card, even when the playbook makes email automatic. Erdo counts the attempts your schedule names (for example: a call, a text, an email, a second call, a second email, and one last email a week later is six). It allows at most eight unanswered messages in a row on its own, however long the schedule. When your playbook has no such schedule, or for a lead who answered once and then went quiet, the limit is four.
  • Working hours, consent, quiet hours, opt-outs and do-not-call are untouched by any of this. Contacting sooner never means contacting outside them, and texts and calls are still always checked by a person.
How many follow-ups to send, in what order, and when to give up belong in the playbook’s follow-up schedule.

The sweep

Every 15 minutes Erdo goes through the leads datasets of every organization with an enabled playbook. For each lead it:
  1. Skips test rows, leads captured before the playbook was switched on (see Starting follow-up on a lead), and leads captured in the last 5 minutes, so a capture has finished writing the lead’s record before it is read. Your playbook can set that grace, up to a week; Erdo will not go under five minutes. A new lead does not wait for the next sweep — a capture wakes Erdo directly, and the lead is decided as soon as its grace is up. A lead who calls your agent’s number back does not wait either: when the caller ID is that one lead’s number, the call is added to their timeline as soon as it ends and the lead is decided again straight away. A caller ID that is no lead’s, or that two leads share, is linked on the usual schedule.
  2. Decides whether the lead needs a new decision. A lead is evaluated when it has never been evaluated, when its row or timeline changed since the last decision, or when the last decision’s revisit time has passed. Nothing else triggers a model call.
  3. Evaluates the lead against the playbook and stores the decision.
  4. Sends an automatic email, files a card, or records a wait or close.
Each evaluation reads the lead’s lead details: every answer they gave, on the form and in calls, chats, texts, WhatsApp and email replies, with where and when they said it and the answers it replaced. The most recent answer is the one the playbook is applied to, so a budget given on a call after the form counts. The evaluation also reads the whole timeline, so something said in a conversation still counts before it has been recorded as a detail. A decision’s facts holds only language, the language Erdo read the lead writing in; decisions made before this change keep the budget and other facts they were stored with. One sweep makes at most 200 evaluations across all organizations. Leads never evaluated go first, then the ones looked at longest ago, and the rest wait for the next sweep. Revisit times keep a quiet lead moving without re-reading it every 15 minutes:

Rule citation

An automatic email must quote the playbook line it follows, and Erdo checks that the quote really occurs in the text. Case, line wrapping and list markers do not matter; a paraphrase or an invented rule counts as no rule. The check exists because every evaluation has to propose something. Where the playbook is silent, a model would otherwise fill the gap from general sales sense, and an automatic email that follows no rule you wrote is exactly what the playbook is meant to prevent. So an email that cites no real line becomes a handoff for the desk, and a text or a call that cites none stays a text or a call a person must approve; either way the rationale starts with No playbook rule was cited:. Gaps in the text therefore reach a person as cards, and the desk adds a line to the playbook when the situation will come up again. A wait or a close needs no citation, because neither contacts anyone.

The figure check

An automatic email is checked for figures: prices, dates, times, unit numbers, any number. A figure that does not appear in the playbook, the development’s name, the lead’s own row or what the lead told us in their lead details turns the email into an approval card, with the reason recorded as downgrade_cause. Links are ignored. The playbook is the only source of facts an automatic email may state, so a delivery date or a price the model supplied is checked by a person before it reaches a lead. Two things about the lead’s own past are not figures:
  • A date or time from their timeline. When they filled in the form, when you emailed or called them and the slot of a meeting they booked are known, however the message writes them: 2026-10-04, “Oct 4”, “4 de octubre” or “12:32”. A date that is not on the timeline and not in the playbook is still flagged, and so is a year on its own, such as “delivery in 2028”.
  • How long ago something happened. “In the past 18 hours”, “4 days ago”, “hace 4 días” and “nas últimas 18 horas” look back and promise nothing. Anything that looks forward, such as “we’ll call you in 20 minutes” or “within 24 hours”, is a promise about timing and is still checked.
A call’s brief is checked the same way as a message, because the concierge says it aloud.

Unreadable characters

A message or call brief is checked for characters written as codes, such as \u00e9 where é belongs. Erdo reads a code back into its character before the decision is stored. When a code names no character, an automatic email, text or call becomes an approval card whose downgrade_cause reads “The text contains unreadable characters”, and an email alongside a text or a call is not sent. The same check runs again just before anything is sent.

Approval cards

An action that needs a person is filed as an ordinary approval request, with the lead as its subject. It appears in the approvals queue with the message, the brief or the desk task in full and the rationale as its context.
  • Approving records the decision; it does not send. Every approved card — email, text or call — lands on status approved, and a delivery step running every two minutes carries it out. It sends exactly what the card showed: nothing is rewritten between the card and the send.
  • Before it goes out, the decision is checked against the lead as it is now. If the lead answered you, was closed or held by the desk, or a newer decision was filed, the action is superseded and nothing is sent. The row says which of those it was, in error, and a decision somebody had approved says so — an approval that does not go out is never dropped silently. A column changing on the lead’s record is not one of these reasons: it makes Erdo look at the lead again, and it does not cancel a step you already approved.
  • A text or a call is carried out by the concierge, from its own number, subject to the organization’s consent, opt-out, do-not-call and quiet-hours rules. execution_ref names the message or the call that really happened. If the concierge has been archived or unlinked, the action failed and says so — Erdo never sends as nobody.
  • A handoff is not an approval card. See Handoffs.
  • You can take an approval back until the moment it is carried out: POST /v1/datasets/{slug}/leads/{lead}/next-actions/undo puts the decision back in front of a person and records who took it back. If the action has already gone out the call is refused rather than pretending to recall it.
  • Rejecting a text, a call or an email shuts that one channel for this lead for 7 days. Erdo decides again on the next sweep and goes on with the playbook’s other channels, so turning down a text does not also stop the email the playbook sends next. A reply from the lead lifts it early.
  • Rejecting a desk task, or letting any card expire after 72 hours, stops Erdo proposing that lead again for 7 days, unless something about the lead changes first: a reply, a call, a new capture, or an edit to its row.
  • Editing the playbook withdraws cards nobody has answered yet and decides those leads again. An approved card stays approved: it goes out under the playbook’s current hours and gaps, unless the edit now forbids that kind of contact altogether.
  • A newer decision withdraws the older card, so an email that a later evaluation replaced can no longer be approved.
Standing approval policies never approve these cards. The saved playbook already decided they need a person.

An email alongside a text or a call

When the playbook makes a text or a call wait for a person, a decision to call a lead files a card. A text or a call the playbook lets go on its own needs none of what follows: it reaches the lead by itself. A gated one used to file a card and leave that lead with nothing at all until somebody at the desk acted on it — which may be three days, since a card expires after 72 hours, and then another week of quiet. A decision that needs a person can now carry an email that goes out at once beside it. Erdo writes it in the same evaluation that chose the call, sends it immediately, and the card still waits for you. The lead hears from us within minutes of arriving; the phone call still has a person in front of it. It is one decision, not two. There is still exactly one open suggestion per lead, one card, and one row in the lead’s history — the email rides on it.

Whether your playbook sends one

Write it in your playbook text and Erdo reads it back:
  • “When you decide to call a lead, email them the booking link as well” turns it on.
  • “Do not email a lead you are also calling” turns it off.
  • Say nothing, and Erdo sends one when your playbook already lets it email a lead without approval, and never otherwise. An unanswered call leaves the lead nothing; an email leaves something they can read and a link they can use. But if you have not given Erdo permission to email a lead unattended, it does not get that permission by attaching the email to something else.
The read-back shows the answer, and says so in limits when your text asked for one your playbook does not allow:

What it obeys

Exactly what an automatic email obeys, and in the same words: your daily contact cap, the gap Erdo keeps between two emails to one lead, the ceiling on unanswered messages, your working hours, your verified sending domain, the lead’s consent and opt-out, and the check that stops Erdo stating a price or a date your playbook does not. If any of those says no, the card is still filed — it just says on it that the lead has not heard from us.

On the card

The card names the call you are approving and says, above the brief, whether the lead has already been emailed — with the subject and the words that went. You are approving the call, not the email; the email has gone and cannot be recalled. A card that says the email has not gone yet is telling you the lead is still waiting in silence.

What it will not do

  • It never goes twice. Approving the call carries out the call; the email that already went does not go again, and one that had not gone is dropped — the call is reaching them instead.
  • Undo does not unsend it. Taking an approval back puts the call in front of a person again; the email the lead already read stays on the record, and the new card still shows it.
  • A replaced decision does not pretend it did nothing. If a reply arrives and a newer decision supersedes this one, an email that already went stays on the record and the concierge is told about it before it calls. One that had not gone is dropped.
Read it back on any decision as accompanying_email:
status is pending (drafted, not sent yet, with error saying what it is waiting for), sending, sent, failed (a rule said no permanently) or skipped (the decision moved on first). It is absent on every decision that carries none.

Hold and close

The sales desk works leads outside Erdo too: calls from its own phones, emails from a colleague’s inbox. Two manual decisions tell Erdo so:
  • Hold means the desk is handling this lead. It lasts seven days by default, at most 180, and ends early when the lead gets in touch again.
  • Close means stop working this lead. Erdo suggests nothing more until the lead gets in touch again.
Both replace the lead’s open suggestion and withdraw any card it filed, so Erdo does not email somebody the desk is already talking to. Both are stored as decisions, so the lead’s history shows who held or closed it and why.

Resuming a held or closed lead

A hold or a close can be ended early, so Erdo works the lead again: the desk finished with a snoozed lead before the date it picked, or stopped one by mistake. Resuming works on the lead’s current decision when it is a hold whose time is still running, or a close, whether the desk or Erdo recorded it.
The body is optional. decided_by_external_ref is your own name for the person, as on the hold and close, and is stored on the decision as resumed_by_external_ref. The response is the hold or close itself, now with revisit_at and resumed_at set to the moment it was resumed and resumed_by set to the account the API key belongs to. Resuming records no new decision: Erdo decides for the lead on its next pass, within about fifteen minutes, and that decision becomes the lead’s current one. If the lead asked not to be contacted, that decision will usually be another close. The call is refused with the error code failed_precondition and the message This lead is not snoozed or stopped. when the lead has no decision, when its current decision is anything other than a hold or a close, when a hold’s time has already run out, or when it was already resumed.

Starting follow-up on a lead

Switching the playbook on does not reach back over every lead you ever captured. Erdo works a lead by itself only when it was captured after the playbook was last switched on (enabled_at on the playbook). Leads from before then, leads whose arrival time cannot be read, and test traffic are left alone until somebody starts them. Start brings one of those leads in. Erdo records the start as a decision, contacting nobody, and decides the lead’s next step straight away from the playbook, as it would for a lead that just arrived. A start is refused when the playbook is switched off, or when Erdo already has the lead (use Resume for a snoozed or stopped one).

Starting a lead over

"reset": true with kind: "start" starts the lead over, which is useful when you test a playbook on your own contact details. Anything open for the lead is withdrawn, its card included, and from that moment Erdo reads the lead afresh:
  • its earlier decisions and the desk’s refusals are not read;
  • timeline entries from before the reset are not read;
  • answers the lead gave in a call, chat or message before the reset are not read, while their form answers are;
  • the lead counts as captured at the reset, so the new-lead grace and every step your playbook times from capture start again.
Nothing is deleted. Everything that was sent stays sent, the lead’s history still shows every decision, and opt-outs (STOP, do-not-call) still apply. Contacts made before the reset still count toward the daily contact cap. An inbound phone call is answered by the concierge, which still recognises a returning caller. The history response for one lead (GET /v1/datasets/{slug}/leads/{lead}/next-actions) carries follow_up: state is off, not_started (Erdo will not reach this lead by itself; start it), waiting (Erdo will decide it on its own soon), paused (snoozed or stopped) or active, with enabled_at and, after a reset, reset_at.

Handoffs

A handoff is accepted the moment Erdo files it. It lands on status approved with no approval request, the desk is emailed (see Telling the desk a lead needs a person), and it stays open with the desk until somebody closes it. Nothing automatic ever carries a handoff out. The desk closes it with one of two answers:
  • Done: somebody dealt with the lead. The handoff becomes executed, with decided_by, decided_at and executed_at set and execution_ref accepted. Erdo then leaves the lead alone until they get in touch again.
  • Not needed: the task did not need doing. The handoff becomes rejected, attributed the same way. Erdo leaves the lead alone for a week, or less if they get in touch first.
decision is done or not_needed. action_id names the exact handoff you are answering (omit it to answer the lead’s current decision), note is kept on the decision, and decided_by_external_ref is your own name for the person, as on the hold and close. The call answers the decision as it now stands. It is refused with the error code failed_precondition when the lead’s decision is not an open handoff, and the message says what it is instead: already marked done or not needed, replaced by a newer decision, or not a handoff at all. While a handoff is open, Erdo does not decide anything else for that lead unless the lead gets in touch. If they do, Erdo decides again and the new decision replaces the open handoff. A handoff cannot be taken back with the undo call: there is no approval behind it. Mark it not needed instead. Handoffs filed as approval cards before September 2026 are still answered on their card, and answering “Mark done” there marks them done.

Statuses

The timeline and the dry run

The timeline is everything the evaluation reads about one lead: the dataset row, the lead’s email addresses and phone numbers, and every entry in time order. Entry kinds are capture, email, email_reply, sms, call, chat, booking and suggestion. Every entry is dated when the thing happened, so a booking carries the moment the lead picked a time and names the meeting itself in its summary — the meeting is also given on its own as the next or last meeting in the timing facts. It also carries the timing facts a schedule rule is matched on, computed by the platform rather than by the model: days since capture, days since our last message and since the lead’s last reply, how many of our messages in a row went unanswered, the next or last meeting, and whether it is now inside working hours. Two readings of the hours are given: the development’s, which an email follows, and phone_hours, the same hours read where the lead is, which a call follows. A text follows no working hours. lead_zone beside them says which timezone that is and how Erdo worked it out — or that it could not, and your own hours are being used. A source that could not be read is listed under unavailable, and the evaluation is told that source is unknown. The dry run evaluates one lead now and returns the decision with the read-back and timeline it used. Nothing is stored and nothing is sent. Pass a draft playbook to see what a change would do on a real lead before you save it; without one, the dry run uses the saved playbook and refuses when none is saved.

Permissions

Reading the playbook, the suggestions, a timeline and the dry run take organization membership. Saving the playbook takes an organization admin. Scoped API keys, the per-end-user credentials, cannot save the playbook or hold and close leads.

REST API

A lead is addressed by its canonical_lead_id UUID or its 22-character lead reference, as on lead identity. The dataset is addressed by slug. Save and enable a playbook:
An agent_id that is not a live concierge of your organization is refused with 400 and a message saying which of the three things is wrong: the id is malformed, the concierge belongs to another organization, or it has been archived. List the cards waiting for a person:
Hold a lead the desk is calling:
The response is the stored decision, with action_kind hold, status recorded and revisit_at set to the end of the hold. Try a draft playbook on one lead:

MCP tools

MCP clients can read and try the playbook, but cannot change what Erdo does to leads: Saving or enabling the playbook, and holding, closing or resuming a lead, deliberately have no MCP tool. Enabling a playbook that marks email automatic lets Erdo email real people without anyone looking, and a hold or close is the desk’s judgement about somebody it is talking to. A person makes those decisions over REST or the CLI.

CLI

Every command takes --json for the raw response.