diff --git a/Cargo.lock b/Cargo.lock index 80faf91..b8d58f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2067,7 +2067,7 @@ dependencies = [ [[package]] name = "tb-prod" -version = "1.0.0" +version = "1.1.0" dependencies = [ "chrono", "clap", diff --git a/crates/tb-prod/Cargo.toml b/crates/tb-prod/Cargo.toml index 2749009..842d5af 100644 --- a/crates/tb-prod/Cargo.toml +++ b/crates/tb-prod/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tb-prod" -version = "1.0.0" +version = "1.1.0" edition = "2024" description = "Productive.io API CLI" authors.workspace = true diff --git a/crates/tb-prod/schema.json b/crates/tb-prod/schema.json index 4b7fed8..f885ec3 100644 --- a/crates/tb-prod/schema.json +++ b/crates/tb-prod/schema.json @@ -1,6 +1,6 @@ { "version": "1.0.0", - "generatedAt": "2026-03-23T16:24:57.699Z", + "generatedAt": "2026-04-07T16:23:13.410Z", "resources": { "activities": { "type": "activities", @@ -8,7 +8,7 @@ "itemName": "activity", "collectionName": "activities", "description": "Activity represents a change or action in the activity feed of a Task, Deal, Project, Company, or Person. Activities track events like creation, updates, deletions, comments, and other changes made to items in the system.", - "descriptionShort": "Tracks changes and actions in the activity feed of tasks, deals, projects, and other entities.", + "descriptionShort": "changes or events in the activity feed of tasks, deals, projects, and other entities", "customActions": {}, "fields": { "id": { @@ -23,6 +23,7 @@ "key": "event", "type": "string", "typeCategory": "primitive", + "param": "event", "readonly": true, "description": "The type of change (create, update, delete, etc.)", "attribute": "event" @@ -31,6 +32,7 @@ "key": "changeset", "type": "hash", "typeCategory": "primitive", + "param": "changeset", "readonly": true, "description": "The object containing the changes made to the item", "attribute": "changeset" @@ -39,6 +41,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "attribute": "created_at" }, @@ -46,6 +49,7 @@ "key": "itemId", "type": "number", "typeCategory": "primitive", + "param": "item_id", "readonly": true, "description": "ID of the item this activity is about", "attribute": "item_id" @@ -54,6 +58,7 @@ "key": "itemName", "type": "string", "typeCategory": "primitive", + "param": "item_name", "readonly": true, "description": "Name or title of the item", "attribute": "item_name" @@ -62,6 +67,7 @@ "key": "itemType", "type": "string", "typeCategory": "primitive", + "param": "item_type", "readonly": true, "description": "Type of item (Comment, Booking, Membership etc.)", "attribute": "item_type" @@ -70,6 +76,7 @@ "key": "itemDeletedAt", "type": "date", "typeCategory": "primitive", + "param": "item_deleted_at", "readonly": true, "description": "Timestamp of when the item was deleted", "attribute": "item_deleted_at" @@ -78,6 +85,7 @@ "key": "parentId", "type": "number", "typeCategory": "primitive", + "param": "parent_id", "readonly": true, "description": "ID of the parent item", "attribute": "parent_id" @@ -86,6 +94,7 @@ "key": "parentName", "type": "string", "typeCategory": "primitive", + "param": "parent_name", "readonly": true, "description": "Name of the parent item", "attribute": "parent_name" @@ -94,6 +103,7 @@ "key": "parentType", "type": "string", "typeCategory": "primitive", + "param": "parent_type", "readonly": true, "description": "Type of the parent item", "attribute": "parent_type" @@ -102,6 +112,7 @@ "key": "parentDeletedAt", "type": "date", "typeCategory": "primitive", + "param": "parent_deleted_at", "readonly": true, "description": "Timestamp of when the parent item was deleted", "attribute": "parent_deleted_at" @@ -110,6 +121,7 @@ "key": "rootId", "type": "number", "typeCategory": "primitive", + "param": "root_id", "readonly": true, "description": "ID of the root item", "attribute": "root_id" @@ -118,6 +130,7 @@ "key": "rootName", "type": "string", "typeCategory": "primitive", + "param": "root_name", "readonly": true, "description": "Name of the root item", "attribute": "root_name" @@ -126,6 +139,7 @@ "key": "rootType", "type": "string", "typeCategory": "primitive", + "param": "root_type", "readonly": true, "description": "Type of the root item", "attribute": "root_type" @@ -134,6 +148,7 @@ "key": "rootDeletedAt", "type": "date", "typeCategory": "primitive", + "param": "root_deleted_at", "readonly": true, "description": "Timestamp of when the root item was deleted", "attribute": "root_deleted_at" @@ -142,6 +157,7 @@ "key": "dealId", "type": "string", "typeCategory": "primitive", + "param": "deal_id", "readonly": true, "filter": "deal_id", "description": "ID of the deal this activity is related to" @@ -150,6 +166,7 @@ "key": "dealIsBudget", "type": "boolean", "typeCategory": "primitive", + "param": "deal_is_budget", "readonly": true, "description": "Indicates whether the deal is a budget", "attribute": "deal_is_budget" @@ -158,6 +175,7 @@ "key": "taskId", "type": "string", "typeCategory": "primitive", + "param": "task_id", "readonly": true, "filter": "task_id", "description": "ID of the task this activity is related to" @@ -166,6 +184,7 @@ "key": "pageId", "type": "string", "typeCategory": "primitive", + "param": "page_id", "readonly": true, "description": "ID of the page this activity is related to" }, @@ -173,6 +192,7 @@ "key": "companyId", "type": "string", "typeCategory": "primitive", + "param": "company_id", "readonly": true, "filter": "company_id", "description": "ID of the company this activity is related to" @@ -181,6 +201,7 @@ "key": "bookingId", "type": "string", "typeCategory": "primitive", + "param": "booking_id", "readonly": true, "filter": "booking_id", "description": "ID of the booking this activity is related to" @@ -189,6 +210,7 @@ "key": "personId", "type": "string", "typeCategory": "primitive", + "param": "person_id", "readonly": true, "filter": "person_id", "description": "ID of the person this activity is related to" @@ -197,6 +219,7 @@ "key": "projectId", "type": "string", "typeCategory": "primitive", + "param": "project_id", "readonly": true, "filter": "project_id", "description": "Filter activities by project ID" @@ -205,6 +228,7 @@ "key": "expenseId", "type": "string", "typeCategory": "primitive", + "param": "expense_id", "readonly": true, "filter": "expense_id", "description": "Filter activities by expense ID" @@ -213,6 +237,7 @@ "key": "madeByAutomation", "type": "boolean", "typeCategory": "primitive", + "param": "is_made_by_automation", "readonly": true, "description": "Whether the activity was triggered by an automation", "attribute": "made_by_automation" @@ -221,6 +246,7 @@ "key": "creator", "type": "people", "typeCategory": "resource", + "param": "creator", "readonly": true, "filter": "creator_id", "description": "The person who created/triggered the activity", @@ -230,6 +256,7 @@ "key": "comment", "type": "comments", "typeCategory": "resource", + "param": "comment", "readonly": true, "description": "The comment associated with this activity", "relationship": "comment" @@ -238,6 +265,7 @@ "key": "email", "type": "emails", "typeCategory": "resource", + "param": "email", "readonly": true, "description": "The email associated with this activity", "relationship": "email" @@ -246,6 +274,7 @@ "key": "attachment", "type": "attachments", "typeCategory": "resource", + "param": "attachment", "readonly": true, "description": "The attachment associated with this activity", "relationship": "attachment" @@ -254,6 +283,7 @@ "key": "before", "type": "date", "typeCategory": "primitive", + "param": "before", "readonly": true, "filter": "before", "description": "Filter activities created before this date" @@ -262,6 +292,7 @@ "key": "after", "type": "date", "typeCategory": "primitive", + "param": "after", "readonly": true, "filter": "after", "description": "Filter activities created after this date" @@ -276,7 +307,7 @@ "itemName": "agent config", "collectionName": "agent configs", "description": "Agent Config stores the customizable settings for an AI agent. Each config belongs to one agent and defines the system instructions (prompt) and the set of tools the agent can use. Updating the config changes the agent behavior without recreating the agent.", - "descriptionShort": "Stores AI agent settings — instructions and tools.", + "descriptionShort": "AI agent instructions and tools", "customActions": {}, "fields": { "id": { @@ -292,6 +323,7 @@ "key": "instructions", "type": "string", "typeCategory": "primitive", + "format": "html", "param": "instructions", "attribute": "instructions" }, @@ -307,6 +339,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "sort": "created_at", "attribute": "created_at" @@ -315,6 +348,7 @@ "key": "updatedAt", "type": "date", "typeCategory": "primitive", + "param": "updated_at", "readonly": true, "sort": "updated_at", "attribute": "updated_at" @@ -323,7 +357,7 @@ "key": "agent", "type": "agents", "typeCategory": "resource", - "param": "agent_id", + "param": "agent", "required": true, "relationship": "agent" } @@ -335,8 +369,8 @@ "domain": "Automation & Configuration", "itemName": "agent", "collectionName": "agents", - "description": "Agent is an AI-powered assistant that can perform tasks and actions within Productive. Agents have a custom role that defines their permissions, an optional manager, and a configuration that defines their instructions and tools.", - "descriptionShort": "AI assistant that performs tasks and actions within Productive.", + "description": "Agent is an AI-powered assistant that can perform tasks and actions within Productive. Agents have a custom role that defines what the agent can do (its permissions), an optional manager, and a configuration that defines their instructions and tools. Memberships control who can see and use the agent.", + "descriptionShort": "AI assistants that perform tasks and actions", "customActions": { "deactivate": { "name": "deactivate", @@ -389,6 +423,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "sort": "created_at", "attribute": "created_at" @@ -397,6 +432,7 @@ "key": "updatedAt", "type": "date", "typeCategory": "primitive", + "param": "updated_at", "readonly": true, "sort": "updated_at", "attribute": "updated_at" @@ -405,14 +441,15 @@ "key": "status", "type": "agent_status", "typeCategory": "enum", + "param": "status", "filter": "status", - "description": "Status of the agent: active (1) or deactivated (2)" + "description": "Status of the agent" }, "customRole": { "key": "customRole", "type": "roles", "typeCategory": "resource", - "param": "custom_role_id", + "param": "custom_role", "required": true, "relationship": "custom_role" }, @@ -420,13 +457,14 @@ "key": "manager", "type": "people", "typeCategory": "resource", - "param": "manager_id", + "param": "manager", "relationship": "manager" }, "agentConfig": { "key": "agentConfig", "type": "agent_configs", "typeCategory": "resource", + "param": "agent_config", "readonly": true, "relationship": "agent_config" } @@ -439,7 +477,7 @@ "itemName": "allocation", "collectionName": "allocations", "description": "Allocation is a read-only view of planned time for people in the Resource Planner.\nUnlike bookings (which can be created/updated/deleted), allocations are aggregated read-only records\nused for reporting and visibility into how people's time is scheduled.\nService allocations represent time scheduled on a project service (billable work).\nEvent allocations represent time off (vacation, sick leave, remote work, etc).\nAllocations are stored in the bookings table but exclude canceled, rejected, and deleted bookings.", - "descriptionShort": "Read-only view of planned time for people in the Resource Planner — covers both project work (service) and time off (event) allocations.", + "descriptionShort": "read-only views of scheduled time for people — project work and time-off allocations", "customActions": {}, "fields": { "id": { @@ -457,7 +495,7 @@ "unit": "hours", "param": "hours", "readonly": true, - "description": "Hours per day. Used with booking method \"1\" (per day).", + "description": "Hours per day. Used with booking method \"per day\".", "attribute": "hours" }, "time": { @@ -477,7 +515,6 @@ "format": "YYYY-MM-DD", "param": "started_on", "readonly": true, - "filter": "started_on", "sort": "started_on", "description": "Start date of the allocation", "attribute": "started_on" @@ -489,7 +526,6 @@ "format": "YYYY-MM-DD", "param": "ended_on", "readonly": true, - "filter": "ended_on", "description": "End date of the allocation", "attribute": "ended_on" }, @@ -526,7 +562,7 @@ "key": "bookingMethodId", "type": "booking_method", "typeCategory": "enum", - "param": "booking_method_id", + "param": "booking_method", "readonly": true, "description": "Method used to specify the time allocation: \"1\" = per day, \"2\" = percentage, \"3\" = total hours", "attribute": "booking_method_id" @@ -545,6 +581,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "attribute": "created_at" }, @@ -552,6 +589,7 @@ "key": "updatedAt", "type": "date", "typeCategory": "primitive", + "param": "updated_at", "readonly": true, "attribute": "updated_at" }, @@ -560,6 +598,7 @@ "type": "date", "typeCategory": "primitive", "format": "YYYY-MM-DD", + "param": "after", "filter": "after", "description": "Filter allocations that end on or after this date (ended_on >= value)" }, @@ -568,6 +607,7 @@ "type": "date", "typeCategory": "primitive", "format": "YYYY-MM-DD", + "param": "before", "filter": "before", "description": "Filter allocations that start on or before this date (started_on <= value)" }, @@ -575,7 +615,7 @@ "key": "person", "type": "people", "typeCategory": "resource", - "param": "person_id", + "param": "person", "filter": "person_id", "description": "Person who is allocated", "relationship": "person" @@ -584,7 +624,7 @@ "key": "service", "type": "services", "typeCategory": "resource", - "param": "service_id", + "param": "service", "description": "Service (project work) this person is allocated to", "relationship": "service" }, @@ -592,7 +632,7 @@ "key": "event", "type": "events", "typeCategory": "resource", - "param": "event_id", + "param": "event", "description": "Absence category this person is allocated to. Present when booking_type is \"event\".", "relationship": "event" }, @@ -600,6 +640,7 @@ "key": "client", "type": "companies", "typeCategory": "resource", + "param": "client", "readonly": true, "description": "Client company associated with the service allocation", "relationship": "client" @@ -608,6 +649,7 @@ "key": "responsible", "type": "people", "typeCategory": "resource", + "param": "responsible", "readonly": true, "description": "Project manager responsible for the service allocation", "relationship": "responsible" @@ -622,7 +664,7 @@ "itemName": "approval policy", "collectionName": "approval policies", "description": "Approval Policy defines reusable rules for who must approve submissions before they are recognized and billable.\nPolicies are typed by what they govern:\n- Event (type_id=1): absence/time-off requests — approvers review bookings for vacation, sick leave, remote work.\n- Budget (type_id=2): time entries and expenses on budgets — controls whether tracked time and logged expenses require review before affecting revenue and profitability.\n- Deal (type_id=3): time entries and expenses on deals — same as budget policies but for sales deals (Beta).\n\nEach policy specifies approver roles (manager, budget/deal owner, project manager, or specific people) and approval mode:\n- No approval needed: submissions are auto-approved.\n- Any one of the listed approvers: single approval is sufficient.\n- All approvers: every listed approver must approve; a single rejection declines the request.\n\nPolicies can be set as default (auto-assigned to new budgets/deals) or assigned in bulk.\nA policy only takes effect if the corresponding organization-wide approval feature is enabled (time approval, expense approval, or absence approval).\nPolicies can be archived when no longer needed.", - "descriptionShort": "Reusable rules defining who must approve absences, time entries, or expenses — and whether one or all approvers are needed.", + "descriptionShort": "rules defining who approves absences, time entries, or expenses — one or all approvers", "customActions": {}, "fields": { "id": { @@ -637,6 +679,7 @@ "key": "name", "type": "string", "typeCategory": "primitive", + "param": "name", "required": true, "attribute": "name" }, @@ -644,43 +687,115 @@ "key": "description", "type": "string", "typeCategory": "primitive", + "param": "description", "attribute": "description" }, "custom": { "key": "custom", "type": "boolean", "typeCategory": "primitive", + "param": "is_custom", "attribute": "custom" }, "default": { "key": "default", "type": "boolean", "typeCategory": "primitive", + "param": "is_default", "attribute": "default" }, "typeId": { "key": "typeId", "type": "approval_policy_type", "typeCategory": "enum", + "param": "approval_policy_type", "attribute": "type_id" }, "archivedAt": { "key": "archivedAt", "type": "date", "typeCategory": "primitive", + "param": "archived_at", "attribute": "archived_at" } }, "collections": {}, "defaultSort": "Sorted by name (ascending) by default." }, + "approval_policy_assignments": { + "type": "approval_policy_assignments", + "domain": "Automation & Configuration", + "itemName": "approval policy assignment", + "collectionName": "approval policy assignments", + "description": "Approval Policy Assignment links an approval policy to a target entity — a person, budget, or deal.\nEach target can have at most one active assignment per policy type.\n\n- target_type \"person\": governs absence/time-off approval for that person's leave requests.\n- target_type \"budget\": governs time entry and expense approval on that budget.\n- target_type \"deal\": governs time entry and expense approval on that deal.\n\nWithout an assignment, a policy has no effect on a specific entity.", + "descriptionShort": "which approval policy governs absences, time entries, or expenses for a person, budget, or deal", + "customActions": {}, + "fields": { + "id": { + "key": "id", + "type": "string", + "typeCategory": "primitive", + "param": "id", + "readonly": true, + "id": true + }, + "targetId": { + "key": "targetId", + "type": "string", + "typeCategory": "primitive", + "param": "target_id", + "readonly": true, + "filter": "target_id", + "description": "ID of the target entity", + "attribute": "target_id" + }, + "targetType": { + "key": "targetType", + "type": "approval_policy_target_type", + "typeCategory": "enum", + "param": "target_type", + "readonly": true, + "filter": "target_type", + "description": "Type of the target entity", + "attribute": "target_type" + }, + "approvalPolicy": { + "key": "approvalPolicy", + "type": "approval_policies", + "typeCategory": "resource", + "param": "approval_policy", + "required": true, + "filter": "approval_policy_id", + "description": "The governing approval policy. Include to get policy details such as approvers, approval mode, and type.", + "relationship": "approval_policy" + }, + "person": { + "key": "person", + "type": "people", + "typeCategory": "resource", + "param": "person", + "description": "The person this policy is assigned to. Only present when target_type is \"person\".", + "relationship": "person" + }, + "deal": { + "key": "deal", + "type": "deals", + "typeCategory": "resource", + "param": "deal", + "description": "The deal or budget this policy is assigned to. Only present when target_type is \"budget\" or \"deal\".", + "relationship": "deal" + } + }, + "collections": {}, + "queryHints": "Filter by target_type and target_id together to find the assignment for a specific entity.\nAlways include approval_policy to get the full policy details alongside the assignment." + }, "approval_statuses": { "type": "approval_statuses", "domain": "Automation & Configuration", "itemName": "approval status", "collectionName": "approval statuses", "description": "Approval Status is a per-approver record tracking one person's approval decision on a booking (absence), time entry, or expense.\nWhen a submission triggers an approval workflow, one Approval Status is created for each designated approver in the policy.\n\nEach record contains:\n- The target entity (booking, time_entry, or expense) and its target_type: event (absence booking), time (time entry), or expense (expense).\n- The designated approver (who should review) and the actual_approver (who performed the action — may differ if someone else acts on their behalf).\n- The linked approval_workflow (the policy that generated this status).\n- An optional note explaining the approval or rejection reason.\n\nApproval statuses are system-managed — they are created automatically when submissions enter the approval flow and updated when approvers take action.\nOnly after all required approvers approve (based on the policy's mode) does the target entity become recognized, billable, and available for invoicing.", - "descriptionShort": "Per-approver decision record for an absence, time entry, or expense — created automatically by the approval policy.", + "descriptionShort": "per-approver decisions on an absence, time entries, or expenses — auto-created by the approval policy", "customActions": {}, "fields": { "id": { @@ -695,6 +810,7 @@ "key": "note", "type": "string", "typeCategory": "primitive", + "param": "note", "description": "Note associated with the approval or rejection", "attribute": "note" }, @@ -702,6 +818,7 @@ "key": "targetType", "type": "approval_status_target_type", "typeCategory": "enum", + "param": "target_type", "description": "Type of the target entity for approval", "attribute": "target_type" }, @@ -709,6 +826,7 @@ "key": "approver", "type": "people", "typeCategory": "resource", + "param": "approver", "description": "Person designated as the approver", "relationship": "approver" }, @@ -716,6 +834,7 @@ "key": "actualApprover", "type": "people", "typeCategory": "resource", + "param": "actual_approver", "description": "Person who actually performed the approval or rejection", "relationship": "actual_approver" }, @@ -723,6 +842,7 @@ "key": "approvalWorkflow", "type": "approval_policies", "typeCategory": "resource", + "param": "approval_workflow", "description": "Approval workflow/policy used for this approval", "relationship": "approval_workflow" }, @@ -730,6 +850,7 @@ "key": "booking", "type": "bookings", "typeCategory": "resource", + "param": "booking", "description": "Associated booking if the approval target is a booking", "relationship": "booking" }, @@ -737,6 +858,7 @@ "key": "expense", "type": "expenses", "typeCategory": "resource", + "param": "expense", "description": "Associated expense if the approval target is an expense", "relationship": "expense" }, @@ -744,6 +866,7 @@ "key": "timeEntry", "type": "time_entries", "typeCategory": "resource", + "param": "time_entry", "description": "Associated time entry if the approval target is a time entry", "relationship": "time_entry" } @@ -756,7 +879,7 @@ "itemName": "attachment", "collectionName": "attachments", "description": "Attachment is a file uploaded to a Task, Deal, Page (Doc), Comment, or Expense. Attachments store documents, images, and other files related to work. The URL field provides a download link to access the file content.", - "descriptionShort": "Uploaded file.", + "descriptionShort": "uploaded files", "customActions": {}, "fields": { "id": { @@ -772,6 +895,7 @@ "key": "name", "type": "string", "typeCategory": "primitive", + "param": "name", "required": true, "attribute": "name" }, @@ -779,6 +903,7 @@ "key": "contentType", "type": "string", "typeCategory": "primitive", + "param": "content_type", "required": true, "attribute": "content_type" }, @@ -786,6 +911,7 @@ "key": "size", "type": "string", "typeCategory": "primitive", + "param": "size", "required": true, "attribute": "size" }, @@ -793,6 +919,7 @@ "key": "url", "type": "string", "typeCategory": "primitive", + "param": "url", "required": true, "description": "File URL of the attachment. Use this URL to download and read the file.", "attribute": "url" @@ -801,6 +928,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "required": true, "attribute": "created_at" }, @@ -808,6 +936,7 @@ "key": "attachmentType", "type": "string", "typeCategory": "primitive", + "param": "attachment_type", "required": true, "attribute": "attachment_type" }, @@ -815,18 +944,21 @@ "key": "attachableType", "type": "string", "typeCategory": "primitive", + "param": "attachable_type", "attribute": "attachable_type" }, "attachableId": { "key": "attachableId", "type": "string", "typeCategory": "primitive", + "param": "attachable_id", "attribute": "attachable_id" }, "creator": { "key": "creator", "type": "people", "typeCategory": "resource", + "param": "creator", "required": true, "filter": "creator_id", "relationship": "creator" @@ -835,7 +967,7 @@ "key": "task", "type": "tasks", "typeCategory": "resource", - "param": "task_id", + "param": "task", "required": true, "filter": "task_id", "relationship": "task", @@ -845,6 +977,7 @@ "key": "deal", "type": "deals", "typeCategory": "resource", + "param": "deal", "required": true, "relationship": "deal", "notIncludable": true @@ -853,7 +986,7 @@ "key": "page", "type": "pages", "typeCategory": "resource", - "param": "page_id", + "param": "page", "required": true, "filter": "page_id", "relationship": "page", @@ -863,7 +996,7 @@ "key": "expense", "type": "expenses", "typeCategory": "resource", - "param": "expense_id", + "param": "expense", "required": true, "relationship": "expense", "notIncludable": true @@ -872,7 +1005,7 @@ "key": "comment", "type": "comments", "typeCategory": "resource", - "param": "comment_id", + "param": "comment", "required": true, "filter": "comment_id", "relationship": "comment", @@ -887,7 +1020,7 @@ "itemName": "automation", "collectionName": "automations", "description": "Automation defines a rule that automatically triggers actions based on events or schedules.\nEvery rule has three parts: When (trigger), Check if (optional conditions), Then (actions).\n\nTrigger types (type_id):\n- Event (1): fires when a target object is created, updated, deleted, or commented on.\n- Time (2): fires on a schedule (daily, weekly, monthly) at a specified time.\n\nTarget types (target_id): task (1), deal (2), budget (3), invoice (4), survey response (5), project (6), booking (7), expense (8), company (9), employee (10).\n\nAvailable actions: send Slack message, send email, create task, create subtask, update field, add comment.\nConditions narrow when the rule fires (e.g., only if deal owner is a specific person, or task type matches a value).\nAutomations can be scoped to specific projects or applied across all projects (resolve_on_all_projects).\nEach automation tracks monthly_runs and monthly_action_runs against the organization's action limit.", - "descriptionShort": "Rule that triggers actions (Slack, email, task creation) based on events or schedules.", + "descriptionShort": "rules triggering actions (e.g. task creation) on events or schedules", "customActions": {}, "fields": { "id": { @@ -902,6 +1035,7 @@ "key": "name", "type": "string", "typeCategory": "primitive", + "param": "name", "sort": "name", "attribute": "name" }, @@ -909,12 +1043,14 @@ "key": "description", "type": "string", "typeCategory": "primitive", + "param": "description", "attribute": "description" }, "enabled": { "key": "enabled", "type": "boolean", "typeCategory": "primitive", + "param": "is_enabled", "sort": "enabled", "attribute": "enabled" }, @@ -922,42 +1058,49 @@ "key": "resolveOnAllProjects", "type": "boolean", "typeCategory": "primitive", + "param": "resolve_on_all_projects", "attribute": "resolve_on_all_projects" }, "isAccessibleByCreatorOnly": { "key": "isAccessibleByCreatorOnly", "type": "boolean", "typeCategory": "primitive", + "param": "is_accessible_by_creator_only", "attribute": "is_accessible_by_creator_only" }, "monthlyRuns": { "key": "monthlyRuns", "type": "number", "typeCategory": "primitive", + "param": "monthly_runs", "attribute": "monthly_runs" }, "monthlyActionRuns": { "key": "monthlyActionRuns", "type": "number", "typeCategory": "primitive", + "param": "monthly_action_runs", "attribute": "monthly_action_runs" }, "automationProjectAssignmentsCount": { "key": "automationProjectAssignmentsCount", "type": "number", "typeCategory": "primitive", + "param": "automation_project_assignments_count", "attribute": "automation_project_assignments_count" }, "typeId": { "key": "typeId", "type": "automation_type", "typeCategory": "enum", + "param": "automation_type", "attribute": "type_id" }, "targetId": { "key": "targetId", "type": "automation_target", "typeCategory": "enum", + "param": "target", "sort": "target_id", "attribute": "target_id" }, @@ -965,42 +1108,49 @@ "key": "triggers", "type": "hash", "typeCategory": "primitive", + "param": "triggers", "attribute": "triggers" }, "repeatScheduleId": { "key": "repeatScheduleId", "type": "string", "typeCategory": "primitive", + "param": "repeat_schedule_id", "attribute": "repeat_schedule_id" }, "scheduleDayId": { "key": "scheduleDayId", "type": "string", "typeCategory": "primitive", + "param": "schedule_day_id", "attribute": "schedule_day_id" }, "scheduleFrameId": { "key": "scheduleFrameId", "type": "string", "typeCategory": "primitive", + "param": "schedule_frame_id", "attribute": "schedule_frame_id" }, "scheduleHour": { "key": "scheduleHour", "type": "number", "typeCategory": "primitive", + "param": "schedule_hour", "attribute": "schedule_hour" }, "steps": { "key": "steps", "type": "hash", "typeCategory": "primitive", + "param": "steps", "attribute": "steps" }, "createdAt": { "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "sort": "created_at", "attribute": "created_at" @@ -1009,6 +1159,7 @@ "key": "updatedAt", "type": "date", "typeCategory": "primitive", + "param": "updated_at", "readonly": true, "sort": "updated_at", "attribute": "updated_at" @@ -1017,6 +1168,7 @@ "key": "totalRuns", "type": "number", "typeCategory": "primitive", + "param": "total_runs", "readonly": true, "sort": "total_runs", "attribute": "total_runs" @@ -1025,6 +1177,7 @@ "key": "totalActionsExecuted", "type": "number", "typeCategory": "primitive", + "param": "total_actions_executed", "readonly": true, "sort": "total_actions_executed", "attribute": "total_actions_executed" @@ -1041,6 +1194,7 @@ "key": "query", "type": "string", "typeCategory": "primitive", + "param": "query", "filter": "query", "description": "Keyword or phrase for fuzzy text matching / filtering of automations" }, @@ -1048,12 +1202,18 @@ "key": "projectId", "type": "string", "typeCategory": "primitive", + "param": "project_id", "readonly": true, "filter": "project_id", "description": "Filter automations by project ID" } }, - "collections": {} + "collections": {}, + "actions": { + "create": false, + "update": false, + "delete": false + } }, "bill_items": { "type": "bill_items", @@ -1061,7 +1221,7 @@ "itemName": "bill item", "collectionName": "bill items", "description": "Bill Item is a line entry on a Bill, linking a specific expense (from the purchase order) to a received quantity.\nEach bill item records how many units of a particular expense have been received in this delivery.\nThe sum of bill item quantities across all bills for an expense determines how much has been received vs ordered.", - "descriptionShort": "Line on a bill — links a PO expense to a received quantity.", + "descriptionShort": "line items on a bill — links a PO expense to a received quantity", "customActions": {}, "fields": { "id": { @@ -1087,7 +1247,7 @@ "key": "bill", "type": "bills", "typeCategory": "resource", - "param": "bill_id", + "param": "bill", "required": true, "filter": "bill_id", "sort": "bill_id", @@ -1098,7 +1258,7 @@ "key": "expense", "type": "expenses", "typeCategory": "resource", - "param": "expense_id", + "param": "expense", "required": true, "filter": "expense_id", "description": "Expense this bill item is for", @@ -1113,7 +1273,7 @@ "itemName": "bill", "collectionName": "bills", "description": "Bill records the receipt of goods or services ordered through a Purchase Order.\nEach bill belongs to exactly one purchase order and contains Bill Items that specify the received quantity per expense.\n\nAs bills are recorded, the parent purchase order's payment status updates automatically:\nnot received → partially received → fully received.\nBills include the vendor's invoice number, date, due date, and description for reconciliation.\nCurrency is inherited from the purchase order.", - "descriptionShort": "Receipt record against a purchase order — tracks what was received from a vendor.", + "descriptionShort": "receipt records against a purchase order — tracks what was received from a vendor", "customActions": {}, "fields": { "id": { @@ -1170,6 +1330,7 @@ "key": "currency", "type": "currency", "typeCategory": "enum", + "param": "currency", "readonly": true, "attribute": "currency" }, @@ -1178,6 +1339,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "total_cost", "readonly": true, "filter": "total_cost", "sort": "total_cost", @@ -1189,6 +1351,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "total_received", "readonly": true, "filter": "total_received", "sort": "total_received", @@ -1199,6 +1362,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "sort": "created_at", "attribute": "created_at" @@ -1207,7 +1371,7 @@ "key": "purchaseOrder", "type": "purchase_orders", "typeCategory": "resource", - "param": "purchase_order_id", + "param": "purchase_order", "required": true, "filter": "purchase_order_id", "sort": "purchase_order_id", @@ -1218,6 +1382,7 @@ "key": "creator", "type": "people", "typeCategory": "resource", + "param": "creator", "readonly": true, "relationship": "creator" }, @@ -1225,6 +1390,7 @@ "key": "deal", "type": "deals", "typeCategory": "resource", + "param": "deal", "readonly": true, "relationship": "deal" }, @@ -1232,7 +1398,7 @@ "key": "attachment", "type": "attachments", "typeCategory": "resource", - "param": "attachment_id", + "param": "attachment", "relationship": "attachment" } }, @@ -1244,11 +1410,11 @@ "itemName": "booking", "collectionName": "bookings", "description": "Booking represents planned time allocation in the Resource Planner — the core of resource scheduling in Productive.\nA booking must have exactly one of service_id (work booking) or event_id (absence booking), never both.\n\nTwo booking types:\n- Work bookings (booking_type=1): schedule a person on a Service in a Budget or Deal. Affect availability, contribute to scheduled revenue (for billable services), and appear as time tracking suggestions. Can optionally be linked to a Task for task-level planning.\n- Absence bookings (booking_type=2): schedule time off or remote work on an Absence Category (Event). Time-off bookings reduce availability; remote work bookings do not. Deduct from the person's entitlement allocation. Can go through absence approval if enabled.\n\nTime allocation methods:\n- Hours per day (booking_method=1): fixed hours each day of the booking period.\n- Percentage (booking_method=2): percentage of the person's daily capacity (e.g. 50% of an 8-hour day = 4 hours).\n- Total hours (booking_method=3): total hours spread evenly across the date range.\n\nBooking status:\n- Confirmed (draft=false): firm allocation that counts toward capacity and scheduled revenue.\n- Tentative (draft=true): soft allocation for potential work. Included in availability calculations but communicated as tentative. Can be toggled to confirmed later.\n\nBookings can be canceled (canceled_at set) rather than deleted, preserving history.\nAutomatic time tracking can be enabled per booking — confirmed bookings auto-generate time entries at midnight.\nBookings can be split, repeated (weekly/monthly), and duplicated. Multiple people can be booked on the same service simultaneously.\nThe overwrite action on absence bookings automatically splits overlapping work bookings to accommodate the absence period.", - "descriptionShort": "Planned work or absence in the Resource Planner — schedules a person on a service or absence category.", + "descriptionShort": "planned work or absence — schedules a person on a service or absence category", "customActions": { "overwrite": { "name": "overwrite", - "description": "Overwrite an absence booking to resolve conflicts. Call this action on the ABSENCE booking ID (the booking with event_id). This will automatically split any overlapping work bookings to accommodate the absence period. NEVER call this on work booking IDs.", + "description": "Overwrite an absence booking to resolve conflicts. Call this action on the ABSENCE booking ID (the booking with event). This will automatically split any overlapping work bookings to accommodate the absence period. NEVER call this on work booking IDs.", "endpoint": "overwrite", "method": "PATCH" } @@ -1330,6 +1496,7 @@ "type": "booking_type", "typeCategory": "enum", "param": "booking_type", + "filter": "booking_type", "description": "Type of booking.", "attribute": "booking_type_id" }, @@ -1337,7 +1504,7 @@ "key": "draft", "type": "boolean", "typeCategory": "primitive", - "param": "draft", + "param": "is_draft", "filter": "draft", "sort": "draft", "attribute": "draft" @@ -1355,6 +1522,7 @@ "key": "canceled", "type": "boolean", "typeCategory": "primitive", + "param": "is_canceled", "filter": "canceled", "description": "Filter by canceled status. Use false to get active (non-canceled) bookings, true to get canceled bookings." }, @@ -1366,11 +1534,70 @@ "param": "custom_fields", "attribute": "custom_fields" }, + "after": { + "key": "after", + "type": "date", + "typeCategory": "primitive", + "format": "YYYY-MM-DD", + "param": "after", + "filter": "after", + "description": "Filter bookings that end on or after this date (ended_on >= value). Use to find bookings active within a date range." + }, + "before": { + "key": "before", + "type": "date", + "typeCategory": "primitive", + "format": "YYYY-MM-DD", + "param": "before", + "filter": "before", + "description": "Filter bookings that start on or before this date (started_on <= value). Use to find bookings active within a date range." + }, + "approvalStatus": { + "key": "approvalStatus", + "type": "booking_approval_status", + "typeCategory": "enum", + "param": "approval_status", + "filter": "approval_status", + "description": "Filter by approval status. Approved=1, Pending=2, Rejected=3, Canceled=5.", + "array": true + }, + "companyId": { + "key": "companyId", + "type": "companies", + "typeCategory": "resource", + "param": "company", + "filter": "company_id", + "description": "Filter bookings by client company (via service → deal → company)" + }, + "budgetId": { + "key": "budgetId", + "type": "deals", + "typeCategory": "resource", + "param": "budget_id", + "filter": "budget_id", + "description": "Filter bookings by deal/budget (via service → deal)" + }, + "projectId": { + "key": "projectId", + "type": "projects", + "typeCategory": "resource", + "param": "project_id", + "filter": "project_id", + "description": "Filter bookings by project/workspace (via service → deal → project)" + }, + "billingTypeId": { + "key": "billingTypeId", + "type": "billing_type", + "typeCategory": "enum", + "param": "billing_type_id", + "filter": "billing_type_id", + "description": "Filter bookings by the billing type of their service." + }, "person": { "key": "person", "type": "people", "typeCategory": "resource", - "param": "person_id", + "param": "person", "required": true, "filter": "person_id", "relationship": "person" @@ -1379,7 +1606,7 @@ "key": "task", "type": "tasks", "typeCategory": "resource", - "param": "task_id", + "param": "task", "filter": "task_id", "relationship": "task" }, @@ -1387,8 +1614,8 @@ "key": "service", "type": "services", "typeCategory": "resource", - "param": "service_id", - "description": "Service for work bookings. Mutually exclusive with event (absence category) — a booking must have exactly one of service_id or event_id, never both, never neither.", + "param": "service", + "description": "Service for work bookings. Mutually exclusive with event (absence category) — a booking must have exactly one of service or event, never both, never neither.", "relationship": "service", "exclusive": "bookable" }, @@ -1396,9 +1623,9 @@ "key": "event", "type": "events", "typeCategory": "resource", - "param": "event_id", + "param": "event", "filter": "event_id", - "description": "Absence category for absence bookings (e.g. vacation, sick leave). Mutually exclusive with service — a booking must have exactly one of service_id or event_id, never both, never neither.", + "description": "Absence category for absence bookings (e.g. vacation, sick leave). Mutually exclusive with service — a booking must have exactly one of service or event, never both, never neither.", "relationship": "event", "exclusive": "bookable" }, @@ -1406,27 +1633,27 @@ "key": "approver", "type": "people", "typeCategory": "resource", - "param": "approver_id", + "param": "approver", "filter": "approver_id", "description": "Person who approved the booking", "relationship": "approver" } }, "collections": {}, - "queryHints": "Users typically care about active bookings, unless they specify otherwise. The default filter scope for bookings should be: { canceled: {eq: false} }", + "queryHints": "Users typically care about active bookings, unless they specify otherwise. The default filter scope for bookings should be: { is_canceled: {eq: false} }", "bulkActions": { "create": true, "update": true, "delete": true } }, - "comments": { - "type": "comments", - "domain": "Documentation", - "itemName": "comment", - "collectionName": "comments", - "description": "Comment is a message in the activity feed of a Task, Deal, Company, or Person.\nComments support rich text formatting and can include attachments.\nHidden comments are private notes visible only to the creator.\n\nWhen creating a comment, provide exactly one parent relationship (task, deal, company, or person).\nMentions format: @[Person:ID:Name]", - "descriptionShort": "Message in the activity feed of a task, deal, company, or person.", + "calendar_events": { + "type": "calendar_events", + "domain": "Other", + "itemName": "calendar event", + "collectionName": "calendar events", + "description": "Calendar Event represents an event from an external calendar integration (Google Calendar or Outlook). These are read-only events synced from a person's connected calendar, showing meetings, out-of-office time, and other scheduled events. Recurring events carry recurring_event_id that links all instances of the same series.", + "descriptionShort": "events synced from an external calendar integration (google cal or outlook)", "customActions": {}, "fields": { "id": { @@ -1437,96 +1664,298 @@ "readonly": true, "id": true }, - "body": { - "key": "body", + "name": { + "key": "name", "type": "string", "typeCategory": "primitive", - "format": "html", - "param": "body", - "required": true, - "attribute": "body" + "param": "name", + "readonly": true, + "attribute": "name" }, - "createdAt": { - "key": "createdAt", + "description": { + "key": "description", + "type": "string", + "typeCategory": "primitive", + "param": "description", + "readonly": true, + "attribute": "description" + }, + "startDate": { + "key": "startDate", "type": "date", "typeCategory": "primitive", + "param": "start_date", "readonly": true, - "sort": "created_at", - "attribute": "created_at" + "filter": "start_date", + "description": "Start date of the event (YYYY-MM-DD format)", + "attribute": "start_date", + "filterConfig": { + "array": false + } }, - "hidden": { - "key": "hidden", - "type": "boolean", + "endDate": { + "key": "endDate", + "type": "date", "typeCategory": "primitive", - "param": "hidden", - "description": "Hidden comments are only seen by the creator", - "attribute": "hidden" + "param": "end_date", + "readonly": true, + "filter": "end_date", + "description": "End date of the event (YYYY-MM-DD format)", + "attribute": "end_date", + "filterConfig": { + "array": false + } }, - "creator": { - "key": "creator", - "type": "people", - "typeCategory": "resource", - "param": "creator_id", - "relationship": "creator" + "startTime": { + "key": "startTime", + "type": "string", + "typeCategory": "primitive", + "param": "start_time", + "readonly": true, + "description": "Start time of the event in HH:MM:SS format (null for all-day events)", + "attribute": "start_time" }, - "project": { - "key": "project", - "type": "projects", - "typeCategory": "resource", - "filter": "project_id", - "description": "Filter comments on tasks within a specific project", - "relationship": "project", - "notIncludable": true + "endTime": { + "key": "endTime", + "type": "string", + "typeCategory": "primitive", + "param": "end_time", + "readonly": true, + "description": "End time of the event in HH:MM:SS format (null for all-day events)", + "attribute": "end_time" }, - "company": { - "key": "company", - "type": "companies", - "typeCategory": "resource", - "param": "company_id", - "filter": "company_id", - "description": "Company being commented on ", - "relationship": "company", - "exclusive": "commentable" + "eventType": { + "key": "eventType", + "type": "string", + "typeCategory": "primitive", + "param": "event_type", + "readonly": true, + "description": "Type of calendar event. Google Calendar values: \"default\", \"outOfOffice\", \"focusTime\", \"workingLocation\". Outlook values: \"free\", \"tentative\", \"busy\", \"oof\", \"workingElsewhere\", \"unknown\".", + "attribute": "event_type" }, - "deal": { - "key": "deal", - "type": "deals", - "typeCategory": "resource", - "param": "deal_id", - "description": "Deal being commented on", - "relationship": "deal", - "exclusive": "commentable" + "creatorName": { + "key": "creatorName", + "type": "string", + "typeCategory": "primitive", + "param": "creator_name", + "readonly": true, + "attribute": "creator_name" }, - "task": { - "key": "task", - "type": "tasks", - "typeCategory": "resource", - "param": "task_id", - "filter": "task_id", - "description": "Task being commented on", - "relationship": "task", - "exclusive": "commentable" + "creatorEmail": { + "key": "creatorEmail", + "type": "string", + "typeCategory": "primitive", + "param": "creator_email", + "readonly": true, + "attribute": "creator_email" }, - "person": { - "key": "person", - "type": "people", - "typeCategory": "resource", - "param": "person_id", - "description": "Person being commented on", - "relationship": "person", - "exclusive": "commentable" + "organizerName": { + "key": "organizerName", + "type": "string", + "typeCategory": "primitive", + "param": "organizer_name", + "readonly": true, + "attribute": "organizer_name" }, - "attachments": { - "key": "attachments", - "type": "attachments", - "typeCategory": "resource", - "relationship": "attachments", - "array": true + "organizerEmail": { + "key": "organizerEmail", + "type": "string", + "typeCategory": "primitive", + "param": "organizer_email", + "readonly": true, + "attribute": "organizer_email" }, - "fuzzyPeople": { + "link": { + "key": "link", + "type": "string", + "typeCategory": "primitive", + "param": "link", + "readonly": true, + "attribute": "link" + }, + "calendar": { + "key": "calendar", + "type": "string", + "typeCategory": "primitive", + "param": "calendar", + "readonly": true, + "description": "Calendar provider name, e.g. \"Google\" or \"Outlook\".", + "attribute": "calendar" + }, + "recurringEventId": { + "key": "recurringEventId", + "type": "string", + "typeCategory": "primitive", + "param": "recurring_event_id", + "readonly": true, + "description": "Identifier linking all instances of a recurring event series. Shared across all expanded instances of the same recurring meeting.", + "attribute": "recurring_event_id" + }, + "createdAt": { + "key": "createdAt", + "type": "date", + "typeCategory": "primitive", + "param": "created_at", + "readonly": true, + "attribute": "created_at" + }, + "updatedAt": { + "key": "updatedAt", + "type": "date", + "typeCategory": "primitive", + "param": "updated_at", + "readonly": true, + "attribute": "updated_at" + }, + "integrationIds": { + "key": "integrationIds", + "type": "string", + "typeCategory": "primitive", + "param": "integration_ids", + "filter": "integration_ids", + "description": "Filter calendar events by integration IDs. Use to scope events to specific calendar integrations." + }, + "calendarIds": { + "key": "calendarIds", + "type": "string", + "typeCategory": "primitive", + "param": "calendar_ids", + "filter": "calendar_ids", + "description": "Filter calendar events by calendar IDs. Use to scope events to specific calendars within an integration." + }, + "person": { + "key": "person", + "type": "people", + "typeCategory": "resource", + "param": "person", + "filter": "person_id", + "description": "Array of person IDs to filter calendar events by. Returns events for any of the specified people. Use to scope events to specific individuals.", + "relationship": "person", + "filterConfig": { + "array": true + } + } + }, + "collections": {}, + "actions": { + "index": true, + "show": false, + "create": false, + "update": false, + "delete": false + } + }, + "comments": { + "type": "comments", + "domain": "Documentation", + "itemName": "comment", + "collectionName": "comments", + "description": "Comment is a message in the activity feed of a Task, Deal, Company, or Person.\nComments support rich text formatting and can include attachments.\nHidden comments are private notes visible only to the creator.\n\nWhen creating a comment, provide exactly one parent relationship (task, deal, company, or person).\nMentions format: @[Person:ID:Name]", + "descriptionShort": "messages in the activity feed of a task, deal, company, or person", + "customActions": {}, + "fields": { + "id": { + "key": "id", + "type": "string", + "typeCategory": "primitive", + "param": "id", + "readonly": true, + "id": true + }, + "body": { + "key": "body", + "type": "string", + "typeCategory": "primitive", + "format": "html", + "param": "body", + "required": true, + "attribute": "body" + }, + "createdAt": { + "key": "createdAt", + "type": "date", + "typeCategory": "primitive", + "param": "created_at", + "readonly": true, + "sort": "created_at", + "attribute": "created_at" + }, + "hidden": { + "key": "hidden", + "type": "boolean", + "typeCategory": "primitive", + "param": "is_hidden", + "description": "Hidden comments are only seen by the creator", + "attribute": "hidden" + }, + "creator": { + "key": "creator", + "type": "people", + "typeCategory": "resource", + "param": "creator", + "relationship": "creator" + }, + "project": { + "key": "project", + "type": "projects", + "typeCategory": "resource", + "param": "project", + "filter": "project_id", + "description": "Filter comments on tasks within a specific project", + "relationship": "project", + "notIncludable": true + }, + "company": { + "key": "company", + "type": "companies", + "typeCategory": "resource", + "param": "company", + "filter": "company_id", + "description": "Company being commented on ", + "relationship": "company", + "exclusive": "commentable" + }, + "deal": { + "key": "deal", + "type": "deals", + "typeCategory": "resource", + "param": "deal", + "description": "Deal being commented on", + "relationship": "deal", + "exclusive": "commentable" + }, + "task": { + "key": "task", + "type": "tasks", + "typeCategory": "resource", + "param": "task", + "filter": "task_id", + "description": "Task being commented on", + "relationship": "task", + "exclusive": "commentable" + }, + "person": { + "key": "person", + "type": "people", + "typeCategory": "resource", + "param": "person", + "description": "Person being commented on", + "relationship": "person", + "exclusive": "commentable" + }, + "attachments": { + "key": "attachments", + "type": "attachments", + "typeCategory": "resource", + "param": "attachments", + "relationship": "attachments", + "array": true + }, + "fuzzyPeople": { "key": "fuzzyPeople", "type": "people", "typeCategory": "resource", + "param": "fuzzy_people", "readonly": true, "filter": "fuzzy_people", "description": "Filter comments by creator (people)", @@ -1544,7 +1973,7 @@ "itemName": "company", "collectionName": "companies", "description": "Company represents a client organization or the user's own organization.\nClient companies are the central hub for managing client relationships — they link to deals, budgets, projects, contacts, and invoices.\n\nEach company can define default invoicing settings (subsidiary, invoice template, tax rate, payment terms) that auto-apply when creating new deals, budgets, or invoices for that client.\nCompanies support hierarchical structures via parent_company_id, tags for categorization, and custom fields for additional data.\nRate cards can be linked to companies to define client-specific pricing.\nThe organization's own company is used for internal (non-billable) projects and as the default rate card source.\nCompanies can be archived when no longer active.", - "descriptionShort": "Client organization linked to deals, budgets, projects, and invoices — with default invoicing settings and rate cards.", + "descriptionShort": "client organizations linked to deals, budgets, projects, and invoices — with invoicing settings and rate cards", "customActions": { "archive": { "name": "archive", @@ -1590,6 +2019,7 @@ "key": "defaultCurrency", "type": "string", "typeCategory": "primitive", + "param": "default_currency", "readonly": true, "attribute": "default_currency" }, @@ -1597,6 +2027,7 @@ "key": "billingName", "type": "string", "typeCategory": "primitive", + "param": "billing_name", "readonly": true, "description": "Legal entity name", "attribute": "billing_name" @@ -1640,6 +2071,7 @@ "key": "dueDays", "type": "number", "typeCategory": "primitive", + "param": "due_days", "filter": "due_days", "description": "Default payment terms in days for invoices", "attribute": "due_days", @@ -1649,6 +2081,7 @@ "key": "contact", "type": "hash", "typeCategory": "primitive", + "param": "contact", "description": "Contact and address information (address, phone, email, etc.)", "attribute": "contact" }, @@ -1656,6 +2089,7 @@ "key": "tagList", "type": "string", "typeCategory": "primitive", + "param": "tags", "filter": "tags", "description": "Tags assigned to the company for categorization", "attribute": "tag_list", @@ -1666,6 +2100,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "filter": "created_at", "sort": "created_at", @@ -1676,6 +2111,7 @@ "key": "archivedAt", "type": "date", "typeCategory": "primitive", + "param": "archived_at", "readonly": true, "filter": "archived_at", "description": "When the company was archived (null if active)", @@ -1685,6 +2121,7 @@ "key": "lastActivityAt", "type": "date", "typeCategory": "primitive", + "param": "last_activity_at", "readonly": true, "filter": "last_activity_at", "sort": "last_activity_at", @@ -1695,6 +2132,7 @@ "key": "avatarUrl", "type": "string", "typeCategory": "primitive", + "param": "avatar_url", "description": "URL of the company logo/avatar", "attribute": "avatar_url", "serialize": false @@ -1703,6 +2141,7 @@ "key": "subscriberIds", "type": "string", "typeCategory": "primitive", + "param": "subscriber_ids", "filter": "subscriber_id", "description": "IDs of people subscribed to this company", "attribute": "subscriber_ids", @@ -1713,6 +2152,7 @@ "key": "parentCompanyId", "type": "string", "typeCategory": "primitive", + "param": "parent_company_id", "filter": "parent_company_id", "sort": "parent_company", "description": "ID of the parent company in a hierarchical company structure", @@ -1723,6 +2163,7 @@ "key": "status", "type": "archivable_status", "typeCategory": "enum", + "param": "status", "filter": "status", "description": "Filter by active or archived", "serialize": false @@ -1731,6 +2172,7 @@ "key": "projectId", "type": "projects", "typeCategory": "resource", + "param": "project_id", "filter": "project_id", "description": "Filter companies by associated project", "serialize": false @@ -1739,6 +2181,7 @@ "key": "subscriberId", "type": "people", "typeCategory": "resource", + "param": "subscriber_id", "filter": "subscriber_id", "description": "Filter companies by subscribed person", "serialize": false @@ -1772,7 +2215,7 @@ "itemName": "contact entry", "collectionName": "contact entries", "description": "Contact Entry stores contact information (email, phone, address, website) for people, companies, invoices, subsidiaries, and other contactable entities. Each entry has a type and belongs to one contactable entity via a polymorphic relationship.", - "descriptionShort": "Contact information (email, phone, address) for people or companies.", + "descriptionShort": "contact data (email, phone, address) for people or companies", "customActions": {}, "fields": { "id": { @@ -1882,7 +2325,7 @@ "key": "billingAddress", "type": "boolean", "typeCategory": "primitive", - "param": "billing_address", + "param": "is_billing_address", "description": "Whether this is a billing address", "attribute": "billing_address" }, @@ -1898,7 +2341,7 @@ "key": "company", "type": "companies", "typeCategory": "resource", - "param": "company_id", + "param": "company", "filter": "company_id", "description": "Company this contact entry belongs to", "relationship": "company", @@ -1908,7 +2351,7 @@ "key": "person", "type": "people", "typeCategory": "resource", - "param": "person_id", + "param": "person", "filter": "person_id", "description": "Person this contact entry belongs to", "relationship": "person", @@ -1918,7 +2361,7 @@ "key": "invoice", "type": "invoices", "typeCategory": "resource", - "param": "invoice_id", + "param": "invoice", "filter": "invoice_id", "description": "Invoice this contact entry belongs to", "relationship": "invoice", @@ -1928,7 +2371,7 @@ "key": "subsidiary", "type": "subsidiaries", "typeCategory": "resource", - "param": "subsidiary_id", + "param": "subsidiary", "filter": "subsidiary_id", "description": "Subsidiary this contact entry belongs to", "relationship": "subsidiary", @@ -1938,7 +2381,7 @@ "key": "purchaseOrder", "type": "purchase_orders", "typeCategory": "resource", - "param": "purchase_order_id", + "param": "purchase_order", "description": "Purchase order this contact entry belongs to", "relationship": "purchase_order", "exclusive": "contactable" @@ -1947,6 +2390,7 @@ "key": "contactableId", "type": "string", "typeCategory": "primitive", + "param": "contactable_id", "readonly": true, "filter": "contactable_id", "description": "Filter by contactable entity ID" @@ -1960,7 +2404,7 @@ "itemName": "contract", "collectionName": "contracts", "description": "Contract defines a recurring (retainer) arrangement where a Budget automatically regenerates at set intervals.\nIntervals include weekly, biweekly, monthly, quarterly, semiannual, and annual. The next occurrence date determines when Productive creates a new budget.\n\nEach contract is linked to a template deal/budget that serves as the blueprint for each new occurrence.\nConfigurable per-recurrence settings:\n- Roll over unused hours: carry forward unused (or overused) hours from one period to the next for accurate retainer tracking.\n- Copy expenses: duplicate expenses (with amounts, custom fields, descriptions) into each new budget. Payment status resets to unpaid.\n- Copy purchase order number: maintain the same PO reference across all recurring budgets.\n- Automatic invoice drafts can be configured to generate with each new occurrence.\n\nContracts have a start date, optional end date (for indefinite recurrence, leave blank), and track the next occurrence date.\nThe next occurrence can also be triggered manually for planning ahead.", - "descriptionShort": "Recurring (retainer) arrangement — auto-generates new budgets at set intervals with configurable rollover.", + "descriptionShort": "recurring retainers — auto-generates budgets at set intervals with rollover", "customActions": {}, "fields": { "id": { @@ -2013,7 +2457,7 @@ "key": "template", "type": "deals", "typeCategory": "resource", - "param": "template_id", + "param": "template", "required": true, "filter": "template_id", "description": "Deal the contract is associated with", @@ -2055,7 +2499,7 @@ "itemName": "custom field option", "collectionName": "custom field options", "description": "Custom Field Option is a selectable choice for a single-select (dropdown) or multi-select custom field. Each option belongs to a specific custom field and has a display name, position for ordering, and optional color for visual distinction. Options can be archived when no longer needed — archived options remain on existing records but are hidden from new selections.", - "descriptionShort": "Selectable choice for a dropdown or multi-select custom field.", + "descriptionShort": "selectable options for a dropdown or multi-select custom fields", "customActions": {}, "fields": { "id": { @@ -2072,7 +2516,6 @@ "typeCategory": "primitive", "param": "name", "required": true, - "filter": "name", "attribute": "name" }, "position": { @@ -2087,6 +2530,7 @@ "key": "archivedAt", "type": "date", "typeCategory": "primitive", + "param": "archived_at", "attribute": "archived_at" }, "colorId": { @@ -2100,7 +2544,7 @@ "key": "customField", "type": "custom_fields", "typeCategory": "resource", - "param": "custom_field_id", + "param": "custom_field", "required": true, "filter": "custom_field_id", "relationship": "custom_field", @@ -2115,7 +2559,7 @@ "itemName": "custom_field_section", "collectionName": "custom field sections", "description": "Custom Field Section groups related custom fields together for visual organization. Sections create logical categories (e.g., \"Financial Details\", \"Client Info\") on detail views of tasks, deals, projects, and other customizable resources. Each custom field can belong to one section.", - "descriptionShort": "Categories for Custom Fields.", + "descriptionShort": "categories for custom fields", "customActions": {}, "fields": { "id": { @@ -2143,7 +2587,7 @@ "itemName": "custom field", "collectionName": "custom fields", "description": "Custom Field adds user-defined data to resources like tasks, deals, budgets, projects, people, companies, invoices, expenses, bookings, and services.\nEach field has a customizable_type that determines which resource it extends, and a data_type that determines the input format:\ntext, number, select (single dropdown), multiselect, date, person reference, or file attachment.\n\nCustom fields can be:\n- Global: applies organization-wide to all instances of the target resource type.\n- Project-scoped: applies only within a specific project (for task custom fields).\n- Required: a value must be provided when creating or updating the resource.\n- Sensitive: visible only to users with sensitive field access permission.\n\nSelect and multiselect fields have associated custom field options that define the available choices.\nFields are organized into custom field sections for visual grouping.\nFields can be archived when no longer needed.", - "descriptionShort": "User-defined data field (text, number, dropdown, date, person, file) extending tasks, deals, people, and other resources.", + "descriptionShort": "user-defined fields (text, number, dropdown, date, person, file) on tasks, deals, people, and other resources", "customActions": {}, "fields": { "id": { @@ -2190,7 +2634,7 @@ "key": "global", "type": "boolean", "typeCategory": "primitive", - "param": "global", + "param": "is_global", "required": true, "filter": "global", "description": "Defines if the custom field is global (not bound to a project)", @@ -2200,7 +2644,7 @@ "key": "required", "type": "boolean", "typeCategory": "primitive", - "param": "required", + "param": "is_required", "required": true, "description": "Defines if the custom field value is required on the object", "attribute": "required" @@ -2217,7 +2661,7 @@ "key": "sensitive", "type": "boolean", "typeCategory": "primitive", - "param": "sensitive", + "param": "is_sensitive", "required": true, "description": "Is the custom field value sensitive (visible only to people with a sensitive access permission)?", "attribute": "sensitive" @@ -2226,6 +2670,7 @@ "key": "archivedAt", "type": "date", "typeCategory": "primitive", + "param": "archived_at", "readonly": true, "attribute": "archived_at" }, @@ -2233,7 +2678,7 @@ "key": "project", "type": "projects", "typeCategory": "resource", - "param": "project_id", + "param": "project", "filter": "project_id", "description": "Project the custom field is scoped to (if not global)", "relationship": "project" @@ -2242,7 +2687,7 @@ "key": "section", "type": "custom_field_sections", "typeCategory": "resource", - "param": "section_id", + "param": "section", "relationship": "section" }, "aggregationTypeId": { @@ -2265,6 +2710,7 @@ "key": "options", "type": "custom_field_options", "typeCategory": "resource", + "param": "options", "readonly": true, "relationship": "options", "array": true @@ -2273,6 +2719,7 @@ "key": "survey", "type": "surveys", "typeCategory": "resource", + "param": "survey", "description": "Survey this custom field belongs to (for survey-type custom fields)", "relationship": "survey" } @@ -2285,7 +2732,7 @@ "itemName": "deal_status", "collectionName": "deal statuses", "description": "Deal Status (Pipeline Stage) represents a named stage within a Pipeline that deals progress through.\nEach deal status belongs to exactly one pipeline and has an ordered position within it.\n\nEach status has a stage status that determines the deal outcome when moved to it:\n- Open (status_id=1): deal is active and in progress.\n- Won (status_id=2): deal was successfully closed. Probability defaults to 100%.\n- Lost (status_id=3): deal was not successful. Probability defaults to 0%. Can require a lost reason (lost_reason_enabled).\n- Delivered (status_id=4): budget work has been completed.\n\nPer-stage configuration:\n- Probability (0-100%): default win probability for revenue forecasting when a deal enters this stage.\n- Tracking toggles: time tracking, expense tracking, and booking creation can be enabled/disabled per stage.\n- The stage status cannot be changed after creation, as it would affect all existing deals in that status.", - "descriptionShort": "Named stage in a pipeline — defines deal outcome (open/won/lost/delivered) and tracking capabilities.", + "descriptionShort": "pipeline stages that define deal outcome (open/won/lost/delivered) and tracking capabilities", "customActions": {}, "fields": { "id": { @@ -2320,7 +2767,7 @@ "key": "statusId", "type": "pipeline_stage_status", "typeCategory": "enum", - "param": "status_id", + "param": "status", "required": true, "sort": "status_id", "description": "Whether deals in this pipeline stage are considered open (in progress), won (closed successfully), lost (closed unsuccessfully), or delivered (work completed)", @@ -2348,7 +2795,7 @@ "key": "pipeline", "type": "pipelines", "typeCategory": "resource", - "param": "pipeline_id", + "param": "pipeline", "required": true, "filter": "pipeline_id", "sort": "pipeline_id", @@ -2374,6 +2821,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "sort": "created_at", "attribute": "created_at" @@ -2382,6 +2830,7 @@ "key": "archivedAt", "type": "date", "typeCategory": "primitive", + "param": "archived_at", "readonly": true, "attribute": "archived_at" }, @@ -2413,6 +2862,7 @@ "key": "used", "type": "boolean", "typeCategory": "primitive", + "param": "is_used", "readonly": true, "description": "Whether this status is currently used by any deals", "attribute": "used" @@ -2429,9 +2879,22 @@ "domain": "CRM & Sales", "itemName": "deal", "collectionName": "deals", - "description": "Deal represents a potential or actual job with a client company.\nDeals are a polymorphic resource with two subtypes:\n- Sales Deals (budget=false) — track opportunities through pipeline stages with win probability for revenue forecasting. Time can be tracked for presales work but is not billable until the deal is won.\n- Production Budgets (budget=true) — active jobs where work is delivered, tracked, and billed. Budgets can be client-facing (billable) or internal (non-billable).\n\nDeals contain Services — line items that define deliverables with billing types (Fixed, Time & Materials, Non-billable), pricing, quantity, and where time entries and expenses are tracked.\nServices can be organized into Sections and can be moved between deals/budgets.\nDeals can be linked to Projects for task management and can be recurring (retainer) through Contracts, which auto-generate new budget occurrences at set intervals.\nFinancial tracking includes revenue, cost (labor + expenses), profit, and margin. Invoicing is only possible from budgets, not from sales deals directly.", - "descriptionShort": "Client job — either a sales deal tracking pipeline opportunities, or a production budget where work is delivered and billed.", - "customActions": {}, + "description": "Deal represents a potential or actual job with a client company.\nDeals are a polymorphic resource with two subtypes (differentiated by stage_type):\n- Sales Deals (budget=false) — track opportunities through pipeline stages with win probability for revenue forecasting. Time can be tracked for presales work but is not billable until the deal is won.\n- Production Budgets (budget=true) — active jobs where work is delivered, tracked, and billed. Budgets can be client-facing (billable) or internal (non-billable).\n\nDeals contain Services — line items that define deliverables with billing types (Fixed, Time & Materials, Non-billable), pricing, quantity, and where time entries and expenses are tracked.\nServices can be organized into Sections and can be moved between deals/budgets.\nDeals can be linked to Projects for task management and can be recurring (retainer) through Contracts, which auto-generate new budget occurrences at set intervals.\nFinancial tracking includes revenue, cost (labor + expenses), profit, and margin. Invoicing is only possible from budgets, not from sales deals directly.", + "descriptionShort": "sales deals or production budgets — tracks pipeline opportunities or deliverables and billable work", + "customActions": { + "close": { + "name": "close", + "description": "Close a budget (sets closed_at to now).", + "endpoint": "close", + "method": "PUT" + }, + "open": { + "name": "open", + "description": "Re-open a previously closed budget (clears closed_at).", + "endpoint": "open", + "method": "PUT" + } + }, "fields": { "id": { "key": "id", @@ -2472,17 +2935,24 @@ "key": "budget", "type": "boolean", "typeCategory": "primitive", - "param": "budget", + "param": "is_budget", "required": true, - "filter": "budget", - "description": "Indicates if the deal is a client budget (actual job in production that people work on)", + "description": "Whether the record is a sales deal or a production budget", "attribute": "budget" }, + "stageType": { + "key": "stageType", + "type": "stage_type", + "typeCategory": "enum", + "param": "stage_type", + "filter": "type", + "description": "Filter by whether the record is a sales deal or a production budget" + }, "company": { "key": "company", "type": "companies", "typeCategory": "resource", - "param": "company_id", + "param": "company", "required": true, "filter": "company_id", "sort": "company_name", @@ -2493,7 +2963,7 @@ "key": "responsible", "type": "people", "typeCategory": "resource", - "param": "responsible_id", + "param": "responsible", "required": true, "filter": "responsible_id", "sort": "responsible_name", @@ -2503,7 +2973,7 @@ "key": "project", "type": "projects", "typeCategory": "resource", - "param": "project_id", + "param": "project", "filter": "project_id", "sort": "project_name", "description": "Project associated with the deal or budget, if any. Only budgets can have associated internal projects. Deals can only have client projects", @@ -2523,7 +2993,7 @@ "key": "subsidiary", "type": "subsidiaries", "typeCategory": "resource", - "param": "subsidiary_id", + "param": "subsidiary", "required": true, "filter": "subsidiary_id", "relationship": "subsidiary" @@ -2563,6 +3033,7 @@ "key": "suffix", "type": "string", "typeCategory": "primitive", + "param": "suffix", "description": "Suffix indicating the period if the deal is auto-recurring (used for retainer deals)", "attribute": "suffix" }, @@ -2593,7 +3064,7 @@ "key": "contract", "type": "contracts", "typeCategory": "resource", - "param": "contract_id", + "param": "contract", "filter": "contract_id", "description": "Contract the deal is associated with, if the deal is a retainer deal", "relationship": "contract" @@ -2602,14 +3073,14 @@ "key": "documentType", "type": "document_types", "typeCategory": "resource", - "param": "document_type_id", + "param": "document_type", "relationship": "document_type" }, "lost_reason": { "key": "lost_reason", "type": "lost_reasons", "typeCategory": "resource", - "param": "lost_reason_id", + "param": "lost_reason", "filter": "lost_reason_id", "description": "Reason why the deal was lost. Required when setting a deal status that has lostReasonEnabled=true. Check the target deal status's lostReasonEnabled property - if true, you must provide a lost reason before submitting.", "relationship": "lost_reason" @@ -2618,6 +3089,7 @@ "key": "pipeline", "type": "pipelines", "typeCategory": "resource", + "param": "pipeline", "filter": "pipeline_id", "description": "Sales pipeline this deal belongs to", "relationship": "pipeline", @@ -2627,6 +3099,7 @@ "key": "contact", "type": "people", "typeCategory": "resource", + "param": "contact", "filter": "contact_id", "description": "Contact person at the client company for this deal", "relationship": "contact" @@ -2635,6 +3108,7 @@ "key": "creator", "type": "people", "typeCategory": "resource", + "param": "creator", "readonly": true, "filter": "creator_id", "description": "Person who created the deal", @@ -2645,6 +3119,7 @@ "type": "string", "typeCategory": "primitive", "format": "html", + "param": "note", "description": "Deal notes or description (HTML content)", "attribute": "note" }, @@ -2652,6 +3127,7 @@ "key": "tagList", "type": "string", "typeCategory": "primitive", + "param": "tags", "filter": "tags", "description": "Tags assigned to the deal for categorization", "attribute": "tag_list", @@ -2661,6 +3137,7 @@ "key": "lostComment", "type": "string", "typeCategory": "primitive", + "param": "lost_comment", "description": "Comment explaining why the deal was lost", "attribute": "lost_comment" }, @@ -2668,6 +3145,7 @@ "key": "purchaseOrderNumber", "type": "string", "typeCategory": "primitive", + "param": "purchase_order_number", "filter": "purchase_order_number", "sort": "purchase_order_number", "description": "Client purchase order number reference for invoicing", @@ -2677,6 +3155,7 @@ "key": "colorId", "type": "number", "typeCategory": "primitive", + "param": "color_id", "filter": "color_id", "description": "Color identifier for visual categorization in pipeline views", "attribute": "color_id", @@ -2686,6 +3165,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "filter": "created_at", "sort": "created_at", @@ -2696,6 +3176,7 @@ "key": "closedAt", "type": "date", "typeCategory": "primitive", + "param": "closed_at", "readonly": true, "filter": "closed_at", "sort": "closed_at", @@ -2707,6 +3188,7 @@ "type": "date", "typeCategory": "primitive", "format": "YYYY-MM-DD", + "param": "delivered_on", "filter": "delivered_on", "description": "Date when the work/deliverable was delivered to the client", "attribute": "delivered_on" @@ -2716,6 +3198,7 @@ "type": "date", "typeCategory": "primitive", "format": "YYYY-MM-DD", + "param": "sales_closed_on", "filter": "sales_closed_on", "description": "Date when the deal was closed from a sales perspective (won or lost). Distinct from closed_at which tracks operational budget closure.", "attribute": "sales_closed_on" @@ -2724,6 +3207,7 @@ "key": "salesStatusUpdatedAt", "type": "date", "typeCategory": "primitive", + "param": "sales_status_updated_at", "readonly": true, "description": "When the deal last moved between pipeline stages", "attribute": "sales_status_updated_at", @@ -2733,6 +3217,7 @@ "key": "lastActivityAt", "type": "date", "typeCategory": "primitive", + "param": "last_activity_at", "readonly": true, "filter": "last_activity_at", "sort": "last_activity_at", @@ -2744,6 +3229,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "revenue", "readonly": true, "filter": "revenue", "sort": "revenue", @@ -2755,6 +3241,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "cost", "readonly": true, "filter": "cost", "sort": "cost", @@ -2766,6 +3253,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "profit", "readonly": true, "filter": "profit", "sort": "profit", @@ -2777,6 +3265,7 @@ "type": "number", "typeCategory": "primitive", "unit": "percentage", + "param": "profit_margin", "readonly": true, "filter": "profit_margin", "sort": "profit_margin", @@ -2788,6 +3277,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "budget_total", "readonly": true, "filter": "budget_total", "sort": "budget_total", @@ -2799,6 +3289,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "budget_used", "readonly": true, "filter": "budget_used", "sort": "budget_used", @@ -2810,6 +3301,7 @@ "type": "number", "typeCategory": "primitive", "unit": "minutes", + "param": "worked_time", "readonly": true, "filter": "worked_time", "sort": "worked_time", @@ -2821,6 +3313,7 @@ "type": "number", "typeCategory": "primitive", "unit": "minutes", + "param": "estimated_time", "readonly": true, "filter": "estimated_time", "sort": "estimated_time", @@ -2832,6 +3325,7 @@ "type": "number", "typeCategory": "primitive", "unit": "minutes", + "param": "budgeted_time", "readonly": true, "filter": "budgeted_time", "sort": "budgeted_time", @@ -2843,6 +3337,7 @@ "type": "number", "typeCategory": "primitive", "unit": "minutes", + "param": "billable_time", "readonly": true, "filter": "billable_time", "sort": "billable_time", @@ -2854,6 +3349,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "projected_revenue", "readonly": true, "filter": "projected_revenue", "sort": "projected_revenue", @@ -2865,6 +3361,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "invoiced", "readonly": true, "filter": "invoiced", "sort": "invoiced", @@ -2876,6 +3373,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "pending_invoicing", "readonly": true, "filter": "pending_invoicing", "sort": "pending_invoicing", @@ -2886,6 +3384,7 @@ "key": "previousProbability", "type": "number", "typeCategory": "primitive", + "param": "previous_probability", "readonly": true, "filter": "previous_probability", "description": "Win probability before the most recent change (0-100 scale)", @@ -2896,6 +3395,7 @@ "key": "daysSinceLastActivity", "type": "number", "typeCategory": "primitive", + "param": "days_since_last_activity", "readonly": true, "filter": "days_since_last_activity", "description": "Number of days since the last activity on the deal", @@ -2906,6 +3406,7 @@ "key": "daysInCurrentStage", "type": "number", "typeCategory": "primitive", + "param": "days_in_current_stage", "readonly": true, "filter": "days_in_current_stage", "description": "Number of days the deal has been in its current pipeline stage", @@ -2915,6 +3416,7 @@ "key": "daysSinceCreated", "type": "number", "typeCategory": "primitive", + "param": "days_since_created", "readonly": true, "filter": "days_since_created", "description": "Number of days since the deal was created (or days from creation to sales close for closed deals)", @@ -2925,6 +3427,7 @@ "key": "timeApproval", "type": "boolean", "typeCategory": "primitive", + "param": "requires_time_approval", "filter": "time_approval", "description": "Whether time entries on this budget require approval before they count", "attribute": "time_approval", @@ -2934,6 +3437,7 @@ "key": "expenseApproval", "type": "boolean", "typeCategory": "primitive", + "param": "requires_expense_approval", "description": "Whether expenses on this budget require approval", "attribute": "expense_approval", "serialize": false @@ -2943,6 +3447,7 @@ "type": "number", "typeCategory": "primitive", "unit": "percentage", + "param": "budget_warning", "filter": "budget_warning", "sort": "budget_warning", "description": "Budget warning threshold percentage (0-100). Triggers a notification when budget usage exceeds this value.", @@ -2952,6 +3457,7 @@ "key": "trackingTypeId", "type": "budget_tracking_type", "typeCategory": "enum", + "param": "tracking_type_id", "filter": "tracking_type_id", "description": "Controls who can track time: all services, only assigned services, or only assigned service types", "attribute": "tracking_type_id" @@ -2960,6 +3466,7 @@ "key": "status", "type": "budget_status", "typeCategory": "enum", + "param": "status", "filter": "status", "description": "Filter by operational budget status: open (work ongoing) or closed (work complete)" }, @@ -2967,6 +3474,7 @@ "key": "stageStatusId", "type": "pipeline_stage_status", "typeCategory": "enum", + "param": "stage_status", "filter": "stage_status_id", "description": "Filter by deal stage status: open, won, or lost. Applies to both sales deals and budgets." }, @@ -2974,6 +3482,7 @@ "key": "salesStatusId", "type": "pipeline_stage_status", "typeCategory": "enum", + "param": "sales_status", "filter": "sales_status_id", "description": "Filter by sales pipeline status: open, won, or lost" }, @@ -2981,6 +3490,7 @@ "key": "needsClosing", "type": "boolean", "typeCategory": "primitive", + "param": "needs_closing", "filter": "needs_closing", "description": "Filter for budgets past their end date that have not been closed yet" }, @@ -2988,6 +3498,7 @@ "key": "needsInvoicing", "type": "boolean", "typeCategory": "primitive", + "param": "needs_invoicing", "filter": "needs_invoicing", "description": "Filter for closed budgets that still have uninvoiced revenue" }, @@ -2995,6 +3506,7 @@ "key": "recurring", "type": "boolean", "typeCategory": "primitive", + "param": "is_recurring", "filter": "recurring", "description": "Filter for recurring deals (linked to a contract) vs one-off deals" }, @@ -3003,6 +3515,7 @@ "type": "number", "typeCategory": "primitive", "unit": "percentage", + "param": "budget_usage", "filter": "budget_usage", "description": "Filter by budget consumption percentage (0-100 scale, e.g. 75 means 75% of budget used)" }, @@ -3011,6 +3524,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "budget_remaining", "filter": "budget_remaining", "description": "Filter by remaining budget amount in cents (budget_total minus budget_used)" }, @@ -3018,6 +3532,7 @@ "key": "subscriberId", "type": "people", "typeCategory": "resource", + "param": "subscriber_id", "filter": "subscriber_id", "description": "Filter deals by subscribed/following person" } @@ -3036,7 +3551,7 @@ "inverse": "deal" } }, - "queryHints": "Deals is a polymorphic resource with subtypes: sales deals and budgets.\nEach subtype has a different default filter scope:\n- sales deals: { budget: {eq: false}, stage_status_id: {eq: '1'} }\n- budgets: { budget: {eq: true}, status: {eq: '1'} }\nWhen users ask about \"deals\" without specifying a subtype, default to sales deals.\nUsers typically refer to production budgets just as \"budgets\".\nDefault filter scope (open deals and open budgets) should be applied, unless user specifies otherwise.", + "queryHints": "Deals is a polymorphic resource with subtypes: sales deals and budgets.\nEach subtype has a different default filter scope:\n- sales deals: { stage_type: {eq: '1'}, stage_status: {eq: '1'} }\n- budgets: { stage_type: {eq: '2'}, status: {eq: '1'} }\nWhen users ask about \"deals\" without specifying a subtype, the default is sales deals.\nUsers typically refer to production budgets just as \"budgets\".\nThe default filter scope is open deals and open budgets, unless the user specifies otherwise.", "searchQuickResultType": [ "deal", "budget" @@ -3052,7 +3567,7 @@ "itemName": "deleted item", "collectionName": "deleted items", "description": "A record of a soft-deleted resource in the recycle bin. Deleted items track what was deleted, when, by whom, and can be restored to recover the original resource. Supported item types include: deal, project, budget, invoice, task, service, dashboard, time_entry, purchase_order, page, booking, event, expense, template, survey.", - "descriptionShort": "Soft-deleted resource in the recycle bin, restorable by users.", + "descriptionShort": "soft-deleted and restoreable records in the recycle bin", "customActions": { "restore": { "name": "restore", @@ -3074,6 +3589,7 @@ "key": "name", "type": "string", "typeCategory": "primitive", + "param": "name", "readonly": true, "sort": "name", "description": "Name of the deleted resource", @@ -3083,6 +3599,7 @@ "key": "location", "type": "string", "typeCategory": "primitive", + "param": "location", "readonly": true, "sort": "location", "description": "Where the item was located (e.g., deal/budget name for services)", @@ -3092,6 +3609,7 @@ "key": "itemId", "type": "string", "typeCategory": "primitive", + "param": "item_id", "readonly": true, "description": "ID of the original deleted resource", "attribute": "item_id" @@ -3109,6 +3627,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "sort": "created_at", "description": "When the item was deleted", @@ -3118,6 +3637,7 @@ "key": "recoveredAt", "type": "date", "typeCategory": "primitive", + "param": "recovered_at", "readonly": true, "description": "When the item was restored (null if not yet restored)", "attribute": "recovered_at" @@ -3126,6 +3646,7 @@ "key": "deleter", "type": "people", "typeCategory": "resource", + "param": "deleter", "readonly": true, "description": "Person who deleted the item", "relationship": "deleter" @@ -3139,7 +3660,7 @@ "itemName": "discussion", "collectionName": "discussions", "description": "Discussion is a threaded conversation attached to a doc page. Discussions enable collaborative review by allowing comments on specific parts of a document. Each discussion has a status (active or resolved), can be reopened after resolution, and supports subscriber notifications. Discussions belong to a specific page.", - "descriptionShort": "Threaded conversation attached to a doc page for collaborative review.", + "descriptionShort": "threaded conversations on a doc page for collaborative review", "customActions": { "resolve": { "name": "resolve", @@ -3179,6 +3700,7 @@ "key": "excerpt", "type": "string", "typeCategory": "primitive", + "param": "excerpt", "readonly": true, "description": "Preview excerpt of the discussion content", "attribute": "excerpt" @@ -3187,6 +3709,7 @@ "key": "resolvedAt", "type": "date", "typeCategory": "primitive", + "param": "resolved_at", "readonly": true, "sort": "resolved_at", "description": "When the discussion was resolved", @@ -3196,6 +3719,7 @@ "key": "subscriberIds", "type": "string", "typeCategory": "primitive", + "param": "subscriber_ids", "readonly": true, "description": "IDs of people subscribed to this discussion", "attribute": "subscriber_ids", @@ -3205,6 +3729,7 @@ "key": "status", "type": "discussion_status", "typeCategory": "enum", + "param": "status", "readonly": true, "filter": "status", "description": "Filter by discussion status: 1=active, 2=resolved" @@ -3213,6 +3738,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "sort": "created_at", "attribute": "created_at" @@ -3221,6 +3747,7 @@ "key": "updatedAt", "type": "date", "typeCategory": "primitive", + "param": "updated_at", "readonly": true, "sort": "updated_at", "attribute": "updated_at" @@ -3229,7 +3756,7 @@ "key": "page", "type": "pages", "typeCategory": "resource", - "param": "page_id", + "param": "page", "required": true, "filter": "page_id", "description": "Doc page this discussion belongs to", @@ -3244,7 +3771,7 @@ "itemName": "document type", "collectionName": "document types", "description": "Document Type defines the template and settings for generating PDF documents.\nFour document types: Invoice (also used for credit notes), Proposal (for deals and budgets), Budget Status, and Purchase Order.\n\nEach document type controls:\n- Content: which fields appear (totals, line item details, attachments, notes, footer), their order, and layout.\n- Localization: language and date format for the document.\n- Visual style: linked to a Document Style that defines fonts, colors, headers/footers, and logo placement.\n- Default tax rates: up to two tax components (e.g. federal + state) that pre-fill on documents.\n- Subsidiary: determines which legal entity's branding and details appear.\n\nDocument types can be set as defaults per subsidiary or per client company.\nSelection priority for invoices: client company default → subsidiary default → first template alphabetically.\nDocument types can be archived when outdated.", - "descriptionShort": "Template for PDF generation — controls content, layout, localization, and branding of financial documents.", + "descriptionShort": "templates for PDF generation of financial documents — content, layout, and branding", "customActions": {}, "fields": { "id": { @@ -3259,6 +3786,7 @@ "key": "name", "type": "string", "typeCategory": "primitive", + "param": "name", "required": true, "attribute": "name" }, @@ -3266,30 +3794,35 @@ "key": "tax1Name", "type": "string", "typeCategory": "primitive", + "param": "tax1_name", "attribute": "tax1_name" }, "tax1Value": { "key": "tax1Value", "type": "number", "typeCategory": "primitive", + "param": "tax1_value", "attribute": "tax1_value" }, "tax2Name": { "key": "tax2Name", "type": "string", "typeCategory": "primitive", + "param": "tax2_name", "attribute": "tax2_name" }, "tax2Value": { "key": "tax2Value", "type": "number", "typeCategory": "primitive", + "param": "tax2_value", "attribute": "tax2_value" }, "documentTemplateId": { "key": "documentTemplateId", "type": "document_template", "typeCategory": "enum", + "param": "document_template", "filter": "document_template_id", "attribute": "document_template_id" }, @@ -3297,6 +3830,7 @@ "key": "exportableTypeId", "type": "exportable_type", "typeCategory": "enum", + "param": "exportable_type", "filter": "exportable_type_id", "attribute": "exportable_type_id" }, @@ -3304,6 +3838,7 @@ "key": "status", "type": "archivable_status", "typeCategory": "enum", + "param": "status", "filter": "status", "description": "Whether the document type is active or archived", "attribute": "status" @@ -3312,6 +3847,7 @@ "key": "archivedAt", "type": "date", "typeCategory": "primitive", + "param": "archived_at", "readonly": true, "attribute": "archived_at" }, @@ -3342,6 +3878,7 @@ "key": "subsidiary", "type": "subsidiaries", "typeCategory": "resource", + "param": "subsidiary", "filter": "subsidiary_id", "relationship": "subsidiary" }, @@ -3349,12 +3886,14 @@ "key": "documentStyle", "type": "string", "typeCategory": "primitive", + "param": "document_style", "relationship": "document_style" }, "attachments": { "key": "attachments", "type": "attachments", "typeCategory": "resource", + "param": "attachments", "relationship": "attachments", "array": true } @@ -3368,11 +3907,11 @@ }, "einvoice_configurations": { "type": "einvoice_configurations", - "domain": "Other", + "domain": "Financial", "itemName": "e-invoice configuration", "collectionName": "e-invoice configurations", "description": "EInvoiceConfiguration holds e-invoicing settings for a subsidiary. It includes flags for\nenabling different e-invoice formats (FACE, KSeF, XRechnung, MER) and a kpdCodeMapping\nwhich maps service type IDs to KPD code IDs for automatic KPD code assignment on Croatian\ne-invoices. When a line item's service type has a KPD code mapped in the subsidiary's\ne-invoice configuration, that KPD code can be automatically applied.", - "descriptionShort": "E-invoicing settings for a subsidiary — format flags and KPD code mappings.", + "descriptionShort": "e-invoicing settings for subsidiaries", "customActions": {}, "fields": { "id": { @@ -3435,7 +3974,7 @@ "key": "subsidiary", "type": "subsidiaries", "typeCategory": "resource", - "param": "subsidiary_id", + "param": "subsidiary", "required": true, "filter": "subsidiary_id", "description": "The subsidiary this e-invoice configuration belongs to", @@ -3444,27 +3983,14 @@ }, "collections": {} }, - "emails": { - "type": "emails", - "domain": "CRM & Sales", - "itemName": "email", - "collectionName": "emails", - "description": "Email is a record synced from external email providers (Gmail, Outlook) or received via BCC forwarding.\nEmails can be linked to contacts, deals, budgets, invoices, projects, and tasks for relationship tracking and communication history.\n\nEmails are organized in threads and appear in the activity feed of linked items.\nRead/unread status syncs bidirectionally with the email provider.\nEmails can be auto-linked to deals based on contact matching, or manually linked by users.\n\nLifecycle: unresolved → resolved or dismissed. Mostly read-only — email content comes from external sources.\nEmails can be marked as read or dismissed via actions.", - "descriptionShort": "Email record synced from external providers, linked to contacts, deals, projects, tasks, invoices or budgets.", - "customActions": { - "dismiss": { - "name": "dismiss", - "description": "Dismiss the email", - "endpoint": "dismiss", - "method": "PATCH" - }, - "read": { - "name": "read", - "description": "Mark email as read", - "endpoint": "read", - "method": "PATCH" - } - }, + "email_threads": { + "type": "email_threads", + "domain": "Email", + "itemName": "email_thread", + "collectionName": "email_threads", + "description": "A conversation thread from a connected Gmail or Outlook inbox. Supports browsing, searching, listing, reading, archiving, moving, and managing email threads. Threads can be linked to Productive resources like deals, projects, and tasks.", + "descriptionShort": "user's live Gmail or Outlook inbox — browse, search, read, and manage emails", + "customActions": {}, "fields": { "id": { "key": "id", @@ -3478,63 +4004,246 @@ "key": "subject", "type": "string", "typeCategory": "primitive", + "param": "subject", "readonly": true, - "description": "Email subject line", + "description": "Email thread subject line", "attribute": "subject" }, - "body": { - "key": "body", + "externalId": { + "key": "externalId", "type": "string", "typeCategory": "primitive", - "format": "html", + "param": "external_id", "readonly": true, - "description": "Email body content", - "attribute": "body" + "description": "External provider thread ID (Gmail thread ID or Outlook conversation ID)", + "attribute": "external_id" }, - "snippet": { - "key": "snippet", - "type": "string", + "participants": { + "key": "participants", + "type": "hash", "typeCategory": "primitive", + "param": "participants", "readonly": true, - "description": "Short preview snippet of the email body", - "attribute": "snippet" + "description": "Thread participants — array of {type: \"To\"|\"From\"|\"Cc\"|\"Bcc\", name: string, address: string}", + "attribute": "participants", + "array": true }, - "autoLinked": { - "key": "autoLinked", - "type": "boolean", + "createdAt": { + "key": "createdAt", + "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, - "description": "Whether the email was automatically linked to a deal", - "attribute": "auto_linked" + "attribute": "created_at" }, - "outgoing": { - "key": "outgoing", - "type": "boolean", + "updatedAt": { + "key": "updatedAt", + "type": "date", "typeCategory": "primitive", + "param": "updated_at", "readonly": true, - "description": "Whether this is an outgoing (sent) email", - "attribute": "outgoing" + "attribute": "updated_at" }, - "from": { - "key": "from", - "type": "string", + "receivedAt": { + "key": "receivedAt", + "type": "date", "typeCategory": "primitive", + "param": "received_at", "readonly": true, - "description": "Sender email address", - "attribute": "from" + "description": "When the last email in the thread was received", + "attribute": "received_at" }, - "unread": { - "key": "unread", + "hasAttachments": { + "key": "hasAttachments", "type": "boolean", "typeCategory": "primitive", + "param": "has_attachments", "readonly": true, - "description": "Whether the email is unread", + "description": "Whether any email in the thread has attachments", + "attribute": "has_attachments" + }, + "unread": { + "key": "unread", + "type": "boolean", + "typeCategory": "primitive", + "param": "is_unread", + "readonly": true, + "description": "Whether the thread has unread emails", + "attribute": "unread" + }, + "linkedType": { + "key": "linkedType", + "type": "string", + "typeCategory": "primitive", + "param": "linked_type", + "readonly": true, + "description": "Type of linked Productive resource (e.g. Deal, Project)", + "attribute": "linked_type" + }, + "linkedId": { + "key": "linkedId", + "type": "string", + "typeCategory": "primitive", + "param": "linked_id", + "readonly": true, + "description": "ID of linked Productive resource", + "attribute": "linked_id" + }, + "integration": { + "key": "integration", + "type": "integrations", + "typeCategory": "resource", + "param": "integration", + "readonly": true, + "filter": "integration_id", + "description": "The email integration this thread belongs to. Auto-included by the API — do not request via include param.", + "relationship": "integration", + "notIncludable": true, + "filterConfig": { + "required": true + } + }, + "emails": { + "key": "emails", + "type": "emails", + "typeCategory": "resource", + "param": "emails", + "readonly": true, + "description": "Individual emails in this thread. Auto-included by the API — do not request via include param.", + "relationship": "emails", + "notIncludable": true, + "array": true + }, + "query": { + "key": "query", + "type": "string", + "typeCategory": "primitive", + "param": "query", + "readonly": true, + "filter": "query", + "description": "Search query passed to the native email provider search API. See the email-inbox guide for syntax details." + }, + "folderId": { + "key": "folderId", + "type": "string", + "typeCategory": "primitive", + "param": "folder_id", + "readonly": true, + "filter": "folder_id", + "description": "Filter threads by folder/label ID" + } + }, + "collections": {} + }, + "emails": { + "type": "emails", + "domain": "CRM & Sales", + "itemName": "email", + "collectionName": "emails", + "description": "Email is a record synced from external email providers (Gmail, Outlook) or received via BCC forwarding.\nEmails can be linked to contacts, deals, budgets, invoices, projects, and tasks for relationship tracking and communication history.\n\nEmails are organized in threads and appear in the activity feed of linked items.\nRead/unread status syncs bidirectionally with the email provider.\nEmails can be auto-linked to deals based on contact matching, or manually linked by users.\n\nLifecycle: unresolved → resolved or dismissed. Mostly read-only — email content comes from external sources.\nEmails can be marked as read or dismissed via actions.\n\nNote: This resource represents emails linked to CRM records.\nGmail and Outlook inbox thread browsing and management (listing, searching, archiving,\nmoving) is handled by the email_threads resource.", + "descriptionShort": "emails synced from external providers, linked to contacts, deals, projects, and tasks", + "customActions": { + "dismiss": { + "name": "dismiss", + "description": "Dismiss the email", + "endpoint": "dismiss", + "method": "PATCH" + }, + "read": { + "name": "read", + "description": "Mark email as read", + "endpoint": "read", + "method": "PATCH" + } + }, + "fields": { + "id": { + "key": "id", + "type": "string", + "typeCategory": "primitive", + "param": "id", + "readonly": true, + "id": true + }, + "subject": { + "key": "subject", + "type": "string", + "typeCategory": "primitive", + "param": "subject", + "readonly": true, + "description": "Email subject line", + "attribute": "subject" + }, + "body": { + "key": "body", + "type": "string", + "typeCategory": "primitive", + "format": "html", + "param": "body", + "readonly": true, + "description": "Email body content (plain text). May be empty for Outlook emails — use bodyHtml instead.", + "attribute": "body" + }, + "bodyHtml": { + "key": "bodyHtml", + "type": "string", + "typeCategory": "primitive", + "format": "html", + "param": "body_html", + "readonly": true, + "description": "Email body content (HTML). Primary body field for Outlook emails where body (plain text) is empty.", + "attribute": "body_html" + }, + "snippet": { + "key": "snippet", + "type": "string", + "typeCategory": "primitive", + "param": "snippet", + "readonly": true, + "description": "Short preview snippet of the email body", + "attribute": "snippet" + }, + "autoLinked": { + "key": "autoLinked", + "type": "boolean", + "typeCategory": "primitive", + "param": "is_auto_linked", + "readonly": true, + "description": "Whether the email was automatically linked to a deal", + "attribute": "auto_linked" + }, + "outgoing": { + "key": "outgoing", + "type": "boolean", + "typeCategory": "primitive", + "param": "is_outgoing", + "readonly": true, + "description": "Whether this is an outgoing (sent) email", + "attribute": "outgoing" + }, + "from": { + "key": "from", + "type": "string", + "typeCategory": "primitive", + "param": "from", + "readonly": true, + "description": "Sender email address", + "attribute": "from" + }, + "unread": { + "key": "unread", + "type": "boolean", + "typeCategory": "primitive", + "param": "is_unread", + "readonly": true, + "description": "Whether the email is unread", "attribute": "unread" }, "createdAt": { "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "attribute": "created_at" }, @@ -3542,6 +4251,7 @@ "key": "deliveredAt", "type": "date", "typeCategory": "primitive", + "param": "delivered_at", "readonly": true, "description": "When the email was delivered", "attribute": "delivered_at" @@ -3550,6 +4260,7 @@ "key": "receivedAt", "type": "date", "typeCategory": "primitive", + "param": "received_at", "readonly": true, "description": "When the email was received", "attribute": "received_at" @@ -3558,6 +4269,7 @@ "key": "dismissedAt", "type": "date", "typeCategory": "primitive", + "param": "dismissed_at", "readonly": true, "description": "When the email was dismissed", "attribute": "dismissed_at" @@ -3566,6 +4278,7 @@ "key": "creator", "type": "people", "typeCategory": "resource", + "param": "creator", "readonly": true, "filter": "creator_id", "description": "Person who synced this email", @@ -3575,7 +4288,7 @@ "key": "deal", "type": "deals", "typeCategory": "resource", - "filter": "deal_id", + "param": "deal", "description": "Deal this email is linked to", "relationship": "deal" }, @@ -3583,6 +4296,7 @@ "key": "invoice", "type": "invoices", "typeCategory": "resource", + "param": "invoice", "description": "Invoice this email is linked to", "relationship": "invoice" }, @@ -3590,6 +4304,7 @@ "key": "thread", "type": "emails", "typeCategory": "resource", + "param": "thread", "description": "Parent email thread", "relationship": "thread", "notIncludable": true @@ -3598,6 +4313,7 @@ "key": "attachments", "type": "attachments", "typeCategory": "resource", + "param": "attachments", "readonly": true, "relationship": "attachments", "array": true @@ -3606,6 +4322,7 @@ "key": "status", "type": "email_status", "typeCategory": "enum", + "param": "status", "readonly": true, "filter": "status", "description": "Filter by email status: 1=unresolved, 2=resolved, 3=dismissed" @@ -3614,6 +4331,7 @@ "key": "recipientId", "type": "people", "typeCategory": "resource", + "param": "recipient", "readonly": true, "filter": "recipient_id", "description": "Filter emails by recipient" @@ -3622,6 +4340,7 @@ "key": "companyId", "type": "companies", "typeCategory": "resource", + "param": "company", "readonly": true, "filter": "company_id", "description": "Filter emails by company" @@ -3636,7 +4355,7 @@ "itemName": "entitlement", "collectionName": "entitlements", "description": "Entitlement represents a time-off allocation for a person on a specific absence category (event) for a defined period.\nOnly applicable to absence categories with a limited limitation type (limited by days or hours).\n\nEach entitlement tracks:\n- Allocated: total days or hours the person is entitled to (e.g. 21 vacation days). Can include half-day allocations (e.g. 4.5 days).\n- Used: days/hours consumed through approved absence bookings (auto-calculated).\n- Pending: days/hours in bookings awaiting approval (auto-calculated).\n- Available balance: allocated - used - pending.\n\nEntitlements are scoped to a date range (start_date to end_date), typically a calendar year.\nA person must have an entitlement allocated before they can request time off for that absence category.\nHolidays (from the person's holiday calendar) are excluded from entitlement deductions — booking over a holiday does not reduce the balance.", - "descriptionShort": "Time-off allocation for a person on an absence category — tracks allocated, used, and pending balance.", + "descriptionShort": "time-off balance for a person — allocated, used, and pending", "customActions": {}, "fields": { "id": { @@ -3685,6 +4404,7 @@ "key": "used", "type": "number", "typeCategory": "primitive", + "param": "used", "readonly": true, "filter": "used", "description": "Days or hours already used through approved bookings (auto-calculated)", @@ -3694,6 +4414,7 @@ "key": "pending", "type": "number", "typeCategory": "primitive", + "param": "pending", "readonly": true, "description": "Days or hours pending approval (auto-calculated)", "attribute": "pending" @@ -3710,7 +4431,7 @@ "key": "person", "type": "people", "typeCategory": "resource", - "param": "person_id", + "param": "person", "required": true, "filter": "person_id", "sort": "person", @@ -3721,7 +4442,7 @@ "key": "event", "type": "events", "typeCategory": "resource", - "param": "event_id", + "param": "event", "required": true, "filter": "event_id", "sort": "event", @@ -3737,7 +4458,7 @@ "itemName": "absence category", "collectionName": "absence categories", "description": "Absence Category (Event) defines a type of time off or remote work that people can be booked on in the Resource Planner.\nConfigured by admins. Examples: Vacation, Sick Leave, Parental Leave, Remote Work.\n\nEach category is configured with:\n- Absence type: time_off (person is away, reduces availability for project work) or remote_work (person works remotely, does not affect availability).\n- Compensation: paid (event_type=1, included in internal cost calculations) or unpaid (event_type=2).\n- Limitation type: limited by days (2), limited by hours (3), or unlimited (4). Limited categories require Entitlements to define each person's annual quota.\n\nPeople are booked on absence categories via absence Bookings (bookings with event_id set).\nAbsence bookings can go through an approval workflow if absence approval is enabled for the organization.\nCategories can sync status to Slack and external calendars when status sync is enabled.\nCategories can be archived when no longer needed.", - "descriptionShort": "Absence category (e.g. vacation, sick leave, remote work) — defines time-off type, compensation, and usage limits for booking people.", + "descriptionShort": "absence categories (e.g. vacation) with time-off type, compensation, and usage limits", "customActions": {}, "fields": { "id": { @@ -3788,8 +4509,8 @@ }, "status": { "key": "status", - "type": "string", - "typeCategory": "primitive", + "type": "archivable_status", + "typeCategory": "enum", "param": "status", "attribute": "status" } @@ -3810,13 +4531,109 @@ ] } }, + "expense_line_items": { + "type": "expense_line_items", + "domain": "Other", + "itemName": "expense line item", + "collectionName": "expense line items", + "description": "A line item on an expense, with a name, quantity, and unit price. Individual line items are managed via bulk operations on this resource. The expense_line_items field on the parent expense replaces all line items on every write and cannot target individual ones.", + "descriptionShort": "expense line items with name, quantity, and unit price", + "customActions": {}, + "fields": { + "id": { + "key": "id", + "type": "string", + "typeCategory": "primitive", + "param": "id", + "readonly": true, + "id": true + }, + "name": { + "key": "name", + "type": "string", + "typeCategory": "primitive", + "param": "name", + "required": true, + "description": "Description of the line item", + "attribute": "name" + }, + "quantity": { + "key": "quantity", + "type": "number", + "typeCategory": "primitive", + "param": "quantity", + "required": true, + "description": "Number of units", + "attribute": "quantity" + }, + "unitPrice": { + "key": "unitPrice", + "type": "hash", + "typeCategory": "primitive", + "param": "unit_price", + "readonly": true, + "description": "Unit price as a money object, e.g. {amount: \"100.00\", currency: \"USD\"}", + "attribute": "unit_price" + }, + "unitPriceAmount": { + "key": "unitPriceAmount", + "type": "number", + "typeCategory": "primitive", + "unit": "money", + "param": "unit_price_amount", + "required": true, + "description": "Unit price in cents (e.g. 50000 = 500.00). Immutable after the expense is paid.", + "attribute": "unit_price", + "serialize": false + }, + "position": { + "key": "position", + "type": "number", + "typeCategory": "primitive", + "param": "position", + "description": "Display order within the expense", + "attribute": "position" + }, + "taxRate": { + "key": "taxRate", + "type": "tax_rates", + "typeCategory": "resource", + "param": "tax_rate", + "filter": "tax_rate_id", + "description": "Tax rate applied to this line item", + "relationship": "tax_rate" + }, + "expense": { + "key": "expense", + "type": "expenses", + "typeCategory": "resource", + "param": "expense", + "required": true, + "createOnly": true, + "filter": "expense_id", + "description": "The expense this line item belongs to", + "relationship": "expense" + } + }, + "collections": {}, + "bulkActions": { + "create": true, + "update": true, + "delete": true + }, + "actions": { + "create": false, + "update": false, + "delete": false + } + }, "expenses": { "type": "expenses", "domain": "Financial", "itemName": "expense", "collectionName": "expenses", - "description": "Expense is a non-labor cost logged against a Service in a Deal or Budget (e.g. travel, accommodation, software licenses, subcontractors, stock purchases).\nExpenses can only be tracked on services with tracking unit set to Piece and expense tracking enabled.\n\nEach expense has several independent statuses:\n- Approval: unapproved → approved or rejected. Only approved expenses affect revenue and can be invoiced. Approval can be required via policies on budgets/deals.\n- Payment: unpaid or paid (with pay_on due date and paid_on actual date).\n- Invoicing: not invoiced → drafted → finalized. Billable expenses can be included on client invoices.\n- Reimbursement: not reimbursable, requested, or reimbursed. Tracks whether the employee who incurred the expense gets paid back.\n\nRevenue impact depends on the service's billing type:\n- T&M by piece: approved expenses generate revenue (billable_amount × quantity).\n- Fixed by piece: approved expenses assume (transfer) revenue from the service's fixed total.\n- Non-billable: expenses generate cost only, never revenue.\n\nExpenses can be linked to Purchase Orders for vendor management and financial compliance.\nBillable amount can differ from cost amount via a markup percentage.", - "descriptionShort": "Non-labor cost on a service (e.g. travel, software) — billable or non-billable, with approval, payment, invoicing, and reimbursement workflows.", + "description": "Expense is a non-labor cost logged against a Service in a Deal or Budget (e.g. travel, accommodation, software licenses, subcontractors, stock purchases).\nExpenses can only be tracked on services with tracking unit set to Piece and expense tracking enabled.\n\nEach expense has several independent statuses:\n- Approval: unapproved → approved or rejected. Only approved expenses affect revenue and can be invoiced. Approval can be required via policies on budgets/deals.\n- Payment: unpaid or paid (with pay_on due date and paid_on actual date).\n- Invoicing: not invoiced → drafted → finalized. Billable expenses can be included on client invoices.\n- Reimbursement: not reimbursable, requested, or reimbursed. Tracks whether the employee who incurred the expense gets paid back.\n\nRevenue impact depends on the service's billing type:\n- T&M by piece: approved expenses generate revenue (billable_amount × quantity).\n- Fixed by piece: approved expenses assume (transfer) revenue from the service's fixed total.\n- Non-billable: expenses generate cost only, never revenue.\n\nExpenses can be linked to Purchase Orders for vendor management and financial compliance.\nBillable amount can differ from cost amount via a markup percentage.\n\nConstraints:\n- A purchase_order can only be linked to an expense with a single line item (or no line items).\n- unit_price and quantity on a line item are immutable once the expense is paid.\n- Line items are immutable on approved expenses.", + "descriptionShort": "non-labor costs on a service (e.g. software) — with approval, invoicing, and reimbursement workflows", "customActions": {}, "fields": { "id": { @@ -3854,7 +4671,6 @@ "typeCategory": "primitive", "format": "YYYY-MM-DD", "param": "pay_on", - "required": true, "sort": "pay_on", "description": "Date when the expense payment is due", "attribute": "pay_on" @@ -3874,7 +4690,6 @@ "type": "number", "typeCategory": "primitive", "param": "position", - "required": true, "description": "Position of the expense in the deal", "attribute": "position" }, @@ -3882,8 +4697,7 @@ "key": "invoiced", "type": "boolean", "typeCategory": "primitive", - "param": "invoiced", - "required": true, + "param": "is_invoiced", "description": "Is the expense invoiced to the client?", "attribute": "invoiced" }, @@ -3891,8 +4705,7 @@ "key": "approved", "type": "boolean", "typeCategory": "primitive", - "param": "approved", - "required": true, + "param": "is_approved", "description": "Is the expense approved by the responsible person?", "attribute": "approved" }, @@ -3909,7 +4722,7 @@ "key": "rejected", "type": "boolean", "typeCategory": "primitive", - "param": "rejected", + "param": "is_rejected", "description": "Is the expense rejected by the responsible person?", "attribute": "rejected" }, @@ -3933,8 +4746,7 @@ "key": "reimbursable", "type": "boolean", "typeCategory": "primitive", - "param": "reimbursable", - "required": true, + "param": "is_reimbursable", "description": "Is the expense reimbursable to the employee?", "attribute": "reimbursable" }, @@ -3952,8 +4764,7 @@ "type": "number", "typeCategory": "primitive", "param": "quantity", - "required": true, - "description": "Quantity of the expense line item", + "description": "Quantity of the expense (not needed when using expense_line_items)", "attribute": "quantity" }, "quantityReceived": { @@ -3967,8 +4778,7 @@ "key": "draft", "type": "boolean", "typeCategory": "primitive", - "param": "draft", - "required": true, + "param": "is_draft", "sort": "draft", "description": "Is the expense a draft?", "attribute": "draft" @@ -3987,9 +4797,8 @@ "typeCategory": "primitive", "unit": "money", "param": "amount", - "required": true, "sort": "amount", - "description": "Amount of the expense line item", + "description": "Total expense cost in cents. Required when not using expense_line_items (simple mode). Auto-calculated from line items when expense_line_items are provided and should not be set in that case.", "attribute": "amount" }, "totalAmount": { @@ -4008,7 +4817,6 @@ "typeCategory": "primitive", "unit": "money", "param": "billable_amount", - "required": true, "sort": "billable_amount", "description": "Amount of the expense that is billable to the client", "attribute": "billable_amount" @@ -4023,6 +4831,24 @@ "sort": "profit", "attribute": "profit" }, + "expenseLineItems": { + "key": "expenseLineItems", + "type": "hash", + "typeCategory": "primitive", + "param": "expense_line_items", + "description": "Write-only. Replaces all existing line items when provided. Each item requires name, unit_price (cents), and quantity. Amount is calculated automatically.", + "attribute": "expense_line_items", + "serialize": false + }, + "lineItems": { + "key": "lineItems", + "type": "expense_line_items", + "typeCategory": "resource", + "param": "line_items", + "readonly": true, + "description": "Current line items on this expense (read-only). Writes go through the expense_line_items attribute or via the expense_line_items resource directly.", + "relationship": "expense_line_items" + }, "customFields": { "key": "customFields", "type": "hash", @@ -4035,8 +4861,7 @@ "key": "deal", "type": "deals", "typeCategory": "resource", - "param": "deal_id", - "required": true, + "param": "deal", "filter": "deal_id", "sort": "deal_name", "relationship": "deal" @@ -4045,8 +4870,7 @@ "key": "serviceType", "type": "service_types", "typeCategory": "resource", - "param": "service_type_id", - "required": true, + "param": "service_type", "filter": "service_type_id", "sort": "service_type_name", "relationship": "service_type" @@ -4055,8 +4879,7 @@ "key": "person", "type": "people", "typeCategory": "resource", - "param": "person_id", - "required": true, + "param": "person", "filter": "person_id", "description": "Person that made the expense", "relationship": "person" @@ -4065,8 +4888,7 @@ "key": "vendor", "type": "companies", "typeCategory": "resource", - "param": "vendor_id", - "required": true, + "param": "vendor", "filter": "vendor_id", "description": "Vendor company the expense is for", "relationship": "vendor" @@ -4075,7 +4897,7 @@ "key": "service", "type": "services", "typeCategory": "resource", - "param": "service_id", + "param": "service", "required": true, "filter": "service_id", "sort": "service_name", @@ -4086,8 +4908,7 @@ "key": "taxRate", "type": "tax_rates", "typeCategory": "resource", - "param": "tax_rate_id", - "required": true, + "param": "tax_rate", "filter": "tax_rate_id", "sort": "tax_rate_id", "relationship": "tax_rate" @@ -4096,8 +4917,7 @@ "key": "attachment", "type": "attachments", "typeCategory": "resource", - "param": "attachment_id", - "required": true, + "param": "attachment", "filter": "attachment_id", "relationship": "attachment" }, @@ -4105,6 +4925,7 @@ "key": "creator", "type": "people", "typeCategory": "resource", + "param": "creator", "readonly": true, "filter": "creator_id", "description": "Person who created the expense", @@ -4114,6 +4935,7 @@ "key": "approver", "type": "people", "typeCategory": "resource", + "param": "approver", "readonly": true, "filter": "approver_id", "description": "Person who approved the expense", @@ -4123,6 +4945,7 @@ "key": "rejecter", "type": "people", "typeCategory": "resource", + "param": "rejecter", "readonly": true, "description": "Person who rejected the expense", "relationship": "rejecter" @@ -4131,6 +4954,7 @@ "key": "purchaseOrder", "type": "purchase_orders", "typeCategory": "resource", + "param": "purchase_order", "filter": "purchase_order_id", "description": "Purchase order this expense is linked to", "relationship": "purchase_order" @@ -4139,6 +4963,7 @@ "key": "invoiceAttribution", "type": "invoice_attributions", "typeCategory": "resource", + "param": "invoice_attribution", "filter": "invoice_id", "description": "Invoice this expense is attributed to", "relationship": "invoice_attribution" @@ -4147,6 +4972,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "filter": "created_at", "sort": "created_at", @@ -4157,6 +4983,7 @@ "key": "taxInclusion", "type": "boolean", "typeCategory": "primitive", + "param": "is_tax_inclusive", "description": "Whether the expense amount includes tax", "attribute": "tax_inclusion" }, @@ -4165,6 +4992,7 @@ "type": "number", "typeCategory": "primitive", "unit": "percentage", + "param": "markup", "description": "Markup percentage applied to calculate the billable amount from the cost amount", "attribute": "markup" }, @@ -4173,6 +5001,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "amount_with_tax", "readonly": true, "filter": "amount_with_tax", "sort": "amount_with_tax", @@ -4184,6 +5013,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "total_amount_with_tax", "readonly": true, "description": "Total amount including tax in cents (quantity * amount_with_tax)", "attribute": "total_amount_with_tax" @@ -4193,6 +5023,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "recognized_revenue", "readonly": true, "filter": "recognized_revenue", "sort": "recognized_revenue", @@ -4203,6 +5034,7 @@ "key": "exchangeRate", "type": "number", "typeCategory": "primitive", + "param": "exchange_rate", "readonly": true, "description": "Exchange rate to organization default currency", "attribute": "exchange_rate", @@ -4212,6 +5044,7 @@ "key": "companyId", "type": "companies", "typeCategory": "resource", + "param": "company_id", "filter": "company_id", "description": "Filter expenses by client company (via deal)" }, @@ -4219,6 +5052,7 @@ "key": "projectId", "type": "projects", "typeCategory": "resource", + "param": "project_id", "filter": "project_id", "description": "Filter expenses by project (via deal)" }, @@ -4226,6 +5060,7 @@ "key": "responsibleId", "type": "people", "typeCategory": "resource", + "param": "responsible", "filter": "responsible_id", "description": "Filter expenses by deal responsible person" }, @@ -4233,6 +5068,7 @@ "key": "status", "type": "expense_payment_status", "typeCategory": "enum", + "param": "status", "filter": "status", "description": "Filter by payment status: paid or unpaid" }, @@ -4240,6 +5076,7 @@ "key": "invoicingStatus", "type": "expense_invoicing_status", "typeCategory": "enum", + "param": "invoicing_status", "filter": "invoicing_status", "description": "Filter by invoicing workflow status: not invoiced, drafted, or finalized" }, @@ -4247,6 +5084,7 @@ "key": "approvalStatus", "type": "expense_approval_status", "typeCategory": "enum", + "param": "approval_status", "filter": "approval_status", "description": "Filter by approval status: approved, unapproved, rejected, or auto-approved" }, @@ -4254,6 +5092,7 @@ "key": "reimbursement", "type": "expense_reimbursement_status", "typeCategory": "enum", + "param": "reimbursement", "filter": "reimbursement", "description": "Filter by reimbursement status: none, requested, or reimbursed" } @@ -4267,7 +5106,7 @@ "itemName": "view", "collectionName": "Views", "description": "View (internally called Filter) is a saved configuration of filters, groupers, sorters, and visible fields.\nThis resource serves two purposes:\n- Views: saved perspectives on list screens throughout the application (e.g. \"My open tasks\", \"Overdue budgets\", \"Design team bookings\"). Scoped to a filterable_collection (tasks, deals, people, bookings, etc.).\n- Reports: saved analytical reports built from data sources (e.g. time entries, budgets, invoices, financial items). Reports support aggregations, charts, and can be added to dashboards as widgets.\n\nBoth views and reports store their configuration in the params field.\nThey can be private (visible only to the creator) or shared with other users via memberships, with \"Can view\" or \"Full access\" levels.\nReports can be organized into custom categories for easier navigation.", - "descriptionShort": "Saved view (list filters/sorters) or saved report (aggregated data analysis).", + "descriptionShort": "saved views (filters/sorters) or reports (aggregated analysis)", "customActions": {}, "fields": { "id": { @@ -4291,6 +5130,7 @@ "key": "filterableCollection", "type": "string", "typeCategory": "primitive", + "param": "filterable_collection", "readonly": true, "sort": "filterable_collection", "description": "Type of objects the view is made for (e.g. \"tasks\", \"deals\", \"people\", etc.)", @@ -4300,6 +5140,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "sort": "created_at", "attribute": "created_at" @@ -4308,6 +5149,7 @@ "key": "updatedAt", "type": "date", "typeCategory": "primitive", + "param": "updated_at", "readonly": true, "sort": "updated_at", "attribute": "updated_at" @@ -4317,6 +5159,7 @@ "type": "hash", "typeCategory": "primitive", "unit": "filter_params", + "param": "params", "readonly": true, "description": "Filter parameters", "attribute": "params" @@ -4330,7 +5173,7 @@ "itemName": "folder", "collectionName": "folders", "description": "Folder (also called Board) is a container for grouping Task Lists within a Project.\nA project can have multiple folders to organize work into logical sections (e.g. sprints, phases, work streams, priorities).\nEach folder contains one or more task lists, and each task list contains tasks.\n\nFolders can be reordered within a project, moved to another project (with all tasks and task lists), duplicated, and archived.\nArchiving a folder does not change the status of tasks inside it — tasks may still appear in reports unless separately closed.\nTasks within folders can be viewed in List, Board, Table, Calendar, Timeline, or Gantt layouts.", - "descriptionShort": "Container for grouping task lists within a project (e.g. sprints, phases).", + "descriptionShort": "collections of task lists within a project (e.g. sprints, phases)", "customActions": { "archive": { "name": "archive", @@ -4366,6 +5209,7 @@ "key": "status", "type": "archivable_status", "typeCategory": "enum", + "param": "status", "filter": "status", "description": "Filter by active or archived" }, @@ -4373,7 +5217,7 @@ "key": "project", "type": "projects", "typeCategory": "resource", - "param": "project_id", + "param": "project", "required": true, "filter": "project_id", "relationship": "project" @@ -4403,7 +5247,7 @@ "itemName": "holiday calendar", "collectionName": "holiday calendars", "description": "Holiday Calendar defines a set of public/bank holidays for a specific country or region.\nConfigured by admins. Each organization can have multiple calendars for different regions or subsidiaries.\n\nPeople are assigned to a holiday calendar through their cost rate (salary) records.\nHolidays in the assigned calendar are treated as non-working days — they reduce the person's capacity and availability across Productive:\n- Resource Planner: bookings over holidays don't count hours.\n- Time tracking: holidays are marked as non-working; time can still be logged manually.\n- Absence booking: holidays are excluded from time-off allowance deductions.\n- Workload layout: capacity shows as zero on holidays.\n\nWhen autogenerate_holidays is enabled, holidays are pre-filled and updated based on the selected country and state.\nWhen disabled, holidays must be added manually. If a state is not selected, only nationwide holidays are included.", - "descriptionShort": "Set of holidays for a country or region that affects availability.", + "descriptionShort": "set of holidays for a country that affects availability", "customActions": {}, "fields": { "id": { @@ -4452,7 +5296,7 @@ "itemName": "holiday", "collectionName": "holidays", "description": "Holiday is a specific non-working day within a Holiday Calendar (e.g. Christmas, New Year, Independence Day).\nEach holiday has a name and date, and belongs to exactly one holiday calendar.\n\nHolidays reduce availability and capacity to zero for that day for all people assigned to the parent calendar.\nThey are excluded from absence allowance calculations — booking time off over a holiday does not deduct from the person's entitlement.\n\nHolidays can be auto-generated by the parent calendar (based on country/state) or created manually.\nIf an auto-generated holiday is deleted, it will not reappear unless the calendar is recreated.", - "descriptionShort": "Non-working day within a holiday calendar (e.g. Christmas).", + "descriptionShort": "non-working day within a holiday calendar", "customActions": {}, "fields": { "id": { @@ -4485,22 +5329,24 @@ "type": "date", "typeCategory": "primitive", "format": "YYYY-MM-DD", + "param": "after", "filter": "after", - "description": "Filter holidays that occur on or after this date (date >= value)" + "description": "Filter holidays on or after this date" }, "before": { "key": "before", "type": "date", "typeCategory": "primitive", "format": "YYYY-MM-DD", + "param": "before", "filter": "before", - "description": "Filter holidays that occur on or before this date (date <= value)" + "description": "Filter holidays on or before this date" }, "holidayCalendar": { "key": "holidayCalendar", "type": "holiday_calendars", "typeCategory": "resource", - "param": "holiday_calendar_id", + "param": "holiday_calendar", "required": true, "filter": "holiday_calendar_id", "relationship": "holiday_calendar" @@ -4509,19 +5355,119 @@ "key": "creator", "type": "people", "typeCategory": "resource", + "param": "creator", "readonly": true, "relationship": "creator" } }, "collections": {} }, + "integrations": { + "type": "integrations", + "domain": "Email", + "itemName": "integration", + "collectionName": "integrations", + "description": "External service connected to the organization. Calendar integrations (Google Calendar, Outlook Calendar) sync events; email integrations (Gmail, Outlook Mail) power the inbox — realm_id holds the connected email address.", + "descriptionShort": "connected external services (Gmail, Google Calendar, Outlook, Slack, Xero, etc.)", + "customActions": {}, + "fields": { + "id": { + "key": "id", + "type": "string", + "typeCategory": "primitive", + "param": "id", + "readonly": true, + "id": true + }, + "name": { + "key": "name", + "type": "string", + "typeCategory": "primitive", + "param": "name", + "readonly": true, + "description": "Integration name", + "attribute": "name" + }, + "integrationTypeId": { + "key": "integrationTypeId", + "type": "integration_type", + "typeCategory": "enum", + "param": "integration_type", + "readonly": true, + "filter": "integration_type_id", + "description": "Type of integration (calendar or email)", + "attribute": "integration_type_id" + }, + "realmId": { + "key": "realmId", + "type": "string", + "typeCategory": "primitive", + "param": "realm_id", + "readonly": true, + "description": "Account identifier — for email integrations this is the email address of the connected account", + "attribute": "realm_id" + }, + "connectedAt": { + "key": "connectedAt", + "type": "date", + "typeCategory": "primitive", + "param": "connected_at", + "readonly": true, + "description": "When the integration was connected", + "attribute": "connected_at" + }, + "deactivatedAt": { + "key": "deactivatedAt", + "type": "date", + "typeCategory": "primitive", + "param": "deactivated_at", + "readonly": true, + "description": "When the integration was deactivated (null = active)", + "attribute": "deactivated_at" + }, + "calendars": { + "key": "calendars", + "type": "hash", + "typeCategory": "primitive", + "param": "calendars", + "readonly": true, + "description": "List of calendars available from this integration", + "attribute": "calendars" + }, + "lastSyncedAt": { + "key": "lastSyncedAt", + "type": "date", + "typeCategory": "primitive", + "param": "last_synced_at", + "readonly": true, + "description": "When the integration last synced data", + "attribute": "last_synced_at" + }, + "creator": { + "key": "creator", + "type": "people", + "typeCategory": "resource", + "param": "creator", + "readonly": true, + "relationship": "creator" + } + }, + "collections": {}, + "actions": { + "index": true, + "show": true, + "create": false, + "update": false, + "delete": false + } + }, "invoice_attributions": { "type": "invoice_attributions", "domain": "Financial", "itemName": "invoice attribution", "collectionName": "invoice attributions", "description": "Invoice Attribution is a junction record linking an Invoice to a Budget (deal with budget=true), specifying what portion of the invoice amount is attributed to that budget.\n\nA single invoice can span multiple budgets — each attribution defines the amount allocated to one budget.\nThis enables:\n- Split invoicing: one invoice covers work from several budgets for the same client.\n- Budget invoicing tracking: the attributed amount feeds into the budget's \"invoiced\" and \"pending_invoicing\" calculations.\n\nOptionally scoped to a date range (date_from, date_to) for time-based billing periods (e.g. monthly T&M invoicing).\nThe currency is inherited from the invoice and is read-only on the attribution.", - "descriptionShort": "Links an invoice to a budget — defines how much of the invoice amount is attributed to that budget.", + "descriptionShort": "links between invoices and budgets which define the attributed amount", "customActions": {}, "fields": { "id": { @@ -4564,6 +5510,7 @@ "key": "currency", "type": "currency", "typeCategory": "enum", + "param": "currency", "readonly": true, "attribute": "currency" }, @@ -4571,7 +5518,7 @@ "key": "invoice", "type": "invoices", "typeCategory": "resource", - "param": "invoice_id", + "param": "invoice", "required": true, "filter": "invoice_id", "relationship": "invoice" @@ -4580,7 +5527,7 @@ "key": "budget", "type": "deals", "typeCategory": "resource", - "param": "budget_id", + "param": "budget", "required": true, "filter": "budget_id", "description": "Deal/budget this invoice amount is attributed to", @@ -4595,7 +5542,7 @@ "itemName": "invoice", "collectionName": "invoices", "description": "Invoice is a financial document sent to a client for payment.\nInvoices can only be created from budgets (not directly from sales deals). They contain Line Items detailing the billed work.\n\nTwo document types via invoice_type: regular invoice (1) or credit note (2).\nCredit notes reverse or adjust a previous invoice (linked via parent_invoice) and have negative line item quantities.\n\nInvoice lifecycle: draft → finalized → sent → paid.\n- Draft: freely editable, no invoice number yet. Line items can be generated from uninvoiced time & expenses, total/remaining budget amount, or a percentage of total budget.\n- Finalized: invoice number assigned, locked by default. Only users with edit-finalized permission can unlock. Currency is locked on the budget once the first invoice (even draft) exists.\n- Sent: marked as sent (manually or via email from Productive). Payment reminders can be added. Cannot be edited unless marked as unsent first.\n- Paid: fully paid (tracked via Payments). Partial payments are possible — amount_paid, amount_unpaid, and amount_written_off track the payment state.\n\nEach invoice belongs to a client company and subsidiary (issuing legal entity).\nInvoices are linked to one or more budgets via Invoice Attributions, which specify how much of the invoice amount is attributed to each budget.\nSupports tax calculations per line item, discounts, purchase order numbers, multi-currency, tags, custom fields, and export to accounting tools.", - "descriptionShort": "Client-facing billing document — draft → finalized → sent → paid — with line items generated from budget services.", + "descriptionShort": "billing documents — draft → finalized → sent → paid — with line items from budget services", "customActions": {}, "fields": { "id": { @@ -4610,6 +5557,7 @@ "key": "number", "type": "string", "typeCategory": "primitive", + "param": "number", "filter": "number", "sort": "number", "description": "Auto-generated invoice number", @@ -4627,7 +5575,7 @@ "key": "invoiceTypeId", "type": "invoice_type", "typeCategory": "enum", - "param": "invoice_type_id", + "param": "invoice_type", "filter": "invoice_type", "description": "Whether this is a regular invoice or a credit note", "attribute": "invoice_type_id" @@ -4671,6 +5619,7 @@ "type": "date", "typeCategory": "primitive", "format": "YYYY-MM-DD", + "param": "sent_on", "filter": "sent_on", "sort": "sent_on", "description": "Date the invoice was sent to the client", @@ -4681,6 +5630,7 @@ "type": "date", "typeCategory": "primitive", "format": "YYYY-MM-DD", + "param": "paid_on", "readonly": true, "filter": "paid_on", "description": "Date the invoice was fully paid", @@ -4691,6 +5641,7 @@ "type": "date", "typeCategory": "primitive", "format": "YYYY-MM-DD", + "param": "finalized_on", "readonly": true, "description": "Date the invoice was finalized", "attribute": "finalized_on" @@ -4743,7 +5694,7 @@ "key": "exported", "type": "boolean", "typeCategory": "primitive", - "param": "exported", + "param": "is_exported", "description": "Whether the invoice has been exported to an accounting system", "attribute": "exported" }, @@ -4751,6 +5702,7 @@ "key": "credited", "type": "boolean", "typeCategory": "primitive", + "param": "is_credited", "readonly": true, "filter": "credited", "sort": "credited", @@ -4761,6 +5713,7 @@ "key": "paymentTerms", "type": "number", "typeCategory": "primitive", + "param": "payment_terms", "readonly": true, "description": "Number of days between invoice date and due date", "attribute": "payment_terms" @@ -4770,6 +5723,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "amount", "readonly": true, "filter": "amount", "sort": "amount", @@ -4781,6 +5735,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "amount_tax", "readonly": true, "sort": "amount_tax", "description": "Tax amount", @@ -4791,6 +5746,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "amount_with_tax", "readonly": true, "filter": "amount_with_tax", "sort": "amount_with_tax", @@ -4802,6 +5758,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "amount_paid", "readonly": true, "sort": "amount_paid", "description": "Amount that has been paid", @@ -4812,6 +5769,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "amount_unpaid", "readonly": true, "description": "Remaining unpaid amount", "attribute": "amount_unpaid" @@ -4821,6 +5779,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "amount_written_off", "readonly": true, "sort": "amount_written_off", "description": "Amount written off", @@ -4831,6 +5790,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "amount_credited", "readonly": true, "sort": "amount_credited", "description": "Amount covered by credit notes", @@ -4840,6 +5800,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "filter": "created_at", "sort": "created_at", @@ -4857,7 +5818,7 @@ "key": "company", "type": "companies", "typeCategory": "resource", - "param": "company_id", + "param": "company", "required": true, "filter": "company_id", "sort": "company_name", @@ -4868,7 +5829,7 @@ "key": "subsidiary", "type": "subsidiaries", "typeCategory": "resource", - "param": "subsidiary_id", + "param": "subsidiary", "filter": "subsidiary_id", "relationship": "subsidiary" }, @@ -4876,13 +5837,14 @@ "key": "documentType", "type": "document_types", "typeCategory": "resource", - "param": "document_type_id", + "param": "document_type", "relationship": "document_type" }, "billTo": { "key": "billTo", "type": "contact_entries", "typeCategory": "resource", + "param": "bill_to", "readonly": true, "description": "Billing recipient contact data — contains country, address, VAT of the client being billed", "relationship": "bill_to" @@ -4891,6 +5853,7 @@ "key": "billFrom", "type": "contact_entries", "typeCategory": "resource", + "param": "bill_from", "readonly": true, "description": "Billing sender contact data — contains country, address, VAT of the issuing subsidiary", "relationship": "bill_from" @@ -4899,6 +5862,7 @@ "key": "creator", "type": "people", "typeCategory": "resource", + "param": "creator", "readonly": true, "filter": "creator_id", "description": "Person who created the invoice", @@ -4908,7 +5872,7 @@ "key": "issuer", "type": "people", "typeCategory": "resource", - "param": "issuer_id", + "param": "issuer", "filter": "issuer_id", "description": "Person issuing the invoice", "relationship": "issuer" @@ -4917,7 +5881,7 @@ "key": "parentInvoice", "type": "invoices", "typeCategory": "resource", - "param": "parent_invoice_id", + "param": "parent_invoice", "filter": "parent_invoice_id", "description": "Parent invoice (for credit notes)", "relationship": "parent_invoice" @@ -4926,7 +5890,7 @@ "key": "attachment", "type": "attachments", "typeCategory": "resource", - "param": "attachment_id", + "param": "attachment", "relationship": "attachment" } }, @@ -4935,11 +5899,11 @@ }, "kpd_codes": { "type": "kpd_codes", - "domain": "Other", + "domain": "Financial", "itemName": "KPD code", "collectionName": "KPD codes", "description": "KPD (Klasifikacija Proizvoda po Djelatnostima) codes are product classification codes\nused in Croatian e-invoicing. Each code classifies a product or service for tax and\nregulatory purposes. KPD codes (8-character) are specific product codes, while NKD codes\n(shorter) are broader activity classifications. These codes are assigned to invoice line\nitems for e-invoice compliance.", - "descriptionShort": "Croatian product classification code for e-invoicing compliance.", + "descriptionShort": "Croatian product classification codes for e-invoicing compliance", "customActions": {}, "fields": { "id": { @@ -4954,6 +5918,7 @@ "key": "code", "type": "string", "typeCategory": "primitive", + "param": "code", "readonly": true, "filter": "code", "description": "The classification code (e.g. \"01.11.71\")", @@ -4963,6 +5928,7 @@ "key": "kpdName", "type": "string", "typeCategory": "primitive", + "param": "kpd_name", "readonly": true, "description": "Name/description of the KPD code", "attribute": "kpd_name" @@ -4971,6 +5937,7 @@ "key": "isKpd", "type": "boolean", "typeCategory": "primitive", + "param": "is_kpd", "readonly": true, "filter": "is_kpd", "description": "True for KPD codes (8-char), false for NKD codes (shorter)", @@ -4985,7 +5952,7 @@ "itemName": "line item", "collectionName": "line items", "description": "Line Item is an individual charge entry on an Invoice.\nEach line item has a description, quantity, unit (hour/day/piece), unit price, optional discount, and a tax rate.\nAmounts (net, tax, total) are computed server-side from quantity × unit_price - discount + tax.\n\nLine items can be generated in three ways:\n- From uninvoiced time and expenses: pulls approved, uninvoiced time entries and expenses from the budget's services.\n- From total/remaining budget amount: creates line items for the full or remaining budget value.\n- From a percentage of the total budget: invoices a fraction of the budget.\n\nLine items can be linked to a service and/or expense for traceability back to the budget.\nDescriptions support rich text and dynamic fields (e.g. person name, task title, period) for flexible presentation.\nLine items can be grouped by service, budget, project, or task on the invoice.\nCurrency is inherited from the parent invoice.", - "descriptionShort": "Charge entry on an invoice — quantity, unit price, tax, and optional link to a service or expense.", + "descriptionShort": "invoice lines with quantity, unit price, tax, and optional link to a service or expense", "customActions": {}, "fields": { "id": { @@ -5055,6 +6022,7 @@ "key": "taxName", "type": "string", "typeCategory": "primitive", + "param": "tax_name", "readonly": true, "filter": "tax_name", "description": "Name of the applied tax (derived from tax rate)", @@ -5065,6 +6033,7 @@ "type": "number", "typeCategory": "primitive", "unit": "percentage", + "param": "tax_value", "readonly": true, "filter": "tax_value", "description": "Tax percentage (derived from tax rate)", @@ -5075,6 +6044,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "amount", "readonly": true, "description": "Net amount before tax", "attribute": "amount" @@ -5084,6 +6054,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "amount_tax", "readonly": true, "description": "Tax amount", "attribute": "amount_tax" @@ -5093,6 +6064,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "amount_with_tax", "readonly": true, "description": "Total amount including tax", "attribute": "amount_with_tax" @@ -5101,6 +6073,7 @@ "key": "currency", "type": "currency", "typeCategory": "enum", + "param": "currency", "readonly": true, "description": "Currency inherited from the parent invoice", "attribute": "currency" @@ -5109,7 +6082,7 @@ "key": "invoice", "type": "invoices", "typeCategory": "resource", - "param": "invoice_id", + "param": "invoice", "required": true, "filter": "invoice_id", "description": "Parent invoice this line item belongs to", @@ -5119,7 +6092,7 @@ "key": "service", "type": "services", "typeCategory": "resource", - "param": "service_id", + "param": "service", "filter": "service_id", "description": "Service (billing point) this line item was generated from", "relationship": "service" @@ -5128,7 +6101,7 @@ "key": "expense", "type": "expenses", "typeCategory": "resource", - "param": "expense_id", + "param": "expense", "filter": "expense_id", "description": "Expense this line item was generated from", "relationship": "expense" @@ -5137,7 +6110,7 @@ "key": "serviceType", "type": "service_types", "typeCategory": "resource", - "param": "service_type_id", + "param": "service_type", "filter": "service_type_id", "relationship": "service_type" }, @@ -5145,7 +6118,7 @@ "key": "taxRate", "type": "tax_rates", "typeCategory": "resource", - "param": "tax_rate_id", + "param": "tax_rate", "required": true, "description": "Tax rate applied to this line item", "relationship": "tax_rate" @@ -5154,7 +6127,7 @@ "key": "kpdCode", "type": "kpd_codes", "typeCategory": "resource", - "param": "kpd_code_id", + "param": "kpd_code", "description": "KPD classification code for Croatian e-invoicing", "relationship": "kpd_code" } @@ -5167,7 +6140,7 @@ "itemName": "lost reason", "collectionName": "lost reasons", "description": "Lost Reason is a configurable label explaining why a deal was lost (e.g. \"Price too high\", \"Went with competitor\", \"Unrealistic timeline\").\nWhen a deal moves to a pipeline stage with lost_reason_enabled=true, selecting a lost reason becomes mandatory.\nOrganizations define their own set of lost reasons for sales reporting and win/loss analysis.", - "descriptionShort": "Label explaining why a deal was lost.", + "descriptionShort": "labels explaining why a deal was lost", "customActions": {}, "fields": { "id": { @@ -5194,8 +6167,8 @@ "domain": "People & Organization", "itemName": "membership", "collectionName": "memberships", - "description": "Membership controls who can access a target resource (project, doc, dashboard, view, or survey).\nAccess can be granted to a person (type_id=1), a dynamic group (type_id=2), or a team (type_id=3).\n\nAccess levels vary by target type:\n- Projects: member (access_type_id=5) — grants access to tasks, docs, and budgets within the project.\n- Docs (pages): full (1), write (2), read (3), or comment (4).\n- Views/Dashboards/Surveys: full (1) or read (3).\n\nDynamic groups are predefined: employees (2), project members (6), project manager (8), deal owner (9), users that can manage project (10).\nIf someone cannot be assigned to a task or track time, they likely need a membership on that project first.", - "descriptionShort": "Controls who can access projects, docs, views, and other shared resources.", + "description": "Membership controls who can access a target resource (project, doc, dashboard, view, survey, or agent).\nAccess can be granted to a person (type_id=1), a dynamic group (type_id=2), or a team (type_id=3).\n\nAccess levels vary by target type:\n- Projects: member (access_type=5) — grants access to tasks, docs, and budgets within the project.\n- Docs (pages): full (1), write (2), read (3), or comment (4).\n- Agents: full (1) or read (3).\n- Views/Dashboards/Surveys: full (1) or read (3).\n\nDynamic groups are predefined: employees (2), project members (6), project manager (8), deal owner (9), users that can manage project (10), agent manager (12).\nIf someone cannot be assigned to a task or track time, they likely need a membership on that project first.", + "descriptionShort": "access controls for projects, docs, views, dashboards, surveys, and agents", "customActions": {}, "fields": { "id": { @@ -5210,29 +6183,28 @@ "key": "typeId", "type": "membership_type", "typeCategory": "enum", - "param": "type_id", + "param": "membership_type", "required": true, "filter": "type_id", - "description": "1=person, 2=dynamic_group, 3=team", "attribute": "type_id" }, "accessTypeId": { "key": "accessTypeId", "type": "access_type", "typeCategory": "enum", - "param": "access_type_id", + "param": "access_type", "required": true, "filter": "access_type_id", - "description": "Access level: 1=full, 2=write, 3=read, 4=comment, 5=member. Available levels depend on target resource type. Filter/Dashboard/Survey: [full, read]. Quote/Workspace: [member]. Others: [full, write, read, comment].", + "description": "Available levels depend on target resource type. Filter/Dashboard/Survey/Agent: [full, read]. Quote/Workspace: [member]. Others: [full, write, read, comment].", "attribute": "access_type_id" }, "dynamicGroupId": { "key": "dynamicGroupId", "type": "dynamic_group", "typeCategory": "enum", - "param": "dynamic_group_id", + "param": "dynamic_group", "filter": "dynamic_group_id", - "description": "Required when type_id=2. Predefined group: 2=employees, 6=project_members, 8=project_manager, 9=deal_owner, 10=users_that_can_manage_project", + "description": "Required when membership_type is dynamic_group.", "attribute": "dynamic_group_id" }, "targetId": { @@ -5252,55 +6224,64 @@ "param": "target_type", "readonly": true, "filter": "target_type", - "description": "Type of the target resource (Workspace, Page, Dashboard, Filter, Quote, Pulse, Surveys::Survey).", + "description": "Type of the target resource (Workspace, Page, Dashboard, Filter, Quote, Pulse, Surveys::Survey, Agents::Agent).", "attribute": "target_type" }, "person": { "key": "person", "type": "people", "typeCategory": "resource", - "param": "person_id", + "param": "person", "filter": "person_id", - "description": "Required when type_id=1. Person receiving access", + "description": "Required when membership_type=1. Person receiving access", "relationship": "person" }, "team": { "key": "team", "type": "teams", "typeCategory": "resource", - "param": "team_id", + "param": "team", "filter": "team_id", - "description": "Required when type_id=3. Team receiving access", + "description": "Required when membership_type=3. Team receiving access", "relationship": "team" }, "project": { "key": "project", "type": "projects", "typeCategory": "resource", - "param": "project_id", + "param": "project", "filter": "project_id", - "description": "Required when giving access to a project. Projects use access_type_id=5 (member)", + "description": "Required when giving access to a project.", "relationship": "project" }, "page": { "key": "page", "type": "pages", "typeCategory": "resource", - "param": "page_id", + "param": "page", "filter": "page_id", - "description": "Required when giving access to a doc. Docs support access_type_id: 1=full, 2=write, 3=read, 4=comment", + "description": "Required when giving access to a doc.", "relationship": "page" + }, + "agent": { + "key": "agent", + "type": "agents", + "typeCategory": "resource", + "param": "agent", + "filter": "agent_id", + "description": "Required when giving access to an agent.", + "relationship": "agent" } }, "collections": {} }, "notifications": { "type": "notifications", - "domain": "Other", + "domain": "Communication", "itemName": "notification", "collectionName": "notifications", "description": "Notification represents an inbox item for the user. Notifications track changes to tasks, deals, pages, and other objects. Each notification has a target object, unread activity count, and can be marked as read, dismissed, or restored.", - "descriptionShort": "Inbox item tracking changes to tasks, deals, pages, and other objects.", + "descriptionShort": "inbox items", "customActions": { "read": { "name": "read", @@ -5334,6 +6315,7 @@ "key": "title", "type": "string", "typeCategory": "primitive", + "param": "title", "readonly": true, "description": "Title of the notification", "attribute": "title" @@ -5342,6 +6324,7 @@ "key": "targetId", "type": "number", "typeCategory": "primitive", + "param": "target_id", "readonly": true, "description": "ID of the target object (task, deal, page, etc.)", "attribute": "target_id" @@ -5350,6 +6333,7 @@ "key": "targetType", "type": "string", "typeCategory": "primitive", + "param": "target_type", "readonly": true, "description": "Type of the target object (Task, Deal, Page, etc.)", "attribute": "target_type" @@ -5358,6 +6342,7 @@ "key": "targetLabel", "type": "string", "typeCategory": "primitive", + "param": "target_label", "readonly": true, "description": "Label of the target object", "attribute": "target_label" @@ -5366,6 +6351,7 @@ "key": "targetTitle", "type": "string", "typeCategory": "primitive", + "param": "target_title", "readonly": true, "description": "Title of the target object", "attribute": "target_title" @@ -5374,6 +6360,7 @@ "key": "parentId", "type": "number", "typeCategory": "primitive", + "param": "parent_id", "readonly": true, "description": "ID of the parent object", "attribute": "parent_id" @@ -5382,6 +6369,7 @@ "key": "parentType", "type": "string", "typeCategory": "primitive", + "param": "parent_type", "readonly": true, "description": "Type of the parent object", "attribute": "parent_type" @@ -5390,6 +6378,7 @@ "key": "parentTitle", "type": "string", "typeCategory": "primitive", + "param": "parent_title", "readonly": true, "description": "Title of the parent object", "attribute": "parent_title" @@ -5398,6 +6387,7 @@ "key": "rootId", "type": "number", "typeCategory": "primitive", + "param": "root_id", "readonly": true, "description": "ID of the root object", "attribute": "root_id" @@ -5406,6 +6396,7 @@ "key": "rootType", "type": "string", "typeCategory": "primitive", + "param": "root_type", "readonly": true, "description": "Type of the root object", "attribute": "root_type" @@ -5414,6 +6405,7 @@ "key": "read", "type": "boolean", "typeCategory": "primitive", + "param": "is_read", "readonly": true, "description": "Whether the notification has been read", "attribute": "read" @@ -5422,6 +6414,7 @@ "key": "dismissed", "type": "boolean", "typeCategory": "primitive", + "param": "is_dismissed", "readonly": true, "filter": "dismissed", "description": "Whether the notification has been dismissed" @@ -5430,6 +6423,7 @@ "key": "mention", "type": "boolean", "typeCategory": "primitive", + "param": "has_mention", "readonly": true, "filter": "mention", "description": "Filter for notifications with mentions" @@ -5438,6 +6432,7 @@ "key": "important", "type": "boolean", "typeCategory": "primitive", + "param": "is_important", "readonly": true, "filter": "important", "description": "Filter for important notifications" @@ -5446,6 +6441,7 @@ "key": "newActivitiesCount", "type": "number", "typeCategory": "primitive", + "param": "new_activities_count", "readonly": true, "description": "Number of unread activities on this notification", "attribute": "new_activities_count" @@ -5454,6 +6450,7 @@ "key": "excerpt", "type": "string", "typeCategory": "primitive", + "param": "excerpt", "readonly": true, "description": "Short preview text of the notification content", "attribute": "excerpt" @@ -5462,6 +6459,7 @@ "key": "lastActionAt", "type": "date", "typeCategory": "primitive", + "param": "last_action_at", "readonly": true, "description": "Timestamp of the last action on the notification", "attribute": "last_action_at" @@ -5470,6 +6468,7 @@ "key": "firstUnreadActivityId", "type": "string", "typeCategory": "primitive", + "param": "first_unread_activity_id", "readonly": true, "description": "ID of the first unread activity", "attribute": "first_unread_activity_id" @@ -5478,6 +6477,7 @@ "key": "madeByAutomation", "type": "boolean", "typeCategory": "primitive", + "param": "is_made_by_automation", "readonly": true, "description": "Whether the notification was triggered by an automation", "attribute": "made_by_automation" @@ -5486,30 +6486,32 @@ "key": "changeset", "type": "hash", "typeCategory": "primitive", + "param": "changeset", "readonly": true, "description": "Object containing the latest changes", "attribute": "changeset" }, "after": { "key": "after", - "type": "string", + "type": "datetime", "typeCategory": "primitive", - "readonly": true, + "param": "after", "filter": "after", - "description": "Cursor-based pagination: load notifications after this cursor" + "description": "Load notifications with last_action_at after this datetime" }, "before": { "key": "before", - "type": "string", + "type": "datetime", "typeCategory": "primitive", - "readonly": true, + "param": "before", "filter": "before", - "description": "Cursor-based pagination: load notifications before this cursor" + "description": "Load notifications with last_action_at before this datetime" }, "actor": { "key": "actor", "type": "people", "typeCategory": "resource", + "param": "actor", "readonly": true, "description": "The person who triggered the notification", "relationship": "actor" @@ -5518,6 +6520,7 @@ "key": "owner", "type": "organization_memberships", "typeCategory": "resource", + "param": "owner", "readonly": true, "description": "The organization membership that owns this notification", "relationship": "owner", @@ -5525,7 +6528,7 @@ } }, "collections": {}, - "queryHints": "Users typically care about active (non-dismissed) notifications they are subscribed to (important=true), unless they specify otherwise. The default filter scope for notifications should be: { dismissed: {eq: 'false'}, important: {eq: 'true'} }." + "queryHints": "Users typically care about active (non-dismissed) notifications they are subscribed to (is_important=true), unless they specify otherwise. The default filter scope for notifications should be: { is_dismissed: {eq: 'false'}, is_important: {eq: 'true'} }." }, "organization_memberships": { "type": "organization_memberships", @@ -5533,7 +6536,7 @@ "itemName": "organization_membership", "collectionName": "organization memberships", "description": "Organization Membership links a user to an organization, granting them access. Each membership connects a person (profile) and a user (login account) to a specific organization. A user can be a member of multiple organizations.", - "descriptionShort": "Links a user to an organization, granting access.", + "descriptionShort": "links between users and organizations, granting access", "customActions": {}, "fields": { "id": { @@ -5548,20 +6551,21 @@ "key": "organization", "type": "organizations", "typeCategory": "resource", - "param": "organization_id", + "param": "organization", "relationship": "organization" }, "person": { "key": "person", "type": "people", "typeCategory": "resource", - "param": "person_id", + "param": "person", "relationship": "person" }, "user": { "key": "user", "type": "users", "typeCategory": "resource", + "param": "user", "readonly": true, "relationship": "user" } @@ -5574,7 +6578,7 @@ "itemName": "organization_subscription", "collectionName": "organization subscriptions", "description": "Organization Subscription holds the current pricing plan and product entitlements for an organization. Exposes which subscription features are available (switch on/off) or metered (with usage limits). Read-only — subscriptions are managed through billing.", - "descriptionShort": "Current pricing plan and feature entitlements for an organization.", + "descriptionShort": "pricing plan and feature entitlements for an organizations", "customActions": {}, "fields": { "id": { @@ -5589,6 +6593,7 @@ "key": "currentPlan", "type": "hash", "typeCategory": "primitive", + "param": "current_plan", "readonly": true, "attribute": "current_plan" }, @@ -5596,6 +6601,7 @@ "key": "currentProducts", "type": "hash", "typeCategory": "primitive", + "param": "current_products", "readonly": true, "attribute": "current_products" } @@ -5608,7 +6614,7 @@ "itemName": "organization", "collectionName": "organizations", "description": "Organization is the top-level account in Productive. It represents a company that uses Productive to manage its business operations. An organization owns all other data — projects, deals, people, invoices, etc. It defines global settings: currency, time zone, fiscal year, working hours, locale, and date/number formats. Organizations contain subsidiaries (legal entities), service types, workflows, pipelines, rate cards, tax rates, and custom fields.", - "descriptionShort": "Top-level account representing a company using Productive.", + "descriptionShort": "top-level accounts, companies using Productive", "customActions": {}, "fields": { "id": { @@ -5623,6 +6629,7 @@ "key": "name", "type": "string", "typeCategory": "primitive", + "param": "name", "required": true, "sort": "name", "attribute": "name" @@ -5631,6 +6638,7 @@ "key": "timeZone", "type": "string", "typeCategory": "primitive", + "param": "time_zone", "required": true, "attribute": "time_zone" }, @@ -5638,6 +6646,7 @@ "key": "company", "type": "companies", "typeCategory": "resource", + "param": "company", "readonly": true, "relationship": "company" }, @@ -5645,6 +6654,7 @@ "key": "weekStartDay", "type": "week_start_day", "typeCategory": "enum", + "param": "week_start_day", "attribute": "week_start_day_id", "serialize": false }, @@ -5652,6 +6662,7 @@ "key": "fiscalYearStart", "type": "date", "typeCategory": "primitive", + "param": "fiscal_year_start", "description": "Date when the fiscal year starts", "attribute": "fiscal_year_start", "serialize": false @@ -5660,6 +6671,7 @@ "key": "owner", "type": "people", "typeCategory": "resource", + "param": "owner", "readonly": true, "relationship": "owner", "serialize": false @@ -5668,13 +6680,24 @@ "key": "flags", "type": "hash", "typeCategory": "primitive", + "param": "flags", "attribute": "flags", "serialize": false }, + "releaseChannel": { + "key": "releaseChannel", + "type": "string", + "typeCategory": "primitive", + "param": "release_channel", + "description": "Release channel for feature flags: stable, beta, or alpha", + "attribute": "release_channel", + "serialize": false + }, "currency": { "key": "currency", "type": "string", "typeCategory": "primitive", + "param": "currency", "required": true, "description": "Currency used by default for new deals, budgets, and financial operations", "attribute": "currency" @@ -5684,6 +6707,7 @@ "type": "number", "typeCategory": "primitive", "unit": "hours", + "param": "working_hours", "description": "Default working hours for each day of the week (Mon-Sun)", "attribute": "working_hours", "array": true, @@ -5694,6 +6718,7 @@ "type": "number", "typeCategory": "primitive", "unit": "minutes", + "param": "man_day_minutes", "description": "Number of minutes in a man-day, used for converting time to man-days in reports", "attribute": "man_day_minutes", "serialize": false @@ -5702,6 +6727,7 @@ "key": "locale", "type": "string", "typeCategory": "primitive", + "param": "locale", "description": "Default locale for the organization (e.g. en, de, fr)", "attribute": "locale", "serialize": false @@ -5710,6 +6736,7 @@ "key": "dateFormatId", "type": "number", "typeCategory": "primitive", + "param": "date_format_id", "description": "Date display format preference for the organization", "attribute": "date_format_id", "serialize": false @@ -5718,6 +6745,7 @@ "key": "timeFormatId", "type": "number", "typeCategory": "primitive", + "param": "time_format_id", "description": "Time display format preference (e.g. 12h vs 24h)", "attribute": "time_format_id", "serialize": false @@ -5726,6 +6754,7 @@ "key": "numberFormatId", "type": "number", "typeCategory": "primitive", + "param": "number_format_id", "description": "Number display format preference (e.g. decimal/thousand separators)", "attribute": "number_format_id", "serialize": false @@ -5734,6 +6763,7 @@ "key": "addons", "type": "string", "typeCategory": "primitive", + "param": "addons", "attribute": "addons", "array": true, "serialize": false @@ -5742,6 +6772,7 @@ "key": "subsidiaryCount", "type": "number", "typeCategory": "primitive", + "param": "subsidiary_count", "attribute": "subsidiary_count", "serialize": false }, @@ -5749,6 +6780,7 @@ "key": "expenseSettings", "type": "hash", "typeCategory": "primitive", + "param": "expense_settings", "attribute": "expense_settings", "serialize": false }, @@ -5756,6 +6788,7 @@ "key": "organizationSubscription", "type": "organization_subscriptions", "typeCategory": "resource", + "param": "organization_subscription", "readonly": true, "relationship": "organization_subscription", "serialize": false @@ -5812,7 +6845,7 @@ "itemName": "page", "collectionName": "pages", "description": "Page is a rich text document in a hierarchical structure. A page is either a root page (what users call a \"Doc\") or a child page nested under a parent within the same Doc.\n- Root page (Doc): has no parent_page_id or root_page_id. Can be linked to a Project or standalone. Owns all sharing and access settings — child pages inherit them.\n- Child page: must set both parent_page_id and root_page_id on creation. Nested arbitrarily deep.\n\nSharing is controlled at the Doc (root page) level via Memberships:\n- Access levels: view, comment, edit, or full access. Can be granted to individuals or teams.\n- Project docs are visible to project members by default; standalone docs are visible only to their creator.\n- Docs can also be shared publicly via a read-only web link (public_access).\n\nPages support rich formatting (ProseMirror schema): tables, lists, checklists, banners, embedded files/images, and cover images.\nPages can be moved between docs or projects, and child pages can be converted to docs and vice versa.", - "descriptionShort": "Rich text page — either a root page (Doc) with sharing settings, or a child page nested within a Doc hierarchy.", + "descriptionShort": "rich text pages — root (Docs) with sharing, or child pages in a Doc hierarchy", "customActions": {}, "fields": { "id": { @@ -5846,6 +6879,7 @@ "key": "coverImageUrl", "type": "string", "typeCategory": "primitive", + "param": "cover_image_url", "readonly": true, "attribute": "cover_image_url" }, @@ -5853,6 +6887,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "sort": "created_at", "attribute": "created_at" @@ -5861,6 +6896,7 @@ "key": "editedAt", "type": "date", "typeCategory": "primitive", + "param": "edited_at", "readonly": true, "sort": "edited_at", "description": "Last time the page content was edited", @@ -5868,7 +6904,7 @@ }, "iconId": { "key": "iconId", - "type": "number", + "type": "string", "typeCategory": "primitive", "param": "icon_id", "attribute": "icon_id" @@ -5884,7 +6920,7 @@ "key": "publicAccess", "type": "boolean", "typeCategory": "primitive", - "param": "public_access", + "param": "has_public_access", "description": "Whether the page is accessible via a public shared link", "attribute": "public_access" }, @@ -5892,7 +6928,7 @@ "key": "public", "type": "boolean", "typeCategory": "primitive", - "param": "public", + "param": "is_public", "description": "Whether the page is visible to all organization members", "attribute": "public" }, @@ -5900,6 +6936,7 @@ "key": "creator", "type": "people", "typeCategory": "resource", + "param": "creator", "readonly": true, "filter": "creator_id", "sort": "creator_name", @@ -5918,7 +6955,7 @@ "key": "project", "type": "projects", "typeCategory": "resource", - "param": "project_id", + "param": "project", "filter": "project_id", "sort": "project_name", "relationship": "project" @@ -5927,24 +6964,25 @@ "key": "rootPage", "type": "pages", "typeCategory": "resource", - "param": "root_page_id", + "param": "root_page", "filter": "root_page_id", - "description": "Root page (top-level Doc) of the hierarchy. Required together with parent_page_id when creating a child page — both must be set or both omitted.", + "description": "Root page (top-level Doc) of the hierarchy. Required together with parent_page when creating a child page — both must be set or both omitted.", "relationship": "root_page" }, "parentPage": { "key": "parentPage", "type": "pages", "typeCategory": "resource", - "param": "parent_page_id", + "param": "parent_page", "filter": "parent_page_id", - "description": "Direct parent page in the hierarchy. Required together with root_page_id when creating a child page — both must be set or both omitted.", + "description": "Direct parent page in the hierarchy. Required together with root_page when creating a child page — both must be set or both omitted.", "relationship": "parent_page" }, "attachments": { "key": "attachments", "type": "attachments", "typeCategory": "resource", + "param": "attachments", "readonly": true, "relationship": "attachments", "array": true @@ -5961,7 +6999,7 @@ "itemName": "payment", "collectionName": "payments", "description": "Payment records money received against an invoice, or an amount written off as uncollectable.\nThe invoice must be marked as sent before payments can be recorded.\n\nTwo types of payment records:\n- Payment (paid_on set): actual money received from the client. Reduces the invoice's amount_unpaid.\n- Write-off (written_off_on set): forgiven debt that won't be collected. Reduces amount_unpaid and increases amount_written_off on the invoice.\n\nMultiple payments can be recorded against a single invoice for partial payments.\nWhen total payments + write-offs equal the invoice amount_with_tax, the invoice status changes to \"Paid\".\nPayments can be synced one-way from accounting tools (Xero, QuickBooks, Exact, E-conomic) — synced payments cannot be deleted in Productive.\nCurrency is inherited from the invoice and is read-only.", - "descriptionShort": "Money received or amount written off against an invoice — tracks partial and full payment state.", + "descriptionShort": "money received or written off against an invoices", "customActions": {}, "fields": { "id": { @@ -6006,6 +7044,7 @@ "key": "externalId", "type": "string", "typeCategory": "primitive", + "param": "external_id", "readonly": true, "filter": "external_id", "description": "External system identifier", @@ -6015,6 +7054,7 @@ "key": "currency", "type": "currency", "typeCategory": "enum", + "param": "currency", "readonly": true, "attribute": "currency" }, @@ -6034,7 +7074,7 @@ "key": "invoice", "type": "invoices", "typeCategory": "resource", - "param": "invoice_id", + "param": "invoice", "required": true, "filter": "invoice_id", "description": "Invoice this payment applies to", @@ -6048,8 +7088,8 @@ "domain": "People & Organization", "itemName": "person", "collectionName": "people", - "description": "Person is the central resource in Productive — most other resources reference people as assignees, creators, approvers, or responsible parties.\nPeople is a polymorphic resource with five subtypes, distinguished by hrm_type_id and person_type:\n\n1. Employees (hrm_type_id=1, person_type=1):\nFull organization members with login access. Count as paid seats.\nCan be assigned to tasks, track time, log expenses, be booked on services in the Resource Planner, and request time off.\nHave cost rates (salaries) that determine hourly cost for profitability tracking, working capacity, and holiday calendar.\nAssigned to teams, subsidiaries, and service types. Have a manager for org chart hierarchy.\nPermissions are controlled via system or custom permission sets.\n\n2. Contractors (hrm_type_id=1, person_type=1):\nExternal collaborators with login access, employed by a different company. Count as paid seats.\nSame capabilities as employees (tasks, time tracking, bookings, cost rates) but linked to an external company.\nOverhead is typically disabled on their cost rates since they don't generate organizational overhead.\n\n3. Clients (hrm_type_id=2, person_type=1):\nExternal users invited to collaborate on specific projects. Free seats (no cost).\nClient Staff: can view and manage tasks, comment, and collaborate on docs within shared projects.\nClient Managers: additionally can view budgets and a client-facing subset of financial data (services, time entries, expenses) on budgets where client access is enabled.\nCannot access profitability data, cost rates, or internal projects. Custom client permissions can be created for tailored access.\n\n4. Contacts (hrm_type_id=2, person_type=2):\nCRM records without login access. Store contact details, notes, and linked emails.\nCannot collaborate in the app but can be converted to any user type (Employee, Contractor, or Client) at any time via the invite action.\nArchived via archived_at (not deactivated_at which is for users).\n\n5. Placeholders (person_type=3):\nNamed resource slots for capacity planning before a real person is hired or assigned.\nCan have cost rates and be booked on services in the Resource Planner, but cannot be added to projects, assigned to tasks, or track time.\nConfirmed placeholder bookings can be reassigned to a real person. Available on Professional (5) and Ultimate (10) plans.\n\nPeople can be active (status=1) or deactivated/archived (status=2).\nPeople can set custom status (emoji + text with expiration) that syncs to Slack and external calendars.", - "descriptionShort": "Central resource representing employees, contractors, clients, contacts, or placeholders — with type-specific capabilities and access.", + "description": "Person is the central resource in Productive — most other resources reference people as assignees, creators, approvers, or responsible parties.\nPeople is a polymorphic resource with five subtypes, distinguished by hrm_type and person_type:\n\n1. Employees (hrm_type=1, person_type=1):\nFull organization members with login access. Count as paid seats.\nCan be assigned to tasks, track time, log expenses, be booked on services in the Resource Planner, and request time off.\nHave cost rates (salaries) that determine hourly cost for profitability tracking, working capacity, and holiday calendar.\nAssigned to teams, subsidiaries, and service types. Have a manager for org chart hierarchy.\nPermissions are controlled via system or custom permission sets.\n\n2. Contractors (hrm_type=1, person_type=1):\nExternal collaborators with login access, employed by a different company. Count as paid seats.\nSame capabilities as employees (tasks, time tracking, bookings, cost rates) but linked to an external company.\nOverhead is typically disabled on their cost rates since they don't generate organizational overhead.\n\n3. Clients (hrm_type=2, person_type=1):\nExternal users invited to collaborate on specific projects. Free seats (no cost).\nClient Staff: can view and manage tasks, comment, and collaborate on docs within shared projects.\nClient Managers: additionally can view budgets and a client-facing subset of financial data (services, time entries, expenses) on budgets where client access is enabled.\nCannot access profitability data, cost rates, or internal projects. Custom client permissions can be created for tailored access.\n\n4. Contacts (hrm_type=2, person_type=2):\nCRM records without login access. Store contact details, notes, and linked emails.\nCannot collaborate in the app but can be converted to any user type (Employee, Contractor, or Client) at any time via the invite action.\nArchived via archived_at (not deactivated_at which is for users).\n\n5. Placeholders (person_type=3):\nNamed resource slots for capacity planning before a real person is hired or assigned.\nCan have cost rates and be booked on services in the Resource Planner, but cannot be added to projects, assigned to tasks, or track time.\nConfirmed placeholder bookings can be reassigned to a real person. Available on Professional (5) and Ultimate (10) plans.\n\nPeople can be active (status=1) or deactivated/archived (status=2).\nPeople can set custom status (emoji + text with expiration) that syncs to Slack and external calendars.", + "descriptionShort": "employees, contractors, clients, contacts, or placeholders — with type-specific capabilities and access", "customActions": { "invite": { "name": "invite", @@ -6112,6 +7152,7 @@ "key": "avatarUrl", "type": "string", "typeCategory": "primitive", + "param": "avatar_url", "readonly": true, "description": "URL of the person's avatar image.", "attribute": "avatar_url", @@ -6121,6 +7162,7 @@ "key": "agent", "type": "boolean", "typeCategory": "primitive", + "param": "is_agent", "readonly": true, "description": "Whether this person is an AI agent (not a human user).", "attribute": "agent" @@ -6129,6 +7171,7 @@ "key": "contact", "type": "hash", "typeCategory": "primitive", + "param": "contact", "readonly": true, "description": "Contact information hash containing phone numbers, addresses, and other contact details. Only visible if the current user has permission to view contact information.", "attribute": "contact" @@ -6137,6 +7180,7 @@ "key": "statusEmoji", "type": "string", "typeCategory": "primitive", + "param": "status_emoji", "readonly": true, "description": "Custom status emoji set by the person (e.g. vacation, focus mode).", "attribute": "status_emoji" @@ -6145,6 +7189,7 @@ "key": "statusText", "type": "string", "typeCategory": "primitive", + "param": "status_text", "readonly": true, "description": "Custom status text set by the person (e.g. \"On vacation until Monday\").", "attribute": "status_text" @@ -6153,6 +7198,7 @@ "key": "statusExpiresAt", "type": "date", "typeCategory": "primitive", + "param": "status_expires_at", "readonly": true, "description": "When the custom status automatically expires.", "attribute": "status_expires_at" @@ -6161,6 +7207,7 @@ "key": "lastSeenAt", "type": "date", "typeCategory": "primitive", + "param": "last_seen_at", "readonly": true, "sort": "last_seen_at", "description": "Timestamp when the person was last active in Productive.", @@ -6170,6 +7217,7 @@ "key": "hrmTypeId", "type": "hrm_type", "typeCategory": "enum", + "param": "hrm_type", "readonly": true, "filter": "hrm_type_id", "description": "Determines whether the person is an employee/contractor or a CRM contact/client. Use this filter to query people by category.", @@ -6187,21 +7235,24 @@ "key": "personType", "type": "person_type", "typeCategory": "enum", + "param": "person_type", "filter": "person_type", - "description": "Filter by person type: users (1), contacts (2), or placeholders (3)" + "description": "Filter by person type" }, "status": { "key": "status", "type": "person_status", "typeCategory": "enum", + "param": "status", "readonly": true, "filter": "status", - "description": "Status of the person: active (1) or deactivated (2)" + "description": "Status of the person" }, "projectWatching": { "key": "projectWatching", "type": "projects", "typeCategory": "resource", + "param": "project_watching", "filter": "project_watching", "description": "Filter to find people who should be subscribed to new tasks in the project (aka \"project watchers\")" }, @@ -6209,6 +7260,7 @@ "key": "accessibleProjectId", "type": "projects", "typeCategory": "resource", + "param": "accessible_project_id", "filter": "accessible_project_id", "description": "Filter to find people who have access and can collaborate on the project(s)", "array": true @@ -6217,6 +7269,7 @@ "key": "subscribableType", "type": "subscribable_type", "typeCategory": "enum", + "param": "subscribable_type", "filter": "subscribable_type", "description": "Type of the resource the person is subscribed to" }, @@ -6236,6 +7289,7 @@ "key": "archivedAt", "type": "date", "typeCategory": "primitive", + "param": "archived_at", "readonly": true, "description": "Date when the contact was archived (soft-deleted). Only applicable to contacts — employees/contractors use deactivated_at instead.", "attribute": "archived_at" @@ -6244,6 +7298,7 @@ "key": "deactivatedAt", "type": "date", "typeCategory": "primitive", + "param": "deactivated_at", "readonly": true, "filter": "deactivated_at", "description": "Date when the user was deactivated. Applicable to employees and contractors (users with login access). Contacts use archived_at instead.", @@ -6253,6 +7308,7 @@ "key": "virtual", "type": "boolean", "typeCategory": "primitive", + "param": "is_virtual", "readonly": true, "description": "Whether this is a virtual person (not a real individual). Virtual people are used for shared/pooled resource slots.", "attribute": "virtual" @@ -6261,6 +7317,7 @@ "key": "placeholder", "type": "boolean", "typeCategory": "primitive", + "param": "is_placeholder", "readonly": true, "description": "Whether this is a placeholder person (unnamed resource slot used for capacity planning before a real person is assigned).", "attribute": "placeholder" @@ -6269,6 +7326,7 @@ "key": "joinedAt", "type": "date", "typeCategory": "primitive", + "param": "joined_at", "readonly": true, "sort": "joined_at", "description": "Date when the person joined the organization (employment start date)", @@ -6278,6 +7336,7 @@ "key": "availabilities", "type": "hash", "typeCategory": "primitive", + "param": "availabilities", "readonly": true, "description": "Serialized salary/engagement periods defining the person's working schedule. Array of tuples: [started_on, ended_on, working_hours, holiday_calendar_id]. working_hours is an array of 7 numbers (hours per weekday, Mon=0..Sun=6) or 14 numbers for alternating week schedules (week1 Mon..Sun, week2 Mon..Sun). ended_on is null for the current/open-ended engagement.", "attribute": "availabilities" @@ -6294,7 +7353,7 @@ "key": "manager", "type": "people", "typeCategory": "resource", - "param": "manager_id", + "param": "manager", "filter": "manager_id", "sort": "manager", "relationship": "manager" @@ -6303,7 +7362,7 @@ "key": "customRole", "type": "roles", "typeCategory": "resource", - "param": "custom_role_id", + "param": "permission_set", "description": "Permission set (role) assigned to the person", "relationship": "custom_role" }, @@ -6311,7 +7370,7 @@ "key": "company", "type": "companies", "typeCategory": "resource", - "param": "company_id", + "param": "company", "required": true, "filter": "company_id", "sort": "company_name", @@ -6322,6 +7381,7 @@ "key": "subsidiary", "type": "subsidiaries", "typeCategory": "resource", + "param": "subsidiary", "filter": "subsidiary_id", "description": "Subsidiary (legal entity) the person belongs to. Used for financial reporting and overhead calculations.", "relationship": "subsidiary" @@ -6330,6 +7390,7 @@ "key": "teams", "type": "teams", "typeCategory": "resource", + "param": "teams", "description": "Teams the person is a member of.", "relationship": "teams", "array": true @@ -6338,13 +7399,21 @@ "key": "autotracking", "type": "boolean", "typeCategory": "primitive", - "param": "autotracking", + "param": "has_autotracking_enabled", "description": "Whether automatic time tracking is enabled for this person", "attribute": "autotracking" + }, + "approvalPolicyAssignment": { + "key": "approvalPolicyAssignment", + "type": "approval_policy_assignments", + "typeCategory": "resource", + "param": "approval_policy_assignment", + "description": "The approval policy assignment for this person — defines which absence approval policy governs their time-off requests", + "relationship": "approval_policy_assignment" } }, "collections": {}, - "queryHints": "People is a polymorphic resource with subtypes: employees, contacts, clients, and placeholders.\nUsers typically care about active people records, unless they specify otherwise.\nThe default filter scope for all subtypes is: { status: {eq: '1'} }\n\nEach subtype has additional filters:\n- employees: { hrm_type_id: {eq: '1'}, person_type: {eq: '1'} }\n- contacts: { hrm_type_id: {eq: '2'}, person_type: {eq: '2'} }\n- clients: { hrm_type_id: {eq: '2'}, person_type: {eq: '1'} }\n- placeholders: { person_type: {eq: '3'} }\nWhen users ask about \"people\" without specifying a subtype, they typically mean \"employees\".", + "queryHints": "People is a polymorphic resource with subtypes: employees, contacts, clients, and placeholders.\nUsers typically care about active people records, unless they specify otherwise.\nThe default filter scope for all subtypes is: { status: {eq: '1'} }\n\nEach subtype has additional filters:\n- employees: { hrm_type: {eq: '1'}, person_type: {eq: '1'} }\n- contacts: { hrm_type: {eq: '2'}, person_type: {eq: '2'} }\n- clients: { hrm_type: {eq: '2'}, person_type: {eq: '1'} }\n- placeholders: { person_type: {eq: '3'} }\nWhen users ask about \"people\" without specifying a subtype, they typically mean \"employees\".", "searchQuickResultType": [ "person" ], @@ -6373,8 +7442,8 @@ "domain": "CRM & Sales", "itemName": "pipeline", "collectionName": "pipelines", - "description": "Pipeline defines the stages (Deal Statuses) that Deals move through.\nTwo types: sales (pipeline_type_id=1) for tracking opportunities from lead to close, and production (pipeline_type_id=2) for managing budgets.\n\nOrganizations can have multiple pipelines for different product lines, customer segments, or sales teams.\nThe number of pipelines depends on the subscription plan (Essential: 1, Professional: 3, Ultimate: 5).\n\nEach pipeline contains ordered Deal Statuses (stages) with:\n- A stage status: open, won, or lost. Moving a deal to a won/lost stage triggers the corresponding deal outcome.\n- Default probability (0-100%) for revenue forecasting (Ultimate plan). Won stages default to 100%, lost to 0%.\n- Per-stage toggles for time tracking, expense tracking, and booking creation on deals in that stage.\n- Optional mandatory lost reason requirement when a deal enters a lost stage.\n\nConfigured by admins in sales settings.", - "descriptionShort": "Ordered set of deal stages — sales pipeline for opportunities or production pipeline for budgets.", + "description": "Pipeline defines the stages (Deal Statuses) that Deals move through.\nTwo types: sales (pipeline_type=1) for tracking opportunities from lead to close, and production (pipeline_type=2) for managing budgets.\n\nOrganizations can have multiple pipelines for different product lines, customer segments, or sales teams.\nThe number of pipelines depends on the subscription plan (Essential: 1, Professional: 3, Ultimate: 5).\n\nEach pipeline contains ordered Deal Statuses (stages) with:\n- A stage status: open, won, or lost. Moving a deal to a won/lost stage triggers the corresponding deal outcome.\n- Default probability (0-100%) for revenue forecasting (Ultimate plan). Won stages default to 100%, lost to 0%.\n- Per-stage toggles for time tracking, expense tracking, and booking creation on deals in that stage.\n- Optional mandatory lost reason requirement when a deal enters a lost stage.\n\nConfigured by admins in sales settings.", + "descriptionShort": "deal stages — sales pipelines for opportunities or production pipelines for budgets", "customActions": {}, "fields": { "id": { @@ -6397,6 +7466,7 @@ "key": "pipelineTypeId", "type": "pipeline_type", "typeCategory": "enum", + "param": "pipeline_type", "filter": "pipeline_type_id", "attribute": "pipeline_type_id" }, @@ -6404,12 +7474,13 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "attribute": "created_at" }, "iconId": { "key": "iconId", - "type": "number", + "type": "string", "typeCategory": "primitive", "param": "icon_id", "attribute": "icon_id" @@ -6441,7 +7512,7 @@ "itemName": "price", "collectionName": "prices", "description": "Price is a line item on a Rate Card that serves as a service template.\nWhen adding services to a deal/budget from a rate card, prices pre-fill the service configuration.\n\nEach price defines:\n- Service type, name, and description (template for the service).\n- Billing type (Fixed, T&M, Non-billable) and tracking unit (hour, day, piece).\n- Rate (price per unit), quantity, currency, discount, and markup.\n- Tracking toggles: time tracking, expense tracking, booking tracking, and budget cap.\n- Estimated hours for internal planning.\n\nPrices belong to a Rate Card, which is either a company-wide default (linked to the organization's company) or a client-specific rate card (linked to a client company).\nWhen both exist, client-specific prices appear alongside company defaults when working with that client's deals/budgets.", - "descriptionShort": "Rate card line item — service template defining billing type, rate, unit, and tracking defaults.", + "descriptionShort": "rate card line items with billing type, rate, unit, and tracking defaults", "customActions": {}, "fields": { "id": { @@ -6595,7 +7666,7 @@ "key": "serviceType", "type": "service_types", "typeCategory": "resource", - "param": "service_type_id", + "param": "service_type", "required": true, "filter": "service_type_id", "sort": "service_type", @@ -6605,7 +7676,7 @@ "key": "company", "type": "companies", "typeCategory": "resource", - "param": "company_id", + "param": "company", "required": true, "filter": "company_id", "relationship": "company" @@ -6614,7 +7685,7 @@ "key": "rateCard", "type": "rate_cards", "typeCategory": "resource", - "param": "rate_card_id", + "param": "rate_card", "filter": "rate_card_id", "relationship": "rate_card" } @@ -6626,8 +7697,8 @@ "domain": "Project Management", "itemName": "project", "collectionName": "projects", - "description": "Project is a workspace where work is organized and tracked.\nTwo types: client (project_type=2) for billable client work, and internal (project_type=1) for non-billable overhead.\n\nProjects contain:\n- Folders and Task Lists for organizing tasks. Tasks follow the project's Workflow (configurable task statuses).\n- Docs (Pages) for documentation, shared with project members by default.\n- Budgets linked for financial tracking — client projects have billable budgets, internal projects only have non-billable budgets.\n- Surveys (Forms) for collecting structured data from users, with automations that can create tasks from responses.\n\nProjects can be viewed in List, Board, Table, Calendar, Timeline, or Gantt layouts.\nAccess is controlled via Memberships — project members, teams, and clients can be added with varying permissions.\nClients can collaborate on tasks in client projects. With the Client Manager permission and explicit budget access enabled, clients can also view a client-facing subset of financial data (services, time entries, expenses) on budgets they are invited to.\nInternal projects cannot have clients added. Converting between client and internal is possible but resets billable data.\nProjects can be archived when completed.", - "descriptionShort": "Workspace for tasks, docs, and budgets — client project (billable) or internal project (overhead).", + "description": "Project is a workspace where work is organized and tracked.\nTwo types: client (project_type=2) for billable client work, and internal (project_type=1) for non-billable overhead.\n\nProjects contain:\n- Folders and Task Lists for organizing tasks. Tasks follow the project's Workflow (configurable task statuses).\n- Docs (Pages) for documentation, shared with project members by default.\n- Budgets linked for financial tracking — client projects have billable budgets, internal projects only have non-billable budgets.\n- Surveys (Forms) for collecting structured data from users, with automations that can create tasks from responses.\n\nProjects can be viewed in List, Board, Table, Calendar, Timeline, or Gantt layouts.\nAccess is controlled via Memberships — project members, teams, and clients can be added with varying permissions.\nClients can collaborate on tasks in client projects. With the Client Manager permission and explicit budget access enabled, clients can also view a client-facing subset of financial data (services, time entries, expenses) on budgets they are invited to.\nInternal projects cannot have clients added. Converting between client and internal is possible but resets billable data.\nProjects can be archived when completed. Archived projects have restricted editing — only name, project manager, and custom field values can be updated. Other fields, memberships, folders, and task lists cannot be modified until the project is restored.", + "descriptionShort": "workspaces for tasks, docs, surveys, budgets and invoices — billable or internal (overhead)", "customActions": { "archive": { "name": "archive", @@ -6664,6 +7735,7 @@ "key": "projectNumber", "type": "string", "typeCategory": "primitive", + "param": "project_number", "readonly": true, "filter": "project_number", "sort": "project_number", @@ -6674,6 +7746,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "filter": "created_at", "sort": "created_at", @@ -6684,6 +7757,7 @@ "key": "archivedAt", "type": "date", "typeCategory": "primitive", + "param": "archived_at", "readonly": true, "description": "When the project was archived (null if active)", "attribute": "archived_at" @@ -6692,6 +7766,7 @@ "key": "lastActivityAt", "type": "date", "typeCategory": "primitive", + "param": "last_activity_at", "readonly": true, "sort": "last_activity_at", "description": "When the last activity occurred on the project", @@ -6701,6 +7776,7 @@ "key": "projectColorId", "type": "number", "typeCategory": "primitive", + "param": "project_color", "filter": "project_color", "description": "Color identifier for visual categorization", "attribute": "project_color_id" @@ -6709,6 +7785,7 @@ "key": "status", "type": "archivable_status", "typeCategory": "enum", + "param": "status", "filter": "status", "description": "Filter by active or archived" }, @@ -6716,6 +7793,7 @@ "key": "personId", "type": "people", "typeCategory": "resource", + "param": "member", "filter": "person_id", "description": "Filter projects by team member" }, @@ -6740,7 +7818,7 @@ "key": "company", "type": "companies", "typeCategory": "resource", - "param": "company_id", + "param": "company", "required": true, "filter": "company_id", "sort": "company_name", @@ -6751,7 +7829,7 @@ "key": "projectManager", "type": "people", "typeCategory": "resource", - "param": "project_manager_id", + "param": "project_manager", "required": true, "filter": "responsible_id", "description": "Responsible for the project", @@ -6761,7 +7839,7 @@ "key": "workflow", "type": "workflows", "typeCategory": "resource", - "param": "workflow_id", + "param": "workflow", "required": true, "filter": "workflow_id", "description": "Workflow for project's task statuses", @@ -6812,11 +7890,11 @@ }, "proposal_sections": { "type": "proposal_sections", - "domain": "Other", + "domain": "CRM & Sales", "itemName": "proposal section", "collectionName": "proposal sections", "description": "Proposal Section groups Proposal Services within a Proposal.\nSections are a snapshot of the deal's sections at the time of proposal creation or regeneration.\nThey organize proposal services into logical categories (e.g. by phase, department, or deliverable type).\nEach section has a name, position, and optional editor configuration for rich text content.\nSections are read-only — changes require regenerating the proposal from the deal.", - "descriptionShort": "Snapshot grouping of proposal services — mirrors a deal section.", + "descriptionShort": "groups of proposal services which mirrors a deal section", "customActions": {}, "fields": { "id": { @@ -6831,6 +7909,7 @@ "key": "name", "type": "string", "typeCategory": "primitive", + "param": "name", "readonly": true, "attribute": "name" }, @@ -6838,6 +7917,7 @@ "key": "position", "type": "number", "typeCategory": "primitive", + "param": "position", "readonly": true, "attribute": "position" }, @@ -6845,6 +7925,7 @@ "key": "preferences", "type": "hash", "typeCategory": "primitive", + "param": "preferences", "readonly": true, "attribute": "preferences" }, @@ -6852,6 +7933,7 @@ "key": "editorConfig", "type": "hash", "typeCategory": "primitive", + "param": "editor_config", "readonly": true, "description": "Rich text editor configuration for the section content", "attribute": "editor_config" @@ -6860,6 +7942,7 @@ "key": "proposal", "type": "proposals", "typeCategory": "resource", + "param": "proposal", "relationship": "proposal" } }, @@ -6867,11 +7950,11 @@ }, "proposal_services": { "type": "proposal_services", - "domain": "Other", + "domain": "CRM & Sales", "itemName": "proposal service", "collectionName": "proposal services", "description": "Proposal Service is a line item within a Proposal, representing a specific type of work with its billing details.\nProposal services are synced from the deal's services when the proposal is created or regenerated — they are a snapshot, not a live reference.\n\nEach proposal service captures: name, description, service type, billing type (Fixed/T&M/Non-billable), unit, quantity, price, discount, markup, and computed totals (budget_total, revenue, discount_amount, markup_amount).\nServices are grouped into Proposal Sections that mirror the deal's sections.\nThe origin_service_id links back to the deal service it was copied from.\nMost fields are read-only — changes to the deal's services require regenerating the proposal to update.", - "descriptionShort": "Snapshot of a deal service within a proposal — billing type, quantity, price, and computed totals.", + "descriptionShort": "deal service snapshots in a proposal with billing type, quantity, price, and totals", "customActions": {}, "fields": { "id": { @@ -6886,6 +7969,7 @@ "key": "name", "type": "string", "typeCategory": "primitive", + "param": "name", "readonly": true, "sort": "name", "attribute": "name" @@ -6894,6 +7978,7 @@ "key": "description", "type": "string", "typeCategory": "primitive", + "param": "description", "readonly": true, "attribute": "description" }, @@ -6901,6 +7986,7 @@ "key": "position", "type": "number", "typeCategory": "primitive", + "param": "position", "readonly": true, "attribute": "position" }, @@ -6908,6 +7994,7 @@ "key": "quantity", "type": "number", "typeCategory": "primitive", + "param": "quantity", "readonly": true, "description": "Proposed quantity in pieces, hours, or days", "attribute": "quantity" @@ -6917,6 +8004,7 @@ "type": "number", "typeCategory": "primitive", "unit": "percentage", + "param": "discount", "readonly": true, "description": "Discount percentage on the proposed service", "attribute": "discount" @@ -6926,6 +8014,7 @@ "type": "number", "typeCategory": "primitive", "unit": "percentage", + "param": "markup", "readonly": true, "description": "Markup percentage on the proposed service", "attribute": "markup" @@ -6934,29 +8023,33 @@ "key": "unitId", "type": "number", "typeCategory": "primitive", + "param": "unit_id", "readonly": true, "attribute": "unit_id" }, "originServiceId": { "key": "originServiceId", - "type": "number", + "type": "string", "typeCategory": "primitive", + "param": "origin_service_id", "readonly": true, "description": "ID of the deal service this proposal service was synced from", "attribute": "origin_service_id" }, "initialServiceId": { "key": "initialServiceId", - "type": "number", + "type": "string", "typeCategory": "primitive", + "param": "initial_service_id", "readonly": true, "description": "ID of the initial deal service", "attribute": "initial_service_id" }, "billingTypeId": { "key": "billingTypeId", - "type": "number", - "typeCategory": "primitive", + "type": "billing_type", + "typeCategory": "enum", + "param": "billing_type", "readonly": true, "description": "Proposed billing type: Fixed, Time and Materials, or Non-billable", "attribute": "billing_type_id" @@ -6965,6 +8058,7 @@ "key": "budgetCapEnabled", "type": "boolean", "typeCategory": "primitive", + "param": "is_budget_cap_enabled", "readonly": true, "description": "Whether budget cap is enabled for the proposed service", "attribute": "budget_cap_enabled" @@ -6973,6 +8067,7 @@ "key": "currency", "type": "currency", "typeCategory": "enum", + "param": "currency", "readonly": true, "attribute": "currency" }, @@ -6981,6 +8076,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "budget_total", "readonly": true, "sort": "budget", "description": "Total budget of the proposed service", @@ -6991,6 +8087,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "budget_used", "readonly": true, "attribute": "budget_used" }, @@ -6999,6 +8096,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "price", "readonly": true, "description": "Price of the proposed service", "attribute": "price" @@ -7008,6 +8106,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "revenue", "readonly": true, "description": "Revenue of the proposed service", "attribute": "revenue" @@ -7016,6 +8115,7 @@ "key": "billableTime", "type": "number", "typeCategory": "primitive", + "param": "billable_time", "readonly": true, "attribute": "billable_time" }, @@ -7024,6 +8124,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "discount_amount", "readonly": true, "attribute": "discount_amount" }, @@ -7032,6 +8133,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "markup_amount", "readonly": true, "attribute": "markup_amount" }, @@ -7039,6 +8141,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "attribute": "created_at" }, @@ -7046,6 +8149,7 @@ "key": "deal", "type": "deals", "typeCategory": "resource", + "param": "deal", "readonly": true, "relationship": "deal" }, @@ -7053,6 +8157,7 @@ "key": "proposal", "type": "proposals", "typeCategory": "resource", + "param": "proposal", "required": true, "filter": "proposal_id", "relationship": "proposal" @@ -7061,6 +8166,7 @@ "key": "proposalSection", "type": "proposal_sections", "typeCategory": "resource", + "param": "proposal_section", "readonly": true, "relationship": "proposal_section" }, @@ -7068,6 +8174,7 @@ "key": "serviceType", "type": "service_types", "typeCategory": "resource", + "param": "service_type", "readonly": true, "relationship": "service_type" } @@ -7077,11 +8184,11 @@ }, "proposals": { "type": "proposals", - "domain": "Other", + "domain": "CRM & Sales", "itemName": "proposal", "collectionName": "proposals", "description": "Proposal is a sales document that presents proposed work and pricing to a client for approval.\nProposals are created on sales deals — each proposal is a snapshot of the deal's sections and services at the time of creation or last sync.\n\nLifecycle: draft → sent → accepted or rejected.\n- Draft: editable, can be regenerated to sync with deal changes. Uses a document type for styling and layout.\n- Sent: shared via email or public link. Generating a public link automatically sets status to sent.\n- Accepted: client accepted (and optionally e-signed) via the public link. Signed proposals are locked and cannot be edited.\n- Rejected: marked by the user in Productive. Disables the public link for signing.\n\nE-signature support: clients can type, draw, or upload a signature. Acceptance is logged with an Audit PDF containing signer details, IP address, timestamp, and PDF fingerprint.\nA disclaimer can be configured that clients must accept before signing.\n\nPlan differences: Essential allows one PDF proposal per deal. Professional/Ultimate add public links and e-signature. Ultimate allows multiple proposals per deal plus analytics.\nProposals include a tax rate, purchase order number, custom fields, and note/footer with variable interpolation.", - "descriptionShort": "Sales document for a deal — presents work and pricing to a client, with e-signature and approval tracking.", + "descriptionShort": "sales quotes for deals — scope and pricing presentation with e-signature and approval", "customActions": {}, "fields": { "id": { @@ -7121,6 +8228,7 @@ "key": "linkStatus", "type": "proposal_link_status", "typeCategory": "enum", + "param": "link_status", "readonly": true, "filter": "link_status", "description": "Whether the public link is active or inactive", @@ -7153,6 +8261,7 @@ "key": "sentAt", "type": "date", "typeCategory": "primitive", + "param": "sent_at", "readonly": true, "filter": "sent_at", "description": "When the proposal was sent to the client", @@ -7162,6 +8271,7 @@ "key": "statusChangedAt", "type": "date", "typeCategory": "primitive", + "param": "status_changed_at", "readonly": true, "filter": "status_changed_at", "attribute": "status_changed_at" @@ -7184,6 +8294,7 @@ "key": "signed", "type": "boolean", "typeCategory": "primitive", + "param": "is_signed", "readonly": true, "description": "Whether the proposal has been signed by the client", "attribute": "signed" @@ -7192,6 +8303,7 @@ "key": "responderName", "type": "string", "typeCategory": "primitive", + "param": "responder_name", "readonly": true, "description": "Name of the person who accepted the proposal", "attribute": "responder_name" @@ -7200,6 +8312,7 @@ "key": "responderEmail", "type": "string", "typeCategory": "primitive", + "param": "responder_email", "readonly": true, "description": "Email of the person who accepted the proposal", "attribute": "responder_email" @@ -7208,6 +8321,7 @@ "key": "exchangeRate", "type": "number", "typeCategory": "primitive", + "param": "exchange_rate", "readonly": true, "attribute": "exchange_rate" }, @@ -7215,6 +8329,7 @@ "key": "exchangeDate", "type": "date", "typeCategory": "primitive", + "param": "exchange_date", "readonly": true, "attribute": "exchange_date" }, @@ -7222,6 +8337,7 @@ "key": "currency", "type": "currency", "typeCategory": "enum", + "param": "currency", "readonly": true, "attribute": "currency" }, @@ -7230,6 +8346,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "budget_total", "readonly": true, "filter": "budget_total", "description": "Total proposal amount", @@ -7239,6 +8356,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "filter": "created_at", "attribute": "created_at" @@ -7254,6 +8372,7 @@ "key": "noteInterpolated", "type": "string", "typeCategory": "primitive", + "param": "note_interpolated", "readonly": true, "description": "Note with variables interpolated", "attribute": "note_interpolated" @@ -7262,6 +8381,7 @@ "key": "footerInterpolated", "type": "string", "typeCategory": "primitive", + "param": "footer_interpolated", "readonly": true, "description": "Footer with variables interpolated", "attribute": "footer_interpolated" @@ -7270,6 +8390,7 @@ "key": "originalPdfUrl", "type": "string", "typeCategory": "primitive", + "param": "original_pdf_url", "readonly": true, "description": "URL of the original proposal PDF", "attribute": "original_pdf_url" @@ -7278,6 +8399,7 @@ "key": "auditPdfUrl", "type": "string", "typeCategory": "primitive", + "param": "audit_pdf_url", "readonly": true, "description": "URL of the audit trail PDF", "attribute": "audit_pdf_url" @@ -7286,6 +8408,7 @@ "key": "publicUuid", "type": "string", "typeCategory": "primitive", + "param": "public_uuid", "readonly": true, "description": "UUID for the public proposal link", "attribute": "public_uuid" @@ -7294,6 +8417,7 @@ "key": "updatedAt", "type": "date", "typeCategory": "primitive", + "param": "updated_at", "readonly": true, "filter": "updated_at", "attribute": "updated_at" @@ -7310,6 +8434,7 @@ "key": "client", "type": "companies", "typeCategory": "resource", + "param": "client", "readonly": true, "filter": "company_id", "description": "Client company the proposal is for", @@ -7319,7 +8444,7 @@ "key": "deal", "type": "deals", "typeCategory": "resource", - "param": "deal_id", + "param": "deal", "required": true, "filter": "deal_id", "description": "Deal this proposal belongs to", @@ -7329,7 +8454,7 @@ "key": "documentType", "type": "document_types", "typeCategory": "resource", - "param": "document_type_id", + "param": "document_type", "required": true, "description": "Defines the structure, style, and content of the proposal document.", "relationship": "document_type" @@ -7338,6 +8463,7 @@ "key": "responsible", "type": "people", "typeCategory": "resource", + "param": "responsible", "readonly": true, "filter": "responsible_id", "relationship": "responsible" @@ -7346,6 +8472,7 @@ "key": "subsidiary", "type": "subsidiaries", "typeCategory": "resource", + "param": "subsidiary", "readonly": true, "relationship": "subsidiary" }, @@ -7353,13 +8480,14 @@ "key": "taxRate", "type": "tax_rates", "typeCategory": "resource", - "param": "tax_rate_id", + "param": "tax_rate", "relationship": "tax_rate" }, "contact": { "key": "contact", "type": "people", "typeCategory": "resource", + "param": "contact", "readonly": true, "relationship": "contact" }, @@ -7367,6 +8495,7 @@ "key": "creator", "type": "people", "typeCategory": "resource", + "param": "creator", "readonly": true, "filter": "creator_id", "description": "Person who created the proposal", @@ -7376,6 +8505,7 @@ "key": "project", "type": "projects", "typeCategory": "resource", + "param": "project", "readonly": true, "relationship": "project" }, @@ -7383,6 +8513,7 @@ "key": "proposalFrom", "type": "contact_entries", "typeCategory": "resource", + "param": "proposal_from", "readonly": true, "description": "Sender contact information", "relationship": "proposal_from" @@ -7391,6 +8522,7 @@ "key": "proposalTo", "type": "contact_entries", "typeCategory": "resource", + "param": "proposal_to", "readonly": true, "description": "Recipient contact information", "relationship": "proposal_to" @@ -7399,6 +8531,7 @@ "key": "dealCreator", "type": "people", "typeCategory": "resource", + "param": "deal_creator", "readonly": true, "description": "Person who created the deal", "relationship": "deal_creator" @@ -7422,7 +8555,7 @@ "itemName": "purchase order", "collectionName": "purchase orders", "description": "Purchase Order (PO) is a document sent to a vendor to order goods or services.\nEach PO is tied to a single budget and cannot span multiple budgets. Available on the Ultimate plan.\n\nPO lifecycle: draft → finalized → sent → received.\n- Draft: expenses are created as draft line items against budget services (services must have unit=Piece with expense tracking enabled).\n- Finalized: all linked expenses are also finalized, impacting the budget. A PO number is assigned.\n- Sent: marked as sent to the vendor (manually or via email). Sent POs cannot be edited unless marked as unsent first.\n- Received: tracked via Bills that record received quantities. Payment status updates automatically (not received → partially received → fully received).\n\nEach expense line item on the PO is a separate Expense record linked to a service in the budget.\nExpenses can be unlinked from a PO (keeping them in the budget) or deleted (removing from both).\nDeleting a PO deletes all linked items unless unlinked first.\nSupports multi-currency, vendor management, document templates, and export to accounting tools.", - "descriptionShort": "Vendor procurement document tied to a budget — each line item becomes an expense on a budget service.", + "descriptionShort": "vendor procurement documents on a budget — line items become expenses on budget services", "customActions": {}, "fields": { "id": { @@ -7438,6 +8571,7 @@ "key": "number", "type": "string", "typeCategory": "primitive", + "param": "number", "filter": "number", "sort": "number", "description": "Auto-generated purchase order number", @@ -7498,6 +8632,7 @@ "key": "receivedOn", "type": "date", "typeCategory": "primitive", + "param": "received_on", "readonly": true, "filter": "received_on", "sort": "received_on", @@ -7516,6 +8651,7 @@ "key": "footer", "type": "string", "typeCategory": "primitive", + "param": "footer", "readonly": true, "attribute": "footer" }, @@ -7532,6 +8668,7 @@ "key": "paymentStatusId", "type": "purchase_order_payment_status", "typeCategory": "enum", + "param": "payment_status_id", "readonly": true, "filter": "payment_status_id", "sort": "payment_status_id", @@ -7542,6 +8679,7 @@ "key": "sentStatus", "type": "purchase_order_sent_status", "typeCategory": "enum", + "param": "sent_status", "readonly": true, "filter": "sent_status", "sort": "sent_status", @@ -7552,6 +8690,7 @@ "key": "exchangeRate", "type": "number", "typeCategory": "primitive", + "param": "exchange_rate", "readonly": true, "attribute": "exchange_rate" }, @@ -7559,6 +8698,7 @@ "key": "exported", "type": "boolean", "typeCategory": "primitive", + "param": "is_exported", "readonly": true, "description": "Whether the purchase order has been exported to an accounting system", "attribute": "exported" @@ -7567,6 +8707,7 @@ "key": "exportedAt", "type": "date", "typeCategory": "primitive", + "param": "exported_at", "readonly": true, "attribute": "exported_at" }, @@ -7575,6 +8716,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "total_cost", "readonly": true, "filter": "total_cost", "sort": "total_cost", @@ -7586,6 +8728,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "total_cost_with_tax", "readonly": true, "filter": "total_cost_with_tax", "sort": "total_cost_with_tax", @@ -7597,6 +8740,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "total_received", "readonly": true, "filter": "total_received", "sort": "total_received", @@ -7607,6 +8751,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "filter": "created_at", "sort": "created_at", @@ -7616,7 +8761,7 @@ "key": "vendor", "type": "companies", "typeCategory": "resource", - "param": "vendor_id", + "param": "vendor", "filter": "vendor_id", "sort": "vendor", "description": "Vendor company this purchase order is sent to", @@ -7626,7 +8771,7 @@ "key": "deal", "type": "deals", "typeCategory": "resource", - "param": "deal_id", + "param": "deal", "required": true, "filter": "deal_id", "sort": "deal_name", @@ -7637,6 +8782,7 @@ "key": "creator", "type": "people", "typeCategory": "resource", + "param": "creator", "readonly": true, "filter": "creator_id", "description": "Person who created the purchase order", @@ -7646,14 +8792,14 @@ "key": "documentType", "type": "document_types", "typeCategory": "resource", - "param": "document_type_id", + "param": "document_type", "relationship": "document_type" }, "attachment": { "key": "attachment", "type": "attachments", "typeCategory": "resource", - "param": "attachment_id", + "param": "attachment", "relationship": "attachment" } }, @@ -7666,7 +8812,7 @@ "itemName": "rate card", "collectionName": "rate cards", "description": "Rate Card is a reusable price list containing Prices (service templates) for Service Types.\nUsed when adding services to deals/budgets from a rate card to pre-fill service configuration.\n\nTwo scopes:\n- Company rate card: linked to the organization's own company. Available for all client deals/budgets. Limited by plan (Professional: 10, Ultimate: 30).\n- Client-specific rate card: linked to a client company. Shown only when working with that client. Unlimited count.\n\nRate cards can be archived when no longer needed — archived cards cannot be used for new deals/budgets but existing ones remain unchanged.\nRate cards can be bulk-updated via CSV export/import for price changes across many services at once.", - "descriptionShort": "Reusable price list of service templates — company-wide defaults or client-specific pricing.", + "descriptionShort": "price lists for services — company-wide or client-specific pricing", "customActions": {}, "fields": { "id": { @@ -7690,43 +8836,346 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", + "readonly": true, + "sort": "created_at", + "attribute": "created_at" + }, + "archivedAt": { + "key": "archivedAt", + "type": "date", + "typeCategory": "primitive", + "param": "archived_at", + "readonly": true, + "attribute": "archived_at" + }, + "pricesCount": { + "key": "pricesCount", + "type": "number", + "typeCategory": "primitive", + "param": "prices_count", + "readonly": true, + "attribute": "prices_count" + }, + "company": { + "key": "company", + "type": "companies", + "typeCategory": "resource", + "param": "company", + "required": true, + "filter": "company_id", + "description": "Company (client, or organization's company for default rate cards) the rate card is for", + "relationship": "company" + } + }, + "collections": { + "pricesCollection": { + "key": "pricesCollection", + "collectionName": "prices", + "type": "prices", + "inverse": "rateCard" + } + } + }, + "resource_requests": { + "type": "resource_requests", + "domain": "Other", + "itemName": "resource request", + "collectionName": "resource requests", + "description": "Resource request (staffing request) represents a request to allocate a person to a service for a given date range. Lifecycle: pending → resolved, rejected, or canceled.", + "descriptionShort": "staffing requests to allocate people to a service for a given date range", + "customActions": { + "resolve": { + "name": "resolve", + "description": "Resolves a resource request by creating bookings for the selected people and marking the request as resolved.", + "endpoint": "resolve", + "method": "POST" + }, + "cancel": { + "name": "cancel", + "description": "Cancels a pending resource request. No additional input required.", + "endpoint": "cancel", + "method": "PATCH" + }, + "reject": { + "name": "reject", + "description": "Rejects a resource request. Requires a rejected_reason in the request body.", + "endpoint": "reject", + "method": "PATCH" + } + }, + "fields": { + "id": { + "key": "id", + "type": "string", + "typeCategory": "primitive", + "param": "id", + "readonly": true, + "id": true + }, + "title": { + "key": "title", + "type": "string", + "typeCategory": "primitive", + "param": "title", + "required": true, + "filter": "title", + "sort": "title", + "description": "Title or label of the resource request", + "attribute": "title" + }, + "note": { + "key": "note", + "type": "string", + "typeCategory": "primitive", + "param": "note", + "description": "Additional notes for the request (free-text, HTML escaped)", + "attribute": "note" + }, + "status": { + "key": "status", + "type": "resource_request_status", + "typeCategory": "enum", + "param": "status", + "readonly": true, + "filter": "status", + "sort": "status", + "description": "Status of the resource request", + "attribute": "status" + }, + "startedOn": { + "key": "startedOn", + "type": "date", + "typeCategory": "primitive", + "format": "YYYY-MM-DD", + "param": "started_on", + "required": true, + "filter": "started_on", + "sort": "started_on", + "description": "Start date of the requested allocation (YYYY-MM-DD)", + "attribute": "started_on" + }, + "endedOn": { + "key": "endedOn", + "type": "date", + "typeCategory": "primitive", + "format": "YYYY-MM-DD", + "param": "ended_on", + "required": true, + "filter": "ended_on", + "sort": "ended_on", + "description": "End date of the requested allocation (YYYY-MM-DD)", + "attribute": "ended_on" + }, + "bookingMethodId": { + "key": "bookingMethodId", + "type": "booking_method", + "typeCategory": "enum", + "param": "booking_method", + "required": true, + "sort": "booking_method_id", + "description": "Booking method used for calculating the allocation", + "attribute": "booking_method_id" + }, + "time": { + "key": "time", + "type": "number", + "typeCategory": "primitive", + "unit": "minutes", + "param": "time", + "filter": "time", + "sort": "time", + "description": "Time in minutes per day. Used when booking_method is per_day. E.g. 480 = 8 hours.", + "attribute": "time" + }, + "percentage": { + "key": "percentage", + "type": "number", + "typeCategory": "primitive", + "unit": "percentage", + "param": "percentage", + "sort": "percentage", + "description": "Percentage of daily capacity (0-100). Used when booking_method is percentage.", + "attribute": "percentage" + }, + "totalTime": { + "key": "totalTime", + "type": "number", + "typeCategory": "primitive", + "unit": "minutes", + "param": "total_time", + "sort": "total_time", + "description": "Total time in minutes distributed across the full date range. Used when booking_method is total_hours.", + "attribute": "total_time" + }, + "maxCostPerHour": { + "key": "maxCostPerHour", + "type": "number", + "typeCategory": "primitive", + "unit": "money", + "param": "max_cost_per_hour", + "description": "Maximum acceptable cost per hour for the requested resource", + "attribute": "max_cost_per_hour" + }, + "currency": { + "key": "currency", + "type": "currency", + "typeCategory": "enum", + "param": "currency", + "required": true, + "description": "Currency code for the cost rate (e.g. USD, EUR)", + "attribute": "currency" + }, + "rejectedReason": { + "key": "rejectedReason", + "type": "string", + "typeCategory": "primitive", + "param": "rejected_reason", + "readonly": true, + "description": "Reason for rejection. Set when status is rejected.", + "attribute": "rejected_reason" + }, + "createdAt": { + "key": "createdAt", + "type": "date", + "typeCategory": "primitive", + "param": "created_at", + "readonly": true, + "filter": "created_at", + "sort": "created_at", + "description": "ISO timestamp when the resource request was created", + "attribute": "created_at" + }, + "resolvedAt": { + "key": "resolvedAt", + "type": "date", + "typeCategory": "primitive", + "param": "resolved_at", + "readonly": true, + "filter": "resolved_at", + "sort": "resolved_at", + "description": "ISO timestamp when the request was resolved", + "attribute": "resolved_at" + }, + "canceledAt": { + "key": "canceledAt", + "type": "date", + "typeCategory": "primitive", + "param": "canceled_at", + "readonly": true, + "description": "ISO timestamp when the request was canceled. Only present when status is canceled.", + "attribute": "canceled_at" + }, + "timeToClose": { + "key": "timeToClose", + "type": "number", + "typeCategory": "primitive", + "param": "time_to_close", + "readonly": true, + "filter": "time_to_close", + "description": "Time to close the request in seconds (from creation to resolution/rejection/cancellation)", + "attribute": "time_to_close" + }, + "exchangeRate": { + "key": "exchangeRate", + "type": "number", + "typeCategory": "primitive", + "param": "exchange_rate", + "readonly": true, + "description": "Exchange rate applied to the cost", + "attribute": "exchange_rate" + }, + "exchangeRateNormalized": { + "key": "exchangeRateNormalized", + "type": "number", + "typeCategory": "primitive", + "param": "exchange_rate_normalized", + "readonly": true, + "description": "Normalized exchange rate", + "attribute": "exchange_rate_normalized" + }, + "exchangeDate": { + "key": "exchangeDate", + "type": "date", + "typeCategory": "primitive", + "param": "exchange_date", + "readonly": true, + "description": "Date the exchange rate was calculated", + "attribute": "exchange_date" + }, + "fields": { + "key": "fields", + "type": "hash", + "typeCategory": "primitive", + "param": "fields", + "description": "System-defined person profile attributes as a key-value hash. Known keys: team_ids (array of team ID strings), job_title (string), subsidiary_id (workplace/subsidiary string ID), service_type_ids (array of service type ID strings), tags (array of tag name strings).", + "attribute": "fields" + }, + "customFields": { + "key": "customFields", + "type": "hash", + "typeCategory": "primitive", + "unit": "custom_field_values", + "param": "custom_fields", + "description": "Employee custom field values. Key = custom field ID (string), value = serialized field value. Query custom fields to find available field IDs.", + "attribute": "custom_fields" + }, + "service": { + "key": "service", + "type": "services", + "typeCategory": "resource", + "param": "service", + "required": true, + "filter": "service_id", + "sort": "service", + "description": "Service (budget line item) the resource is being requested for", + "relationship": "service" + }, + "creator": { + "key": "creator", + "type": "people", + "typeCategory": "resource", + "param": "creator", "readonly": true, - "sort": "created_at", - "attribute": "created_at" + "filter": "creator_id", + "sort": "creator", + "description": "Person who created this resource request", + "relationship": "creator" }, - "archivedAt": { - "key": "archivedAt", - "type": "date", - "typeCategory": "primitive", + "resolver": { + "key": "resolver", + "type": "people", + "typeCategory": "resource", + "param": "resolver", "readonly": true, - "attribute": "archived_at" + "filter": "resolver_id", + "sort": "resolver", + "description": "Person who resolved or rejected this resource request", + "relationship": "resolver" }, - "pricesCount": { - "key": "pricesCount", - "type": "number", - "typeCategory": "primitive", + "customFieldPeople": { + "key": "customFieldPeople", + "type": "people", + "typeCategory": "resource", + "param": "custom_field_people", "readonly": true, - "attribute": "prices_count" + "description": "People linked via custom field values (no nested includes supported)", + "relationship": "custom_field_people", + "array": true }, - "company": { - "key": "company", - "type": "companies", + "customFieldAttachments": { + "key": "customFieldAttachments", + "type": "attachments", "typeCategory": "resource", - "param": "company_id", - "required": true, - "filter": "company_id", - "description": "Company (client, or organization's company for default rate cards) the rate card is for", - "relationship": "company" + "param": "custom_field_attachments", + "readonly": true, + "description": "Attachments linked via custom field values", + "relationship": "custom_field_attachments", + "array": true } }, - "collections": { - "pricesCollection": { - "key": "pricesCollection", - "collectionName": "prices", - "type": "prices", - "inverse": "rateCard" - } - } + "collections": {}, + "searchFilterParam": "query" }, "roles": { "type": "roles", @@ -7734,7 +9183,7 @@ "itemName": "role", "collectionName": "roles", "description": "Permission set (also called a role) defines a named group of permissions that controls what a person can do in the organization. Roles are assigned to users to grant or restrict access to features such as project management, invoicing, time tracking, and administration. Each role targets a specific user type (employee, contractor, or client). Resolved permissions show the final effective permissions after inheritance is applied.", - "descriptionShort": "Permission set is set of permissions controlling what a person can do in the organization.", + "descriptionShort": "permission sets controlling what a person can do in the organization", "customActions": {}, "fields": { "id": { @@ -7758,12 +9207,14 @@ "key": "permissions", "type": "hash", "typeCategory": "primitive", + "param": "permissions", "serialize": false }, "resolvedPermissions": { "key": "resolvedPermissions", "type": "hash", "typeCategory": "primitive", + "param": "resolved_permissions", "attribute": "resolved_permissions", "serialize": false }, @@ -7771,6 +9222,7 @@ "key": "userTypeId", "type": "role_user_type", "typeCategory": "enum", + "param": "user_type", "attribute": "user_type_id", "serialize": false } @@ -7786,7 +9238,7 @@ "itemName": "salary", "collectionName": "salaries", "description": "Salary (Cost Rate) defines a person's compensation and working capacity for a given period.\nA person must have a cost rate to track time or be booked in the Resource Planner.\n\nEach salary record defines:\n- Compensation: a cost amount with a salary_type (hourly, weekly, biweekly, monthly, or annually) and currency.\n- Hourly rate: auto-calculated from cost, working_hours, and salary_type. Used for cost calculations: Cost = worked hours × hourly rate.\n- Working hours: array of hours per weekday (Mon–Sun). Defines the person's weekly capacity for availability calculations.\n- Alternating hours: optional bi-weekly schedule (two different week patterns) for 9-day fortnights or 40/32-hour alternating weeks.\n- Holiday calendar: assigned per salary period, determines which days are non-working for this person.\n- Overhead: whether the person's time generates overhead cost for the organization (typically true for employees, false for contractors).\n\nA person can have multiple salary records over time (e.g. raises, schedule changes). The active one is determined by date range (started_on/ended_on).\nHourly cost for fixed salary types is calculated using full-year capacity, not partial periods, to avoid inflated rates.", - "descriptionShort": "Cost rate and working capacity for a person — determines hourly cost, availability, and overhead.", + "descriptionShort": "people cost rates and working capacities with hourly cost, availability and overhead", "customActions": {}, "fields": { "id": { @@ -7801,7 +9253,7 @@ "key": "defaultSalary", "type": "boolean", "typeCategory": "primitive", - "param": "default_salary", + "param": "is_default_salary", "required": true, "description": "Legacy flag, always set to false for new records. Active cost rate is determined by date range (started_on/ended_on), not by this flag.", "attribute": "default_salary" @@ -7834,7 +9286,7 @@ "key": "overhead", "type": "boolean", "typeCategory": "primitive", - "param": "overhead", + "param": "has_overhead", "required": true, "description": "Does the salary generates overhead (cost) for the organization?", "attribute": "overhead" @@ -7870,7 +9322,7 @@ "key": "alternatingHours", "type": "boolean", "typeCategory": "primitive", - "param": "alternating_hours", + "param": "has_alternating_hours", "description": "Defines whether working hours capacity is alternating between two weeks", "attribute": "alternating_hours" }, @@ -7898,7 +9350,7 @@ "key": "person", "type": "people", "typeCategory": "resource", - "param": "person_id", + "param": "person", "required": true, "filter": "person_id", "relationship": "person" @@ -7907,7 +9359,7 @@ "key": "holidayCalendar", "type": "holiday_calendars", "typeCategory": "resource", - "param": "holiday_calendar_id", + "param": "holiday_calendar", "description": "Holiday calendar assigned to this salary period, affects availability calculations", "relationship": "holiday_calendar" } @@ -7915,13 +9367,137 @@ "collections": {}, "defaultSort": "Sorted by -id by default." }, + "scenario_bookings": { + "type": "scenario_bookings", + "domain": "Financial", + "itemName": "scenario booking", + "collectionName": "scenario bookings", + "description": "ScenarioBooking represents planned time allocation for a person assigned to a scenario service (ScenarioItem).\nIt is the resource-planning counterpart of a regular Booking, but scoped to a Scenario instead of a live Budget.\n\nUse scenario bookings to model how many hours each person will work on each scenario service within a given date range.\nThis enables accurate cost and revenue forecasting in what-if scenarios before committing changes to a deal.\n\nTime allocation methods (booking_method):\n- Hours per day (1): fixed hours each working day of the booking period. Set the \"time\" field (minutes per day).\n- Percentage (2): percentage of the person's daily capacity. Set the \"percentage\" field (0–100).\n- Total hours (3): total hours spread evenly across the date range. Set the \"total_time\" field (minutes total).\n\nEach booking must be created and updated individually — no bulk endpoints are available.\n\nWhen the parent scenario is applied to the deal/budget, scenario bookings are converted into regular Resource Planner bookings.", + "descriptionShort": "planned time allocation for a person on a scenario service — the resource-planning layer of a what-if scenario", + "customActions": {}, + "fields": { + "id": { + "key": "id", + "type": "string", + "typeCategory": "primitive", + "param": "id", + "readonly": true, + "id": true + }, + "startedOn": { + "key": "startedOn", + "type": "date", + "typeCategory": "primitive", + "format": "YYYY-MM-DD", + "param": "started_on", + "required": true, + "filter": "started_on", + "description": "Start date of the booking", + "attribute": "started_on" + }, + "endedOn": { + "key": "endedOn", + "type": "date", + "typeCategory": "primitive", + "format": "YYYY-MM-DD", + "param": "ended_on", + "required": true, + "filter": "ended_on", + "description": "End date of the booking", + "attribute": "ended_on" + }, + "time": { + "key": "time", + "type": "number", + "typeCategory": "primitive", + "unit": "minutes", + "param": "time", + "description": "Minutes per day. Required when booking_method is \"1\" (per day). Not used with other methods.", + "attribute": "time" + }, + "percentage": { + "key": "percentage", + "type": "number", + "typeCategory": "primitive", + "unit": "percentage", + "param": "percentage", + "description": "Percentage of daily capacity (0–100). Required when booking_method is \"2\" (percentage). Not used with other methods.", + "attribute": "percentage" + }, + "totalTime": { + "key": "totalTime", + "type": "number", + "typeCategory": "primitive", + "unit": "minutes", + "param": "total_time", + "description": "Total minutes across the full date range. Required and writable when booking_method is \"3\" (total hours). Read-only for other methods — the API calculates it automatically.", + "attribute": "total_time" + }, + "totalWorkingDays": { + "key": "totalWorkingDays", + "type": "number", + "typeCategory": "primitive", + "param": "total_working_days", + "readonly": true, + "description": "Number of working days in the booking date range. Read-only, calculated by the API.", + "attribute": "total_working_days" + }, + "bookingMethod": { + "key": "bookingMethod", + "type": "booking_method", + "typeCategory": "enum", + "param": "booking_method", + "required": true, + "description": "How time is allocated: per day (\"1\"), percentage (\"2\"), or total hours (\"3\").", + "attribute": "booking_method_id" + }, + "note": { + "key": "note", + "type": "string", + "typeCategory": "primitive", + "param": "note", + "filter": "note", + "description": "Optional note or comment on the booking.", + "attribute": "note" + }, + "customFields": { + "key": "customFields", + "type": "hash", + "typeCategory": "primitive", + "unit": "custom_field_values", + "param": "custom_fields", + "attribute": "custom_fields" + }, + "scenarioItem": { + "key": "scenarioItem", + "type": "scenario_items", + "typeCategory": "resource", + "param": "scenario_item", + "required": true, + "filter": "scenario_item_id", + "description": "The scenario item (person assigned to a scenario service) that this booking belongs to.", + "relationship": "scenario_item" + }, + "person": { + "key": "person", + "type": "people", + "typeCategory": "resource", + "param": "person", + "filter": "person_id", + "description": "The person this booking is for (derived from the scenario item). person should never be passed on create or update — scenario_item should be passed instead.", + "relationship": "person", + "notIncludable": true + } + }, + "collections": {} + }, "scenario_items": { "type": "scenario_items", - "domain": "Other", + "domain": "Financial", "itemName": "scenario item", "collectionName": "scenario items", "description": "ScenarioItem assigns a person to a specific ScenarioService within a Scenario.\nEach item represents one person's contribution to a service, with an optional date range\nand rate overrides (price, cost, discount, markup).\n\nUse scenario items to model who does the work and what it costs in a what-if scenario.\nSupports bulk create, update, and delete for efficient multi-person assignment.\n\nIf person_id is set, the item name is derived from the person and cannot be set manually.\nRates default to the service's rates but can be overridden per item.", - "descriptionShort": "Assigns a person to a scenario service for a date range — defines who does the work and at what rate.", + "descriptionShort": "people assignments on a scenario service with date range and rate", "customActions": {}, "fields": { "id": { @@ -7937,7 +9513,7 @@ "type": "string", "typeCategory": "primitive", "param": "name", - "description": "Name of the scenario item. Automatically set from the person when person_id is provided — do not set manually in that case.", + "description": "Name of the scenario item. Automatically set from the person when person is provided — do not set manually in that case.", "attribute": "name" }, "startDate": { @@ -8006,6 +9582,7 @@ "key": "currency", "type": "string", "typeCategory": "primitive", + "param": "currency", "readonly": true, "description": "Currency code inherited from the scenario service", "attribute": "currency" @@ -8015,6 +9592,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "discount_amount", "readonly": true, "description": "Computed discount amount in cents", "attribute": "discount_amount" @@ -8024,6 +9602,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "markup_amount", "readonly": true, "description": "Computed markup amount in cents", "attribute": "markup_amount" @@ -8032,7 +9611,7 @@ "key": "scenarioService", "type": "scenario_services", "typeCategory": "resource", - "param": "scenario_service_id", + "param": "scenario_service", "required": true, "filter": "service_id", "description": "The scenario service this item belongs to", @@ -8043,7 +9622,7 @@ "key": "person", "type": "people", "typeCategory": "resource", - "param": "person_id", + "param": "person", "filter": "person_id", "description": "The person assigned to this service in the scenario", "relationship": "person" @@ -8052,6 +9631,7 @@ "key": "scenario", "type": "scenarios", "typeCategory": "resource", + "param": "scenario", "description": "The scenario this item belongs to (via scenario service)", "relationship": "scenario", "notIncludable": true @@ -8066,11 +9646,11 @@ }, "scenario_sections": { "type": "scenario_sections", - "domain": "Other", + "domain": "Financial", "itemName": "scenario section", "collectionName": "scenario sections", "description": "ScenarioSection is a grouping of ScenarioServices within a Scenario, mirroring how Sections group Services within a Deal. Each scenario service belongs to exactly one scenario section.", - "descriptionShort": "Grouping of ScenarioServices within a Scenario, mirroring how Sections group Services within a Deal.", + "descriptionShort": "groups of scenario services, mirroring deal sections", "customActions": {}, "fields": { "id": { @@ -8101,7 +9681,7 @@ "key": "scenario", "type": "scenarios", "typeCategory": "resource", - "param": "scenario_id", + "param": "scenario", "required": true, "filter": "scenario_id", "description": "The scenario this section belongs to", @@ -8113,11 +9693,11 @@ }, "scenario_services": { "type": "scenario_services", - "domain": "Other", + "domain": "Financial", "itemName": "scenario service", "collectionName": "scenario services", "description": "ScenarioService is a service line item within a Scenario, equivalent to a Service on a Deal. It defines the deliverable, pricing, and billing configuration for a what-if scenario. Scenario services are created when building out a scenario's service configuration.", - "descriptionShort": "Service line item within a Scenario, equivalent to a Service on a Deal — defines deliverable, pricing, and billing configuration.", + "descriptionShort": "service lines in a scenarios with deliverable, pricing, and billing configuration", "customActions": {}, "fields": { "id": { @@ -8183,7 +9763,7 @@ "typeCategory": "primitive", "unit": "money", "param": "price", - "description": "Price in cents. Required for fixed billing type.", + "description": "Per-unit rate in cents (e.g. hourly rate). Required for fixed billing type. budget_total is computed as price x quantity.", "attribute": "price" }, "discount": { @@ -8216,7 +9796,7 @@ "key": "scenario", "type": "scenarios", "typeCategory": "resource", - "param": "scenario_id", + "param": "scenario", "required": true, "filter": "scenario_id", "description": "The scenario this service belongs to", @@ -8227,9 +9807,8 @@ "key": "scenarioSection", "type": "scenario_sections", "typeCategory": "resource", - "param": "scenario_section_id", + "param": "scenario_section", "required": true, - "filter": "scenario_section_id", "description": "The scenario section this service belongs to", "relationship": "scenario_section", "notIncludable": true @@ -8238,9 +9817,8 @@ "key": "deal", "type": "deals", "typeCategory": "resource", - "param": "deal_id", + "param": "deal", "required": true, - "filter": "deal_id", "description": "The deal this scenario service is associated with", "relationship": "deal", "notIncludable": true @@ -8249,9 +9827,8 @@ "key": "serviceType", "type": "service_types", "typeCategory": "resource", - "param": "service_type_id", + "param": "service_type", "required": true, - "filter": "service_type_id", "relationship": "service_type" }, "revenue": { @@ -8259,6 +9836,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "revenue", "readonly": true, "attribute": "revenue" }, @@ -8267,6 +9845,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "cost", "readonly": true, "attribute": "cost" }, @@ -8275,6 +9854,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "profit", "readonly": true, "attribute": "profit" } @@ -8283,11 +9863,11 @@ }, "scenarios": { "type": "scenarios", - "domain": "Other", + "domain": "Financial", "itemName": "scenario", "collectionName": "scenarios", "description": "Scenario is a financial what-if plan tied to a deal. Scenarios model different service configurations so users can compare financials before committing changes to a deal's actual services. Typical workflow: create → inspect → compare financials → apply.", - "descriptionShort": "Financial what-if plan tied to a deal — models different service configurations so users can compare financials before committing changes.", + "descriptionShort": "what-if plans of deals which model service configurations to compare financials before committing", "customActions": { "refresh": { "name": "refresh", @@ -8329,7 +9909,6 @@ "typeCategory": "primitive", "param": "name", "required": true, - "filter": "name", "attribute": "name" }, "description": { @@ -8362,7 +9941,7 @@ "key": "deal", "type": "deals", "typeCategory": "resource", - "param": "deal_id", + "param": "deal", "required": true, "filter": "deal_id", "description": "The deal this scenario belongs to", @@ -8389,6 +9968,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "budget", "readonly": true, "description": "Total budget amount for this scenario in cents", "attribute": "budget" @@ -8398,6 +9978,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "revenue", "readonly": true, "description": "Total revenue for this scenario in cents", "attribute": "revenue" @@ -8407,6 +9988,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "cost", "readonly": true, "description": "Total cost for this scenario in cents", "attribute": "cost" @@ -8416,6 +9998,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "profit", "readonly": true, "description": "Profit for this scenario in cents (revenue minus cost)", "attribute": "profit" @@ -8425,6 +10008,7 @@ "type": "number", "typeCategory": "primitive", "unit": "percentage", + "param": "margin", "readonly": true, "description": "Profit margin for this scenario as a percentage (0-100 scale)", "attribute": "margin" @@ -8433,6 +10017,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "description": "When the scenario was created", "attribute": "created_at" @@ -8441,6 +10026,7 @@ "key": "updatedAt", "type": "date", "typeCategory": "primitive", + "param": "updated_at", "readonly": true, "description": "When the scenario was last updated", "attribute": "updated_at" @@ -8467,7 +10053,7 @@ "itemName": "search result", "collectionName": "search results", "description": "Search Quick Result represents an item returned from the global quick search. Results span multiple resource types: people, projects, deals, companies, tasks, docs, and budgets. Each result includes the matched item name, resource type, status, and type-specific metadata (e.g., company name for projects, workflow status for tasks). Used by the global search tool to find records across all resource types.", - "descriptionShort": "Item returned from global quick search across searchable resource types.", + "descriptionShort": "global quick search results across resource types", "customActions": {}, "fields": { "id": { @@ -8482,30 +10068,35 @@ "key": "recordId", "type": "string", "typeCategory": "primitive", + "param": "record_id", "attribute": "record_id" }, "recordType": { "key": "recordType", "type": "string", "typeCategory": "primitive", + "param": "record_type", "attribute": "record_type" }, "title": { "key": "title", "type": "string", "typeCategory": "primitive", + "param": "title", "attribute": "title" }, "subtitle": { "key": "subtitle", "type": "string", "typeCategory": "primitive", + "param": "subtitle", "attribute": "subtitle" }, "icon": { "key": "icon", "type": "string", "typeCategory": "primitive", + "param": "icon", "description": "Icon of the search result record", "attribute": "icon" }, @@ -8513,12 +10104,14 @@ "key": "query", "type": "string", "typeCategory": "primitive", + "param": "query", "filter": "query" }, "type": { "key": "type", "type": "search_quick_result_type", "typeCategory": "enum", + "param": "search_result_type", "filter": "type", "filterConfig": { "required": true @@ -8528,6 +10121,7 @@ "key": "status", "type": "search_quick_result_status", "typeCategory": "enum", + "param": "status", "filter": "status", "filterConfig": { "array": false @@ -8537,6 +10131,7 @@ "key": "meta", "type": "hash", "typeCategory": "primitive", + "param": "meta", "attribute": "meta" } }, @@ -8549,7 +10144,7 @@ "itemName": "section", "collectionName": "sections", "description": "Section is an ordered grouping of Services within a Deal or Budget.\nSections organize services into logical categories (e.g. by phase, department, deliverable type, or \"Expenses\").\nEach service belongs to exactly one section; every deal/budget has at least one section.\n\nSections are visible in the budget editor, time tracking (Client → Project → Budget → Section → Service hierarchy),\ninvoicing (line items can be grouped by section), and reports.\nSections can be duplicated along with all their services to speed up budget setup.", - "descriptionShort": "Ordered grouping of services within a deal/budget (e.g. by phase or deliverable type).", + "descriptionShort": "service groupings within a deal/budget (e.g. by phase or deliverable type)", "customActions": {}, "fields": { "id": { @@ -8580,7 +10175,7 @@ "key": "deal", "type": "deals", "typeCategory": "resource", - "param": "deal_id", + "param": "deal", "required": true, "filter": "deal_id", "relationship": "deal" @@ -8595,7 +10190,7 @@ "itemName": "service assignment", "collectionName": "service assignments", "description": "Service Assignment is a junction record linking a person to a specific service within a deal/budget.\nUsed when the budget's tracking type is set to \"Restricted by person\" — only assigned people can track time and log expenses against that service.\n\nIf no one is assigned to a service, the restriction does not apply and everyone on the budget can track against it.\nIf the budget tracking type is not \"Restricted by person\", service assignments have no effect on tracking permissions.\nEach assignment connects exactly one person to one service. A person can be assigned to multiple services, and a service can have multiple people assigned.", - "descriptionShort": "Links a person to a service — restricts who can track time/expenses when budget uses per-person restrictions.", + "descriptionShort": "person-service links for time/expense tracking restrictions", "customActions": {}, "fields": { "id": { @@ -8610,7 +10205,7 @@ "key": "person", "type": "people", "typeCategory": "resource", - "param": "person_id", + "param": "person", "required": true, "filter": "person_id", "relationship": "person" @@ -8619,7 +10214,7 @@ "key": "service", "type": "services", "typeCategory": "resource", - "param": "service_id", + "param": "service", "required": true, "filter": "service_id", "relationship": "service" @@ -8637,7 +10232,7 @@ "itemName": "service type assignment", "collectionName": "service type assignments", "description": "Service Type Assignment is a junction record linking a person to a service type, indicating which categories of work they perform (e.g. Design, Development).\nOnly one assignment per service type per person.\n\nUsed in two contexts:\n- Tracking restriction: when a budget's tracking type is \"Restricted by service type\", only people assigned to the service's service type can track time and log expenses.\n- Resource planning: filters people by their qualified service types when scheduling work in the Resource Planner.\n\nManaged on the person's profile or in the service types settings.", - "descriptionShort": "Links a person to a service type — used for tracking restrictions and resource planning.", + "descriptionShort": "person - service type links for tracking and resource planning restrictions", "customActions": {}, "fields": { "id": { @@ -8652,7 +10247,7 @@ "key": "person", "type": "people", "typeCategory": "resource", - "param": "person_id", + "param": "person", "required": true, "filter": "person_id", "relationship": "person" @@ -8661,7 +10256,7 @@ "key": "serviceType", "type": "service_types", "typeCategory": "resource", - "param": "service_type_id", + "param": "service_type", "required": true, "filter": "service_type_id", "relationship": "service_type" @@ -8679,7 +10274,7 @@ "itemName": "service type", "collectionName": "service types", "description": "Service Type categorizes the kinds of work an organization delivers (e.g. Design, Development, Project Management, Consulting).\nEvery service in a budget must have a service type assigned — it is mandatory.\n\nService types serve multiple purposes:\n- Budget organization: categorize services for consistent structure across deals/budgets.\n- Pricing: rate cards define prices per service type, standardizing billing rates.\n- Tracking restrictions: when a budget uses \"Restricted by service type\", only people assigned to the service's type can track time.\n- Profitability analysis: reports can analyze revenue, cost, and margin per service type across all budgets.\n- Accounting sync: service types can be mapped to item/account codes in connected accounting tools (Xero, QuickBooks, etc.).\n\nService types can be merged (reassigning all services, assignments, and prices to the winner) or archived.\nInitial service types are auto-generated based on the organization's industry during signup.\nConfigured by admins.", - "descriptionShort": "Category of work an organization delivers.", + "descriptionShort": "work categories an organization delivers", "customActions": { "archive": { "name": "archive", @@ -8729,6 +10324,7 @@ "key": "query", "type": "string", "typeCategory": "primitive", + "param": "query", "filter": "query", "description": "Keyword or phrase for partial name matching / filtering of service types" }, @@ -8736,6 +10332,7 @@ "key": "archivedAt", "type": "date", "typeCategory": "primitive", + "param": "archived_at", "readonly": true, "attribute": "archived_at" }, @@ -8743,6 +10340,7 @@ "key": "status", "type": "archivable_status", "typeCategory": "enum", + "param": "status", "filter": "status", "description": "Filter by active or archived" } @@ -8770,7 +10368,7 @@ "itemName": "service", "collectionName": "services", "description": "Service is a line item on a Deal or Budget representing a type of work to be delivered (e.g. Design, Development, Consulting).\nServices are the foundation of financial tracking — they connect time tracking, resource scheduling, invoicing, and profitability analysis.\n\nEach service is configured with:\n- A billing type: Fixed (agreed price regardless of hours), Time & Materials (billed per actual hours/expenses), or Non-billable (internal tracking only, no revenue).\n- A tracking unit: Hours, Days (person-days), or Pieces (discrete items/expenses). The unit determines what generates or assumes revenue.\n- Tracking toggles: time tracking, expense tracking, and booking (resource scheduling) can each be enabled or disabled independently.\n\nRevenue recognition depends on billing type and unit:\n- T&M by hour/day: approved time entries and future bookings generate revenue.\n- T&M by piece: only approved expenses generate revenue.\n- Fixed by hour/day: service holds all revenue upfront; time entries and bookings assume (transfer) revenue from the service.\n- Fixed by piece: only expenses assume revenue from the service.\n- Non-billable: never generates revenue, only costs.\n\nServices belong to a Section within their deal/budget and are categorized by a Service Type (e.g. Design, Development) for cross-project reporting.\nInvoicing is done from budget services — deal services cannot be invoiced directly until the deal is won and work is transferred to a budget.\nServices can be moved between deals/budgets while preserving all linked time entries, expenses, and bookings.", - "descriptionShort": "Deliverable line item on a deal/budget — defines billing type, tracking unit, and connects time tracking, scheduling, invoicing, and profitability.", + "descriptionShort": "line items on a deal/budget with billing type, tracking unit, linking time tracking, scheduling, and invoicing", "customActions": { "move": { "name": "move", @@ -8810,7 +10408,7 @@ "key": "billable", "type": "boolean", "typeCategory": "primitive", - "param": "billable", + "param": "is_billable", "required": true, "description": "Is the service billable to the client?", "attribute": "billable" @@ -8870,7 +10468,7 @@ "key": "serviceType", "type": "service_types", "typeCategory": "resource", - "param": "service_type_id", + "param": "service_type", "required": true, "filter": "service_type_id", "relationship": "service_type" @@ -8879,7 +10477,7 @@ "key": "deal", "type": "deals", "typeCategory": "resource", - "param": "deal_id", + "param": "deal", "required": true, "filter": "deal_id", "sort": "budget", @@ -8889,7 +10487,7 @@ "key": "section", "type": "sections", "typeCategory": "resource", - "param": "section_id", + "param": "section", "required": true, "filter": "section_id", "relationship": "section" @@ -8931,6 +10529,7 @@ "type": "number", "typeCategory": "primitive", "unit": "minutes", + "param": "worked_time", "readonly": true, "description": "Time people actually worked on the service (affects costs)", "attribute": "worked_time" @@ -8940,6 +10539,7 @@ "type": "number", "typeCategory": "primitive", "unit": "minutes", + "param": "billable_time", "readonly": true, "description": "Billable time that will be communicated to the client Company (affects revenue)", "attribute": "billable_time" @@ -8958,6 +10558,7 @@ "type": "number", "typeCategory": "primitive", "unit": "minutes", + "param": "budgeted_time", "readonly": true, "description": "Defines total time budget on the service which is agreed upon with the client Company", "attribute": "budgeted_time" @@ -8976,6 +10577,7 @@ "type": "number", "typeCategory": "primitive", "unit": "minutes", + "param": "booked_time", "readonly": true, "description": "Defines how much time is booked (planned) for people to work on this service", "attribute": "booked_time" @@ -8985,6 +10587,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "profit", "readonly": true, "description": "Profit made on the service", "attribute": "profit" @@ -8994,6 +10597,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "cost", "readonly": true, "description": "Organizational cost of the service (affects profit)", "attribute": "cost" @@ -9003,6 +10607,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "revenue", "readonly": true, "description": "Revenue made on the service (affects profit)", "attribute": "revenue" @@ -9013,7 +10618,7 @@ "typeCategory": "primitive", "unit": "money", "param": "price", - "description": "Price of the service (affects revenue)", + "description": "Per-unit rate in cents (e.g. hourly rate for hour-based services). budget_total is computed as price x quantity.", "attribute": "price" }, "budgetTotal": { @@ -9021,6 +10626,7 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "budget_total", "readonly": true, "description": "Total budget of the service", "attribute": "budget_total" @@ -9030,14 +10636,33 @@ "type": "number", "typeCategory": "primitive", "unit": "money", + "param": "budget_used", "readonly": true, "description": "Budget used on the service (used for progress tracking)", "attribute": "budget_used" }, + "personId": { + "key": "personId", + "type": "number", + "typeCategory": "primitive", + "param": "person", + "filter": "person_id", + "description": "Filter services by person — returns only services the person can track time against (respects the deal tracking type setting)" + }, + "bookableDate": { + "key": "bookableDate", + "type": "date", + "typeCategory": "primitive", + "format": "YYYY-MM-DD", + "param": "bookable_date", + "filter": "bookable_date", + "description": "Filter services where the given date falls within the budget bookable period (deal start/end dates). YYYY-MM-DD format." + }, "query": { "key": "query", "type": "string", "typeCategory": "primitive", + "param": "query", "filter": "query", "description": "Keyword or phrase for fuzzy text matching / filtering of services" } @@ -9056,7 +10681,7 @@ "itemName": "slack channel", "collectionName": "slack channels", "description": "Slack Channel represents a Slack channel connected to the organization via Slack integration. Read-only — channels are synced from Slack. Channels can be public or private, and active or archived. Used to configure Slack notifications for projects and tasks.", - "descriptionShort": "Slack channel connected to the organization via integration.", + "descriptionShort": "slack channels connected to the organization via integration", "customActions": {}, "fields": { "id": { @@ -9071,27 +10696,116 @@ "key": "name", "type": "string", "typeCategory": "primitive", - "readonly": true, - "attribute": "name" + "param": "query", + "readonly": true, + "filter": "query", + "attribute": "name" + }, + "private": { + "key": "private", + "type": "boolean", + "typeCategory": "primitive", + "param": "is_private", + "readonly": true, + "attribute": "private" + }, + "isArchived": { + "key": "isArchived", + "type": "boolean", + "typeCategory": "primitive", + "param": "is_archived", + "readonly": true, + "attribute": "is_archived" + } + }, + "collections": {}, + "endpoint": "slack_channels", + "searchFilterParam": "query", + "actions": { + "index": true, + "show": false, + "create": false, + "update": false, + "delete": false + } + }, + "slack_messages": { + "type": "slack_messages", + "domain": "Communication", + "itemName": "slack message", + "collectionName": "slack messages", + "description": "Slack Message represents a message in a Slack channel. Can be read from channel history or thread replies, and sent via the connected Slack bot integration.", + "descriptionShort": "readable and sendable slack channel messages", + "customActions": {}, + "fields": { + "id": { + "key": "id", + "type": "string", + "typeCategory": "primitive", + "param": "id", + "readonly": true, + "id": true + }, + "channelId": { + "key": "channelId", + "type": "string", + "typeCategory": "primitive", + "param": "channel_id", + "filter": "channel_id", + "attribute": "channel_id" + }, + "text": { + "key": "text", + "type": "string", + "typeCategory": "primitive", + "param": "text", + "attribute": "text" + }, + "user": { + "key": "user", + "type": "string", + "typeCategory": "primitive", + "param": "user", + "readonly": true, + "attribute": "user" + }, + "threadId": { + "key": "threadId", + "type": "string", + "typeCategory": "primitive", + "param": "thread_ts", + "filter": "thread_ts", + "description": "Slack thread parent message ID (Slack ts format) — groups replies under one conversation. Present on threaded messages; null for top-level messages.", + "attribute": "thread_ts" }, - "private": { - "key": "private", - "type": "boolean", + "replyCount": { + "key": "replyCount", + "type": "number", "typeCategory": "primitive", + "param": "reply_count", "readonly": true, - "attribute": "private" + "attribute": "reply_count" }, - "isArchived": { - "key": "isArchived", - "type": "boolean", + "blocks": { + "key": "blocks", + "type": "hash", + "typeCategory": "primitive", + "param": "blocks", + "description": "Slack Block Kit layout blocks — structured rich-text elements (sections, images, actions, etc.) that compose the message body.", + "attribute": "blocks", + "array": true + }, + "createdAt": { + "key": "createdAt", + "type": "string", "typeCategory": "primitive", + "param": "created_at", "readonly": true, - "attribute": "is_archived" + "attribute": "created_at" } }, "collections": {}, - "endpoint": "slack_channels", - "searchFilterParam": "query", + "endpoint": "slack_messages", "actions": { "index": true, "show": false, @@ -9100,13 +10814,13 @@ "delete": false } }, - "slack_messages": { - "type": "slack_messages", - "domain": "Communication", - "itemName": "slack message", - "collectionName": "slack messages", - "description": "Slack Message represents a message sent to a Slack channel via the organization's connected Slack bot integration. Messages can be sent to any channel the bot has access to.", - "descriptionShort": "Message sent to a Slack channel via the organization's Slack bot.", + "slack_users": { + "type": "slack_users", + "domain": "Other", + "itemName": "slack user", + "collectionName": "slack users", + "description": "Slack User represents an active workspace member in the connected Slack organization. Read-only — users are fetched from Slack. Bot accounts and deactivated users are automatically excluded.", + "descriptionShort": "active workspace members in the connected Slack organization", "customActions": {}, "fields": { "id": { @@ -9115,37 +10829,97 @@ "typeCategory": "primitive", "param": "id", "readonly": true, + "description": "Slack user ID (e.g. U061GRG2222).", "id": true }, - "channelName": { - "key": "channelName", + "name": { + "key": "name", + "type": "string", + "typeCategory": "primitive", + "param": "name", + "readonly": true, + "filter": "query", + "description": "Slack username (handle) without the @ prefix. Filters across name, display name, real name, and email.", + "attribute": "name" + }, + "displayName": { + "key": "displayName", "type": "string", "typeCategory": "primitive", + "param": "display_name", "readonly": true, - "filter": "channel_name", - "attribute": "channel_name" + "description": "Display name chosen by the user in their Slack profile. May differ from their real name or username.", + "attribute": "display_name" }, - "text": { - "key": "text", + "realName": { + "key": "realName", "type": "string", "typeCategory": "primitive", + "param": "real_name", "readonly": true, - "attribute": "text" + "description": "Full real name from the user's Slack profile.", + "attribute": "real_name" }, - "slackChannel": { - "key": "slackChannel", - "type": "slack_channel", - "typeCategory": "resource", + "email": { + "key": "email", + "type": "string", + "typeCategory": "primitive", + "param": "email", + "readonly": true, + "description": "Email address from the user's Slack profile.", + "attribute": "email" + }, + "title": { + "key": "title", + "type": "string", + "typeCategory": "primitive", + "param": "title", + "readonly": true, + "description": "Job title or role set in the user's Slack profile.", + "attribute": "title" + }, + "avatarUrl": { + "key": "avatarUrl", + "type": "string", + "typeCategory": "primitive", + "param": "avatar_url", + "readonly": true, + "description": "URL of the user's Slack profile avatar (72x72px).", + "attribute": "avatar_url" + }, + "timezone": { + "key": "timezone", + "type": "string", + "typeCategory": "primitive", + "param": "timezone", + "readonly": true, + "description": "IANA timezone identifier from the user's Slack settings (e.g. Europe/Zagreb).", + "attribute": "timezone" + }, + "statusText": { + "key": "statusText", + "type": "string", + "typeCategory": "primitive", + "param": "status_text", + "readonly": true, + "description": "Custom status text set by the user (e.g. \"In a meeting\").", + "attribute": "status_text" + }, + "statusEmoji": { + "key": "statusEmoji", + "type": "string", + "typeCategory": "primitive", + "param": "status_emoji", "readonly": true, - "filter": "slack_channel_id", - "relationship": "slack_channel" + "description": "Custom status emoji set by the user (e.g. :calendar:).", + "attribute": "status_emoji" } }, "collections": {}, - "endpoint": "slack_messages", + "endpoint": "slack_users", "actions": { "index": true, - "show": false, + "show": true, "create": false, "update": false, "delete": false @@ -9157,7 +10931,7 @@ "itemName": "subsidiary", "collectionName": "subsidiaries", "description": "Subsidiary represents a legal entity within an Organization (e.g. regional offices, divisions, brands).\nEvery organization has at least one subsidiary. Multiple subsidiaries are available on the Ultimate plan.\n\nSubsidiaries hold the \"Bill From\" identity used on financial documents:\n- Company name, tax ID, and address — appear on invoices, proposals, budgets, and purchase orders.\n- Default bank account — populates the \"Pay To\" section on invoices and is used for e-invoicing.\n- Default tax rate — pre-fills tax on invoices, deals, budgets, and expenses unless a client-specific rate is set.\n- Logo — appears on exported PDFs.\n\nDeals, budgets, invoices, purchase orders, expenses, and people (via cost rates) are each assigned to a subsidiary.\nThis enables per-entity financial reporting, multi-currency support, and correct tax handling across jurisdictions.", - "descriptionShort": "Legal entity within an organization — holds billing identity, tax rates, and bank details for financial documents.", + "descriptionShort": "legal entities within an organization with billing identity, tax rates, and bank details", "customActions": {}, "fields": { "id": { @@ -9186,7 +10960,7 @@ "itemName": "survey field option", "collectionName": "survey field options", "description": "Survey Field Option is a selectable choice for a dropdown (select) or multi-select survey field. Each option belongs to a specific survey field and has a display name, position for ordering, and optional color for visual distinction in the form.", - "descriptionShort": "Selectable choice for a dropdown or multi-select form field.", + "descriptionShort": "selectable choices for a dropdown or multi-select survey field", "customActions": {}, "fields": { "id": { @@ -9223,7 +10997,7 @@ "key": "surveyField", "type": "survey_fields", "typeCategory": "resource", - "param": "survey_field_id", + "param": "survey_field", "filter": "survey_field_id", "relationship": "survey_field", "notIncludable": true @@ -9237,7 +11011,7 @@ "itemName": "survey field", "collectionName": "survey fields", "description": "Survey Field defines a question or input within a form (survey).\nEach field has a data type (text, number, date, select, multiselect, checkbox, file, etc.), can be marked as required or optional, and belongs to a specific survey.\n\nFields can optionally be linked to an origin custom field (origin_field) to reuse an existing field definition.\nWhen linked, form submissions can prefill the corresponding custom field on tasks created via automation.\n\nSelect and multiselect fields have associated survey field options that define the available choices.\nThe global flag indicates whether the field is shared across forms or specific to one.\nThe customizable_type specifies which resource type the field maps to (e.g., tasks, deals, projects).", - "descriptionShort": "Question or input field within a form — supports text, number, date, dropdown, file, and other data types.", + "descriptionShort": "form field — text, number, date, dropdown, checkbox, file", "customActions": {}, "fields": { "id": { @@ -9269,7 +11043,7 @@ "key": "required", "type": "boolean", "typeCategory": "primitive", - "param": "required", + "param": "is_required", "attribute": "required" }, "description": { @@ -9283,7 +11057,7 @@ "key": "global", "type": "boolean", "typeCategory": "primitive", - "param": "global", + "param": "is_global", "attribute": "global" }, "customizableType": { @@ -9297,7 +11071,7 @@ "key": "survey", "type": "surveys", "typeCategory": "resource", - "param": "survey_id", + "param": "survey", "filter": "survey_id", "sort": "survey_id", "relationship": "survey", @@ -9307,7 +11081,7 @@ "key": "originField", "type": "custom_fields", "typeCategory": "resource", - "param": "origin_field_id", + "param": "origin_field", "relationship": "origin_field", "notIncludable": true }, @@ -9315,6 +11089,7 @@ "key": "options", "type": "survey_field_options", "typeCategory": "resource", + "param": "options", "readonly": true, "relationship": "options", "array": true @@ -9323,6 +11098,7 @@ "key": "customFieldPeople", "type": "people", "typeCategory": "resource", + "param": "custom_field_people", "readonly": true, "relationship": "custom_field_people", "notIncludable": true, @@ -9337,7 +11113,7 @@ "itemName": "survey", "collectionName": "surveys", "description": "Survey (Form) is a customizable form for collecting structured data within a project.\nForms are used for intake requests, client feedback, internal approvals, support tickets, and standardized data gathering.\n\nEach form belongs to a project and contains configurable fields (text, number, date, dropdown, multi-select, checkbox, file upload, etc.).\nFields can be linked to existing custom fields to reuse definitions and prefill task custom fields on submission.\n\nForms can be shared with different access levels: project members only, everyone in the organization, or anyone with a public link.\n\nForm submissions can trigger automations — creating tasks, sending Slack messages, or emails based on responses and conditions.\nResponses are exportable to PDF, CSV, or XLS.\nForms can be duplicated within the same project or across projects.", - "descriptionShort": "Customizable form within a project for collecting structured data — supports automations on submission.", + "descriptionShort": "project forms for structured data collection — supports automations on submission", "customActions": {}, "fields": { "id": { @@ -9369,7 +11145,7 @@ "key": "project", "type": "projects", "typeCategory": "resource", - "param": "project_id", + "param": "project", "filter": "project_id", "relationship": "project", "notIncludable": true @@ -9378,6 +11154,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "attribute": "created_at" }, @@ -9385,6 +11162,7 @@ "key": "creator", "type": "people", "typeCategory": "resource", + "param": "creator", "readonly": true, "relationship": "creator" }, @@ -9392,6 +11170,7 @@ "key": "surveyFields", "type": "survey_fields", "typeCategory": "resource", + "param": "survey_fields", "readonly": true, "relationship": "survey_fields", "notIncludable": true, @@ -9406,7 +11185,7 @@ "itemName": "task dependency", "collectionName": "task dependencies", "description": "Task Dependency defines a directional relationship between two tasks.\nThree dependency types:\n- Blocking (type_id=1): the source task prevents the dependent task from starting. Visible in Gantt as an arrow.\n- Waiting on (type_id=2): the source task cannot start until the dependent task completes. Visible in Gantt as an arrow.\n- Linked (type_id=3): tasks are related but not blocking each other. Not shown in Gantt.\n\nWhen a blocking/waiting task is closed, the dependency status updates on the dependent task.\nDependencies are lost when tasks are moved to another project.\nSubtasks can also have dependencies. There is no limit on the number of dependencies per task.", - "descriptionShort": "Directional relationship between tasks — blocking, waiting on, or linked.", + "descriptionShort": "task dependency relationships — blocking, waiting on, or linked", "customActions": {}, "fields": { "id": { @@ -9421,7 +11200,7 @@ "key": "typeId", "type": "dependency_type", "typeCategory": "enum", - "param": "type_id", + "param": "dependency_type", "required": true, "filter": "type_id", "description": "Type of dependency: 1=blocking, 2=waiting_on, 3=linked", @@ -9431,7 +11210,7 @@ "key": "task", "type": "tasks", "typeCategory": "resource", - "param": "task_id", + "param": "task", "required": true, "filter": "task_id", "description": "Source task of the dependency", @@ -9441,7 +11220,7 @@ "key": "dependentTask", "type": "tasks", "typeCategory": "resource", - "param": "dependent_task_id", + "param": "dependent_task", "required": true, "filter": "dependent_task_id", "description": "Target task that depends on the source task", @@ -9451,6 +11230,7 @@ "key": "projectId", "type": "projects", "typeCategory": "resource", + "param": "project", "readonly": true, "filter": "project_id", "description": "Filter dependencies by project" @@ -9464,7 +11244,7 @@ "itemName": "task list", "collectionName": "task lists", "description": "Task List is an ordered collection of tasks within a Folder in a Project.\nTask Lists structure work into groups without imposing a predefined meaning — users define what lists represent in their context (e.g. sprints, phases, categories, priorities).\nEach task belongs to exactly one task list; each task list belongs to exactly one folder.\n\nTask lists can be archived when no longer active. Archiving a task list does not change the status of tasks inside it.\nWhen moving tasks between projects with different workflows, task statuses need to be mapped to the target project's workflow.\nTask lists can be duplicated (with their tasks) within the same project or to another project.", - "descriptionShort": "Ordered collection of tasks within a folder — user-defined grouping (e.g. sprints, phases).", + "descriptionShort": "task groupings within a folder (e.g. sprints, phases)", "customActions": { "archive": { "name": "archive", @@ -9500,6 +11280,7 @@ "key": "status", "type": "archivable_status", "typeCategory": "enum", + "param": "status", "filter": "status", "description": "Filter by active or archived" }, @@ -9507,7 +11288,7 @@ "key": "project", "type": "projects", "typeCategory": "resource", - "param": "project_id", + "param": "project", "required": true, "filter": "project_id", "sort": "project_name", @@ -9532,6 +11313,7 @@ "key": "archivedAt", "type": "date", "typeCategory": "primitive", + "param": "archived_at", "readonly": true, "attribute": "archived_at" }, @@ -9539,7 +11321,7 @@ "key": "folder", "type": "folders", "typeCategory": "resource", - "param": "folder_id", + "param": "folder", "required": true, "filter": "folder_id", "relationship": "folder" @@ -9569,7 +11351,7 @@ "itemName": "task", "collectionName": "tasks", "description": "Task represents a unit of work that can be assigned to a person. Tasks live in Task Lists within Folders in a Project.\n\nTask hierarchy:\n- Tasks: standalone work items with an assignee, workflow status, dates, estimates, and tags.\n- Subtasks: nested under a parent task (via parent_task_id). Cannot be moved independently — moving a parent moves its subtasks. Can be converted to standalone tasks and vice versa.\n- Milestones: key deliverables or checkpoints (type_id distinguishes tasks from milestones).\n\nTasks progress through workflow statuses (e.g. To Do, In Progress, Done) defined by the project's Workflow. Statuses belong to three categories: not started, started, and closed.\nClosing a parent task does not close its subtasks, and closing all subtasks does not close the parent.\n\nTasks can include: todo checklists, time estimates (initial_estimate, remaining_time), start/due dates, attachments, subscribers, and an activity feed with comments.\nTime entries can be linked to tasks for granular tracking of what work was done against which budget service.\nBookings can be created directly from tasks when scheduling is enabled, linking resource planning to task-level work.\nTasks can be private (visible only to subscribers) or public (visible to all project members).\nDependencies between tasks define blocking, waiting, and linked relationships.", - "descriptionShort": "Unit of work in a project — assignable, trackable, with workflow statuses, subtasks, and dependencies.", + "descriptionShort": "assignable work items in a project with statuses, todos, subtasks and dependencies", "customActions": {}, "fields": { "id": { @@ -9604,6 +11386,7 @@ "key": "taskNumber", "type": "string", "typeCategory": "primitive", + "param": "task_number", "readonly": true, "filter": "task_number", "sort": "task_number", @@ -9623,6 +11406,7 @@ "key": "taskType", "type": "task_parent_type", "typeCategory": "enum", + "param": "task_type", "filter": "task_type", "description": "Indicates if the task is a parent task or a subtask" }, @@ -9652,7 +11436,7 @@ "key": "private", "type": "boolean", "typeCategory": "primitive", - "param": "private", + "param": "is_private", "required": true, "filter": "public_access", "description": "Private tasks are only visible to task subscribers. Default is false.", @@ -9662,6 +11446,7 @@ "key": "closed", "type": "boolean", "typeCategory": "primitive", + "param": "is_closed", "readonly": true, "description": "Is the task closed?", "attribute": "closed" @@ -9670,6 +11455,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "filter": "created_at", "sort": "created_at", @@ -9680,6 +11466,7 @@ "key": "closedAt", "type": "date", "typeCategory": "primitive", + "param": "closed_at", "readonly": true, "filter": "closed_at", "sort": "closed_at", @@ -9731,6 +11518,7 @@ "type": "number", "typeCategory": "primitive", "unit": "minutes", + "param": "worked_time", "readonly": true, "filter": "worked_time", "sort": "worked_time", @@ -9749,7 +11537,7 @@ "key": "assignee", "type": "people", "typeCategory": "resource", - "param": "assignee_id", + "param": "assignee", "filter": "assignee_id", "sort": "assignee_name", "description": "Person assigned to the task - a responsible person to deliver the task ", @@ -9759,6 +11547,7 @@ "key": "creator", "type": "people", "typeCategory": "resource", + "param": "creator", "readonly": true, "filter": "creator_id", "description": "Person who created the task", @@ -9768,7 +11557,7 @@ "key": "taskList", "type": "task_lists", "typeCategory": "resource", - "param": "task_list_id", + "param": "task_list", "required": true, "filter": "task_list_id", "sort": "task_list_name", @@ -9778,7 +11567,7 @@ "key": "project", "type": "projects", "typeCategory": "resource", - "param": "project_id", + "param": "project", "required": true, "filter": "project_id", "sort": "project_name", @@ -9788,7 +11577,7 @@ "key": "parentTask", "type": "tasks", "typeCategory": "resource", - "param": "parent_task_id", + "param": "parent_task", "filter": "parent_task_id", "description": "Parent task (if the task is a subtask)", "relationship": "parent_task" @@ -9797,7 +11586,7 @@ "key": "workflowStatus", "type": "workflow_statuses", "typeCategory": "resource", - "param": "workflow_status_id", + "param": "workflow_status", "filter": "workflow_status_id", "sort": "workflow_status_name", "description": "Workflow status of the task", @@ -9807,6 +11596,7 @@ "key": "workflowStatusCategoryId", "type": "workflow_status_category", "typeCategory": "enum", + "param": "workflow_status_category", "filter": "workflow_status_category_id", "description": "Filter by workflow status category: not started, started, or closed" }, @@ -9814,6 +11604,7 @@ "key": "taskListStatus", "type": "archivable_status", "typeCategory": "enum", + "param": "task_list_status", "filter": "task_list_status", "description": "Filter tasks by their task list status (active or archived)" }, @@ -9821,6 +11612,7 @@ "key": "boardStatus", "type": "archivable_status", "typeCategory": "enum", + "param": "board_status", "filter": "board_status", "description": "Filter tasks by their board (folder) status (active or archived)" }, @@ -9828,7 +11620,7 @@ "key": "attachments", "type": "attachments", "typeCategory": "resource", - "param": "attachment_id", + "param": "attachments", "relationship": "attachments", "array": true }, @@ -9850,6 +11642,7 @@ "type": "date", "typeCategory": "primitive", "format": "YYYY-MM-DD", + "param": "last_activity_at", "readonly": true, "filter": "last_activity", "sort": "last_activity_at", @@ -9860,6 +11653,7 @@ "key": "subtaskCount", "type": "number", "typeCategory": "primitive", + "param": "subtask_count", "readonly": true, "description": "Number of subtasks", "attribute": "subtask_count" @@ -9868,6 +11662,7 @@ "key": "openSubtaskCount", "type": "number", "typeCategory": "primitive", + "param": "open_subtask_count", "readonly": true, "description": "Number of open (not completed) subtasks", "attribute": "open_subtask_count" @@ -9876,6 +11671,7 @@ "key": "todoCount", "type": "number", "typeCategory": "primitive", + "param": "todo_count", "readonly": true, "description": "Number of todos", "attribute": "todo_count" @@ -9884,6 +11680,7 @@ "key": "openTodoCount", "type": "number", "typeCategory": "primitive", + "param": "open_todo_count", "readonly": true, "description": "Number of open (not completed) todos", "attribute": "open_todo_count" @@ -9892,6 +11689,7 @@ "key": "blockingDependencyCount", "type": "number", "typeCategory": "primitive", + "param": "blocking_dependency_count", "readonly": true, "description": "Number of tasks that this task is blocking", "attribute": "blocking_dependency_count" @@ -9900,6 +11698,7 @@ "key": "waitingOnDependencyCount", "type": "number", "typeCategory": "primitive", + "param": "waiting_on_dependency_count", "readonly": true, "description": "Number of tasks that this task is waiting on", "attribute": "waiting_on_dependency_count" @@ -9919,7 +11718,7 @@ "inverse": "parentTask" } }, - "queryHints": "Users typically care about open tasks in active projects, unless they specify otherwise. The default filter scope for tasks should be:\n{ project.status: {eq: '1'}, task_list_status: {eq: '1'}, board_status: {eq: '1'}, workflow_status_category_id: {not_eq: '3'} }", + "queryHints": "Users typically care about open tasks in active projects, unless they specify otherwise. The default filter scope for tasks should be:\n{ project.status: {eq: '1'}, task_list_status: {eq: '1'}, board_status: {eq: '1'}, workflow_status_category: {not_eq: '3'} }", "searchQuickResultType": [ "task" ], @@ -9935,7 +11734,7 @@ "itemName": "tax rate", "collectionName": "tax rates", "description": "Tax Rate defines a tax or VAT percentage applied to invoices and other financial documents.\nEach tax rate belongs to exactly one subsidiary — only tax rates matching the issuing subsidiary are available on a document.\n\nTax rates can have up to two components (e.g. federal + state tax), each with a name and percentage value.\nAn \"empty\" tax rate (no components) can be created for tax-exempt line items to avoid displaying \"0% tax\".\n\nTax rates are applied per line item on invoices, with a default pre-filled from the subsidiary or client company.\nOnce a tax rate has been used on a finalized invoice, it cannot be edited — duplicate it and create a new one instead.\nTax rates can be archived when outdated; archived rates remain on existing documents but cannot be applied to new ones.", - "descriptionShort": "Tax/VAT percentage tied to a subsidiary — applied per line item on invoices and financial documents.", + "descriptionShort": "tax/vat percentages for subsidiaries — applied per line item on invoices", "customActions": {}, "fields": { "id": { @@ -9989,9 +11788,9 @@ "key": "subsidiary", "type": "subsidiaries", "typeCategory": "resource", - "param": "subsidiary_id", + "param": "subsidiary", "required": true, - "filter": "subsidiary.id", + "filter": "subsidiary_id", "sort": "subsidiary_name", "relationship": "subsidiary" } @@ -10004,7 +11803,7 @@ "itemName": "team membership", "collectionName": "team memberships", "description": "Team Membership is a junction record linking a person to a team.\nCreate a membership to add a person to a team, delete it to remove them. A person can belong to multiple teams.\nTeam memberships enable team-based filtering, reporting, resource planning, and access sharing across projects, bookings, and time entries.", - "descriptionShort": "Defines which teams a person belongs to.", + "descriptionShort": "person-team links", "customActions": {}, "fields": { "id": { @@ -10019,7 +11818,7 @@ "key": "person", "type": "people", "typeCategory": "resource", - "param": "person_id", + "param": "person", "required": true, "filter": "person_id", "sort": "person_name", @@ -10030,7 +11829,7 @@ "key": "team", "type": "teams", "typeCategory": "resource", - "param": "team_id", + "param": "team", "required": true, "filter": "team_id", "description": "Team the person belongs to", @@ -10045,7 +11844,7 @@ "itemName": "team", "collectionName": "teams", "description": "Team is a group of people who share skills, responsibilities, or work together on related projects (e.g., \"Design\", \"Engineering\", \"People Ops\").\nA person can belong to multiple teams via team memberships.\n\nTeams enable:\n- Filtering and grouping across projects, bookings, time entries, and reports by team.\n- Access sharing — team members can be granted shared access to projects and docs.\n- Resource planning — view and manage team capacity in the Resource Planner.\n- Reporting — team-based breakdowns of utilization, profitability, and workload.", - "descriptionShort": "Group of people with shared work or skills, used for reporting and access sharing.", + "descriptionShort": "groups of people, used for reporting and access sharing", "customActions": {}, "fields": { "id": { @@ -10075,7 +11874,7 @@ }, "iconId": { "key": "iconId", - "type": "number", + "type": "string", "typeCategory": "primitive", "param": "icon_id", "attribute": "icon_id" @@ -10084,6 +11883,7 @@ "key": "members", "type": "people", "typeCategory": "resource", + "param": "members", "description": "People in the team", "relationship": "members", "array": true @@ -10106,7 +11906,7 @@ "itemName": "time entry", "collectionName": "time entries", "description": "Time Entry records work done by a person against a service in a deal or budget.\nTime entries are the primary source of labor cost and revenue data in Productive.\n\nFinancial impact:\n- Cost: worked time (time field) × person's hourly cost rate from their salary record.\n- Revenue: billable time (billable_time) × service price. Only applies if the service is billable and the entry is approved.\n- Billable time defaults to worked time but can differ (e.g. internal overhead logged against a billable service).\n\nTracking methods: manual entry, timer (start/stop), or automatic (from bookings, created at midnight for scheduled work).\nEntries can optionally be linked to a Task for granular tracking of what work was done.\n\nLifecycle:\n- Submission: if timesheet submission is enabled, entries must be submitted before they enter the approval queue.\n- Approval: if time approval is enabled on the budget/deal, entries go through approved/rejected workflow. Only approved entries are recognized — they count toward budget usage, revenue, and can be invoiced.\n- Invoicing: once an entry is included on a finalized invoice, it becomes locked and cannot be edited or moved.\n- Financial lock: entries in a locked financial period cannot be modified.\n\nA person must have a cost rate (salary) defined to track time.", - "descriptionShort": "Logged work by a person against a service — drives cost, revenue, and profitability calculations.", + "descriptionShort": "logged work against services — drives cost, revenue, and profitability", "customActions": {}, "fields": { "id": { @@ -10171,6 +11971,7 @@ "key": "createdAt", "type": "date", "typeCategory": "primitive", + "param": "created_at", "readonly": true, "attribute": "created_at" }, @@ -10186,7 +11987,7 @@ "key": "approved", "type": "boolean", "typeCategory": "primitive", - "param": "approved", + "param": "is_approved", "description": "Is the time entry approved by the responsible person? System-managed through approval workflow.", "attribute": "approved" }, @@ -10203,7 +12004,7 @@ "key": "rejected", "type": "boolean", "typeCategory": "primitive", - "param": "rejected", + "param": "is_rejected", "description": "Is the time entry rejected by the responsible person? System-managed through approval workflow.", "attribute": "rejected" }, @@ -10227,10 +12028,19 @@ "key": "submitted", "type": "boolean", "typeCategory": "primitive", - "param": "submitted", + "param": "is_submitted", + "readonly": true, "description": "Whether the time entry was submitted as a Timesheet. System-managed through submission workflow.", "attribute": "submitted" }, + "startedAt": { + "key": "startedAt", + "type": "datetime", + "typeCategory": "primitive", + "param": "started_at", + "description": "When the work started, as an ISO 8601 datetime with timezone offset (e.g. \"2026-03-12T09:00:00+01:00\"). Sets the start position of the time entry on the timeline.", + "attribute": "started_at" + }, "timerStartedAt": { "key": "timerStartedAt", "type": "date", @@ -10252,14 +12062,15 @@ "type": "track_method", "typeCategory": "enum", "param": "track_method", - "description": "How the time was tracked (manual, timer, etc.). Auto-detected by the system.", + "readonly": true, + "description": "How the time was tracked. Auto-detected by the system.", "attribute": "track_method_id" }, "person": { "key": "person", "type": "people", "typeCategory": "resource", - "param": "person_id", + "param": "person", "required": true, "filter": "person_id", "sort": "person_name", @@ -10270,7 +12081,7 @@ "key": "creator", "type": "people", "typeCategory": "resource", - "param": "creator_id", + "param": "creator", "filter": "creator_id", "description": "Person who created the time entry. Defaults to the current user.", "relationship": "creator" @@ -10279,7 +12090,7 @@ "key": "approver", "type": "people", "typeCategory": "resource", - "param": "approver_id", + "param": "approver", "filter": "approver_id", "description": "Person who approved the time entry. Set by the system when approved.", "relationship": "approver" @@ -10288,8 +12099,7 @@ "key": "rejecter", "type": "people", "typeCategory": "resource", - "param": "rejecter_id", - "filter": "rejecter_id", + "param": "rejecter", "description": "Person who rejected the time entry. Set by the system when rejected.", "relationship": "rejecter" }, @@ -10297,7 +12107,7 @@ "key": "service", "type": "services", "typeCategory": "resource", - "param": "service_id", + "param": "service", "required": true, "filter": "service_id", "sort": "service_name", @@ -10307,9 +12117,18 @@ "key": "task", "type": "tasks", "typeCategory": "resource", - "param": "task_id", + "param": "task", "filter": "task_id", "relationship": "task" + }, + "calendarEventId": { + "key": "calendarEventId", + "type": "string", + "typeCategory": "primitive", + "param": "calendar_event", + "filter": "calendar_event_id", + "description": "ID of the calendar event this time entry was created from. Set to the string ID from the calendar event response.", + "attribute": "calendar_event_id" } }, "collections": {}, @@ -10326,7 +12145,7 @@ "itemName": "timer", "collectionName": "timers", "description": "Timer tracks an active time tracking session for a person.\nEach timer is linked to a time entry and records elapsed time in real time.\n\nWhen stopped, the tracked duration is saved to the associated time entry's worked time.\nA person can only have one active timer at a time — starting a new timer automatically stops the previous one.\nIf a budget has overrun limitations and the timer reaches the service limit mid-session, it is automatically shortened.\nTimers are available in the web app and desktop widget.", - "descriptionShort": "Active stopwatch session linked to a time entry — elapsed time is saved when stopped.", + "descriptionShort": "stopwatch session linked to a time entry — saved when stopped", "customActions": { "stop": { "name": "stop", @@ -10348,6 +12167,7 @@ "key": "personId", "type": "string", "typeCategory": "primitive", + "param": "person_id", "readonly": true, "filter": "person_id", "description": "ID of the person who owns this timer", @@ -10377,6 +12197,7 @@ "key": "totalTime", "type": "number", "typeCategory": "primitive", + "param": "total_time", "readonly": true, "description": "Total elapsed time in seconds", "attribute": "total_time" @@ -10385,7 +12206,7 @@ "key": "timeEntry", "type": "time_entries", "typeCategory": "resource", - "param": "time_entry_id", + "param": "time_entry", "required": true, "filter": "time_entry_id", "description": "Time entry this timer is tracking for", @@ -10400,7 +12221,7 @@ "itemName": "timesheet", "collectionName": "timesheets", "description": "Timesheet groups all time entries for a specific person on a specific date.\nActs as a daily aggregate container — one timesheet per person per day, containing all entries across different services and budgets.\n\nTimesheets are the unit of submission in the approval workflow:\n- Employees submit timesheets (by day or full week) to confirm their logged hours are ready for review.\n- Once submitted, no new entries can be added for that day unless the timesheet is un-submitted.\n- Managers can submit or un-submit timesheets on behalf of employees.\n- A weekly timesheet is marked \"Fully Submitted\" only when all days (including weekends) are submitted.\n\nAfter submission, individual time entries within the timesheet go through the approval flow (approved/rejected).\nRejected entries can be edited and are automatically resubmitted.", - "descriptionShort": "Daily aggregate of a person's time entries — the unit of submission in the approval workflow.", + "descriptionShort": "daily aggregates of time entries, unit of submission in approval workflow", "customActions": {}, "fields": { "id": { @@ -10427,7 +12248,7 @@ "key": "person", "type": "people", "typeCategory": "resource", - "param": "person_id", + "param": "person", "required": true, "filter": "person_id", "sort": "person_id", @@ -10450,7 +12271,7 @@ "itemName": "todo", "collectionName": "todos", "description": "Todo is a checklist item within a Task or Deal. Todos break down work into smaller, trackable action items.\nEach todo has a description, a position (order in the list), and can be assigned to a person and marked as closed (done).\n\nTodos belong to exactly one parent — either a task (task_id) or a deal (deal_id), never both.\nOn tasks, todos serve as a lightweight checklist for sub-steps that don't warrant full subtasks.\nOn deals, todos help define next steps and sales actions to move opportunities through the pipeline.", - "descriptionShort": "Checklist item within a task or deal — assignable and completable.", + "descriptionShort": "checklist items on tasks or deals — assignable and completable", "customActions": {}, "fields": { "id": { @@ -10482,7 +12303,7 @@ "key": "closed", "type": "boolean", "typeCategory": "primitive", - "param": "closed", + "param": "is_closed", "required": true, "description": "Defines if the todo item is done", "attribute": "closed" @@ -10491,9 +12312,9 @@ "key": "task", "type": "tasks", "typeCategory": "resource", - "param": "task_id", + "param": "task", "filter": "task_id", - "description": "Task that this todo belongs to. Exactly one of task_id or deal_id must be provided.", + "description": "Task that this todo belongs to. Exactly one of task or deal must be provided.", "relationship": "task", "exclusive": "parent" }, @@ -10501,9 +12322,9 @@ "key": "deal", "type": "deals", "typeCategory": "resource", - "param": "deal_id", + "param": "deal", "filter": "deal_id", - "description": "Deal that this todo belongs to. Exactly one of task_id or deal_id must be provided.", + "description": "Deal that this todo belongs to. Exactly one of task or deal must be provided.", "relationship": "deal", "exclusive": "parent" }, @@ -10511,7 +12332,7 @@ "key": "assignee", "type": "people", "typeCategory": "resource", - "param": "assignee_id", + "param": "assignee", "filter": "assignee_id", "description": "Person assigned to the todo item", "relationship": "assignee" @@ -10530,7 +12351,7 @@ "itemName": "user", "collectionName": "users", "description": "User represents a login account in Productive. Each user has an email for authentication and can be a member of multiple organizations. The user record is separate from the person record — a person is the organizational profile, while the user is the authentication identity. Users have feature flags that control access to experimental features.", - "descriptionShort": "Login account in Productive, separate from the person profile.", + "descriptionShort": "login accounts", "customActions": {}, "fields": { "id": { @@ -10553,6 +12374,7 @@ "key": "flags", "type": "hash", "typeCategory": "primitive", + "param": "flags", "attribute": "flags", "serialize": false } @@ -10566,7 +12388,7 @@ "itemName": "workflow status", "collectionName": "workflow statuses", "description": "Workflow Status is a named stage in a task's lifecycle within a workflow (e.g., \"To Do\", \"In Review\", \"Done\").\nEach status belongs to one of three fixed categories that determine task state:\n- Not Started (category_id=1): task is pending, work has not begun.\n- Started (category_id=2): task is in progress.\n- Closed (category_id=3): task is complete or resolved.\n\nMultiple custom statuses can exist within each category, allowing fine-grained progress tracking.\nThe position field controls the display order of statuses within the workflow.\nTasks can be filtered and grouped by workflow status. Drag-and-drop between statuses is supported within a project.", - "descriptionShort": "Named task status within a workflow — belongs to a Not Started, Started, or Closed category.", + "descriptionShort": "task statuses in a workflow in Not Started, Started, or Closed category", "customActions": {}, "fields": { "id": { @@ -10617,7 +12439,7 @@ "key": "workflow", "type": "workflows", "typeCategory": "resource", - "param": "workflow_id", + "param": "workflow", "required": true, "filter": "workflow_id", "relationship": "workflow" @@ -10643,7 +12465,7 @@ "itemName": "workflow", "collectionName": "workflows", "description": "Workflow defines the set of task statuses available in a project.\nEach project is assigned one workflow, and different projects can use different workflows (e.g., a development workflow vs. a design workflow).\n\nA workflow contains statuses organized into three fixed categories:\n- Not Started: tasks that are pending, work has not begun.\n- Started: tasks that are in progress.\n- Closed: tasks that are complete or resolved.\n\nMultiple custom statuses can be created within each category.\nWhen switching a project's workflow, existing task statuses must be mapped to the new workflow's statuses.\nMoving a status between categories (e.g., Started → Closed) immediately affects all tasks in that status across all projects using the workflow.\nWorkflows can be archived when no longer needed.", - "descriptionShort": "Set of task statuses assigned to a project — organizes tasks into Not Started, Started, and Closed categories.", + "descriptionShort": "task statuses groups, used in a project", "customActions": {}, "fields": { "id": { @@ -10668,6 +12490,7 @@ "key": "archivedAt", "type": "date", "typeCategory": "primitive", + "param": "archived_at", "readonly": true, "attribute": "archived_at" }, @@ -10675,6 +12498,7 @@ "key": "workflowStatuses", "type": "workflow_statuses", "typeCategory": "resource", + "param": "workflow_statuses", "relationship": "workflow_statuses", "array": true } @@ -10692,38 +12516,6 @@ } }, "enums": { - "agent_status": { - "type": "agent_status", - "description": "Status of an agent", - "values": { - "1": { - "label": "Active", - "description": "active agent available for use" - }, - "2": { - "label": "Deactivated", - "description": "deactivated agent that is no longer available" - } - } - }, - "booking_method": { - "type": "booking_method", - "description": "Method for specifying time allocation in resource planner bookings", - "values": { - "1": { - "label": "Per day", - "description": "book specific hours each day (e.g., 4 hours per day)" - }, - "2": { - "label": "Percentage", - "description": "book percentage of daily capacity (e.g., 50% of workday)" - }, - "3": { - "label": "Total hours", - "description": "book total hours spread across date range" - } - } - }, "approval_policy_type": { "type": "approval_policy_type", "description": "Object type that an approval workflow policy applies to", @@ -10807,6 +12599,24 @@ } } }, + "booking_method": { + "type": "booking_method", + "description": "Method for specifying time allocation in resource planner bookings", + "values": { + "1": { + "label": "Per day", + "description": "book specific hours each day (e.g., 4 hours per day)" + }, + "2": { + "label": "Percentage", + "description": "book percentage of daily capacity (e.g., 50% of workday)" + }, + "3": { + "label": "Total hours", + "description": "book total hours spread across date range" + } + } + }, "booking_type": { "type": "booking_type", "description": "Type of booking", @@ -10896,6 +12706,20 @@ } } }, + "stage_type": { + "type": "stage_type", + "description": "Lifecycle stage that determines whether work is pre-sale or in production", + "values": { + "1": { + "label": "Deal", + "description": "pre-sale phase for estimating and planning potential work" + }, + "2": { + "label": "Budget", + "description": "production phase where actual work is being delivered" + } + } + }, "absence_type": { "type": "absence_type", "description": "Category of absence that affects how availability is calculated", @@ -11004,6 +12828,10 @@ "10": { "label": "Users that can manage project", "description": "users_that_can_manage_project - all users who are members of a resource" + }, + "12": { + "label": "Agent manager", + "description": "agent_manager - the manager assigned to an agent" } } }, @@ -11149,6 +12977,35 @@ } } }, + "agent_status": { + "type": "agent_status", + "description": "Status of an agent", + "values": { + "1": { + "label": "Active", + "description": "active agent available for use" + }, + "2": { + "label": "Deactivated", + "description": "deactivated agent that is no longer available" + } + } + }, + "approval_policy_target_type": { + "type": "approval_policy_target_type", + "description": "Type of entity an approval policy is assigned to", + "values": { + "person": { + "label": "Person" + }, + "budget": { + "label": "Budget" + }, + "deal": { + "label": "Deal" + } + } + }, "automation_action": { "type": "automation_action", "description": "Actions that automations can perform.", @@ -11192,6 +13049,10 @@ }, "deliver_budget": { "label": "Deliver budget" + }, + "send_teams_message": { + "label": "Send Teams message", + "description": "send a message to a Microsoft Teams channel" } } }, @@ -11237,6 +13098,28 @@ } } }, + "booking_approval_status": { + "type": "booking_approval_status", + "description": "Approval workflow status of a booking", + "values": { + "1": { + "label": "Approved", + "description": "booking has been approved" + }, + "2": { + "label": "Pending", + "description": "booking is pending approval" + }, + "3": { + "label": "Rejected", + "description": "booking has been rejected" + }, + "5": { + "label": "Canceled", + "description": "booking has been canceled" + } + } + }, "booking_status": { "type": "booking_status", "description": "Status of a booking", @@ -11577,6 +13460,24 @@ } } }, + "integration_type": { + "type": "integration_type", + "description": "Type of external integration", + "values": { + "9": { + "label": "Google Calendar" + }, + "12": { + "label": "Outlook Calendar" + }, + "25": { + "label": "Gmail" + }, + "28": { + "label": "Outlook Mail" + } + } + }, "invoice_payment_status": { "type": "invoice_payment_status", "description": "Payment status of an invoice", @@ -11768,6 +13669,28 @@ } } }, + "resource_request_status": { + "type": "resource_request_status", + "description": "Status of a resource request in its lifecycle", + "values": { + "pending": { + "label": "Pending", + "description": "Request is awaiting resolution" + }, + "resolved": { + "label": "Resolved", + "description": "Request has been resolved and bookings created" + }, + "rejected": { + "label": "Rejected", + "description": "Request has been rejected" + }, + "canceled": { + "label": "Canceled", + "description": "Request has been canceled" + } + } + }, "role_user_type": { "type": "role_user_type", "description": "User type of a role (time tracker or client)", @@ -11891,20 +13814,6 @@ } } }, - "stage_type": { - "type": "stage_type", - "description": "Lifecycle stage that determines whether work is pre-sale or in production", - "values": { - "1": { - "label": "Deal", - "description": "pre-sale phase for estimating and planning potential work" - }, - "2": { - "label": "Budget", - "description": "production phase where actual work is being delivered" - } - } - }, "subscribable_type": { "type": "subscribable_type", "description": "Type of resource a person can be subscribed to", @@ -12000,6 +13909,14 @@ "4": { "label": "Mixed", "description": "combination of timer tracking and manual adjustment" + }, + "5": { + "label": "Autogenerated", + "description": "time entry auto-created from time-off bookings" + }, + "6": { + "label": "AI Generated", + "description": "time entry generated by AI" } } }, diff --git a/crates/tb-prod/src/body.rs b/crates/tb-prod/src/body.rs index cc9b728..0106d95 100644 --- a/crates/tb-prod/src/body.rs +++ b/crates/tb-prod/src/body.rs @@ -129,9 +129,9 @@ mod tests { let tasks = s.resolve_resource("tasks").unwrap(); let input = json!({ "title": "Test task", - "project_id": "100", - "task_list_id": "200", - "assignee_id": "300" + "project": "100", + "task_list": "200", + "assignee": "300" }); let body = build_jsonapi_body(tasks, &input, None).unwrap(); let data = body.get("data").unwrap(); diff --git a/crates/tb-prod/src/schema.rs b/crates/tb-prod/src/schema.rs index 0dbed16..1fa984d 100644 --- a/crates/tb-prod/src/schema.rs +++ b/crates/tb-prod/src/schema.rs @@ -352,8 +352,8 @@ mod tests { let s = schema(); let tasks = s.resolve_resource("tasks").unwrap(); let field = tasks - .field_by_param("assignee_id") - .expect("assignee_id param should exist"); + .field_by_param("assignee") + .expect("assignee param should exist"); assert_eq!(field.type_category, TypeCategory::Resource); assert_eq!(field.field_type, "people"); } diff --git a/crates/tb-prod/src/validate.rs b/crates/tb-prod/src/validate.rs index 3b2a521..d05a275 100644 --- a/crates/tb-prod/src/validate.rs +++ b/crates/tb-prod/src/validate.rs @@ -171,12 +171,12 @@ mod tests { fn validate_create_missing_required() { let s = schema(); let tasks = s.resolve_resource("tasks").unwrap(); - // tasks requires title, project_id, task_list_id + // tasks requires title, project, task_list let input = json!({"title": "Test"}); let errors = validate_create(tasks, &input, s); assert!(!errors.is_empty()); let all = errors.join(" "); - assert!(all.contains("project_id") || all.contains("task_list_id")); + assert!(all.contains("project") || all.contains("task_list")); } #[test] @@ -186,8 +186,8 @@ mod tests { // "id" is readonly with param "id" let input = json!({ "title": "Test", - "project_id": "1", - "task_list_id": "2", + "project": "1", + "task_list": "2", "id": "123" }); let errors = validate_create(tasks, &input, s); @@ -227,8 +227,8 @@ mod tests { let tasks = s.resolve_resource("tasks").unwrap(); let input = json!({ "title": "Test task", - "project_id": "100", - "task_list_id": "200" + "project": "100", + "task_list": "200" }); let errors = validate_create(tasks, &input, s); // May still have errors for other required fields, but not for the ones we provided @@ -238,8 +238,8 @@ mod tests { e.contains("Unknown") || e.contains("readonly") || e.contains("title") - || e.contains("project_id") - || e.contains("task_list_id") + || e.contains("project") + || e.contains("task_list") }) .collect(); assert!(