Yes. Turn off the activation gate, and a recurring service line spawns jobs the moment it is created — no accepted proposal required.
This is the verbal-agreement posture: the client said go on the phone, the work starts Tuesday, and the paperwork follows when it follows.
Why the gate exists at all
By default, an active recurring service line will not spawn jobs until its site has an accepted proposal. That is the paperwork-first posture: nothing lands on the schedule that the client has not signed for.
It is a good default for new business. It is the wrong default for a book of existing relationships — clients you have served for years, who are never going to sign anything, and whose service should not pause while a document sits in an inbox.
Turn the gate off
update_setting
key: scheduling.activation_gate.require_accepted_proposal
value: false
Record a reason when you do it. The setting stores who changed it, when, and why, and you will want that context when you come back to re-arm it.
This is a tenant-wide switch, not per client. Turn it back on once the legacy conversions are through.
Onboard the client with the service line attached
With the gate off, use the direct path — client, site, and active recurring service line in one call:
onboard_client
legal_name, billing_email, client_type, invoicing_cadence, payment_terms_type
sites: [{ name, address }]
lines: [{ site_ref, service_id, frequency_id, client_rate_cents,
day_of_week, week_of_month, anchor_date, ...line facts }]
confirm: false ← preview first, zero writes
The preview echoes the schedule with weekday names spelled out and the next few dates computed, plus a duplicate-client check. Read it properly. Mistakes are cheap here and expensive later.
Then repeat with confirm: true. You get the client, the site, the billing contact, the service line with its recurrence rule, and the spawned jobs — atomically. The response tells you how many jobs spawned and confirms activation_gate_passes: true.
Assign and dispatch
Assignment and dispatch are separate, deliberate acts.
assign_series(contract_service_line_id, contractor_id)
sets the contractor on the line so every future spawn inherits them, re-derives what that contractor is paid from their own rate model, and sweeps the existing scheduled occurrences onto them. It does not notify anyone. It also reports back anything it did not touch — occurrences already dispatched or completed under someone else are never silently reassigned.
Then dispatch. dispatch_job marks a visit as dispatched without an email, for when the contractor was told out of band. propose_send_work_order sends a real branded work order. Both are available; the first is honest about what it is, and warns you that no work order covers the visit.
Keep the proposal, just don't send it
Here is the part operators miss: skipping the proposal as a gate does not mean skipping the proposal as a document.
Build it anyway. Create the proposal, add the lines, render the PDF, and leave it sitting in draft. A draft proposal has no signing token minted and no email sent. It is ready the day the conversation happens.
create_proposal → add_proposal_line → render_artifact_pdf
You now have a client whose service is live and whose paperwork is ready but unsent. That is a legitimate, common, and fully supported state.
If the client later accepts, acceptance de-duplicates against the service lines that already exist — it logs a loud audit skip rather than standing the same schedule up twice.
Re-arm the gate afterwards
Once the conversions are done, set it back to true. Leaving it off permanently means a mistyped service line goes straight onto the schedule with nothing to catch it.