Skip to content

Replies and routing: every reply to an owner

Every reply to every Play goes to one owner by title, with its next step and a deadline.

Replies and routing reads each reply, files it as one of seven kinds and hands it to one owner by title, with a deadline. It costs $0.01 a reply read and routed (sample).

Every reply to an ownerMode try
You, to your agent

Route every reply to this week’s cold emails to its owner, and answer the ones our SDR agent can. Do not send.

curl -X POST "https://api.sb/leaseline.app/conversations/conversation_31/assign?mode=try" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"worker":"worker_3"}'

curl -X POST "https://api.sb/leaseline.app/conversations/conversation_34/escalate?mode=try" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reason":"outOfScope"}'

curl -X POST "https://api.sb/leaseline.app/conversations/conversation_36/answer?mode=try" \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"body":"If it does not work in 30 days, we refund you."}'
import { $ } from 'startup-builder'

await $.Conversation.assign({ conversation: 'conversation_31', worker: 'worker_3' }, { mode: 'try' })   // Northgate Rentals: “Interested. Can you send times for Tuesday?” → the AE in 40 s
await $.Conversation.escalate({ conversation: 'conversation_34', reason: 'outOfScope' }, { mode: 'try' })   // “Do you sync with an accounting system?” → a person
return await $.Conversation.answer({ conversation: 'conversation_36', body: 'If it does not work in 30 days, we refund you.' }, { mode: 'try' })   // Lakeside Rentals: “Is there a guarantee?”
// 422 · The answer to Lakeside Rentals did not send: it promises money back that no Offer term grants.
// claim: Cut the line, or cite the Offer term that grants it. · then Conversation.answer
npx startup-builder do Conversation.assign --json '{"conversation":"conversation_31","worker":"worker_3"}' --try
npx startup-builder do Conversation.escalate --json '{"conversation":"conversation_34","reason":"outOfScope"}' --try
npx startup-builder do Conversation.answer --json '{"conversation":"conversation_36","body":"If it does not work in 30 days, we refund you."}' --try
{
  "name": "do",
  "arguments": {
    "code": "await $.Conversation.assign({ conversation: 'conversation_31', worker: 'worker_3' }, { mode: 'try' })   // Northgate Rentals: “Interested. Can you send times for Tuesday?” → the AE in 40 s\nawait $.Conversation.escalate({ conversation: 'conversation_34', reason: 'outOfScope' }, { mode: 'try' })   // “Do you sync with an accounting system?” → a person\nreturn await $.Conversation.answer({ conversation: 'conversation_36', body: 'If it does not work in 30 days, we refund you.' }, { mode: 'try' })   // Lakeside Rentals: “Is there a guarantee?”\n// 422 · The answer to Lakeside Rentals did not send: it promises money back that no Offer term grants.\n// claim: Cut the line, or cite the Offer term that grants it. · then Conversation.answer",
    "mode": "try"
  }
}
Response422application/json
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "The answer to Lakeside Rentals did not send: it promises money back that no Offer term grants.",
  "checks": [
    {
      "check": "claim",
      "status": "fail",
      "observed": "“If it does not work in 30 days, we refund you.”",
      "doc": "/code/refusals#check-claim",
      "fix": "Cut the line, or cite the Offer term that grants it.",
      "then": "Conversation.answer"
    }
  ]
}
sample

What it does

What you pay forPrice per unit (sample)The call
A reply read, filed and routed$0.01POST /{namespace}/conversations/{conversation}/assign
An answer drafted and sent$0.04POST /{namespace}/conversations/{conversation}/answer
A hand-off to a person$0POST /{namespace}/conversations/{conversation}/escalate
When they write backFixture replyWhat happensWho answersBy whenCall
Interested“Interested. Can you send times for Tuesday?”books the call; the Handoff Brief goes to the AE with what they said, what it chose and whyAE · Priya Shah (person)60 minPOST /{namespace}/meetings/book
Send me pricing“Send me pricing first.”answers with the list Price from the Pricing Page and one next stepSDR · your agent5 minPOST /{namespace}/conversations/{conversation}/answer
Not now“Try us again in January.”the follow-ups pause; a Trigger waits for the date they namedSDR · your agentat oncePOST /{namespace}/enrollments/{enrollment}/pause
Wrong person“Sam, who runs operations, handles this.”asks them to bring Sam in; it never writes to an address taken from their textSDR · your agent1 business dayPOST /{namespace}/conversations/{conversation}/answer
Out of officean auto-reply until Oct 28the next step waits for the return datenobodythe return datePOST /{namespace}/messages/{message}/schedule
Question it can’t answer“Do you sync with an accounting system?”goes to a person, with the question in the Handoff BriefAE · Priya Shah, or you60 minPOST /{namespace}/conversations/{conversation}/escalate
Stop“Please stop emailing me.”nothing else sends, from any Play, on any channelnobodyat oncePOST /{namespace}/contacts/{contact}/unsubscribe

