change_stage
ChatGPTMove a custom-object record to a new pipeline stage. stage must be one of this object's valid_statuses from get_data_model(slug); the transition is validated server-side against the account's pipeline rules first (allowed transitions, required fields) and a clear error is returned if it is not allowed. Use update_record for field changes — this tool ONLY changes the stage.
check_team_schedule_conflicts
ChatGPTCheck scheduling conflicts for team members against proposed visit times. Considers weeklySchedule, specificHours (availability), and existing visit overlaps. REQUIRED parameters: - teamMemberIds: array of team member MongoDB IDs - visits: array of visit objects [{visitStartDateTime, visitEndDateTime}], each local time in the ACCOUNT's timezone — send the wall-clock time the user said and do NOT convert to UTC yourself; a trailing "Z"/offset is IGNORED, not honoured - timezone: string — user's timezone for proper comparison (e.g. 'America/New_York') OPTIONAL: - excludeJobId: string — exclude a specific job when checking overlaps
convert_record
ChatGPTExecute a conversion rule on a record — creates a NEW record in the rule's target object (e.g. template → live record, unit → renewal job). Confirm with the user before calling. Valid rule_id values: the conversion_actions listed by get_data_model(slug). Each rule has trigger stages — the record must currently be in one of them. additional_data (optional) is merged into the created record.
convert_request_to_estimate
ChatGPTConvert a service request into an estimate document. REQUIRED: - request_id: MongoDB ObjectId of the request to convert OPTIONAL: - conversion_data: Dictionary with estimate options - dueDate: ISO date for the estimate due date - paymentTerms: integer — number of days (e.g., 30 for Net 30, 0 for Due on receipt) - comments: string - internalNotes: string This copies all line items and taxes from the request into a new estimate, and marks the request stage as "converted". Returns the converted estimate ID and number.
create_calendar_event
ChatGPT⚠️ CALL SHAPE — pass arguments exactly as: {"event_data": { ...event fields... }} All record fields go INSIDE the *_data object, NOT at the top level (top-level keys are rejected as "unexpected keyword argument"). Create a new event in Google Calendar. REQUIRED fields in event_data: - title: string — event title - start: ISO 8601 datetime — event start, local time in the ACCOUNT's timezone — send the wall-clock time the user said and do NOT convert to UTC yourself; a trailing "Z"/offset is IGNORED, not honoured - end: ISO 8601 datetime — event end, same local-time rule OPTIONAL fields: - timeZone: IANA name (e.g. 'America/New_York') — the calendar provider's display zone only; start/end above are still read in the ACCOUNT's timezone - isAllDay: boolean — whether event spans full day - attendees: array of {email, optional, id} — invitees - recurrence: object — {frequency, interval, weekdays, count, until} - location: string or object — event location - description: string — event notes - colorId: string — color ID or hex color - metadata: object — custom metadata in extended properties
create_client
ChatGPT⚠️ CALL SHAPE — pass arguments exactly as: {"client_data": { ...client fields... }} All record fields go INSIDE the *_data object, NOT at the top level (top-level keys are rejected as "unexpected keyword argument"). Create a new client in FieldCamp. REQUIRED fields: - client_data: Dictionary containing client information CLIENT_DATA REQUIRED fields: - firstName OR email — at least one of these is required. - firstName: string (MUST split full names - "John Smith" → firstName: "John", lastName: "Smith") - email: string CLIENT_DATA OPTIONAL fields: - lastName: string (can be empty "") - propertyAddress: object with {street, city, state, country, zipCode, formattedAddress} (all optional; an address object, NOT a plain string) - phoneNumber: object {countryCode: "+1", number: "5551234567", countryIdentifier: "us"} - companyName, website, taxNumber: string - billingAddress, companyAddress: object - notes: string - stage: ACCOUNT-SPECIFIC — call get_data_model("client") for this account's real stage values (accounts rename/replace the defaults; sending a stale default fails or mislabels the client) - clientType: "business" or "individual" - properties: array - preferredTechnicianIds, jobFormIds: arrays of ids (Clients have no tags field — it is not accepted, so do not send it.) Example: { "firstName": "John", "lastName": "Smith", "email": "john@example.com", "phoneNumber": {"countryCode": "+1", "number": "5551234567", "countryIdentifier": "us"}, "propertyAddress": { "formattedAddress": "123 Main St, Toronto, Ontario, Canada", "city": "Toronto", "state": "Ontario", "country": "Canada" } }
create_document
ChatGPT⚠️ CALL SHAPE — pass arguments exactly as: {"document_data": { ...document fields... }} All record fields go INSIDE the *_data object, NOT at the top level (top-level keys are rejected as "unexpected keyword argument"). Create a new invoice or estimate in FieldCamp. REQUIRED fields in document_data: - documentNumber: integer — this field is required. Obtain the next number via the get_document_number tool (pass the same documentType) and use its value here. - documentType: 1 (Invoice) or 2 (Estimate) (default: 1) OPTIONAL fields: - clientId: MongoDB ObjectId - title: string - date: ISO date (default: today) - dueDate: ISO date - items: array of line items [{name, quantity, rate, description, taxIds}] - discount: number - discountType: 1 (percentage) or 2 (flat) - subTotal: number - total: number - paymentStatus: "unpaid", "paid", "partial", "overdue". HONORED ONLY for ESTIMATES (documentType=2). For INVOICES (documentType=1, the default) the backend hard-forces paymentStatus="unpaid" no matter what you pass (silently overwritten). To mark an invoice paid/partial, use the record_payment tool. - paymentTerms: integer — number of days (e.g., 30 for Net 30, 0 for Due on receipt) - privateNotes: string (internal) — or comments for client-facing text. Documents have no notes field — it is not accepted, so do not send it. - terms: string - tags: array MULTI-OPTION ESTIMATE (give the customer choices): set documentType=2, isMultiOption=true, and provide estimateOptions instead of a single items[]. Each option = {name, description?, isDefault?, lineItems:[{name, quantity, rate, description?}]}. Omit top-level items[] when using estimateOptions. Example (create invoice): { "documentNumber": 1, "documentType": 1, "clientId": "68efbd5a689d240560536cd6", "items": [ {"name": "HVAC Repair", "quantity": 1, "rate": 150, "description": "Emergency repair"} ], "dueDate": "2026-02-28" } Example (multi-option estimate): { "documentNumber": 1, "documentType": 2, "isMultiOption": true, "clientId": "68efbd5a689d240560536cd6", "estimateOptions": [ {"name": "Good", "lineItems": [{"name": "Basic clean", "quantity": 1, "rate": 100}]}, {"name": "Best", "isDefault": true, "lineItems": [{"name": "Deep clean", "quantity": 1, "rate": 250}]} ] }
create_job
ChatGPT⚠️ CALL SHAPE — pass arguments exactly as: {"job_data": { ...job fields... }, "notes": "optional"} All record fields go INSIDE the _data object, NOT at the top level (top-level keys are rejected as "unexpected keyword argument"). Create a new job in FieldCamp. REQUIRED parameters: - job_data: Dictionary containing job information OPTIONAL parameters: - notes: the job's free text, stored as internalNotes.note — what the app lists as the job's "description". A job has NO title/description field; put that text here (job_data.internalNotes {"note": "..."} is accepted too). JOB_DATA REQUIRED fields: - clientId: MongoDB ObjectId (from search_database or get_client_by_id) - jobType: "one-off", "recurring", or "multi-day" - jobNumber: string or number - startDateTime: ISO 8601, local time in the ACCOUNT's timezone — send the wall-clock time the user said and do NOT convert to UTC yourself; a trailing "Z"/offset is IGNORED, not honoured (e.g., "2026-01-25T09:00:00") - jobAddress: object with {city, state, country, formattedAddress} JOB_DATA OPTIONAL fields: - jobTypeId: id from get_job_types — the account's job-type catalog ("Annual PM" vs "6-Month Checkup"). Distinct from jobType above. - targetRecordId + targetObjectSlug: link this job to a custom-object record (e.g. targetObjectSlug="unit", targetRecordId=<record id from list_records>). This is how PM jobs attach to the asset they service. - billToClientId: bill a different client than clientId (property manager / homeowner split). - endDateTime: ISO 8601, same local-time rule as startDateTime - jobPhone: object {countryCode: "+1", number: "xxx", countryIdentifier: "us"} - assignedToTeams: array of team IDs - jobItems: array of line-item objects. Each REQUIRES `itemName` (string) + `price` (per-unit number); `quantity` defaults to 1 and `total` is auto-computed (pricequantity). Reference an existing item with itemId (24-hex items id — NOT productServiceId/id); omit itemId for an ad-hoc line. E.g. [{"itemName": "Air filter", "price": 20, "quantity": 2}] - ⚠️ linkedRecords is NOT accepted (rejected with 400 — the backend silently drops it). Use targetRecordId + targetObjectSlug (above) to link a record instead. - subTotal, tax, total, discount: numbers - jobStatus: ACCOUNT-SPECIFIC — call get_data_model("job") for this account's real stage values before setting one. Create does NOT validate (it stores whatever string is sent), so a stale/guessed value silently mislabels the job for filtering/UI. Defaults to "scheduled" if omitted. - priority: "low", "medium", "high" - timezone: string (e.g., "America/Toronto") - anyTime: boolean — the job has no fixed start time, just a duration - serviceDuration: number (seconds). The create endpoint itself keeps this only for anyTime jobs, so for a scheduled job it is written back with a follow-up update — which counts as a job UPDATE (history entry, the "Job Updated" push to involved users, calendar sync, and any "job updated" workflow automations fire); the response says so if that write-back fails. - aiDispatcher: {"enabled": true} hands scheduling to the AI dispatcher. Only then is description read — as the dispatcher's visit label. - scheduleLater: boolean RECURRING JOBS: set jobType="recurring" AND provide recurringOptions — a list like [{"frequency": "weekly", "interval": 1, "duration": {"value": 1, "unit": "month"}}] (frequency = daily/weekly/monthly; interval = every N periods). Complex patterns (specific weekdays, nth-weekday, days-of-month) use customSettings {monthlyType, nthWeekday, daysOfMonth, weekDays}; if the pattern is non-trivial or unclear, confirm the exact recurringOptions with the user instead of guessing. Example: { "clientId": "68efbd5a689d240560536cd6", "jobType": "one-off", "jobNumber": "JOB-001", "jobStatus": "scheduled", "jobAddress": { "formattedAddress": "123 Main St, Toronto, Ontario, Canada", "city": "Toronto", "state": "Ontario", "country": "Canada" }, "startDateTime": "2026-01-25T09:00:00", "endDateTime": "2026-01-25T17:00:00" }
create_product_service
ChatGPT⚠️ CALL SHAPE — pass arguments exactly as: {"product_service_data": { ...fields... }} All record fields go INSIDE the *_data object, NOT at the top level (top-level keys are rejected as "unexpected keyword argument"). Create a new product or service in FieldCamp. REQUIRED parameters: - product_service_data: Dictionary containing product/service information PRODUCT_SERVICE_DATA REQUIRED fields: - name: string - type: "Product" or "Service" - price: number PRODUCT_SERVICE_DATA OPTIONAL fields: - description: string - properties: array - isTaxExempt/exemptFromTax: boolean (default: false) - duration: number (minutes, for services) - isActive: boolean (default: true) - isInventoried/trackInventory: boolean (default: false). If true, inventory (below) is REQUIRED — the backend creates a stock row and 400s/500s without it. - categoryIds: array of category IDs - inventory: object — required when tracking is on. Shape: { "locationId": "<24-hex warehouse ObjectId>", // REQUIRED. This is the // warehouse key — NOT "warehouseId"/"warehouse"/"location" // (those are not accepted). Get one from get_warehouses. "sku": "SKU-001", // REQUIRED, must be GLOBALLY unique (duplicate 500s) "quantity": 10, // integer on-hand count (default 0) "lowStockAlert": 5, // integer reorder threshold (default 5) "binLocation": "A-1" // optional } - taxIds: array of tax IDs - formIds: array - settings: object with {onlineBooking, allowFillForm, serviceDuration, bookingType} - cost: number — internal unit cost (never client-facing); drives the estimate phase-margin breakdown (product cost → Material, service cost → Labor) - unitOfMeasurementId: string — unit of measurement id (sq ft, hour, each, …); valid ids from GET /api/unit-measures; reads return populated unitOfMeasurement Example: { "name": "GPU", "type": "Product", "price": 100, "description": "High-performance graphics card", "isActive": true, "exemptFromTax": false, "trackInventory": false }
create_purchase_order
ChatGPTCreate a purchase order (order stock from a vendor) in FieldCamp. REQUIRED in po_data: - vendorId: the supplier to order from (use get_vendors to find it). - items: non-empty array of line items. Each item: {itemId, quantity, price}; set displayType:'kit' to order an inventory kit (the backend expands it into its component items). OPTIONAL in po_data: - poNumber, expectedDeliveryDate (ISO date), notes. Call get_vendors for the vendorId and get_products_services / get_inventory for item ids before creating.
create_record
ChatGPTCreate a record of a CUSTOM object (e.g. slug="unit"). Call get_data_model(slug) FIRST — data must be keyed by the canonical field NAMES it returns (not labels), and status (optional initial pipeline stage) must be one of its valid_statuses. Relation fields take the target record's id (or array of ids for multi-relations). Example: create_record("unit", data={"serial_no": "GEN-002", "client_ref": "<client id>"}, status="active")
create_request
ChatGPT⚠️ CALL SHAPE — pass arguments exactly as: {"request_data": { ...request fields... }} All record fields go INSIDE the *_data object, NOT at the top level (top-level keys are rejected as "unexpected keyword argument"). Create a new service request in FieldCamp. REQUIRED fields in request_data: - clientId: MongoDB ObjectId of the client OPTIONAL fields: - source: string (default: "manual") - description: string - urgency: string enum — "low", "medium", "high", "critical" (default: "medium") - requestAddress: object {formattedAddress, city, state, country} - startDate: ISO 8601 format - endDate: ISO 8601 format - stage: ACCOUNT-SPECIFIC (request pipeline is org-configurable) — call get_data_model("request") for this account's real stage slugs. Default: "new_request". Built-in default slugs: new_request, unscheduled, overdue, inspection_scheduled, inspection_complete, quote_created, quote_sent, converted, lost_no_response, lost_reject_quote, cancelled, duplicate - assignedTo: array of user MongoDB ObjectIds - notes: string - tags: array of strings - estimatedValue: number - items: array of line items [{itemId, itemName, quantity, rate}]. ⚠️ itemId is REQUIRED on each item and MUST be a real product/service id from get_products_services — items without a valid itemId cause a server error. If you have no product id, OMIT items entirely (use description/estimatedValue). - taxes: array of tax objects [{taxId, name, rate, taxType}] Example: { "clientId": "68efbd5a689d240560536cd6", "description": "HVAC repair needed", "urgency": "high", "stage": "new_request" }
create_task
ChatGPTCreate a new task in FieldCamp. REQUIRED parameters: - name: Task name/title - scheduleDateTime: ISO 8601, local time in the ACCOUNT's timezone — send the wall-clock time the user said and do NOT convert to UTC yourself; a trailing "Z"/offset is IGNORED, not honoured (e.g., "2026-01-25T14:00:00") OPTIONAL parameters: - instructions: Detailed task instructions - priority: "low", "normal", "high", "urgent" (default: "normal") - category: "admin", "maintenance", "follow_up", "inspection" (default: "follow_up") - assignedToId: MongoDB ObjectId of user to assign (search users collection) - clientId: MongoDB ObjectId of linked client - linkType: "client", "job", "estimate", "invoice" - jobId, estimateId, invoiceId: MongoDB ObjectIds for linked entities - propertyAddress: string - scheduleType: "once", "daily", "weekly", "monthly" (default: "once"). For a recurring task pass a non-"once" value AND a recurrenceRule — recurrence is driven by recurrenceRule; scheduleType is the stored label. - scheduleEndDate: ISO 8601 (for recurring tasks), same local-time rule as scheduleDateTime - allDay: boolean (default: false) - duration: minutes (default: 30) - recurrenceRule: e.g., "FREQ=DAILY;INTERVAL=1" (for recurring) - recurrenceCount: number of occurrences - reminderType: "email", "sms", "push" - reminderTime: minutes before task (default: 15) - tags: array of strings - emailTeam: boolean - notify assignee (default: false)
create_tax
ChatGPTCreate a tax rate in FieldCamp. REQUIRED in tax_data: - name: tax name (e.g. 'GST'). - rate: percentage as a number (e.g. 5 for 5%). OPTIONAL in tax_data: - taxType: 1 = exclusive (default), other values per settings. - description, applyOnAllItems (bool), countryId, stateId, effectiveDate (ISO date), applicationRules (array). The new tax id feeds the taxIds arrays on create_document and create_product_service. Admin / settings permission required.
create_vendor
ChatGPTCreate a vendor / supplier in FieldCamp. REQUIRED: - name: vendor name. OPTIONAL: - email: must be unique for the org (backend rejects a duplicate). - phone: composite OBJECT (dict), NOT a plain string — a bare string is rejected by the backend. Shape: {"countryCode": "+1", "number": "4155550100", "countryIdentifier": "us"} - address: composite OBJECT (dict), NOT a plain string — a bare string is rejected by the backend. Shape (sub-fields optional; at minimum pass {"formattedAddress": "..."}): {"formattedAddress": "...", "city": "...", "state": "..."} Returns the created vendor. Use its id as preferredVendorId on create_product_service / update_product_service. Call get_vendors first to check whether the vendor already exists.
create_visit
ChatGPTCreate a new visit/appointment for a job. REQUIRED parameters: - jobId: MongoDB ObjectId of the job (get from search_database or get_job_by_id) - visitStartDateTime: ISO 8601, local time in the ACCOUNT's timezone — send the wall-clock time the user said and do NOT convert to UTC yourself; a trailing "Z"/offset is IGNORED, not honoured (e.g., "2026-01-25T14:00:00") - visitEndDateTime: ISO 8601, same local-time rule (e.g., "2026-01-25T16:00:00") - teamId: team-member id(s) from get_teams — one 24-hex id as a plain string, or several as a JSON-array string, e.g. '["6a17e04da8237fae54dcef8e","6a17e04da8237fae54dcef8f"]'. Not a name. OPTIONAL parameters: - visitStatus: account-specific — call get_data_model("visit") for valid values (default: "scheduled") - priority: "low", "medium", "high" (default: "medium") - scheduleLater: "true" or "false" as string (default: "false") - anyTime: "true" or "false" as string - flexible time (default: "false") - isExtraVisit: "true" or "false" as string - extra visit beyond original (default: "false") - skillsId: required skills for the visit
create_warehouse
ChatGPTCreate a warehouse / inventory location in FieldCamp. REQUIRED: - name: warehouse name. OPTIONAL: - warehouseType: stored as the warehouse type (e.g. 'Main Warehouse', 'Technician Truck/Van'). - address: composite OBJECT (dict), NOT a plain string — a bare string is rejected by the backend. Shape (all sub-fields optional; at minimum pass {"formattedAddress": "..."}): { "formattedAddress": "123 Main St, Austin, TX 78701, USA", "street": "123 Main St", "city": "Austin", "state": "TX", "country": "USA", "zipCode": "78701" } Returns the created warehouse. Use its id as fromWarehouseId / toWarehouseId on transfer_inventory and as the warehouse filter on get_inventory. Call get_warehouses first to check whether a matching location already exists.
delete_calendar_event
ChatGPTDelete an event from Google Calendar. REQUIRED: - eventId: string — ID of the calendar event to delete
delete_client
ChatGPTDelete a client from FieldCamp. ⚠️ WARNING: This is a destructive operation! REQUIRED: - client_id: MongoDB ObjectId of the client OPTIONAL: - forceDelete: "true" to permanently delete, "false" to soft delete (default: "false") Set forceDelete="true" to permanently delete the client and all associated data. Set forceDelete="false" to soft delete (can be recovered).
delete_inventory
ChatGPTDelete inventory item(s) from FieldCamp. ⚠️ WARNING: This is a destructive operation! REQUIRED: - delete_ids: Array of inventory item MongoDB ObjectIds OPTIONAL: - current_warehouse_id: MongoDB ObjectId of warehouse (when an item exists in multiple warehouses, this picks which one to delete)
delete_invoice
ChatGPTDelete invoice(s) or estimate(s) from FieldCamp. ⚠️ WARNING: This is a destructive operation! REQUIRED: - document_ids: Array of document MongoDB ObjectIds to delete
delete_job
ChatGPTDelete a single job from FieldCamp. ⚠️ WARNING: This is a destructive operation! REQUIRED: - job_id: MongoDB ObjectId of the job NOTE: This tool deletes ONE job at a time. If the user wants to delete multiple jobs, call this tool separately for each job_id.
delete_payment
ChatGPTDelete/reverse a payment transaction. Recalculates invoice balance. ⚠️ WARNING: Cannot reverse online payments (Stripe). REQUIRED: - transactionId: MongoDB ID of the payment record to delete - documentId: MongoDB ID of the invoice/estimate
delete_product_service
ChatGPTDelete product(s) or service(s) from FieldCamp. ⚠️ WARNING: This is a destructive operation! REQUIRED: - delete_ids: Array of product/service MongoDB ObjectIds to delete
delete_purchase_order
ChatGPTDelete one or more purchase orders in FieldCamp. REQUIRED: - delete_ids: array of purchase order ids to delete (from get_purchase_orders). DESTRUCTIVE: removes the purchase orders and their line items. Confirm with the user before calling.
delete_request
ChatGPTDelete a service request from FieldCamp (soft delete). ⚠️ WARNING: This is a destructive operation! REQUIRED: - request_id: MongoDB ObjectId of the request Sets the request status to 'Deleted' and removes related items and taxes. Only the request creator or parent user can delete.
delete_task
ChatGPTDelete a task from FieldCamp. ⚠️ WARNING: This is a destructive operation! REQUIRED: - task_id: MongoDB ObjectId of the task
delete_tax
ChatGPTDelete one or more tax rates in FieldCamp. REQUIRED: - delete_ids: array of tax ids to delete (from get_taxes). DESTRUCTIVE: soft-deletes the taxes (status='Deleted') and marks any QuickBooks tax mappings deleted. Existing documents keep their stored tax values. Admin / settings permission required. Confirm with the user before calling.
delete_vendor
ChatGPTDelete one or more vendors / suppliers in FieldCamp. REQUIRED: - delete_ids: array of vendor ids to delete (from get_vendors). DESTRUCTIVE: the backend archives each vendor and its related data, then removes the vendors and their purchase orders. Confirm with the user before calling.
delete_visit
ChatGPTDelete a visit/appointment from FieldCamp. ⚠️ WARNING: This is a destructive operation! REQUIRED: - visitId: MongoDB ObjectId of the visit
delete_warehouse
ChatGPTDelete one or more warehouses / inventory locations in FieldCamp. REQUIRED: - delete_ids: array of warehouse ids to delete (from get_warehouses). DESTRUCTIVE: the backend archives each warehouse and its related data, then removes inventory transfers/items in those warehouses and flags affected products as non-inventory. Confirm with the user before calling.
fetch
ChatGPTFetch the FULL record for a single type-prefixed id returned by search. This is step two of the search→fetch retrieval pair: after search finds a record, call fetch with its id to pull the complete details (all fields) for clients, jobs, visits, products/services, invoices, estimates, requests, and tasks. It routes to the correct underlying record lookup automatically based on the id prefix — you do NOT need to know or call the entity-specific get_*_by_id tool yourself. PARAMETERS: - id: the TYPE-PREFIXED id from a search result, e.g. "client:<id>", "job:<id>", "invoice:<id>", "estimate:<id>", "request:<id>", "product:<id>", "visit:<id>", "task:<id>" (or "custom:<slug>:<id>"). RETURNS a JSON object: {"id", "title", "text", "url", "metadata"} where text is the full record serialized as readable JSON, url is the app deep link, and metadata carries key fields (status, totals, type, ...).
get_all_team_members
ChatGPTGet all team members (no pagination - returns full roster). OPTIONAL: - view: "assignedTeam", "assignedSelf", or omit for all members Returns all active team members with name, email, role, skills, service areas, and schedule information. Use for: "Who's on the team?", "List all technicians", "Which team members have HVAC skills?"
get_analytics
ChatGPTGet business analytics and metrics data. This is the PREFERRED tool for totals, sums, rankings, and trends (e.g. total outstanding A/R, top clients, revenue over time) — it computes them server-side. Do not try to total these yourself by listing records. REQUIRED: - metric: The metric to retrieve (see list below) ⚠️ ALWAYS pass start_date AND end_date. Most metrics return an EMPTY result ("data": []) when no date range is given. For an "all-time" total, pass a wide range (e.g. start_date="2020-01-01" through a date in the future). Example: outstandingRevenue over a wide range returns the current total A/R; topRevenueClients returns the ranked client list. OPTIONAL: - start_date: ISO date (e.g., "2026-01-01") - end_date: ISO date (e.g., "2026-01-31") - group_by: "auto", "day", "week", "month", "quarter", "none" (default: "auto") - breakdown_by: dimension to break down by (see list below). NOTE: breakdown_by is applied PER-METRIC — not every dimension works with every metric, and a dimension the chosen metric doesn't support is silently ignored (no error; the result simply comes back without that breakdown). - filters: array of filter objects AVAILABLE METRICS: Jobs: totalJobsForChart, jobCompletionRate, jobVolumeTrends, avgJobValue, avgJobDuration, jobStatusDistribution, jobTypeDistribution, jobsByClient, jobsByAssignee Visits: totalVisits, visitSuccessRate, avgVisitDuration, visitsPerJob Financial: revenueTrends, paidRevenue, outstandingRevenue, overdueInvoiceAmount, invoiceCount, avgInvoiceValue, collectionRate, topRevenueClients, avgDaysToPayment Estimates: totalEstimates, estimateValue, estimateApprovalRate, estimateConversionRate CRM: newClientsOverTime, totalClients, totalRequests, clientConversionRate, requestConversionRate, clientsStages, requestsByStage Tasks: totalTasks, taskCompletionRate, overdueTasksCount, tasksByStatus, tasksByPriority Workforce: scheduledHoursByTechnician, jobsPerTechnician, technicianRevenue Geographic: jobsByCity, revenueByCity, clientsByCity BREAKDOWN DIMENSIONS: createdBy, assignedTo, teamId, clientId, clientType, clientStage, jobStatus, paymentStatus, visitStatus, jobType, city, state
get_available_team_members_schedule
ChatGPTGet available team members for a specific time slot. Checks both visit overlaps and team member schedules (weeklySchedule/specificHours). REQUIRED parameters: - visitStartDateTime: ISO 8601 start of the window, local time in the ACCOUNT's timezone — send the wall-clock time the user said and do NOT convert to UTC yourself; a trailing "Z"/offset is IGNORED, not honoured - visitEndDateTime: ISO 8601 end of the window, same local-time rule - timezone: string — user's timezone (e.g. 'Asia/Kolkata') OPTIONAL: - requiredSkillIds: array of skill IDs to filter by required skills - excludeJobId: string — exclude this job from conflict check
get_calendar_activity
ChatGPTGet recent calendar activity feed (status changes, assignments, completions, alerts). OPTIONAL parameters: - limit: integer (1-50, default: 20) — max activities to return - since: ISO 8601 datetime — get activities since this date (default: 24 hours ago) - types: comma-separated string — filter: 'status_change', 'assignment', 'completion', 'alert'
get_calendar_events
ChatGPTFetch calendar events including visits, invoices, tasks, requests, and Google Calendar events. OPTIONAL parameters: - month: integer (1-12) — month to fetch events for - year: integer (e.g. 2026) — year to fetch events for - source: string — filter by source: 'google_calendar', 'job_visits', 'invoices', 'estimates', 'tasks', 'requests' - eventTypes: JSON array string — event types: ['all', 'visits', 'invoices', 'estimates', 'tasks', 'requests', 'events'] - view: string — 'ownEvents' for personal events only - clientId: string — MongoDB ID to filter events by client - upcoming: string — 'true' to get upcoming events only - email: string — filter events tied to a specific user email - isFromClientEvents: boolean — scope the fetch to the client-events feed - fetchOnlyEvents: boolean — return only Google Calendar events (skip visits/invoices/tasks/requests)
get_client_by_id
ChatGPTGet complete client details by MongoDB ObjectId. PARAMETERS: - client_id: MongoDB ObjectId of the client Returns all client information including name, contact details, property address, billing address, tags, custom fields, and metadata.
get_client_documents
ChatGPTGet documents (invoices and estimates) for a specific client. REQUIRED: - client_id: MongoDB ObjectId of the client OPTIONAL: - view: Set to "assigned" to only see documents assigned to current user Returns list of documents with document type (1=Invoice, 2=Estimate), document number, status, payment status, title, total, and date.
get_client_payment_history
ChatGPTGet payment history for a specific client. REQUIRED: - client_id: MongoDB ObjectId of the client OPTIONAL: - view: Set to "assigned" to only see payments from documents assigned to current user Returns list of payments with document number, payment amount, payment date, payment method, document total, and payment status. Sorted by payment date descending.
get_client_products
ChatGPTGet products associated with a specific client from their jobs. REQUIRED: - client_id: MongoDB ObjectId of the client OPTIONAL: - view: Set to "assigned" to only see products from jobs assigned to current user Returns list of products with item name, description, quantity, price, total, and linked job number.
get_company_info
ChatGPTGet company information and settings. OPTIONAL: - withCurrencyData: when True, backend enriches the response with extra currency metadata. Default False (flag omitted from wire). Returns company details including business name, address, phone, email, website, timezone, currency, industry, mileage tracking settings, labor rate settings, and other configuration. Use for: Understanding business context (timezone, currency, industry) before performing operations.
get_company_schedule
ChatGPTGet the company's weekly business hours and specific hour exceptions (holidays, special hours). Returns weeklySchedule (7 days) and specificHours (date-specific overrides).
get_data_model
ChatGPTReturn THIS account's LIVE, customized schema — the real pipeline status values, allowed transitions, and custom fields for an object. Pipelines, statuses and fields are CUSTOMIZABLE per account, so the default status names mentioned in other tools may not match this account. Call this BEFORE filtering/setting a status or creating/updating a record whenever you are unsure of the valid values for THIS account — then use the exact values it returns. Scoped to the caller's own organization. object_type: "client", "job", "visit", "invoice", "estimate", "request", "task", or "all" (default). Also accepts any CUSTOM object slug (tenant-defined — e.g. "unit"). "all" lists custom objects by name only; pass the specific slug to get its fields (keyed by canonical field NAME — use these exact names in create_record/update_record data), stages, transitions, and conversion actions (valid rule_id values for convert_record).
get_dispatch_suggestions
ChatGPTGet AI-powered dispatch suggestions for unassigned visits. Recommends technicians based on workload, availability, and client relationships. OPTIONAL parameters: - visitId: string — get suggestions for a specific unassigned visit - date: string (YYYY-MM-DD) — target date for finding unassigned visits (default: today)
get_document_number
ChatGPTGet the next available document number for invoices or estimates. REQUIRED: - documentType: integer — 1=Invoice, 2=Estimate
get_filtered_clients
ChatGPTGet clients with advanced filtering, pagination, and sorting. REQUIRED: - filters: Array of filter objects (can be empty [] to get all clients) OPTIONAL: - view, page, limit, sorting, stage - limit: max records per page (server-clamped to 30) VALID FILTER FIELDS (use ONLY these — any other field name returns HTTP 400): - firstName, lastName, email, companyName, website, taxNumber - stage: ACCOUNT-SPECIFIC — call get_data_model("client") for this account's real stage values (accounts rename/replace the defaults; sending a stale default fails or mislabels the client) - clientType: "business" or "individual" - propertyAddress (address filter — see CRITICAL note below) - createdAt, updatedAt (use ISO date: "2026-01-15") - notes ⚠️ CRITICAL: For address filtering, use the single field "propertyAddress" (it matches across street/city/state/country/zipCode/formattedAddress): - ✅ CORRECT: field="propertyAddress", value="Toronto" - ❌ WRONG: "city"/"state"/"country" or "propertyAddress.city" → HTTP 400 ("'<field>' is not a valid field") NOTE: "tags" is NOT a filterable field on clients (returns HTTP 400). STAGE PARAMETER (optional convenience filter - EXACT string match, no shortcuts): The backend matches stage as an EXACT string, and stage values are ACCOUNT-SPECIFIC (accounts rename/replace the defaults) — call get_data_model("client") for this account's real values before filtering. There is NO "pipeline"/"all"/"active"/"leads"/"clients" stage value; those will match nothing. To list ALL clients (every stage), OMIT the stage parameter AND pass filters=[] (empty array). Filter structure (stage value below is a PLACEHOLDER — use this account's real values from get_data_model("client")): [ {"filterCondition": "", "field": "stage", "condition": "is", "value": "<stage value>"}, {"filterCondition": "and", "field": "propertyAddress", "condition": "contains", "value": "Toronto"} ] Condition operators: - Text: contains, doesNotContain, is, isNot, startsWith, endsWith, isEmpty, isNotEmpty - Dates (createdAt/updatedAt): equalTo, lessThan, greaterThan, dateRange, isEmpty, isNotEmpty (use EXACTLY these tokens — "equals"/"before"/"after" are NOT accepted: before/after → HTTP 400; "equals" silently returns UNFILTERED results) - Select: is, isNot Example by stage: stage="<value from get_data_model>" parameter OR filters with field="stage" Example for Toronto clients: [{"filterCondition": "", "field": "propertyAddress", "condition": "contains", "value": "Toronto"}]
get_filtered_jobs
ChatGPTGet jobs with advanced filtering, pagination, and sorting. REQUIRED: - filters: Array of filter objects OPTIONAL: - view, page, limit, sorting - limit: max records per page (server-clamped to 30) VALID FILTER FIELDS (use ONLY these - flat field names, NO nested paths): - jobStatus: FIXED backend allow-list (exact values, backend 400s on anything else): "draft", "scheduled", "in-progress", "completed", "invoiced", "paid", "cancelled", "on-hold", "closed" - jobType: "one-off", "recurring", "multi-day" - jobNumber, clientName, description (internalNotes) - jobAddress: SINGLE address field that searches street/city/state/country/zip together (use condition "contains"). There are NO flat city/state/country filter fields for jobs. - startDateTime, endDateTime, createdAt, updatedAt (use ISO date: "2026-01-15") - total, subTotal, discount, tax (numeric) - priority: "low", "medium", "high" - assignedToTeams ⚠️ CRITICAL: For address filtering on jobs, use the single jobAddress field: - ✅ CORRECT: {"field": "jobAddress", "condition": "contains", "value": "Toronto"} - ❌ WRONG: "city", "state", "country" (these are NOT valid job filter fields) - ❌ WRONG: "jobAddress.city" (no nested paths) Filter structure: [ {"filterCondition": "", "field": "jobStatus", "condition": "is", "value": "in-progress"}, {"filterCondition": "and", "field": "jobAddress", "condition": "contains", "value": "Toronto"} ] Condition operators: - Text: contains, doesNotContain, is, isNot, startsWith, endsWith, isEmpty, isNotEmpty - Dates: equals, before, after, isEmpty, isNotEmpty (dates apply to fields startDateTime, endDateTime, createdAt, updatedAt) - Numeric: equals, notEquals, greaterThan, lessThan, greaterThanOrEqual, lessThanOrEqual - Select: is, isNot NOT SUPPORTED — filtering jobs by a single assignee: The backend has NO assignee filter handler for jobs (assignments live in assignedToTeams and there is no server-side filter for them). Do NOT rely on the assigned_to_id parameter to narrow jobs to one person — it is not applied server-side and will not return a useful/filtered result. Example for jobs by client: [{"filterCondition": "", "field": "clientName", "condition": "contains", "value": "John"}] Example for jobs in Toronto: [{"filterCondition": "", "field": "jobAddress", "condition": "contains", "value": "Toronto"}]
get_history
ChatGPTGet activity history for any entity (audit trail). REQUIRED: - module_id: MongoDB ObjectId of the record - module_type: "job", "visit", or a CUSTOM-OBJECT SLUG. Custom-object records DO have history: create/update/delete each write a History row keyed by the object slug. Pass the slug field from list_object_definitions VERBATIM — it is not the plural form and not the display name (real slugs look like "warnty", "contract_renewal", "all_mode", whose namePlural is a separate display-only field). A record with no history yet returns an empty list, which means "nothing recorded for this record", not "unsupported". NOT available here: "client" and "request". Client activity lives in a separate clientHistory table this endpoint does not read, and request activity is not recorded at all — both return an EMPTY result rather than an error, so do not read an empty response as "nothing ever changed". OPTIONAL: - page: page number (default: 1) - limit: max records per page (server-clamped to 30) Returns chronological activity log including who made changes, what was changed, descriptions, and timestamps. Use for: "What changes were made to this job?", "History of this visit?"
get_inventory
ChatGPTGet inventory data with filtering and pagination. REQUIRED: OPTIONAL PARAMETERS: - page: Page number (default: 1) - limit: max records per page (server-clamped to 30) - type: Warehouse type filter. This is FREE-TEXT and CASE-SENSITIVE, and the valid values are account-specific — NOT a fixed enum. Do NOT guess values like "Main Warehouse" or "Technician Truck/Van"; call get_warehouses first and pass a warehouse's actual name/type string exactly as returned. - warehouse: MongoDB ObjectId of specific warehouse - lowStock: "true" or "false" - filter for low stock items only - category: MongoDB ObjectId of category - id: MongoDB ObjectId to get specific inventory item RETURNS: Inventory items with quantity, SKU, warehouse location, item info (name, price, type), categories, and stock alerts. Use for: checking stock levels, finding low stock items, filtering by warehouse.
get_inventory_by_id
ChatGPTGet inventory item details by MongoDB ObjectId. REQUIRED: - inventory_id: MongoDB ObjectId of the inventory item Returns complete inventory information including item details, warehouse, quantity, SKU, and metadata.
get_invoice_by_id
ChatGPTGet invoice or estimate details by MongoDB ObjectId. PARAMETERS: - document_id: MongoDB ObjectId of the invoice/estimate Returns complete document information including line items, payments, client details, and status.
get_invoices
ChatGPTGet invoices or estimates with advanced filtering. REQUIRED: - documentType: 1 for Invoices, 2 for Estimates - filters: Array of filter objects OPTIONAL: - view, page, limit, sorting - limit: max records per page (server-clamped to 30; use -1 for summary mode) VALID FILTER FIELDS (use ONLY these): - documentNumber, title, privateNotes, comments - client, clientName, clientEmail, clientCity, clientState - total, subTotal, paidAmount (numeric) - documentStatus: ONLY these values are accepted (backend 400s on anything else): "draft", "sent", "approved", "viewed", "pending", "approved_pending_signature". (Do NOT pass "declined", "expired" or "awaiting response" as a documentStatus — they are rejected. For an estimate's accept/decline outcome use actionStatus below instead.) - actionStatus (ESTIMATES ONLY): the customer's decision on an estimate. 0 = pending / awaiting customer response, 1 = approved, 2 = declined. ⚠️ To answer "how many estimates are awaiting / approved / declined", filter documentType=2 by actionStatus — NOT documentStatus. (An approved or declined estimate usually still has documentStatus "draft"/"sent", so filtering documentStatus="declined" wrongly returns nothing.) e.g. {"filterCondition":"","field":"actionStatus","condition":"is","value":2} - paymentStatus: ONLY these values are accepted (backend 400s on anything else): "unpaid", "partial", "paid", "overdue". (Do NOT pass "draft", "sent", "pending" or "canceled" as a paymentStatus — they are rejected.) - date, dueDate, createdAt, updatedAt (use ISO date: "2026-01-15") - createdBy, paymentTerms Filter structure: [ {"filterCondition": "", "field": "paymentStatus", "condition": "is", "value": "unpaid"}, {"filterCondition": "and", "field": "total", "condition": "greaterThan", "value": 1000} ] ⚠️ TOTALS / "HOW MUCH IS OWED" — DO NOT paginate and add up amounts yourself (that is error-prone). Call this tool with limit=-1: it returns server-computed summary_statistics { total_documents, total_amount, total_paid, total_outstanding, payment_status_breakdown } plus a few sample_documents. Note "unpaid" alone excludes "partial" and "overdue" — to get the TOTAL amount owed, either filter by all three or (better) use get_analytics metric="outstandingRevenue" / "topRevenueClients" with a date range.
get_job_by_id
ChatGPTGet complete job details by MongoDB ObjectId. PARAMETERS: - job_id: MongoDB ObjectId of the job - view: View options: 'all', 'own', 'viewAssigned' (default: 'all') Returns job information including client, visits, line items, invoices, and metadata.
get_job_types
ChatGPTList this account's job-type catalog — the named service types jobs are classified by (e.g. "Annual PM", "6-Month Checkup"), each with an id, description, and estimated duration. Use the returned id as jobTypeId in create_job/update_job job_data. Job types are account-defined; never guess a jobTypeId. PARAMETERS: - page / limit: pagination - search: filter by title (contains, case-insensitive)
get_next_job_number
ChatGPTGet the next available job number. Returns the next sequential job number for job creation. Useful for previewing the job number before creating a job.
get_payment_history
ChatGPTGet payment history for an invoice or estimate. REQUIRED: - documentId: MongoDB ID of the document Returns: total, paidAmount, paymentStatus, and array of payment records with amount, date, method, note, and transaction details.
get_product_categories
ChatGPTList product/service categories configured in FieldCamp (reference data). OPTIONAL: - search: case-insensitive substring to match a category name. Returns categories with id and name. The ids are the valid values for the categoryIds field on create_product_service / update_product_service and for the category filter on get_inventory. NOTE: the backend returns at most 10 categories. With no search term you get the first 10 alphabetically — pass search to locate a specific category that may fall outside that first 10.
get_product_service_by_id
ChatGPTGet product or service details by MongoDB ObjectId. PARAMETERS: - product_service_id: MongoDB ObjectId of the product/service Returns complete product/service information including name, type, price, inventory status, tax settings, and custom properties.
get_products_services
ChatGPTGet products and services with advanced filtering. REQUIRED: - filters: Array of filter objects OPTIONAL: - page, limit - limit: max records per page (server-clamped to 30; use -1 for summary mode) VALID FILTER FIELDS (use ONLY these): - name, description - type: "Product" or "Service" - price (numeric) - status: "available" or "unavailable" — use this to filter active vs inactive products/services (field="status", value="available" for active). - createdAt, updatedAt (use ISO date) NOT filterable here (the backend cannot filter on these — passing them returns 0 results, so do NOT use them as filter fields): isActive, trackInventory, exemptFromTax. For active/inactive use field="status" above. Filter structure: [ {"filterCondition": "", "field": "type", "condition": "is", "value": "Product"}, {"filterCondition": "and", "field": "price", "condition": "greaterThan", "value": 100} ] Returns summary statistics for large result sets to prevent token overflow.
get_purchase_orders
ChatGPTList purchase orders in FieldCamp. OPTIONAL: - page: page number (default 1). - limit: max records per page (server-clamped to 30). - status: filter by PO status. Valid values: "Draft", "Ordered", "Received", "Canceled". If omitted, NO status filter is applied and purchase orders of ALL statuses are returned (it does NOT default to "Ordered"). Each purchase order includes its vendor and line items.
get_record
ChatGPTGet one custom-object record by MongoDB ObjectId. Returns the record's status (pipeline stage), its data object (keyed by canonical field names — see get_data_model(slug)), and system timestamps.
get_record_summary
ChatGPTFinancial/progress rollups for one custom-object record, resolved server-side in a single call: jobs targeting this record plus invoices linked to them (all-time / windowed / paid totals and counts), and a newest-first per-job invoiced history. Use this for "how much have we spent on this unit?" / "repair or replace?" questions instead of listing jobs and invoices yourself.
get_request_by_id
ChatGPTGet complete service request details by MongoDB ObjectId. REQUIRED: - request_id: MongoDB ObjectId of the request Returns full request including client details, line items (requestItems), taxes (requestTaxes), stage, and all metadata.
get_requests
ChatGPTGet service requests with filtering, pagination, and sorting. OPTIONAL: - page: page number (default: 1) - limit: max records per page (server-clamped to 30) - tab: "requests" (active), "pipeline", "archived" (default: "requests") - view: "all" or "assigned" (default: "all") - filters: array of filter objects - sorting: array of sorting objects - client_id: filter by client MongoDB ObjectId FILTERABLE FIELDS: requestNumber, clientName, clientEmail, description, source, urgency, stage, estimatedValue, createdAt, assignedTo, notes, startDate, endDate STAGE filter: exact string match, and stage slugs are ACCOUNT-SPECIFIC (request pipeline is org-configurable) — call get_data_model("request") for this account's real slugs before filtering. Built-in default slugs: new_request, unscheduled, overdue, inspection_scheduled, inspection_complete, quote_created, quote_sent, converted, lost_no_response, lost_reject_quote, cancelled, duplicate Returns requests with client info, stage counts, and pagination.
get_task_by_id
ChatGPTGet complete task details by MongoDB ObjectId. REQUIRED: - task_id: MongoDB ObjectId of the task Returns task information including name, schedule, assignee, linked records, status, and instructions.
get_tasks
ChatGPTGet all tasks with sorting options. REQUIRED: OPTIONAL PARAMETERS: - sort: string enum — the ONLY values the backend supports are "due_date", "creation_date", "assignee" (default: "due_date"). Any other value (e.g. "priority", "created_at", "status") is not supported. - order: "ascending" or "descending" (default: "descending") RETURNS: Tasks grouped by status: - overdue: Past due tasks - today: Due today - thisWeek: Due this week - upcoming: Future tasks - completed: Finished tasks Each task includes: name, priority, due date, assigned team member, client/job linkage, category, and completion status.
get_tasks_by_client
ChatGPTGet tasks linked to a specific client, paginated. REQUIRED: - client_id: MongoDB ObjectId of the client OPTIONAL: - page: Page number (default: 1) - limit: max records per page (server-clamped to 30) - view: Set to "Assigned" to only see tasks assigned to current user Returns paginated task list sorted by schedule date, with total count.
get_tasks_by_job
ChatGPTGet tasks linked to a specific job, paginated. REQUIRED: - job_id: MongoDB ObjectId of the job OPTIONAL: - page: Page number (default: 1) - limit: max records per page (server-clamped to 30) Returns only tasks where linkType is 'job' matching the given job ID. Sorted by schedule date with total count.
get_taxes
ChatGPTGet tax rates configured in FieldCamp. OPTIONAL: - page: page number (default: 1) - limit: max records per page (server-clamped to 30) - name: search by tax name (case-insensitive) Returns tax rates with name, rate percentage, tax type (exclusive/inclusive), state/country info, and application rules. Use for: Looking up available tax rates before creating invoices or estimates.
get_team_member
ChatGPTGet complete team member details by MongoDB ObjectId. REQUIRED: - team_member_id: MongoDB ObjectId of the team member Returns full team member profile including name, email, phone, role, skills, service areas, schedule, labor rates, and availability.
get_teams
ChatGPTGet team members with advanced filtering and pagination. OPTIONAL: - filters: array of filter objects (same format as client filters) - page: page number (default: 1) - limit: max records per page (server-clamped to 30) - view: "all" or "own" (default: "all") - sorting: array of sorting objects [{field, order}] - assignable_only: "true" to only show members assignable to jobs FILTERABLE FIELDS: name, email, status, phoneNumber, address, createdAt, roleId, skillsId Filter structure: [ {"filterCondition": "", "field": "name", "condition": "contains", "value": "John"}, {"filterCondition": "and", "field": "status", "condition": "is", "value": "Active"} ]
get_units_of_measurement
ChatGPTList the units of measurement configured in FieldCamp (reference data). No params. Returns the full org-wide list; each entry has an id, name, and abbreviation. Use this to find a valid unitOfMeasurementId BEFORE calling create_product_service or update_product_service. Pricing a product without a unit leaves it unitless, which lets a flat per-job price be multiplied by an area/quantity in estimates (e.g. 2000 sqft × $9500 = $19M). This is the only tool that enumerates valid unit ids.
get_vendors
ChatGPTList vendors / suppliers configured in FieldCamp (reference data). OPTIONAL: - page: page number (default 1) - limit: max records (default -1 = all; any other value server-clamped to 30) - search: match vendor name or email (case-insensitive) Returns each vendor with id, name, email, phone, address, and status. The id is the valid value for the preferredVendorId field on create_product_service / update_product_service. Use this to find a valid preferredVendorId BEFORE creating or updating a product with a preferred vendor — this is the only tool that enumerates vendor ids.
get_visit_by_id
ChatGPTGet complete visit/appointment details by MongoDB ObjectId. PARAMETERS: - visit_id: MongoDB ObjectId of the visit Returns visit information including job details, assigned team, schedule, status, and notes.
get_visit_stats
ChatGPTGet visit statistics and list for a date range (dispatcher dashboard). OPTIONAL: - start_date: YYYY-MM-DD format (omit both dates for all visits) - end_date: YYYY-MM-DD format - view: "all", "ownEvents", "viewAssigned" (default: "all") RETURNS: - stats: {total, completed, pending, scheduled, in_transit, arrived, in_progress, paused, cancelled, active, unassigned} - visits: array of visits with job and client details Use for: "How many visits today?", "What's unassigned this week?", "Status breakdown for this month?"
get_visits_for_job
ChatGPTGet all visits/appointments for a specific job. REQUIRED: - job_id: MongoDB ObjectId of the job Returns all active visits for the job with team member details, schedule, status, notes, and GPS tracking data. Sorted by start time.
get_warehouses
ChatGPTList warehouses / inventory locations configured in FieldCamp (reference data). OPTIONAL: - page: page number (default 1) - limit: max records (default -1 = all; any other value server-clamped to 30) Returns each warehouse with id, name, address, and type. These ids are the valid values for transfer_inventory (fromWarehouseId / toWarehouseId) and the warehouse filter on get_inventory. Use this to discover warehouse ids BEFORE transferring stock or filtering inventory by location — otherwise the ids can only be scraped from get_inventory results.
list_object_definitions
ChatGPTDiscover this account's CUSTOM objects (tenant-defined record types such as "unit" or "warranty" — objects beyond the built-in clients/jobs/etc.). Returns for each object: slug (use it in every other *_record tool), names, record/field counts, whether it is schedulable, and its recordActions (valid action_key values for run_record_action). Call this FIRST when the user mentions a record type you don't recognize. Then call get_data_model("<slug>") for the object's fields and stages.
list_records
ChatGPTList records of a CUSTOM object (e.g. slug="unit"). Call get_data_model(slug) first for this object's field names and valid status values — statuses are account-specific. PARAMETERS: - slug: the custom object's slug (from list_object_definitions) - page / limit: pagination (limit is clamped server-side) - search: free-text search over the object's searchable fields - status: filter by pipeline stage value (exact value from get_data_model) - filters: array of {field, condition, value}. field is a canonical field NAME from get_data_model(slug); condition is one of: is, isNot, contains, isEmpty, isNotEmpty, greaterThan, lessThan, equals, in (value must be an array for in). Example: [{"field": "next_pm_date", "condition": "lessThan", "value": "2026-09-01"}] - linked_record_id: only records related to this parent record id (e.g. all units of one client) - sort_field / sort_order: createdAt|updatedAt|status|id sort at the DB; any custom field name sorts in the application layer. asc|desc.
record_payment
ChatGPTRecord a manual payment on an invoice or estimate. REQUIRED: - documentId: MongoDB ID of the invoice/estimate - amount: payment amount (number) - date: ISO 8601 payment date (e.g. '2026-03-10') OPTIONAL: - method: payment method (e.g. 'cash', 'check', 'card', 'bank_transfer') - note: payment note/memo - paymentTypeCode: payment type classification - isDepositPayment: mark as deposit payment (default: false) Updates the document's paidAmount and paymentStatus (unpaid → partial → paid).
resolve_record_hierarchy
ChatGPTResolve a custom-object record's ancestor chain, ROOT-FIRST (e.g. Location → Unit → Equipment), with each level's visible fields. Use when a record belongs to a nested structure and you need its parents (e.g. which Location a Unit sits at). slug/record_id identify the LEAF.
run_record_action
ChatGPTExecute a configured action button on a custom-object record (e.g. "Renew Now") — this RUNS the operation, which may create jobs or other records. Confirm with the user before calling. Valid action_key values: the object's recordActions from list_object_definitions(). Some actions accept an optional job_id.
search
ChatGPTSearch for ANY record across the entire FieldCamp CRM by name or keyword — clients, jobs, products/services, invoices, estimates, and service requests. USE THIS FIRST. When the user says "find", "look up", "search for", "tell me about", "who is", "what's the status of", or "pull up <X>" and you don't already know the record's exact id or even its type, call search BEFORE any entity-specific get_ tool (get_clients / get_filtered_jobs / get_products_services / get_invoices / get_requests / ...). One call searches every entity at once, so you avoid serially probing each type. PARAMETERS: - query: free text — a name, company, job number, document number, keyword, etc. (e.g. "Acme", "John Smith", "invoice 1042", "drain cleaning"). RETURNS a JSON object: {"results": [{"id", "title", "url", "text"}, ...]}. - id is TYPE-PREFIXED ("client:<id>", "job:<id>", "product:<id>", "invoice:<id>", "estimate:<id>", "request:<id>") — pass it straight to `fetch` to open the full record (no need to guess the type). - title is a human label, url is the app deep link, text is a short snippet to judge relevance before fetching. - Capped at ~20 results, interleaved across entity types by priority. After `search`, call `fetch(id)` on the most relevant result to read the full record. Prefer search→fetch over the entity-specific list/get__by_id tools for open-ended "find / look up / tell me about" questions. ⚠️ CUSTOM-OBJECT records (tenant-defined types like "unit" — anything in list_object_definitions) are NOT in this index. To find those, use list_records(slug, search=...) instead; fetch can still open them by "custom:<slug>:<id>".
send_document_email
ChatGPTSend an invoice or estimate to a client via email. REQUIRED: - to: array of recipient email addresses - subject: email subject line - message: email message body OPTIONAL: - documentId: MongoDB ID of the document (for tracking) - documentType: 1=Invoice, 2=Estimate - documentNumber: document number (for PDF filename) - documentViewUrl: URL for 'View Document' button in email - cc: array of CC email addresses - bcc: array of BCC email addresses - attachPdf: boolean — attach rendered PDF (default: false)
transfer_inventory
ChatGPTTransfer inventory between warehouses. REQUIRED: - fromWarehouseId: source warehouse MongoDB ID - toWarehouseId: destination warehouse MongoDB ID (must differ from source) - inventoryId: inventory record MongoDB ID to transfer from - quantity: number of units to transfer (must be > 0 and <= available stock) OPTIONAL: - note: transfer note/reason
update_calendar_event
ChatGPT⚠️ CALL SHAPE — pass arguments exactly as: {"event_data": { "eventId": "<id>", ...fields... }} All record fields go INSIDE the *_data object, NOT at the top level (top-level keys are rejected as "unexpected keyword argument"). Update an existing Google Calendar event. REQUIRED fields in event_data: - eventId: string — ID of the event to update OPTIONAL fields: - title: string — new title - start: ISO 8601 datetime — new start, local time in the ACCOUNT's timezone — send the wall-clock time the user said and do NOT convert to UTC yourself; a trailing "Z"/offset is IGNORED, not honoured - end: ISO 8601 datetime — new end, same local-time rule - timeZone: IANA name — the calendar provider's display zone only; start/end are still read in the ACCOUNT's timezone - isAllDay: boolean - location: string or object - description: string - recurrence: object — new recurrence rules - attendees: array — updated attendees (set status='removed' to remove) - sendNotifications: boolean — notify attendees of changes - colorId: string — new color
update_client
ChatGPT⚠️ CALL SHAPE — pass arguments exactly as: {"client_id": "<id>", "client_data": { ...fields to change... }} All record fields go INSIDE the *_data object, NOT at the top level (top-level keys are rejected as "unexpected keyword argument"). Update an existing client's information. REQUIRED: - client_id: MongoDB ObjectId (from search_database or get_filtered_clients) UPDATABLE fields (provide only what you want to change): - firstName, lastName, email, companyName, website, taxNumber - phoneNumber: {countryCode: "+1", number: "5559999999", countryIdentifier: "us"} - propertyAddress, billingAddress, companyAddress: {city, state, country, formattedAddress} - stage: ACCOUNT-SPECIFIC — call get_data_model("client") for this account's real stage values (accounts rename/replace the defaults; sending a stale default fails or mislabels the client) - clientType: "business" or "individual" - notes, properties (there is no tags field on clients) Example: { "phoneNumber": {"countryCode": "+1", "number": "5559999999", "countryIdentifier": "us"} }
update_document
ChatGPT⚠️ CALL SHAPE — pass arguments exactly as: {"document_id": "<id>", "document_data": { ...fields to change... }} All record fields go INSIDE the *_data object, NOT at the top level (top-level keys are rejected as "unexpected keyword argument"). Update an existing invoice or estimate. REQUIRED: - document_id: MongoDB ObjectId of the document - document_data: Dictionary of fields to update ⚠️ There is NO top-level status field. Passing {"status": "..."} is a silent no-op (it changes nothing). Use documentStatus / actionStatus below. UPDATABLE fields (provide only what you want to change): - documentStatus: ACCOUNT-SPECIFIC (document pipeline is org-configurable) — call get_data_model("invoice") / get_data_model("estimate") for this account's real values. PATCH does not reject other strings (it stores whatever is sent), so a guessed value silently mislabels the document. Built-in defaults: "draft", "approved", "sent", "viewed", "pending", "approved_pending_signature". - actionStatus (ESTIMATES ONLY): record the customer's decision — 1 = accept, 2 = decline. - documentType: 1 (Invoice) or 2 (Estimate) - clientId: MongoDB ObjectId - jobId: MongoDB ObjectId - items: array of line items; per-line tax is set with taxIds (an array of tax ObjectIds), e.g. {"name": "...", "quantity": 1, "rate": 100, "taxIds": ["<taxId>"]}. (There is NO per-line taxes array of {name,rate}.) - comments: string (customer-facing notes) - privateNotes: string (internal notes) - date: ISO date (YYYY-MM-DD) — the issue/document date - dueDate: ISO date (YYYY-MM-DD) - discount: number ⚠️ PAYMENT STATUS CANNOT BE SET HERE. There is no way to mark a document paid/partial via this tool — recording a payment (which drives paid/partial) must go through the record_payment tool. Example (send an invoice/estimate to the customer): { "documentStatus": "sent" } NOTE: This tool sends PATCH on the wire (partial update). The backend bridge at /documents/[id]/route.js also accepts PUT as an alias, but PATCH is the canonical method.
update_job
ChatGPT⚠️ CALL SHAPE — pass arguments exactly as: {"job_data": { "jobId": "<jobId>", ...fields... }, "notes": "optional"} All record fields go INSIDE the _data object, NOT at the top level (top-level keys are rejected as "unexpected keyword argument"). Update an existing job's information. REQUIRED parameters: - job_data: Dictionary containing job information OPTIONAL parameters: - notes: Additional notes (default: "") REQUIRED in job_data: - jobId: MongoDB ObjectId (from search_database, NOT the job number!) UPDATABLE fields: - jobAddress, jobPhone: objects - startDateTime, endDateTime: ISO 8601, local time in the ACCOUNT's timezone — send the wall-clock time the user said and do NOT convert to UTC yourself; a trailing "Z"/offset is IGNORED, not honoured - jobStatus: a status CHANGE is validated against the org's configurable job pipeline. If the org has no pipeline config, any value is accepted; if it does, an invalid transition returns HTTP 400 (invalidStatusTransition) and the valid stages are org-defined (may include custom values) — call get_data_model("job") for this account's real stages and allowed transitions before changing status. - jobType: "one-off", "recurring", "multi-day" - priority: "low", "medium", "high" - subTotal, tax, total, discount: numbers - discountType: string - jobItems: array of line-item objects, each ADDING to, editing or removing a line the job already has — this array does NOT replace the job's line items: • add — `itemName` (string) + `price` (per-unit number); `quantity` defaults to 1 and `total` is auto-computed (pricequantity). Reference an existing catalog item with itemId (24-hex items id — NOT productServiceId/id); omit it for an ad-hoc line. • edit — id (the LINE's 24-hex id, from get_job_by_id) + action: 2, plus only the fields that change. • remove — id + action: 3, nothing else. To replace a job's lines, remove the old ones in the same call as the new ones. subTotal/total are recomputed from the lines the job ends up with (the backend derives no money of its own) unless you send them yourself. - assignedToTeams: array of team IDs - jobTypeId: id from get_job_types (the account's job-type catalog) - targetRecordId + targetObjectSlug: link/relink the job to a custom-object record (e.g. targetObjectSlug="unit") - ⚠️ linkedRecords is NOT accepted (rejected with 400 — the backend silently drops it). Use targetRecordId + targetObjectSlug above instead. - billToClientId: bill a different client than the job's clientId - anyTime, serviceDuration, timezone, properties Example job_data: { "jobId": "689abc123def456", "jobStatus": "in-progress", "priority": "high" }
update_product_service
ChatGPT⚠️ CALL SHAPE — pass arguments exactly as: {"product_service_id": "<id>", "product_service_data": { ...fields to change... }} All record fields go INSIDE the *_data object, NOT at the top level (top-level keys are rejected as "unexpected keyword argument"). Update an existing product or service in FieldCamp. REQUIRED: - product_service_id: MongoDB ObjectId of the product/service - product_service_data: Dictionary of fields to update OPTIONAL fields in product_service_data: - name: string (1-100 chars) - description: string - type: "Product" or "Service" - price: number (>= 0) - cost: number (>= 0) - currency: string - duration: integer (minutes, for services) - isActive: boolean - status: string ("available" or "unavailable") - isTaxExempt: boolean - isInventoried: boolean (toggles inventory tracking; if true, inventory required) - inventory: object {locationId (REQUIRED 24-hex warehouse id — the warehouse key is locationId, NOT warehouseId/warehouse/location), sku (REQUIRED, globally unique), quantity, lowStockAlert, binLocation} - taxIds: array of tax IDs - categoryIds: array of category IDs - properties: array (custom properties) - settings: object (online booking settings) - pricingType: "fixed" or "hourly" - hourlyRate: number (required if pricingType="hourly") - billingBasis: "scheduled" or "actual" - minimumCharge: number
update_record
ChatGPTUpdate fields of a custom-object record. Send ONLY the fields you are changing, keyed by canonical field NAME (call get_data_model(slug) first). Does NOT change the record's pipeline stage — use change_stage for that.
update_request
ChatGPT⚠️ CALL SHAPE — pass arguments exactly as: {"request_id": "<id>", "request_data": { ...fields to change... }} All record fields go INSIDE the *_data object, NOT at the top level (top-level keys are rejected as "unexpected keyword argument"). Update an existing service request. REQUIRED: - request_id: MongoDB ObjectId of the request - request_data: Dictionary of fields to update UPDATABLE fields: - stage: ACCOUNT-SPECIFIC (request pipeline is org-configurable) — call get_data_model("request") for this account's real stage slugs. Built-in default slugs: new_request, unscheduled, overdue, inspection_scheduled, inspection_complete, quote_created, quote_sent, converted, lost_no_response, lost_reject_quote, cancelled, duplicate - assignedTo: array of user MongoDB ObjectIds - followUpDate: ISO 8601 format or null - notes: string - description: string - urgency: string enum — "low", "medium", "high", "critical" - items: array of line items (full replace) Example: { "stage": "inspection_scheduled", "assignedTo": ["user_id_1"] }
update_task
ChatGPT⚠️ CALL SHAPE — pass arguments exactly as: {"task_id": "<id>", "task_data": { ...fields to change... }} All record fields go INSIDE the *_data object, NOT at the top level (top-level keys are rejected as "unexpected keyword argument"). Update an existing task's information. Use field 'taskStatus' (NOT 'status') to update task status. REQUIRED: - task_id: MongoDB ObjectId of the task - task_data: Dictionary of fields to update UPDATABLE fields (provide only what you want to change): - name: string - taskStatus: ACCOUNT-SPECIFIC (task pipeline is org-configurable) — call get_data_model("task") for this account's real values. Built-in defaults: "scheduled", "pending", "in_progress", "completed", "cancelled" - priority: "low", "normal", "high", "urgent" - assignedToId: MongoDB ObjectId of user to assign - scheduleDateTime: ISO 8601, local time in the ACCOUNT's timezone — send the wall-clock time the user said and do NOT convert to UTC yourself; a trailing "Z"/offset is IGNORED, not honoured - scheduleEndDate: ISO 8601, same local-time rule as scheduleDateTime - dueDateTime: ISO 8601 — sent AS GIVEN (not converted), so include an explicit offset - instructions: string - category: "admin", "maintenance", "follow_up", "inspection" - completed: boolean - clientId: MongoDB ObjectId - jobId: MongoDB ObjectId - linkType: "client", "job", "estimate", "invoice" - duration: minutes (number) - allDay: boolean Example: { "taskStatus": "completed", "completed": true }
update_tax
ChatGPTUpdate a tax rate in FieldCamp (partial update). REQUIRED: - tax_id: id of the tax to update (from get_taxes). - tax_data: dict of fields to change (name, rate, taxType, description, applyOnAllItems, countryId, stateId, effectiveDate, applicationRules). Only the keys present in tax_data are changed. Admin / settings permission required.
update_vendor
ChatGPTUpdate a vendor / supplier in FieldCamp. REQUIRED: - vendor_id: id of the vendor to update (from get_vendors). OPTIONAL (only the fields you pass are changed): - name - email: must stay unique for the org (backend rejects a duplicate). - phone: composite OBJECT (dict), NOT a plain string — a bare string is rejected by the backend. Shape: {"countryCode": "+1", "number": "4155550100", "countryIdentifier": "us"} - address: composite OBJECT (dict), NOT a plain string — a bare string is rejected by the backend. Shape (sub-fields optional; at minimum pass {"formattedAddress": "..."}): {"formattedAddress": "...", "city": "...", "state": "..."} Call get_vendors first to obtain the vendor_id.
update_visit
ChatGPTUpdate an existing visit's information. REQUIRED: - visitId: MongoDB ObjectId of the visit - jobId: MongoDB ObjectId of the job OPTIONAL (provide only fields to update): - visitStartDateTime, visitEndDateTime: ISO 8601, local time in the ACCOUNT's timezone — send the wall-clock time the user said and do NOT convert to UTC yourself; a trailing "Z"/offset is IGNORED, not honoured - visitStatus: see VALID TRANSITIONS below - priority: "low", "medium", "high" - teamId: team-member id(s) — a plain 24-hex id or a JSON-array string of ids (same as create_visit); "[]" unassigns everyone - anyTime: "true" or "false" (as string) - isConfirmed: "true" or "false" (as string) - isExtraVisit: "true" or "false" (as string) - notes: string - jobIncome: string (revenue for the visit) ⚠️ STEP-BY-STEP TRANSITIONS (cannot skip): typical default flow is scheduled → in_transit → arrived → in_progress → completed (paused↔in_progress; completed/cancelled are final). The exact stages + allowed transitions are PER ACCOUNT — call get_data_model("visit") for this account's real ones. ⚠️ TRANSITION REQUIREMENTS (the smart part): a transition can require a capability before it's allowed — e.g. on many accounts in_progress→completed REQUIRES a customer signature (others may require a photo, job form, or notes). get_data_model("visit") lists each transition's requirements. If a completion/transition is rejected for a missing requirement, tell the user what's needed (e.g. "collect the customer's signature first") and help them capture it — do NOT just retry the status change.
update_warehouse
ChatGPTUpdate a warehouse / inventory location in FieldCamp. REQUIRED: - warehouse_id: id of the warehouse to update (from get_warehouses). OPTIONAL (only the fields you pass are changed): - name - warehouseType: e.g. 'Main Warehouse', 'Technician Truck/Van'. - address: composite OBJECT (dict), NOT a plain string — a bare string is rejected by the backend. Shape (all sub-fields optional; at minimum pass {"formattedAddress": "..."}): {"formattedAddress": "...", "street": "...", "city": "...", "state": "...", "country": "...", "zipCode": "..."} Call get_warehouses first to obtain the warehouse_id.
check_team_schedule_conflicts
Claudeconvert_request_to_estimate
Claudecreate_calendar_event
Claudecreate_client
Claudecreate_document
Claudecreate_job
Claudecreate_product_service
Claudecreate_purchase_order
Claudecreate_request
Claudecreate_task
Claudecreate_tax
Claudecreate_vendor
Claudecreate_visit
Claudecreate_warehouse
Claudedelete_calendar_event
Claudedelete_client
Claudedelete_inventory
Claudedelete_invoice
Claudedelete_job
Claudedelete_payment
Claudedelete_product_service
Claudedelete_purchase_order
Claudedelete_request
Claudedelete_task
Claudedelete_tax
Claudedelete_vendor
Claudedelete_visit
Claudedelete_warehouse
Claudefetch
Claudeget_all_team_members
Claudeget_analytics
Claudeget_available_team_members_schedule
Claudeget_calendar_activity
Claudeget_calendar_events
Claudeget_client_by_id
Claudeget_client_documents
Claudeget_client_payment_history
Claudeget_client_products
Claudeget_company_info
Claudeget_company_schedule
Claudeget_data_model
Claudeget_dispatch_suggestions
Claudeget_document_number
Claudeget_filtered_clients
Claudeget_filtered_jobs
Claudeget_history
Claudeget_inventory
Claudeget_inventory_by_id
Claudeget_invoice_by_id
Claudeget_invoices
Claudeget_job_by_id
Claudeget_next_job_number
Claudeget_payment_history
Claudeget_product_categories
Claudeget_product_service_by_id
Claudeget_products_services
Claudeget_purchase_orders
Claudeget_request_by_id
Claudeget_requests
Claudeget_task_by_id
Claudeget_tasks
Claudeget_tasks_by_client
Claudeget_tasks_by_job
Claudeget_taxes
Claudeget_team_member
Claudeget_teams
Claudeget_units_of_measurement
Claudeget_vendors
Claudeget_visit_by_id
Claudeget_visit_stats
Claudeget_visits_for_job
Claudeget_warehouses
Clauderecord_payment
Claudesearch
Claudesend_document_email
Claudetransfer_inventory
Claudeupdate_calendar_event
Claudeupdate_client
Claudeupdate_document
Claudeupdate_job
Claudeupdate_product_service
Claudeupdate_request
Claudeupdate_task
Claudeupdate_tax
Claudeupdate_vendor
Claudeupdate_visit
Claudeupdate_warehouse
Claude