# Schedule recurring work before a proposal is signed

> Set scheduling.activation_gate.require_accepted_proposal to false, then onboard the client with lines[] attached — the service line activates and spawns jobs immediately. Assign the series, dispatch, and build the proposal anyway but leave it in draft. Re-arm the gate when the migration is done.

URL: https://biloh.com.au/docs/how-to/schedule-recurring-work-without-a-signed-proposal
Category: How-to guides | Audience: operator | Updated: 2026-08-28

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.

## Related

- [When completing a job bills the client](/docs/concepts/when-completing-a-job-bills-the-client)
- [How to send a proposal](/docs/how-to/send-a-proposal)
- [Can it handle residential and commercial clients?](/docs/explanation/residential-and-commercial-clients)