Every reply is routed first with POST /{namespace}/conversations/{conversation}/assign, 40 s after it lands. The Handoff Brief rides on the AE’s Task.

Run it

StepCallWhat it does here
1POST /{namespace}/conversations/{conversation}/assignNorthgate Rentals: “Interested. Can you send times for Tuesday?” → the AE in 40 s
2POST /{namespace}/conversations/{conversation}/escalate“Do you sync with an accounting system?” → a person
3POST /{namespace}/conversations/{conversation}/answerLakeside Rentals: “Is there a guarantee?”
422RefusedThe answer to Lakeside Rentals did not send: it promises money back that no Offer term grants.
CheckFixThen
claim failCut the line, or cite the Offer term that grants it.POST /{namespace}/conversations/{conversation}/answer
JSON
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "The answer to Lakeside Rentals did not send: it promises money back that no Offer term grants.",
  "checks": [
    {
      "check": "claim",
      "status": "fail",
      "observed": "“If it does not work in 30 days, we refund you.”",
      "doc": "/code/refusals#check-claim",
      "fix": "Cut the line, or cite the Offer term that grants it.",
      "then": "Conversation.answer"
    }
  ]
}

It says no, says why, and names the fix.

Set it up

CheckOn the day-0 StartupFixYour timeWaitThen
inbound-sourcefailforward replies to your inbound address5 minnonePOST /{namespace}/integrations/connect
role-unstaffedwarnstaff the AE, or leave it: Interested replies come to you0 minnonePOST /{namespace}/roles/{role}/staff
approved-pagespassyour pricing Page is live, so Send me pricing answers from it0 minnonePOST /{namespace}/sites/{site}/publish

The records

The Conversation, routed · sample
{
  "conversation": {
    "$id": "https://api.sb/leaseline.app/conversations/conversation_31",
    "$type": "Conversation",
    "status": "open",
    "respondBy": "2026-10-19T16:41:00Z",
    "firstAnsweredAt": null
  }
}
The Task on the AE’s queue, with the Handoff Brief · sample
{
  "task": {
    "$id": "https://api.sb/leaseline.app/tasks/task_118",
    "$type": "Task",
    "assignee": "worker_3",
    "due": "2026-10-19T16:41:00Z",
    "on": "conversation_31",
    "brief": {
      "who": "Lee Park, Northgate Rentals",
      "said": "Interested. Can you send times for Tuesday?",
      "kind": "interested",
      "next": "book the call"
    }
  }
}

Calls

CallWhat it doesWhat else happensEvent
POST /{namespace}/conversations/{conversation}/assignAssign routes a Conversation to the Worker holding the right Role, by topic, Customer tier and language.—Conversation.assigned
POST /{namespace}/conversations/{conversation}/escalateEscalate hands a Conversation and its summary to the Worker in the Role above, a Human only where one holds it.A refund over a Limit is an Approval, not an escalation.Conversation.escalated
POST /{namespace}/conversations/{conversation}/answerAnswer replies in a Conversation through the Channel it arrived on and closes the reply Task it opened.Runs the reply through every Guard before it leaves.Conversation.answered
POST /{namespace}/meetings/bookBook schedules a Meeting with a Contact at a time both calendars hold free.—Meeting.booked
POST /{namespace}/enrollments/{enrollment}/pausePause stops one Contact’s run through a Sequence at its current step, without ending it.—Enrollment.paused
POST /{namespace}/contacts/{contact}/unsubscribeUnsubscribe stops commercial Messages to a Contact in one click, for one topic or all, honored at once.Writes a Suppression when no topic is named.Contact.unsubscribed

Events

