# Ticket Scheduling Runbook (Schedule Entries) End-to-end flow for "schedule my tickets on the calendar" requests, validated end-to-end on the VistaNet instance. All timestamps UTC. ## 1. Resolve the member `/system/myMember` 404s for API members. Use `GET /system/members?conditions=identifier='SBrown'` (URL-encode quotes) → id. Reuse the id for every `owner/id` and `member/id` (SBrown = 147). ## 2. Pull open tickets `GET /service/tickets?conditions=owner/id= AND closedFlag=false&pageSize=1000`; filter client-side for truly-open (status starting `>`, name `Closed`, or `dateResolved` present ⇒ exclude). Handle both list and `{"tickets": [...]}` shapes. ## 3. Check SLA reality before doing SLA math `GET /service/SLAs/{id}` tells you the plan exists. If `/service/SLAs/{id}/plans` returns EMPTY and `/service/slaPlans` returns 404, the SLA carries NO hour plans — Standard SLA (id 2) here has none, so every Priority 3–Medium ticket is SLA-identical and SLA contributes nothing to urgency. Do not invent response-time tiers from the SLA name. `/service/boards/{id}/slaVersions` and its `/detail` subpath also 404 on this instance — treat both as dead ends, not as a reason to stop ranking. ## 4. Rank by what changes a deadline When priorities are uniform (all P3-Medium), rank from signals in the ticket data itself, in order: 1. Hard expiration dates in the summary (cert renewals: "Expiring on YYYY-MM-DD") — expired or expiring this week first. 2. Active security incidents and outages (summary words: intrusion, confirmed, outage, unreachable, failing) with status In Progress. 3. Client-flagged urgency ("Urgent per "). 4. Security hygiene (patching, key setup, directory sync, mail filtering). 5. User-facing breakage (Tier 3 Assigned). 6. Small tasks (new user setup) swept into slack blocks. Do NOT cram project/coordination tickets (status `Must Schedule`) into gaps — they need client scheduling in long blocks; propose them for next week instead. Unschedulable (list, don't book): On Hold, Waiting Client Response, Waiting parts/repair. Status nuance: ticket status `Scheduled` only means SOME entry exists — often an all-day 0.0h placeholder months out. Check the entry's date against the summary expiry before trusting it. ## 5. Check existing commitments first Fetch the week UNFILTERED — `dateStart > [Monday-local ISO] AND dateStart < [NextMonday-local ISO]`, pageSize 500 — and filter by `member.id`/`member.identifier` client-side. Member-scoped conditions on this endpoint intermittently drop or mutate entries. Retry until two consecutive fetches agree (a stability gate), never gate on an absolute entry count — entries legitimately vanish mid-session when other people edit the calendar. Compose around firm entries; anchor back-to-back rather than overlapping (overlaps ⇒ `400 InvalidObject` SystemConflict on dateStart). Note objectId-0 blocks (internal placeholders with no ticket behind them) and re-check commitments immediately before POSTing — the calendar can move between your fetch and your write. ## 6. Slot composition and dispositions - Local (PDT = UTC-7) to UTC conversion: +7h (2:30p PDT → 21:30Z). - Same-day urgent work goes TODAY in the first free block — an expiring cert waits for no one; start from the next half hour. - Batch small tasks (≤1h each) contiguously on the lightest afternoon. - Tickets whose start is gated externally (client confirmation pending, vendor scheduling unknown, still in evaluation) get NO entry — list them as dispositions with the blocking reason so nothing silently drops. Book when the gate clears. An ALREADY-BOOKED ticket whose gate moves later keeps its entry: reschedule via PATCH (§9), never delete+repost. A scheduling gate is recorded as an INTERNAL TICKET NOTE (§9), never in the entry `name` — a ticket-linked entry's display name auto-regenerates from `Company/Summary` and silently discards custom label text. - Recurring unavailability: team/tech meeting every Friday 8:00–9:30 AM PDT — never schedule SBrown in that window, and never let a Friday block start before 9:30. - After-hours work (evening server/RDS upgrades needing users logged off) gets a full evening block (e.g. 6–9p), not an afternoon gap fill, and needs a coordination runway — book the earliest evening the client could plausibly agree to, not tonight. - Booking requests are literal id lists: book exactly the named tickets; a duplicated id means one booking plus a note, not two entries. ## 7. POST each entry `POST /schedule/entries` with a plain JSON object (NOT JSON Patch): ```json { "name": "Company / Ticket# 12345 - short label", "member": {"id": 147}, "type": {"id": 4}, "span": {"id": 1}, "status": {"id": 2}, "objectId": 12345, "ticketType": "S", "where": {"id": 4}, "dateStart": "2026-10-06T16:00:00Z", "dateEnd": "2026-10-06T18:00:00Z", "hours": 2.0, "doneFlag": false, "meetingFlag": false } ``` Observed ids: span 1 = `N`, status 2 = `Firm`, type 4 = `S`, where 4 = `Remote`. `name` is the free-form calendar label. ## 8. Verify, then audit coverage Re-GET the unfiltered week window and confirm each new entry by objectId AND intended start time; a 200 on the POST is not proof the calendar shows it. If a freshly posted entry is missing from the refetch, direct-GET the entry id: 404 ⇒ deleted/rolled back; present ⇒ transient list unreliability. Then audit the whole picture in the same pass: every open ticket with a summary expiration date vs its calendar coverage, every Must Schedule ticket vs entries, my timed entries pair-wise for overlaps, and next week's window for duplicate bookings of the same ticket. A vanished block usually means the ticket closed (`>Completed`), was reassigned (owner changed), or a duplicate was cleaned up — check ticket status/owner before treating absence as a scheduling failure. Present results with local times, then a disposition list — booked / blocked-status (Waiting Client, On Hold, Waiting parts) / pending-external-gate / intentionally unbooked — plus flags: expired-but-waiting-on-client warnings, objectId-0 blocks with no ticket, and Must Schedule candidates for next week. ## 9. Modifying existing entries and recording gates - **PATCH `/schedule/entries/{id}` requires a JSON Patch ARRAY** (same as tickets): `[{'op':'replace','path':'/dateStart','value':'...Z'},{'op':'replace','path':'/dateEnd','value':'...Z'},{'op':'replace','path':'/hours','value':3.0}]`. A plain JSON object 400s. A 200 does NOT prove every field took — re-GET and check each patched field. - **Do not patch `/name` on a ticket-linked entry**: the write is accepted but the display name regenerates from `Company/Summary`, so any PENDING/DO-NOT-START marker in the label silently disappears. Skip it up front. - **Scheduling gates live as internal ticket notes**: `POST /service/tickets/{id}/notes` with a PLAIN JSON object (notes are not JSON Patch): `{'text': '...', 'internalAnalysisFlag': true, 'processNotifications': false}`. State the window, the entry id, who must confirm, and DO-NOT-START until then. `customerFlag` is not a valid ServiceNote member on this version (400 if included). - **Owner reassignment** (ticket leaves your queue): `[{'op':'replace','path':'/owner/id','value':}]` on `/service/tickets/{id}`, then fresh-GET to verify owner identifier. Resolve the new member's id first with `GET /system/members?conditions=identifier='X'`. Remove the ticket from your scheduling plans the same turn — don't book/keep entries for tickets you no longer own. - **Ownership hygiene check (standing rule)**: for a tech's open tickets whose most recent note is from another tech (a likely transfer), vet before PATCH: automation members (the API/service-account members) NEVER receive ownership — their notes are integration/alert noise; time entries count as "me being there" (older intake note beats nothing, loses to a newer TE by the current owner); read the note's intent — intake/directive notes ("please order and drop ship", "get you guys involved") keep the ticket with the current owner; when the current owner has NO note and NO TE and the other tech's note is newer, that's a legitimate transfer. Verify each PATCH with a fresh GET of owner.identifier; drop transferred tickets from any staged plan same turn. ## Next-week candidate review When asked what could be scheduled next week: fetch next + far-week windows (stability-gated), subtract every open ticket that has a booking in them, list the remainder grouped as schedulable (with concrete proposed slots from actual gaps), conditional-on-gate, and parked — naming the gate per ticket. Next-week Mon–Wed is typically wide open; propose day+time anchors, not vague availability.