Skip to content

Contact.enroll

Start one person on a Sequence that sends from your inbox and stops on reply.

Action class
send
Approval
Sends on its own
Emits
Contact.enrolled
Sites
Gmail, LinkedIn, Outlook
Price
Free
POST https://api.sb/{your-domain}/contacts/enroll

Starts one person on a Sequence that sends from your Mailbox and stops the moment they reply. The hub’s definition of Contact.enroll.

Inputs

NameTypeDefaultMeaning
contactContactRequiredThe Contact to enroll.
sequenceSequenceRequiredThe Sequence to run.

Outputs

FieldTypeWhat null means
contactContactNever null.
enrollmentEnrollmentNever null. In try mode, the run as it would start; nothing is stored.
enrollment.statusstringNever null: active from the first step until the run ends.
enrollment.stepstringNever null: the step the Contact is on, starting at the first.
enrollment.nextAtdatetimeNull while paused or once exited: no step is waiting.
enrollment.exitReasonstringNull while the run is active.
firstStepMessageNull in send and do. In try mode, the first step rendered for this Contact, so you read it before anything sends.

Effects

Action class

send: an approval rule on send can make it wait for your OK

Modes
  • try: Renders the first step for this Contact and when each later step would fire; nothing sends and no Enrollment is stored.
  • send: Returns the active Enrollment at once; each step sends at its own time.
  • do: Returns the active Enrollment at once; each step sends at its own time.
Idempotency

Only with a key: the same Idempotency-Key and input return the first Action, and the same key with other input returns 409. A Contact already active on the Sequence is never enrolled twice: the repeat returns the open Enrollment.

Saved or shared

The Enrollment is saved on the Contact. A reply, a bounce, an unsubscribe or a purchase ends it and records its exitReason.

Emits

Contact.enrolled with { contact, enrollment, sequence, nextAt }

Performed by

Prospector

Price

Free on your own account: the platform charges nothing for the call.

Standing approval

It goes out on its own, inside the Limits of your standing approval: a Mandate granted with Mandate.authorize. One approval rule makes it wait for your OK.

On each Venue

SiteFields
Gmailfrom, to, subject, body, purpose
LinkedInbody Formats 3
Outlookto, subject, body, purpose

Gmail

Through Gmail.

Our fieldGmail’s field
Message.fromraw: From header (Your address, or a send-as alias you set up in Gmail)
Message.toraw: To header
Message.subjectraw: Subject header (A reply keeps the thread’s subject, so Gmail threads it)
Message.bodyraw: text/plain and text/html parts
Message.purposeraw: List-Unsubscribe and List-Unsubscribe-Post headers (A commercial purpose adds the one-click unsubscribe headers Gmail shows as a link)
  • Cold sends. 30 a day per inbox after 14 days of warm-up, held by your standing approval; a Sequence spreads the rest over the next days.
  • Replies. Gmail pushes each new message within seconds; the platform renews the mailbox watch daily, inside the 7 days Gmail allows.

LinkedIn

Through LinkedIn.

Our fieldLinkedIn’s field
Message.bodyinvitation note or message (Typed into LinkedIn’s own screens by the browser agent)
  • Follow-ups. One first message and one follow-up per person; any reply stops the rest.
  • Replies. Read from your LinkedIn inbox every 30 minutes on weekdays, since LinkedIn sends no webhook for member messages.
Feed post Single image ad, 1200 × 628, 1200 × 1200 or 720 × 900 Document ad

Outlook

Through Outlook.

Our fieldOutlook’s field
Message.tomessage.toRecipients
Message.subjectmessage.subject
Message.bodymessage.body (contentType html or text)
Message.purposemessage.internetMessageHeaders (A commercial purpose adds the one-click unsubscribe headers)
  • Cold sends. 30 a day per inbox after 14 days of warm-up, held by your standing approval; a Sequence spreads the rest over the next days.

What try does

AccountWhat try does
GmailRenders the exact email, headers included, and returns it with the time it would send; nothing reaches Gmail and no draft is saved.
LinkedInPosts render as LinkedIn will show them and nothing is sent; requests and messages return each person, the note and the day it goes, and no browser session opens.
OutlookRenders the exact email or invite and returns it with the time it would go; nothing reaches Outlook and no draft or event is saved.

Refuses when

CheckErrorFixThen call
A send or Sequence step whose purpose the Contact has given no Consent forno-consentRecord the Contact’s yes, with where they gave it, before the first send.Consent.create
A send or Sequence step to a Contact on a Suppression, from any Playsuppressed-contactLeave them out: run the List again, which drops every suppressed Contact.Collection.query
A new-lead send to a Contact with an active Subscriptioncustomer-collisionTalk to them yourself instead: the Contact leaves the List.Lead.assign
A first cold email from a Mailbox that has not finished warmingmailbox-warmWait for the warm-up to finish, 14 days from day 0; warm intros keep running.Mailbox.warm

Every call through an account can also meet the shared account refusals: grant-missing, needs-reauth, account-not-connected, over-mandate, quota-reached, venue-rejected.

The no-consent payload
JSON
{
  "type": "https://startupbuilder.dev/errors/no-consent",
  "title": "No yes on record",
  "status": 422,
  "detail": "A send or Sequence step whose purpose the Contact has given no Consent for.",
  "fix": "Record the Contact’s yes, with where they gave it, before the first send.",
  "next": {
    "verb": "Consent.create",
    "input": {}
  },
  "instance": "https://api.sb/leaseline.app/actions/action_1"
}

When it waits

Returns in one response; nothing waits.

Example

Text
Put Maya Chen at Cedar Hollow Rentals on the personal first touch, the
first of today’s 12.

To retry, send the same Idempotency-Key: the retry returns the first answer for $0. A new key reads again.

Test values

A sk_test_ key answers these the same way every time, at $0 (every test value).

Test valueAlways returnsWhat it is for
contact_test_active{"status":"active","step":"email-1","exitReason":null}Enrolls and renders the first step without sending, so your agent can read the run it starts.
contact_test_suppressedRefuses with suppressed-contactThe address sits on a Suppression, so the enroll refuses before any step is planned.
contact_test_no_consentRefuses with no-consentThe Contact gave no Consent for the Sequence’s purpose, so the enroll refuses.
maxCost: 0.0001Refuses with max-costAny priced call with a maxCost of 0.0001 is refused before it spends: the price is above the cap.
rate-limited.testRefuses with rate-limitedAny call naming this hostname answers 429 with Retry-After, so your retry logic runs.
sources-busy.testRefuses with sources-busyAny call naming this hostname answers 503 as if every route were busy, and nothing is spent.

Used by

None.