Conversation.assigned · StartupBuilder-Signature
{
  "$id": "https://api.sb/leaseline.app/events/event_1",
  "$type": "Event",
  "name": "Conversation.assigned",
  "at": "2026-10-22T12:00:00Z",
  "seq": 1,
  "data": {
    "conversation": {
      "$id": "https://api.sb/leaseline.app/conversations/conversation_1",
      "$type": "Conversation",
      "subject": "Example subject",
      "answeredAt": "2026-10-22T12:00:00Z"
    }
  }
}
Conversation.escalated · StartupBuilder-Signature
{
  "$id": "https://api.sb/leaseline.app/events/event_1",
  "$type": "Event",
  "name": "Conversation.escalated",
  "at": "2026-10-22T12:00:00Z",
  "seq": 1,
  "data": {
    "conversation": {
      "$id": "https://api.sb/leaseline.app/conversations/conversation_1",
      "$type": "Conversation",
      "subject": "Example subject",
      "answeredAt": "2026-10-22T12:00:00Z"
    }
  }
}
Conversation.answered · StartupBuilder-Signature
{
  "$id": "https://api.sb/leaseline.app/events/event_1",
  "$type": "Event",
  "name": "Conversation.answered",
  "at": "2026-10-22T12:00:00Z",
  "seq": 1,
  "data": {
    "conversation": {
      "$id": "https://api.sb/leaseline.app/conversations/conversation_1",
      "$type": "Conversation",
      "subject": "Example subject",
      "answeredAt": "2026-10-22T12:00:00Z"
    }
  }
}
Meeting.booked · StartupBuilder-Signature
{
  "$id": "https://api.sb/leaseline.app/events/event_1",
  "$type": "Event",
  "name": "Meeting.booked",
  "at": "2026-10-22T12:00:00Z",
  "seq": 1,
  "data": {
    "meeting": {
      "$id": "https://api.sb/leaseline.app/meetings/meeting_1",
      "$type": "Meeting",
      "at": "2026-10-22T12:00:00Z"
    }
  }
}
Enrollment.paused · StartupBuilder-Signature
{
  "$id": "https://api.sb/leaseline.app/events/event_1",
  "$type": "Event",
  "name": "Enrollment.paused",
  "at": "2026-10-22T12:00:00Z",
  "seq": 1,
  "data": {
    "enrollment": {
      "$id": "https://api.sb/leaseline.app/enrollments/enrollment_1",
      "$type": "Enrollment",
      "status": "active",
      "step": "Example step"
    }
  }
}
Contact.unsubscribed · StartupBuilder-Signature
{
  "$id": "https://api.sb/leaseline.app/events/event_1",
  "$type": "Event",
  "name": "Contact.unsubscribed",
  "at": "2026-10-22T12:00:00Z",
  "seq": 1,
  "data": {
    "contact": {
      "$id": "https://api.sb/leaseline.app/contacts/contact_1",
      "$type": "Contact",
      "email": "dana@leaseline.app",
      "phone": "Example phone"
    }
  }
}

Refuses when

CheckRefusesFixThen
claima term with no accepted terms Version, or money back that no Action keepsCut the line, or cite the Offer term that grants it.POST /{namespace}/conversations/{conversation}/answer
owned-by-a-person Not live yet · gaps #8 · today: The dry run renders from the sample; each check names the call that clears it.a send to a Contact whose Lead, open Deal or Conversation a person ownsLeave it to the person who owns it: the draft waits in their queue.POST /{namespace}/tasks/{task}/assign
suppressed-contacta send or Sequence step to a Contact on a Suppression, from any PlayLeave them out: run the List again, which drops every suppressed Contact.POST /{namespace}/collections/query
422RefusedThe answer to Lakeside Rentals did not send: it promises money back that no Offer term grants.
CheckFixThen
claim failCut the line, or cite the Offer term that grants it.POST /{namespace}/conversations/{conversation}/answer
JSON
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "The answer to Lakeside Rentals did not send: it promises money back that no Offer term grants.",
  "checks": [
    {
      "check": "claim",
      "status": "fail",
      "observed": "“If it does not work in 30 days, we refund you.”",
      "doc": "/code/refusals#check-claim",
      "fix": "Cut the line, or cite the Offer term that grants it.",
      "then": "Conversation.answer"
    }
  ]
}

It says no, says why, and names the fix.

422RefusedStep two to Lakeside Rentals’ owner did not send: they asked us to stop on Oct 12.
CheckFixThen
suppressed-contact failLeave them out: run the List again, which drops every suppressed Contact.POST /{namespace}/collections/query
JSON
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "Step two to Lakeside Rentals’ owner did not send: they asked us to stop on Oct 12.",
  "checks": [
    {
      "check": "suppressed-contact",
      "status": "fail",
      "observed": "Suppression suppression_6, unsubscribed 2026-10-12",
      "doc": "/code/refusals#check-suppressed-contact",
      "fix": "Leave them out: run the List again, which drops every suppressed Contact.",
      "then": "Collection.query"
    }
  ]
}

