A backfill applies a workflow to entities (tickets or time entries) that already exist in your PSA, instead of waiting for new ones to come in via callbacks. Use it to apply a newly-built or refined workflow to history without flooding your environment all at once.Documentation Index
Fetch the complete documentation index at: https://docs.neoagent.io/llms.txt
Use this file to discover all available pages before exploring further.
When to use a backfill
- You just built a new triage workflow and want it to process the last 30 days of open tickets, not just newly-created ones.
- You changed your dispatch rules and want to re-run the corrected logic over recent tickets.
- You want to test a workflow on a small sample of historical tickets before enabling it for live callbacks.
How it works
A backfill creates a long-running orchestrator (a Temporal workflow) that:- Queries your PSA for entities matching the backfill’s filter spec.
- Drops entities that already have a successful execution of the target workflow (so re-runs are idempotent).
- Within the configured execution window, signals child workflow executions in batches of
max_in_flight. - Tracks succeeded and failed counts via Temporal visibility queries.
Setting one up
From the dashboard, go to Backfills → New backfill. The wizard has four steps:Choose a filter
Either Reuse workflow filters (the backfill processes the same entities the workflow normally matches, optionally narrowed with extra rules) or Custom filters (the backfill defines its own entity scope, ignoring the workflow’s filters).See Filter tickets for the rule-builder reference — the same filter syntax used in workflow conditions.
Configure the execution window
Pick the days of the week and start/end times when the backfill is allowed to dispatch. Times are interpreted in the timezone you select (defaults to your browser’s timezone).
Execution windows
Windows tell the orchestrator when it’s allowed to dispatch. Outside the window, the orchestrator stays alive but doesn’t fan out — the row’s state staysRUNNING and the detail page shows a “Waiting for window” sub-badge with the next opening time.
Each day can have one or more time windows. Windows can span midnight: 22:00 → 06:00 means the window runs from 22:00 on the configured day through 06:00 the next morning.
Filter spec
The filter spec defines which entities the backfill dispatches. Shape:conditions shape is the same FIND_ENTITIES filter used by the workflow editor — see Filter tickets. When you choose Reuse workflow filters, the wizard merges the workflow’s existing conditions with any extra rules you add and snapshots them into filter_spec at submit time. Later edits to the workflow don’t shift an in-flight backfill.
In Custom filters mode, the workflow’s own filters are intentionally bypassed at dispatch time. The backfill is the filter authority — every entity matching your rules runs the workflow, even if the workflow’s own filter would normally reject it.
States
| State | Meaning |
|---|---|
RUNNING | Orchestrator alive. Dispatches when inside the execution window. |
PAUSED | User paused. Orchestrator stays alive but skips dispatch. |
COMPLETED | All matching entities have a successful execution. |
CANCELLED | User cancelled. Orchestrator stopped. |
FAILED | Unrecoverable error in the orchestrator. |
RUNNING but currently outside the configured window — useful when a customer creates a backfill at 10 AM for a 22:00 window and wonders why nothing’s happening.
Counts on the row
- started — entities the orchestrator has dispatched (one Temporal workflow run per entity). Equals
processed_counton the DB row. - succeeded — child workflow runs that completed successfully.
- failed — child workflow runs that completed with failure.
- in flight —
started − succeeded − failed. Children mid-run.
Pause, resume, cancel
| Action | Effect |
|---|---|
| Pause | Orchestrator stops dispatching at the next tick. In-flight children continue to completion. |
| Resume | Orchestrator picks up from last_cursor (the last entity it dispatched) on the next tick. |
| Cancel | Terminal. Orchestrator stops, row state becomes CANCELLED. In-flight children still complete on their own. |
Cost
Each child execution is billed at the target workflow’s normal credit cost — a backfill of 1,000 tickets through a triage agent at 2 credits per run costs 2,000 credits. Backfills don’t add a markup; they’re just a pacing mechanism for the existing workflow’s per-run cost. The wizard’s preview step shows the upper-bound credit cost (total_entities × credits_per_run) before you commit, so the cost ceiling is explicit at create time.
Concurrency control
max_in_flight (default 5) caps how many child workflows are running concurrently. The orchestrator checks the live RUNNING count for the target workflow (regardless of source) and only dispatches up to that cap.
API endpoints
The backfill API is internal — the dashboard uses it, but it’s not part of the public API contract. Endpoints live under/api/backfills.
| Method | Path | What it does |
|---|---|---|
| POST | /api/backfills | Create a backfill (or preview cost with ?preview=true). |
| POST | /api/backfills/verify | Preflight: count how many entities the filter would match. |
| GET | /api/backfills | List backfills for the caller’s tenant. Filter by state query param. |
| GET | /api/backfills/{id} | Get a single backfill row. |
| POST | /api/backfills/{id}/pause | Signal pause. |
| POST | /api/backfills/{id}/resume | Signal resume. |
| POST | /api/backfills/{id}/cancel | Signal cancel. |
Create payload
Verify payload
Same shape as create, but only the fields needed for filter evaluation. Returns a safety classification (OK / WARNING / ERROR) and the matched entity count:
Troubleshooting
State is RUNNING but no progress is happening
State is RUNNING but no progress is happening
The orchestrator is alive but waiting for the next execution window. The detail page shows a “Waiting for window” sub-badge with the next opening time. If you created the backfill at 10 AM for a 22:00 window, this is expected — nothing is broken.
A second backfill for the same workflow gets rejected
A second backfill for the same workflow gets rejected
A
409 Conflict from POST /api/backfills (or WorkflowAlreadyStartedError at the Temporal layer) means there’s already a RUNNING or PAUSED backfill for that target workflow in your tenant. Cancel or pause-and-cancel the existing one first.processed count keeps climbing but succeeded / failed stays at 0
processed count keeps climbing but succeeded / failed stays at 0
Reconciliation queries Temporal visibility on each tick. There’s a ~1 second eventual-consistency lag — wait one tick and refresh. If counts stay at zero for more than ~30 seconds, the child workflows themselves may be hung; check the workflow’s Event History to see what they’re doing.
A failed child blocks the backfill from completing
A failed child blocks the backfill from completing
The orchestrator only marks
COMPLETED when every matching entity has a successful execution. Entities with only a FAILED row keep getting re-dispatched on each tick (Temporal’s deterministic workflow_id deduplicates the actual run, but processed_count keeps bumping). Cancel and re-create the backfill, or wait for a future “retry failed” action.The slot math isn't giving my backfill all max_in_flight slots
The slot math isn't giving my backfill all max_in_flight slots
max_in_flight caps total concurrent executions of the target workflow, not just backfill-driven ones. If live triggered traffic is consuming slots, your backfill shares the pool. This is intentional — it protects your PSA’s rate limits.Limits and guardrails
- Concurrency: 1–10 per backfill (
max_in_flight). - Safety thresholds at verify time: OK ≤ 5,000 matching entities, WARNING ≤ 50,000, ERROR > 100,000. Backfills above the WARNING threshold can still be created; ERROR-level can’t.
- Orchestrator lifetime: 7 days max. A backfill that hasn’t finished in 7 days will time out — usually a sign the filter is too wide for the window cadence.
- Concurrent backfills per workflow: 1 active (
RUNNINGorPAUSED) per(client, target_workflow_id). Multiple completed/cancelled backfills for the same workflow are fine.
