# /syncro — Syncro PSA ticket management Create, update, close, comment on, and bill tickets in Syncro PSA. ## Usage ``` /syncro Show open tickets summary /syncro ticket View ticket details + comments /syncro create Create new ticket /syncro update Update ticket status /syncro close Close/resolve a ticket /syncro comment Add a comment to a ticket /syncro bill Create invoice from ticket time entries /syncro search Search tickets by subject/customer /syncro customers Search customers ``` ## API Configuration **Base URL:** `https://computerguru.syncromsp.com/api/v1` **API Key:** SOPS vault `msp-tools/syncro.sops.yaml` → `credentials.credential` **Rate limit:** 180 requests/minute per IP **Docs:** https://api-docs.syncromsp.com/ ## Implementation When invoked, use the Syncro REST API via `curl`. All requests include `?api_key=` as query parameter (NOT in header — Syncro uses query param auth). ### Get API key ```bash API_KEY=$(bash D:/vault/scripts/vault.sh get-field msp-tools/syncro.sops.yaml credentials.credential) BASE="https://computerguru.syncromsp.com/api/v1" ``` If `vault.sh get-field` fails (yq not installed), fall back to: ```bash API_KEY=$(sops -d D:/vault/msp-tools/syncro.sops.yaml | python -c "import sys,yaml; print(yaml.safe_load(sys.stdin)['credentials']['credential'])") ``` ### Endpoints reference #### Tickets | Operation | Method | Endpoint | Body | |---|---|---|---| | List tickets | GET | `/tickets?status=&per_page=25` | — | | Get ticket | GET | `/tickets/` | — | | Create ticket | POST | `/tickets` | `{"customer_id": N, "subject": "...", "problem_type": "...", "status": "New"}` | | Update ticket | PUT | `/tickets/` | `{"status": "In Progress", "priority": "..."}` | | Delete ticket | DELETE | `/tickets/` | — | **Ticket statuses:** `New`, `In Progress`, `Waiting on Customer`, `Waiting on Vendor`, `Scheduled`, `Resolved`, `Invoiced`, `Closed` **Ticket fields (create/update):** - `customer_id` (required for create) - `subject` (required for create) - `problem_type` (string, free-form) - `status` (string, one of the statuses above) - `priority` (string) - `due_date` (ISO date) - `user_id` (assign to tech) - `contact_id` (customer contact) - `ticket_type_id` (ticket category) #### Comments (with optional time entry) | Operation | Method | Endpoint | Body | |---|---|---|---| | Add comment | POST | `/tickets//comment` | `{"subject": "Update", "body": "...", "hidden": false, "do_not_email": false}` | | Add comment + time | POST | `/tickets//comment` | Same as above, PLUS: `"product_id": N, "minutes_spent": 60, "bill_time_now": false` | **Comment fields:** - `subject` — comment header (e.g., "Update", "Resolution", "Internal Note") - `body` — comment text (HTML supported) - `hidden` — if true, internal-only (customer can't see) - `do_not_email` — if true, don't email customer about this comment - `product_id` — labor product ID (see labor products table below). Adds billable time to the ticket. - `minutes_spent` — integer, minutes of work (60 = 1hr minimum in most cases) - `bill_time_now` — if true, immediately creates a charge (equivalent to "Charge now" checkbox in GUI) **This is the primary way to log time.** Comment + time in one call mirrors the GUI workflow exactly. Timer entries (`/tickets/{id}/timer_entry`) exist but are rarely used. #### Customers | Operation | Method | Endpoint | |---|---|---| | List/search | GET | `/customers?query=&per_page=25` | | Get customer | GET | `/customers/` | | Create customer | POST | `/customers` | #### Timer Entries (add time to ticket) | Operation | Method | Endpoint | Body | |---|---|---|---| | Add time | POST | `/tickets//timer_entry` | `{"start_at": "ISO8601", "end_at": "ISO8601", "notes": "...", "billable": true, "product_id": N}` | | List timers | GET | `/ticket_timers?ticket_id=` | **IMPORTANT:** `product_id` must be a **labor product**, not an invoice product. Common labor products: - `1190473` — Labor - Remote Business (standard remote work) - `26118` — Labor - Onsite Business - `26184` — Labor - Emergency or After Hours Business - `9269129` — Labor - Prepaid Project Labor - `9269124` — Labor - Internal Labor - `26117` — Fee - Travel Time - `68055` — Labor - Website Labor #### Invoices | Operation | Method | Endpoint | Body | |---|---|---|---| | List invoices | GET | `/invoices?per_page=25` | | Get invoice | GET | `/invoices/` | | Create from ticket | POST | `/invoices` | `{"ticket_id": N, "customer_id": N, "category": "Standard"}` | | Delete invoice | DELETE | `/invoices/` | — | **"Make Invoice" flow:** Timer entries on the ticket become invoice line items when you POST `/invoices` with the ticket_id. This is the equivalent of clicking "Make Invoice" in the GUI. #### Invoice Line Items | Operation | Method | Endpoint | Body | |---|---|---|---| | Add line item | POST | `/invoices//line_items` | `{"item": "...", "quantity": 1, "price": 125.00, "product_id": N}` | ### Display formatting When showing ticket lists, format as: ``` #32164 New Jerry Burger Own cloud thing again #32163 New LeeAnn Parkinson Remote - Jim cant access his email #32162 Invoiced Len's Auto Brokerage Server upgrade ``` When showing ticket detail, include: - Ticket number, subject, status, priority - Customer name + contact - Created date, due date, last updated - Assigned tech - Comments (most recent first, truncated to last 5) - Time entries if any - Billing status ### Billing workflow When `/syncro bill ` is called: 1. Get ticket details 2. Ask: "How many minutes + labor type?" (default: 60 min, Labor - Remote Business) 3. Add comment with time: `POST /tickets/{id}/comment` with `product_id`, `minutes_spent`, `bill_time_now: false`, and work notes as body 4. Then create invoice: `POST /invoices` with `{"ticket_id": N, "customer_id": N, "category": "Standard"}` 5. Update ticket status to "Invoiced" **The flow mirrors the GUI: add comment with time attached → Make Invoice.** When `/syncro comment --time 60 --labor remote` is called: - Post the comment with time in one API call - `--labor` maps to product IDs: `remote` → 1190473, `onsite` → 26118, `emergency` → 26184, `project` → 9269129, `internal` → 9269124, `travel` → 26117, `website` → 68055 ### Error handling - 401: API key invalid or expired - 404: ticket/customer/invoice not found - 422: validation error (show the error message from response body) - 429: rate limited (wait 60s and retry) ### Integration with session logs When closing a ticket (`/syncro close`), offer to create a session log entry in `clients//session-logs/` documenting what was resolved. Pull the ticket subject, comments, and resolution into a structured log.