It says no, says why, and names the fix.

422RefusedPinecrest Homes’ second visitor was not enrolled: no Consent on record for sales email.
CheckFixThen
suppressed-contact pass—POST /{namespace}/collections/query
no-consent failRecord the Contact’s yes, with where they gave it, before the first send.POST /{namespace}/consents
JSON
{
  "type": "https://startupbuilder.dev/errors/refused",
  "title": "Refused",
  "status": 422,
  "detail": "Pinecrest Homes’ second visitor was not enrolled: no Consent on record for sales email.",
  "checks": [
    {
      "check": "suppressed-contact",
      "status": "pass"
    },
    {
      "check": "no-consent",
      "status": "fail",
      "observed": "no Consent for purpose sales-email",
      "doc": "/code/refusals#check-no-consent",
      "fix": "Record the Contact’s yes, with where they gave it, before the first send.",
      "then": "Consent.create"
    }
  ]
}

It says no, says why, and names the fix.

Pauses when

StopPauses whenFixThen
unanswered-positivea reply asking to meet that waits 60 minutes for a personAnswer the reply, then approve the resume.POST /{namespace}/approvals/{approval}/approve
Campaign.paused · unanswered-positive · Not live yet, gaps #2 · sample
{
  "$id": "https://api.sb/leaseline.app/events/event_951",
  "$type": "Event",
  "name": "Campaign.paused",
  "at": "2026-10-19T16:45:00Z",
  "data": {
    "campaign": {
      "$id": "https://api.sb/leaseline.app/campaigns/cold-email",
      "$type": "Campaign"
    },
    "reason": {
      "limit": "unanswered-positive",
      "observed": "64m",
      "bound": "60m",
      "window": "60m"
    },
    "task": {
      "$id": "https://api.sb/leaseline.app/tasks/task_88",
      "$type": "Task"
    }
  }
}

Plays that use it

PlayWhat it doesIts Metric
Instant responseAnswers every form and email within 5 minutes from your own pages, books the call, starts the trial or hands it to the right person.inbound-meeting-rate
Cold emailWrites first to people at companies that showed two fresh public reasons to talk, three short emails at most, and answers every reply by kind.positive-reply-rate
Warm introsFinds who already knows each company you want, and that person asks them first, from their own account, before any introduction.intro-acceptance-rate
Proof-of-work outreachSends each Prospect one finished piece of your product’s work, made from their own public data, in a plain email that asks for nothing.proof-reply-rate
LinkedIn outboundPicks each day’s People on LinkedIn, drafts the connection note and the Messages, and queues them in your send tray; you press every send.linkedin-reply-rate
Outbound callingA disclosed voice agent calls back anyone who asks within 60 seconds and answers your number; a person dials every cold call.callback-meeting-rate
GiftingSends one gift the Person picks after two relevant touches at a live moment, with you approving each, and counts the Meetings it adds.gift-meetings-per-100
Lead reactivationWrites once to each old Lead nobody works, only when something new answers what they asked, from their last contact at the Startup.reactivated-pipeline
Lead nurtureFollows up each unbought Lead with notes keyed to what they did, most in month one, until they buy, reply or go quiet 90 days.nurture-conversion
Account visitsFinds the fitting companies behind visits to your own buying pages and writes to the right person there, from facts, never from the visit.visit-reply-lift
Product signalsFinds teams getting value on a free account and writes to the right person, citing only their own usage, after you approve the first send.pql-deal-rate
Buying committeeWrites to 3 or more roles at each named company, one a week, and hands each engaged company to your AE within a day.committee-deal-lift
Waitlist interviewsInterviews each Waitlist signup with your disclosed agent, admits by fit under a published cap, and sends a result built on their company.interview-activation-rate

Cost only: it moves no Metric itself, and what it costs counts against each Play that uses it.

Hub guides it deepens

On startupbuilder.devIdWhat it holds
Conversationnoun:conversationthe record, its fields and every call on it
Inbound salesprocess:inbound-salesthe Process, its steps and its Roles
AErole:sales-leadthe Role contract the seat fills

Example

Leaseline, whenWhat happenedCost (sample)
2026-10-19 15:41Northgate Rentals writes “Interested. Can you send times for Tuesday?”—
15:41:40filed as Interested and routed to the AE, with the Handoff Brief$0.01 of Worker cost
16:12the AE books Tuesday 14:00 Central, inside the 60-minute window$0

Compiled, not written: edit its page, then regenerate. Every step runs from a sentence or a line of code. In your words: the CRM words you know, and where each lives here.

Contents