← back to Cli Printing Press
feat(catalog): generate Pipedrive CLI from official OpenAPI spec
451b7cb7e63e659ffbcbd2d02c0da2bc0231d8d4 · 2026-03-25 00:03:31 -0700 · Matt Van Horn
CRM from the terminal - zero CLI competition. 7/7 quality gates pass.
Covers deals, persons, organizations, pipelines, activities, leads,
and more. Auth via PIPEDRIVE_API_TOKEN env var.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Files touched
A catalog/pipedrive.yamlA pipedrive-cli/.golangci.ymlA pipedrive-cli/.goreleaser.yamlA pipedrive-cli/MakefileA pipedrive-cli/README.mdA pipedrive-cli/cmd/pipedrive-cli/main.goA pipedrive-cli/go.modA pipedrive-cli/go.sumA pipedrive-cli/internal/cli/activity-fields.goA pipedrive-cli/internal/cli/activity-types.goA pipedrive-cli/internal/cli/auth.goA pipedrive-cli/internal/cli/billing.goA pipedrive-cli/internal/cli/call-logs.goA pipedrive-cli/internal/cli/call-logs_recordings.goA pipedrive-cli/internal/cli/channels.goA pipedrive-cli/internal/cli/channels_conversations.goA pipedrive-cli/internal/cli/currencies.goA pipedrive-cli/internal/cli/deal-fields.goA pipedrive-cli/internal/cli/deals.goA pipedrive-cli/internal/cli/deals_changelog.goA pipedrive-cli/internal/cli/deals_duplicate.goA pipedrive-cli/internal/cli/deals_files.goA pipedrive-cli/internal/cli/deals_flow.goA pipedrive-cli/internal/cli/deals_followers.goA pipedrive-cli/internal/cli/deals_mail-messages.goA pipedrive-cli/internal/cli/deals_merge.goA pipedrive-cli/internal/cli/deals_participants-changelog.goA pipedrive-cli/internal/cli/deals_participants.goA pipedrive-cli/internal/cli/deals_permitted-users.goA pipedrive-cli/internal/cli/doctor.goA pipedrive-cli/internal/cli/files.goA pipedrive-cli/internal/cli/files_download.goA pipedrive-cli/internal/cli/filters.goA pipedrive-cli/internal/cli/goals.goA pipedrive-cli/internal/cli/goals_results.goA pipedrive-cli/internal/cli/helpers.goA pipedrive-cli/internal/cli/lead-fields.goA pipedrive-cli/internal/cli/lead-labels.goA pipedrive-cli/internal/cli/lead-sources.goA pipedrive-cli/internal/cli/leads.goA pipedrive-cli/internal/cli/leads_permitted-users.goA pipedrive-cli/internal/cli/legacy-teams.goA pipedrive-cli/internal/cli/legacy-teams_users.goA pipedrive-cli/internal/cli/mailbox.goA pipedrive-cli/internal/cli/meetings.goA pipedrive-cli/internal/cli/note-fields.goA pipedrive-cli/internal/cli/notes.goA pipedrive-cli/internal/cli/notes_comments.goA pipedrive-cli/internal/cli/oauth.goA pipedrive-cli/internal/cli/organization-fields.goA pipedrive-cli/internal/cli/organization-relationships.goA pipedrive-cli/internal/cli/organizations.goA pipedrive-cli/internal/cli/organizations_changelog.goA pipedrive-cli/internal/cli/organizations_files.goA pipedrive-cli/internal/cli/organizations_flow.goA pipedrive-cli/internal/cli/organizations_followers.goA pipedrive-cli/internal/cli/organizations_mail-messages.goA pipedrive-cli/internal/cli/organizations_merge.goA pipedrive-cli/internal/cli/organizations_permitted-users.goA pipedrive-cli/internal/cli/permission-sets.goA pipedrive-cli/internal/cli/permission-sets_assignments.goA pipedrive-cli/internal/cli/person-fields.goA pipedrive-cli/internal/cli/persons.goA pipedrive-cli/internal/cli/persons_changelog.goA pipedrive-cli/internal/cli/persons_files.goA pipedrive-cli/internal/cli/persons_flow.goA pipedrive-cli/internal/cli/persons_followers.goA pipedrive-cli/internal/cli/persons_mail-messages.goA pipedrive-cli/internal/cli/persons_merge.goA pipedrive-cli/internal/cli/persons_permitted-users.goA pipedrive-cli/internal/cli/persons_picture.goA pipedrive-cli/internal/cli/persons_products.goA pipedrive-cli/internal/cli/pipelines.goA pipedrive-cli/internal/cli/pipelines_conversion-statistics.goA pipedrive-cli/internal/cli/pipelines_deals.goA pipedrive-cli/internal/cli/pipelines_movement-statistics.goA pipedrive-cli/internal/cli/product-fields.goA pipedrive-cli/internal/cli/products.goA pipedrive-cli/internal/cli/products_deals.goA pipedrive-cli/internal/cli/products_files.goA pipedrive-cli/internal/cli/products_followers.goA pipedrive-cli/internal/cli/products_permitted-users.goA pipedrive-cli/internal/cli/project-templates.goA pipedrive-cli/internal/cli/projects.goA pipedrive-cli/internal/cli/projects_activities.goA pipedrive-cli/internal/cli/projects_archive.goA pipedrive-cli/internal/cli/projects_groups.goA pipedrive-cli/internal/cli/projects_plan.goA pipedrive-cli/internal/cli/projects_tasks.goA pipedrive-cli/internal/cli/recents.goA pipedrive-cli/internal/cli/roles.goA pipedrive-cli/internal/cli/roles_assignments.goA pipedrive-cli/internal/cli/roles_pipelines.goA pipedrive-cli/internal/cli/roles_settings.goA pipedrive-cli/internal/cli/root.goA pipedrive-cli/internal/cli/stages.goA pipedrive-cli/internal/cli/stages_deals.goA pipedrive-cli/internal/cli/tasks.goA pipedrive-cli/internal/cli/user-connections.goA pipedrive-cli/internal/cli/user-settings.goA pipedrive-cli/internal/cli/users.goA pipedrive-cli/internal/cli/users_followers.goA pipedrive-cli/internal/cli/users_permissions.goA pipedrive-cli/internal/cli/users_role-assignments.goA pipedrive-cli/internal/cli/users_role-settings.goA pipedrive-cli/internal/cli/webhooks.goA pipedrive-cli/internal/client/client.goA pipedrive-cli/internal/config/config.goA pipedrive-cli/internal/types/types.go
Diff
commit 451b7cb7e63e659ffbcbd2d02c0da2bc0231d8d4
Author: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Date: Wed Mar 25 00:03:31 2026 -0700
feat(catalog): generate Pipedrive CLI from official OpenAPI spec
CRM from the terminal - zero CLI competition. 7/7 quality gates pass.
Covers deals, persons, organizations, pipelines, activities, leads,
and more. Auth via PIPEDRIVE_API_TOKEN env var.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---
catalog/pipedrive.yaml | 11 +
pipedrive-cli/.golangci.yml | 12 +
pipedrive-cli/.goreleaser.yaml | 36 ++
pipedrive-cli/Makefile | 16 +
pipedrive-cli/README.md | 446 +++++++++++++++++++++
pipedrive-cli/cmd/pipedrive-cli/main.go | 17 +
pipedrive-cli/go.mod | 15 +
pipedrive-cli/go.sum | 16 +
pipedrive-cli/internal/cli/activity-fields.go | 51 +++
pipedrive-cli/internal/cli/activity-types.go | 177 ++++++++
pipedrive-cli/internal/cli/auth.go | 250 ++++++++++++
pipedrive-cli/internal/cli/billing.go | 51 +++
pipedrive-cli/internal/cli/call-logs.go | 223 +++++++++++
pipedrive-cli/internal/cli/call-logs_recordings.go | 61 +++
pipedrive-cli/internal/cli/channels.go | 188 +++++++++
.../internal/cli/channels_conversations.go | 57 +++
pipedrive-cli/internal/cli/currencies.go | 56 +++
pipedrive-cli/internal/cli/deal-fields.go | 235 +++++++++++
pipedrive-cli/internal/cli/deals.go | 355 ++++++++++++++++
pipedrive-cli/internal/cli/deals_changelog.go | 63 +++
pipedrive-cli/internal/cli/deals_duplicate.go | 55 +++
pipedrive-cli/internal/cli/deals_files.go | 66 +++
pipedrive-cli/internal/cli/deals_flow.go | 69 ++++
pipedrive-cli/internal/cli/deals_followers.go | 128 ++++++
pipedrive-cli/internal/cli/deals_mail-messages.go | 63 +++
pipedrive-cli/internal/cli/deals_merge.go | 61 +++
.../internal/cli/deals_participants-changelog.go | 63 +++
pipedrive-cli/internal/cli/deals_participants.go | 136 +++++++
.../internal/cli/deals_permitted-users.go | 55 +++
pipedrive-cli/internal/cli/doctor.go | 121 ++++++
pipedrive-cli/internal/cli/files.go | 337 ++++++++++++++++
pipedrive-cli/internal/cli/files_download.go | 55 +++
pipedrive-cli/internal/cli/filters.go | 243 +++++++++++
pipedrive-cli/internal/cli/goals.go | 227 +++++++++++
pipedrive-cli/internal/cli/goals_results.go | 67 ++++
pipedrive-cli/internal/cli/helpers.go | 357 +++++++++++++++++
pipedrive-cli/internal/cli/lead-fields.go | 59 +++
pipedrive-cli/internal/cli/lead-labels.go | 162 ++++++++
pipedrive-cli/internal/cli/lead-sources.go | 51 +++
pipedrive-cli/internal/cli/leads.go | 393 ++++++++++++++++++
.../internal/cli/leads_permitted-users.go | 55 +++
pipedrive-cli/internal/cli/legacy-teams.go | 232 +++++++++++
pipedrive-cli/internal/cli/legacy-teams_users.go | 118 ++++++
pipedrive-cli/internal/cli/mailbox.go | 235 +++++++++++
pipedrive-cli/internal/cli/meetings.go | 106 +++++
pipedrive-cli/internal/cli/note-fields.go | 51 +++
pipedrive-cli/internal/cli/notes.go | 306 ++++++++++++++
pipedrive-cli/internal/cli/notes_comments.go | 211 ++++++++++
pipedrive-cli/internal/cli/oauth.go | 148 +++++++
pipedrive-cli/internal/cli/organization-fields.go | 235 +++++++++++
.../internal/cli/organization-relationships.go | 225 +++++++++++
pipedrive-cli/internal/cli/organizations.go | 30 ++
.../internal/cli/organizations_changelog.go | 63 +++
pipedrive-cli/internal/cli/organizations_files.go | 66 +++
pipedrive-cli/internal/cli/organizations_flow.go | 69 ++++
.../internal/cli/organizations_followers.go | 128 ++++++
.../internal/cli/organizations_mail-messages.go | 63 +++
pipedrive-cli/internal/cli/organizations_merge.go | 61 +++
.../internal/cli/organizations_permitted-users.go | 55 +++
pipedrive-cli/internal/cli/permission-sets.go | 88 ++++
.../internal/cli/permission-sets_assignments.go | 63 +++
pipedrive-cli/internal/cli/person-fields.go | 235 +++++++++++
pipedrive-cli/internal/cli/persons.go | 32 ++
pipedrive-cli/internal/cli/persons_changelog.go | 63 +++
pipedrive-cli/internal/cli/persons_files.go | 66 +++
pipedrive-cli/internal/cli/persons_flow.go | 69 ++++
pipedrive-cli/internal/cli/persons_followers.go | 128 ++++++
.../internal/cli/persons_mail-messages.go | 63 +++
pipedrive-cli/internal/cli/persons_merge.go | 61 +++
.../internal/cli/persons_permitted-users.go | 55 +++
pipedrive-cli/internal/cli/persons_picture.go | 112 ++++++
pipedrive-cli/internal/cli/persons_products.go | 63 +++
pipedrive-cli/internal/cli/pipelines.go | 26 ++
.../cli/pipelines_conversion-statistics.go | 72 ++++
pipedrive-cli/internal/cli/pipelines_deals.go | 81 ++++
.../internal/cli/pipelines_movement-statistics.go | 72 ++++
pipedrive-cli/internal/cli/product-fields.go | 225 +++++++++++
pipedrive-cli/internal/cli/products.go | 27 ++
pipedrive-cli/internal/cli/products_deals.go | 66 +++
pipedrive-cli/internal/cli/products_files.go | 66 +++
pipedrive-cli/internal/cli/products_followers.go | 136 +++++++
.../internal/cli/products_permitted-users.go | 55 +++
pipedrive-cli/internal/cli/project-templates.go | 90 +++++
pipedrive-cli/internal/cli/projects.go | 424 ++++++++++++++++++++
pipedrive-cli/internal/cli/projects_activities.go | 55 +++
pipedrive-cli/internal/cli/projects_archive.go | 55 +++
pipedrive-cli/internal/cli/projects_groups.go | 55 +++
pipedrive-cli/internal/cli/projects_plan.go | 146 +++++++
pipedrive-cli/internal/cli/projects_tasks.go | 55 +++
pipedrive-cli/internal/cli/recents.go | 66 +++
pipedrive-cli/internal/cli/roles.go | 203 ++++++++++
pipedrive-cli/internal/cli/roles_assignments.go | 135 +++++++
pipedrive-cli/internal/cli/roles_pipelines.go | 92 +++++
pipedrive-cli/internal/cli/roles_settings.go | 99 +++++
pipedrive-cli/internal/cli/root.go | 153 +++++++
pipedrive-cli/internal/cli/stages.go | 24 ++
pipedrive-cli/internal/cli/stages_deals.go | 72 ++++
pipedrive-cli/internal/cli/tasks.go | 253 ++++++++++++
pipedrive-cli/internal/cli/user-connections.go | 51 +++
pipedrive-cli/internal/cli/user-settings.go | 51 +++
pipedrive-cli/internal/cli/users.go | 227 +++++++++++
pipedrive-cli/internal/cli/users_followers.go | 55 +++
pipedrive-cli/internal/cli/users_permissions.go | 55 +++
.../internal/cli/users_role-assignments.go | 63 +++
pipedrive-cli/internal/cli/users_role-settings.go | 55 +++
pipedrive-cli/internal/cli/webhooks.go | 153 +++++++
pipedrive-cli/internal/client/client.go | 300 ++++++++++++++
pipedrive-cli/internal/config/config.go | 104 +++++
pipedrive-cli/internal/types/types.go | 4 +
109 files changed, 12580 insertions(+)
diff --git a/catalog/pipedrive.yaml b/catalog/pipedrive.yaml
new file mode 100644
index 00000000..de711cfd
--- /dev/null
+++ b/catalog/pipedrive.yaml
@@ -0,0 +1,11 @@
+name: pipedrive
+display_name: Pipedrive
+description: CRM for sales teams - deals, contacts, pipelines, activities, and organizations
+category: crm
+spec_url: https://developers.pipedrive.com/docs/api/v1/openapi.yaml
+spec_format: yaml
+openapi_version: "3.0"
+tier: official
+verified_date: "2026-03-25"
+homepage: https://developers.pipedrive.com
+notes: "Zero CLI competition. CRM from the terminal."
diff --git a/pipedrive-cli/.golangci.yml b/pipedrive-cli/.golangci.yml
new file mode 100644
index 00000000..5397226d
--- /dev/null
+++ b/pipedrive-cli/.golangci.yml
@@ -0,0 +1,12 @@
+linters:
+ enable:
+ - errorlint
+ - govet
+ - ineffassign
+ - staticcheck
+ - unused
+
+formatters:
+ enable:
+ - gofmt
+ - goimports
diff --git a/pipedrive-cli/.goreleaser.yaml b/pipedrive-cli/.goreleaser.yaml
new file mode 100644
index 00000000..b91676c6
--- /dev/null
+++ b/pipedrive-cli/.goreleaser.yaml
@@ -0,0 +1,36 @@
+version: 2
+project_name: pipedrive-cli
+changelog:
+ disable: true
+builds:
+ - id: pipedrive-cli
+ main: ./cmd/pipedrive-cli
+ binary: pipedrive-cli
+ env:
+ - CGO_ENABLED=0
+ ldflags:
+ - -s -w -X github.com/USER/pipedrive-cli/internal/cli.version={{ .Version }}
+ targets:
+ - darwin_amd64
+ - darwin_arm64
+ - linux_amd64
+ - linux_arm64
+ - windows_amd64
+ - windows_arm64
+archives:
+ - formats: [tar.gz]
+ name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
+ format_overrides:
+ - goos: windows
+ formats: [zip]
+checksum:
+ name_template: checksums.txt
+brews:
+ - name: pipedrive-cli
+ repository:
+ owner: USER
+ name: homebrew-tap
+ homepage: "https://github.com/USER/pipedrive-cli"
+ description: ""
+ install: |
+ bin.install "pipedrive-cli"
diff --git a/pipedrive-cli/Makefile b/pipedrive-cli/Makefile
new file mode 100644
index 00000000..7ba8307e
--- /dev/null
+++ b/pipedrive-cli/Makefile
@@ -0,0 +1,16 @@
+.PHONY: build test lint install clean
+
+build:
+ go build -o bin/pipedrive-cli ./cmd/pipedrive-cli
+
+test:
+ go test ./...
+
+lint:
+ golangci-lint run
+
+install:
+ go install ./cmd/pipedrive-cli
+
+clean:
+ rm -rf bin/
diff --git a/pipedrive-cli/README.md b/pipedrive-cli/README.md
new file mode 100644
index 00000000..fc363da0
--- /dev/null
+++ b/pipedrive-cli/README.md
@@ -0,0 +1,446 @@
+# pipedrive-cli
+
+
+
+## Install
+
+### Homebrew
+
+```
+brew install USER/tap/pipedrive-cli
+```
+
+### Go
+
+```
+go install github.com/USER/pipedrive-cli/cmd/pipedrive-cli@latest
+```
+
+### Binary
+
+Download from [Releases](https://github.com/USER/pipedrive-cli/releases).
+
+## Quick Start
+
+```bash
+# 1. Set your API credentials
+export PIPEDRIVE_TOKEN="your-key-here"
+
+# 2. Verify everything works
+pipedrive-cli doctor
+
+# 3. Start using it
+pipedrive-cli activity-fields --help
+```
+
+## Usage
+
+<!-- HELP_OUTPUT -->
+
+## Commands
+
+### activity-fields
+
+Activity fields represent different fields that an activity has.
+
+- **`pipedrive-cli activity-fields get`** - Get all activity fields
+
+### activity-types
+
+Activity types represent different kinds of activities that can be stored. Each activity type is presented to the user with an icon and a name. Additionally, a color can be defined (not implemented in the Pipedrive app as of today). Activity types are linked to activities via `ActivityType.key_string = Activity.type`. The `key_string` will be generated by the API based on the given name of the activity type upon creation, and cannot be changed. Activity types should be presented to the user in an ordered manner, using the `ActivityType.order_nr` value.
+
+- **`pipedrive-cli activity-types add`** - Add new activity type
+- **`pipedrive-cli activity-types delete`** - Delete an activity type
+- **`pipedrive-cli activity-types get`** - Get all activity types
+- **`pipedrive-cli activity-types update`** - Update an activity type
+
+### billing
+
+Billing is responsible for handling your subscriptions, payments, plans and add-ons.
+
+- **`pipedrive-cli billing get-company-addons`** - Get all add-ons for a single company
+
+### call-logs
+
+Call logs describe the outcome of a phone call managed by an integrated provider. Since these logs are also considered activities, they can be associated with a deal or a lead, a person and/or an organization. Call logs do differ from other activities, as they only receive the information needed to describe the phone call.
+
+- **`pipedrive-cli call-logs add`** - Add a call log
+- **`pipedrive-cli call-logs delete`** - Delete a call log
+- **`pipedrive-cli call-logs get`** - Get details of a call log
+- **`pipedrive-cli call-logs get-user`** - Get all call logs assigned to a particular user
+
+### channels
+
+Channels API allows you to integrate your existing messaging channels into Pipedrive through [Messaging app extension](https://pipedrive.readme.io/docs/messaging-app-extension). It enables you to manage and interact with the channel’s conversations, participants and messages inside Pipedrive Messaging inbox: get the historical conversation, receive and send new messages. These endpoints are accessible only through **Messengers integration** OAuth scope together with Messaging manifest in building the [Messaging app extension](https://pipedrive.readme.io/docs/messaging-app-extension).
+
+- **`pipedrive-cli channels add`** - Add a channel
+- **`pipedrive-cli channels delete`** - Delete a channel
+- **`pipedrive-cli channels receive-message`** - Receives an incoming message
+
+### currencies
+
+Supported currencies which can be used to represent the monetary value of a deal, or a value of any monetary type custom field. The `Currency.code` field must be used to point to a currency. `Currency.code` is the ISO-4217 format currency code for non-custom currencies. You can differentiate custom and non-custom currencies using the `is_custom_flag` property. For custom currencies, it is intended that the formatted sums are displayed in the UI using the following format: [sum][non-breaking space character][currency.symbol], for example: 500 users. Custom currencies cannot be added or removed via the API yet — rather the admin users of the account must configure them from the Pipedrive app.
+
+- **`pipedrive-cli currencies get`** - Get all supported currencies
+
+### deal-fields
+
+Deal fields represent the near-complete schema for a deal in the context of the company of the authorized user. Each company can have a different schema for their deals, with various custom fields. In the context of using deal fields as a schema for defining the data fields of a deal, it must be kept in mind that some types of custom fields can have additional data fields which are not separate deal fields per se. Such is the case with monetary, daterange and timerange fields – each of these fields will have one additional data field in addition to the one presented in the context of deal fields. For example, if there is a monetary field with the key `ffk9s9` stored on the account, `ffk9s9` would hold the numeric value of the field, and `ffk9s9_currency` would hold the ISO currency code that goes along with the numeric value. To find out which data fields are available, fetch one deal and list its keys.
+
+- **`pipedrive-cli deal-fields add`** - Add a new deal field
+- **`pipedrive-cli deal-fields delete`** - Delete multiple deal fields in bulk
+- **`pipedrive-cli deal-fields delete-dealfields`** - Delete a deal field
+- **`pipedrive-cli deal-fields get`** - Get all deal fields
+- **`pipedrive-cli deal-fields get-dealfields`** - Get one deal field
+- **`pipedrive-cli deal-fields update`** - Update a deal field
+
+### deals
+
+Deals represent ongoing, lost or won sales to an organization or to a person. Each deal has a monetary value and must be placed in a stage. Deals can be owned by a user, and followed by one or many users. Each deal consists of standard data fields but can also contain a number of custom fields. The custom fields can be recognized by long hashes as keys. These hashes can be mapped against `DealField.key`. The corresponding label for each such custom field can be obtained from `DealField.name`.
+
+- **`pipedrive-cli deals get-archived`** - Get all archived deals
+- **`pipedrive-cli deals get-archived-summary`** - Get archived deals summary
+- **`pipedrive-cli deals get-archived-timeline`** - Get archived deals timeline
+- **`pipedrive-cli deals get-summary`** - Get deals summary
+- **`pipedrive-cli deals get-timeline`** - Get deals timeline
+
+### files
+
+Files are documents of any kind (images, spreadsheets, text files, etc.) that are uploaded to Pipedrive, and usually associated with a particular deal, person, organization, product, note or activity. Remote files can only be associated with a particular deal, person or organization. Note that the API currently does not support downloading files although it lets you retrieve a file’s meta-info along with a URL which can be used to download the file by using a standard HTTP GET request.
+
+- **`pipedrive-cli files add`** - Add file
+- **`pipedrive-cli files add-and-link-it`** - Create a remote file and link it to an item
+- **`pipedrive-cli files delete`** - Delete a file
+- **`pipedrive-cli files get`** - Get all files
+- **`pipedrive-cli files get-id`** - Get one file
+- **`pipedrive-cli files link-to-item`** - Link a remote file to an item
+- **`pipedrive-cli files update`** - Update file details
+
+### filters
+
+Each filter is essentially a set of data validation conditions. A filter of the same kind can be applied when fetching a list of deals, leads, persons, organizations or products in the context of a pipeline. Filters are limited to a maximum of 16 conditions. When applied, only items matching the conditions of the filter are returned. Detailed definitions of filter conditions and additional functionality is not yet available.
+
+- **`pipedrive-cli filters add`** - Add a new filter
+- **`pipedrive-cli filters delete`** - Delete multiple filters in bulk
+- **`pipedrive-cli filters delete-id`** - Delete a filter
+- **`pipedrive-cli filters get`** - Get all filters
+- **`pipedrive-cli filters get-helpers`** - Get all filter helpers
+- **`pipedrive-cli filters get-id`** - Get one filter
+- **`pipedrive-cli filters update`** - Update filter
+
+### goals
+
+Goals help your team meet your sales targets. There are three types of goals - company, team and user.
+
+- **`pipedrive-cli goals add`** - Add a new goal
+- **`pipedrive-cli goals delete`** - Delete existing goal
+- **`pipedrive-cli goals get`** - Find goals
+- **`pipedrive-cli goals update`** - Update existing goal
+
+### lead-fields
+
+Lead fields represent the near-complete schema for a lead in the context of the company of the authorized user. Each company can have a different schema for their leads, with various custom fields. In the context of using lead fields as a schema for defining the data fields of a lead, it must be kept in mind that some types of custom fields can have additional data fields which are not separate lead fields per se. Such is the case with monetary, daterange and timerange fields – each of these fields will have one additional data field in addition to the one presented in the context of lead fields. For example, if there is a monetary field with the key `ffk9s9` stored on the account, `ffk9s9` would hold the numeric value of the field, and `ffk9s9_currency` would hold the ISO currency code that goes along with the numeric value. To find out which data fields are available, fetch one lead and list its keys.
+
+- **`pipedrive-cli lead-fields get`** - Get all lead fields
+
+### lead-labels
+
+Lead labels allow you to visually categorize your leads. There are three default lead labels: hot, cold, and warm, but you can add as many new custom labels as you want.
+
+- **`pipedrive-cli lead-labels add`** - Add a lead label
+- **`pipedrive-cli lead-labels delete`** - Delete a lead label
+- **`pipedrive-cli lead-labels get`** - Get all lead labels
+- **`pipedrive-cli lead-labels update`** - Update a lead label
+
+### lead-sources
+
+A lead source indicates where your lead came from. Currently, these are the possible lead sources: `Manually created`, `Deal`, `Web forms`, `Prospector`, `Leadbooster`, `Live chat`, `Import`, `Website visitors`, `Workflow automation`, and `API`. Lead sources are pre-defined and cannot be edited. Please note that leads sourced from the Chatbot feature are assigned the value `Leadbooster`. Please also note that this list is not final and new sources may be added as needed.
+
+- **`pipedrive-cli lead-sources get`** - Get all lead sources
+
+### leads
+
+Leads are potential deals stored in Leads Inbox before they are archived or converted to a deal. Each lead needs to be named (using the `title` field) and be linked to a person or an organization. In addition to that, a lead can contain most of the fields a deal can (such as `value` or `expected_close_date`).
+
+- **`pipedrive-cli leads add`** - Add a lead
+- **`pipedrive-cli leads delete`** - Delete a lead
+- **`pipedrive-cli leads get`** - Get all leads
+- **`pipedrive-cli leads get-archived`** - Get all archived leads
+- **`pipedrive-cli leads get-id`** - Get one lead
+- **`pipedrive-cli leads search`** - Search leads
+- **`pipedrive-cli leads update`** - Update a lead
+
+### legacy-teams
+
+Legacy teams allow you to form groups of users withing the organization for more efficient management. Previously Legacy Teams were called Teams and occupied the `v1/teams*` path. They're being deprecated because we are preparing for an upgraded version of the Teams API, which requires migrating the current functionality to a new path URL `v1/legacyTeams*`. The functionality and [OAuth scopes](https://pipedrive.readme.io/docs/marketplace-scopes-and-permissions-explanations) of all the Teams API endpoints will remain the same.
+
+- **`pipedrive-cli legacy-teams add-team`** - Add a new team
+- **`pipedrive-cli legacy-teams get-team`** - Get a single team
+- **`pipedrive-cli legacy-teams get-teams`** - Get all teams
+- **`pipedrive-cli legacy-teams get-user-teams`** - Get all teams of a user
+- **`pipedrive-cli legacy-teams update-team`** - Update a team
+
+### mailbox
+
+Mailbox was designed to be the email control hub inside Pipedrive. Pipedrive supports all major providers (including Gmail, Outlook and also custom IMAP/SMTP). There are 2 options for syncing user emails: 2-way sync: Mail Connection is established with the mail provider (example Gmail). There can be only 1 active Mail Connection per user in company. 1-way sync: SmartBCC feature which stores the copies of email messages to Pipedrive by adding the SmartBCC specific address to mail recipients.
+
+- **`pipedrive-cli mailbox delete-mail-thread`** - Delete mail thread
+- **`pipedrive-cli mailbox get-mail-message`** - Get one mail message
+- **`pipedrive-cli mailbox get-mail-thread`** - Get one mail thread
+- **`pipedrive-cli mailbox get-mail-thread-messages`** - Get all mail messages of mail thread
+- **`pipedrive-cli mailbox get-mail-threads`** - Get mail threads
+- **`pipedrive-cli mailbox update-mail-thread-details`** - Update mail thread details
+
+### meetings
+
+Meetings API allows integrating video calling apps into Pipedrive through [Video Calling App extension](https://pipedrive.readme.io/docs/video-calling-app-extension). It enables you to manage and interact with your video calls and meetings inside Pipedrive. These endpoints are accessible only through apps with video calls integration [OAuth scope](https://pipedrive.readme.io/docs/marketplace-scopes-and-permissions-explanations).
+
+- **`pipedrive-cli meetings delete-user-provider-link`** - Delete the link between a user and the installed video call integration
+- **`pipedrive-cli meetings save-user-provider-link`** - Link a user with the installed video call integration
+
+### note-fields
+
+Note fields represent different fields that a note has.
+
+- **`pipedrive-cli note-fields get`** - Get all note fields
+
+### notes
+
+Notes are pieces of textual (HTML-formatted) information that can be attached to deals, persons and organizations. Notes are usually displayed in the UI in chronological order – newest first – and in context with other updates regarding the item they are attached to. The maximum note size is approximately 100,000 characters (or 100KB per note).
+
+- **`pipedrive-cli notes add`** - Add a note
+- **`pipedrive-cli notes delete`** - Delete a note
+- **`pipedrive-cli notes get`** - Get all notes
+- **`pipedrive-cli notes get-id`** - Get one note
+- **`pipedrive-cli notes update`** - Update a note
+
+### oauth
+
+Using OAuth 2.0 is necessary for developing apps that are available in the Pipedrive Marketplace. Authorization via OAuth 2.0 is a well-known and stable way to get fine-grained access to an API. To retrieve OAuth2 tokens you should send requests to the `https://oauth.pipedrive.com` domain. After registering the app, you must add the necessary server-side logic to your app to establish the OAuth flow. Please read more about authorization step on the [Pipedrive Developers page](https://pipedrive.readme.io/docs/marketplace-oauth-authorization).
+
+- **`pipedrive-cli oauth authorize`** - Requesting authorization
+- **`pipedrive-cli oauth get-tokens`** - Getting the tokens
+- **`pipedrive-cli oauth refresh-tokens`** - Refreshing the tokens
+
+### organization-fields
+
+Organization fields represent the near-complete schema for an organization in the context of the company of the authorized user. Each company can have a different schema for their organizations, with various custom fields. In the context of using organization fields as a schema for defining the data fields of an organization, it must be kept in mind that some types of custom fields can have additional data fields which are not separate organization fields per se. Such is the case with monetary, daterange and timerange fields – each of these fields will have one additional data field in addition to the one presented in the context of organization fields. For example, if there is a monetary field with the key `ffk9s9` stored on the account, `ffk9s9` would hold the numeric value of the field, and `ffk9s9_currency` would hold the ISO currency code that goes along with the numeric value. To find out which data fields are available, fetch one organization and list its keys.
+
+- **`pipedrive-cli organization-fields add`** - Add a new organization field
+- **`pipedrive-cli organization-fields delete`** - Delete multiple organization fields in bulk
+- **`pipedrive-cli organization-fields delete-organizationfields`** - Delete an organization field
+- **`pipedrive-cli organization-fields get`** - Get all organization fields
+- **`pipedrive-cli organization-fields get-organizationfields`** - Get one organization field
+- **`pipedrive-cli organization-fields update`** - Update an organization field
+
+### organization-relationships
+
+Organization relationships represent how different organizations are related to each other. The relationship can be hierarchical (parent-child companies) or lateral as defined by the `type` field - either `parent` or `related`.
+
+- **`pipedrive-cli organization-relationships add`** - Create an organization relationship
+- **`pipedrive-cli organization-relationships delete`** - Delete an organization relationship
+- **`pipedrive-cli organization-relationships get`** - Get all relationships for organization
+- **`pipedrive-cli organization-relationships get-organizationrelationships`** - Get one organization relationship
+- **`pipedrive-cli organization-relationships update`** - Update an organization relationship
+
+### organizations
+
+Organizations are companies and other kinds of organizations you are making deals with. Persons can be associated with organizations so that each organization can contain one or more persons.
+
+
+### permission-sets
+
+Permission sets define what users in the account can do: which actions they are allowed to perform and which features they can access. Permission sets are app-specific, where apps are large parts of functionality, e.g., sales app, which allows accessing sales data, global permissions, which oversee cross-product features (for example contacts, insights, products) or account settings, which provides access to billing, user management, company settings and security center. Some permission sets with types such as admin and regular are pre-created for the account, while other custom ones can be created by users (depending on the tier the account is on).
+
+- **`pipedrive-cli permission-sets get`** - Get all permission sets
+- **`pipedrive-cli permission-sets get-permissionsets`** - Get one permission set
+
+### person-fields
+
+Person fields represent the near-complete schema for a person in the context of the company of the authorized user. Each company can have a different schema for their persons, with various custom fields. In the context of using person fields as a schema for defining the data fields of a person, it must be kept in mind that some types of custom fields can have additional data fields which are not separate person fields per se. Such is the case with monetary, daterange and timerange fields – each of these fields will have one additional data field in addition to the one presented in the context of person fields. For example, if there is a monetary field with the key `ffk9s9` stored on the account, `ffk9s9` would hold the numeric value of the field, and `ffk9s9_currency` would hold the ISO currency code that goes along with the numeric value. To find out which data fields are available, fetch one person and list its keys.
+
+- **`pipedrive-cli person-fields add`** - Add a new person field
+- **`pipedrive-cli person-fields delete`** - Delete multiple person fields in bulk
+- **`pipedrive-cli person-fields delete-personfields`** - Delete a person field
+- **`pipedrive-cli person-fields get`** - Get all person fields
+- **`pipedrive-cli person-fields get-personfields`** - Get one person field
+- **`pipedrive-cli person-fields update`** - Update a person field
+
+### persons
+
+Persons are your contacts, the customers you are doing deals with. Each person can belong to an organization. Persons should not be confused with users.
+
+
+### pipelines
+
+Pipelines are essentially ordered collections of stages.
+
+
+### product-fields
+
+Product fields represent the near-complete schema for a product in the context of the company of the authorized user. Each company can have a different schema for their products, with various custom fields. In the context of using product fields as a schema for defining the data fields of a product, it must be kept in mind that some types of custom fields can have additional data fields which are not separate product fields per se. Such is the case with monetary, daterange and timerange fields – each of these fields will have one additional data field in addition to the one presented in the context of product fields. For example, if there is a monetary field with the key `ffk9s9` stored on the account, `ffk9s9` would hold the numeric value of the field, and `ffk9s9_currency` would hold the ISO currency code that goes along with the numeric value. To find out which data fields are available, fetch one product and list its keys.
+
+- **`pipedrive-cli product-fields add`** - Add a new product field
+- **`pipedrive-cli product-fields delete`** - Delete multiple product fields in bulk
+- **`pipedrive-cli product-fields delete-productfields`** - Delete a product field
+- **`pipedrive-cli product-fields get`** - Get all product fields
+- **`pipedrive-cli product-fields get-productfields`** - Get one product field
+- **`pipedrive-cli product-fields update`** - Update a product field
+
+### products
+
+Products are the goods or services you are dealing with. Each product can have N different price points - firstly, each product can have a price in N different currencies, and secondly, each product can have N variations of itself, each having N prices in different currencies. Note that only one price per variation per currency is supported. Products can be instantiated to deals. In the context of instatiation, a custom price, quantity, duration and discount can be applied.
+
+
+### project-templates
+
+Project templates allow you to have reusable and dynamic structure to simplify creation of a project. Project template can contain information about activities, tasks and groups that will be used when creating a project.
+
+- **`pipedrive-cli project-templates get`** - Get all project templates
+- **`pipedrive-cli project-templates get-projecttemplates`** - Get details of a template
+
+### projects
+
+Projects represent ongoing, completed or canceled projects attached to an organization, person or to deals. Each project has an owner and must be placed in a phase. Each project consists of standard data fields but can also contain a number of custom fields. The custom fields can be recognized by long hashes as keys.
+
+- **`pipedrive-cli projects add`** - Add a project
+- **`pipedrive-cli projects delete`** - Delete a project
+- **`pipedrive-cli projects get`** - Get all projects
+- **`pipedrive-cli projects get-board`** - Get details of a board
+- **`pipedrive-cli projects get-boards`** - Get all project boards
+- **`pipedrive-cli projects get-id`** - Get details of a project
+- **`pipedrive-cli projects get-phase`** - Get details of a phase
+- **`pipedrive-cli projects get-phases`** - Get project phases
+- **`pipedrive-cli projects update`** - Update a project
+
+### recents
+
+Recent changes across all item types in Pipedrive (deals, persons, etc).
+
+- **`pipedrive-cli recents get`** - Get recents
+
+### roles
+
+Roles are a part of the Visibility groups’ feature that allow the admin user to categorize other users and dictate what items they will be allowed access to see.
+
+- **`pipedrive-cli roles add`** - Add a role
+- **`pipedrive-cli roles delete`** - Delete a role
+- **`pipedrive-cli roles get`** - Get all roles
+- **`pipedrive-cli roles get-id`** - Get one role
+- **`pipedrive-cli roles update`** - Update role details
+
+### stages
+
+Stage is a logical component of a pipeline, and essentially a bucket that can hold a number of deals. In the context of the pipeline a stage belongs to, it has an order number which defines the order of stages in that pipeline.
+
+
+### tasks
+
+Tasks represent actions that need to be completed and must be associated with a project. Tasks have an optional due date, can be assigned to a user and can have subtasks.
+
+- **`pipedrive-cli tasks add`** - Add a task
+- **`pipedrive-cli tasks delete`** - Delete a task
+- **`pipedrive-cli tasks get`** - Get all tasks
+- **`pipedrive-cli tasks get-id`** - Get details of a task
+- **`pipedrive-cli tasks update`** - Update a task
+
+### user-connections
+
+Manage user connections.
+
+- **`pipedrive-cli user-connections get`** - Get all user connections
+
+### user-settings
+
+View user settings.
+
+- **`pipedrive-cli user-settings get`** - List settings of an authorized user
+
+### users
+
+Users are people with access to your Pipedrive account. A user may belong to one or many Pipedrive accounts, so deleting a user from one Pipedrive account will not remove the user from the data store if he/she is connected to multiple accounts. Users should not be confused with persons.
+
+- **`pipedrive-cli users add`** - Add a new user
+- **`pipedrive-cli users find-by-name`** - Find users by name
+- **`pipedrive-cli users get`** - Get all users
+- **`pipedrive-cli users get-current`** - Get current user data
+- **`pipedrive-cli users get-id`** - Get one user
+- **`pipedrive-cli users update`** - Update user details
+
+### webhooks
+
+See <a href="https://pipedrive.readme.io/docs/guide-for-webhooks-v2?ref=api_reference" target="_blank" rel="noopener noreferrer">the guide for Webhooks</a> for more information.
+
+- **`pipedrive-cli webhooks add`** - Create a new Webhook
+- **`pipedrive-cli webhooks delete`** - Delete existing Webhook
+- **`pipedrive-cli webhooks get`** - Get all Webhooks
+
+
+## Output Formats
+
+```bash
+# Human-readable table (default)
+pipedrive-cli activity-fields list
+
+# JSON for scripting and agents
+pipedrive-cli activity-fields list --json
+
+# Filter specific fields
+pipedrive-cli activity-fields list --json --select id,name,status
+
+# Plain tab-separated for piping
+pipedrive-cli activity-fields list --plain
+
+# Dry run (show request without sending)
+pipedrive-cli activity-fields list --dry-run
+```
+
+## Agent Usage
+
+This CLI is designed for AI agent consumption:
+
+```bash
+# All commands support --json for structured output
+pipedrive-cli activity-fields list --json --select id,name
+
+# --dry-run shows the exact API request without sending
+pipedrive-cli activity-fields list --dry-run
+
+# Non-interactive - never prompts, never pages
+# Errors go to stderr with typed exit codes
+```
+
+Exit codes: `0` success, `2` usage error, `3` not found, `4` auth error, `5` API error, `7` rate limited, `10` config error.
+
+## Health Check
+
+```bash
+pipedrive-cli doctor
+```
+
+<!-- DOCTOR_OUTPUT -->
+
+## Configuration
+
+Config file: `~/.config/pipedrive-cli/config.toml`
+
+Environment variables:
+- `PIPEDRIVE_TOKEN`
+
+## Troubleshooting
+
+**Authentication errors (exit code 4)**
+- Run `pipedrive-cli doctor` to check credentials
+- Verify the environment variable is set: `echo $PIPEDRIVE_TOKEN`
+
+**Not found errors (exit code 3)**
+- Check the resource ID is correct
+- Run the `list` command to see available items
+
+**Rate limit errors (exit code 7)**
+- The CLI auto-retries with exponential backoff
+- If persistent, wait a few minutes and try again
+
+---
+
+Generated by [CLI Printing Press](https://github.com/mvanhorn/cli-printing-press)
diff --git a/pipedrive-cli/cmd/pipedrive-cli/main.go b/pipedrive-cli/cmd/pipedrive-cli/main.go
new file mode 100644
index 00000000..efe45d17
--- /dev/null
+++ b/pipedrive-cli/cmd/pipedrive-cli/main.go
@@ -0,0 +1,17 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/USER/pipedrive-cli/internal/cli"
+)
+
+func main() {
+ if err := cli.Execute(); err != nil {
+ fmt.Fprintln(os.Stderr, err.Error())
+ os.Exit(cli.ExitCode(err))
+ }
+}
diff --git a/pipedrive-cli/go.mod b/pipedrive-cli/go.mod
new file mode 100644
index 00000000..220f425d
--- /dev/null
+++ b/pipedrive-cli/go.mod
@@ -0,0 +1,15 @@
+module github.com/USER/pipedrive-cli
+
+go 1.23
+
+require (
+ github.com/mattn/go-isatty v0.0.20
+ github.com/pelletier/go-toml/v2 v2.2.4
+ github.com/spf13/cobra v1.9.1
+)
+
+require (
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
+ github.com/spf13/pflag v1.0.6 // indirect
+ golang.org/x/sys v0.6.0 // indirect
+)
diff --git a/pipedrive-cli/go.sum b/pipedrive-cli/go.sum
new file mode 100644
index 00000000..d0bfb4e0
--- /dev/null
+++ b/pipedrive-cli/go.sum
@@ -0,0 +1,16 @@
+github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
+github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
+github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
+github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
+github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/pipedrive-cli/internal/cli/activity-fields.go b/pipedrive-cli/internal/cli/activity-fields.go
new file mode 100644
index 00000000..e1d25aad
--- /dev/null
+++ b/pipedrive-cli/internal/cli/activity-fields.go
@@ -0,0 +1,51 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newActivityFieldsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "activity-fields",
+ Short: "Activity fields represent different fields that an activity has.",
+ }
+
+ cmd.AddCommand(newActivityFieldsGetCmd(flags))
+ return cmd
+}
+
+func newActivityFieldsGetCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all activity fields",
+ Example: " pipedrive-cli activity-fields get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/activityFields"
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/activity-types.go b/pipedrive-cli/internal/cli/activity-types.go
new file mode 100644
index 00000000..2e75c7e6
--- /dev/null
+++ b/pipedrive-cli/internal/cli/activity-types.go
@@ -0,0 +1,177 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newActivityTypesCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "activity-types",
+ Short: "Activity types represent different kinds of activities that can be stored. Each activity type is presented to the...",
+ }
+
+ cmd.AddCommand(newActivityTypesAddCmd(flags))
+ cmd.AddCommand(newActivityTypesDeleteCmd(flags))
+ cmd.AddCommand(newActivityTypesGetCmd(flags))
+ cmd.AddCommand(newActivityTypesUpdateCmd(flags))
+ return cmd
+}
+
+func newActivityTypesAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyColor string
+ var bodyIconKey string
+ var bodyName string
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Add new activity type",
+ Example: " pipedrive-cli activity-types add --icon-key value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/activityTypes"
+ body := map[string]any{}
+ if bodyColor != "" {
+ body["color"] = bodyColor
+ }
+ if bodyIconKey != "" {
+ body["icon_key"] = bodyIconKey
+ }
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyColor, "color", "", "A designated color for the activity type in 6-character HEX format (e.g. `FFFFFF` for white, `000000` for black)")
+ cmd.Flags().StringVar(&bodyIconKey, "icon-key", "", "Icon graphic to use for representing this activity type")
+ _ = cmd.MarkFlagRequired("icon-key")
+ cmd.Flags().StringVar(&bodyName, "name", "", "The name of the activity type")
+ _ = cmd.MarkFlagRequired("name")
+
+ return cmd
+}
+
+func newActivityTypesDeleteCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete <id>",
+ Short: "Delete an activity type",
+ Example: " pipedrive-cli activity-types delete <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/activityTypes/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newActivityTypesGetCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all activity types",
+ Example: " pipedrive-cli activity-types get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/activityTypes"
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newActivityTypesUpdateCmd(flags *rootFlags) *cobra.Command {
+ var bodyColor string
+ var bodyIconKey string
+ var bodyName string
+ var bodyOrderNr int
+
+ cmd := &cobra.Command{
+ Use: "update <id>",
+ Short: "Update an activity type",
+ Example: " pipedrive-cli activity-types update <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/activityTypes/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyColor != "" {
+ body["color"] = bodyColor
+ }
+ if bodyIconKey != "" {
+ body["icon_key"] = bodyIconKey
+ }
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ if bodyOrderNr != 0 {
+ body["order_nr"] = bodyOrderNr
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyColor, "color", "", "A designated color for the activity type in 6-character HEX format (e.g. `FFFFFF` for white, `000000` for black)")
+ cmd.Flags().StringVar(&bodyIconKey, "icon-key", "", "Icon graphic to use for representing this activity type")
+ cmd.Flags().StringVar(&bodyName, "name", "", "The name of the activity type")
+ cmd.Flags().IntVar(&bodyOrderNr, "order-nr", 0, "An order number for this activity type. Order numbers should be used to order the types in the activity type selections.")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/auth.go b/pipedrive-cli/internal/cli/auth.go
new file mode 100644
index 00000000..c4b4b3ba
--- /dev/null
+++ b/pipedrive-cli/internal/cli/auth.go
@@ -0,0 +1,250 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "context"
+ "crypto/rand"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "net"
+ "net/http"
+ "net/url"
+ "os"
+ "os/exec"
+ "runtime"
+ "strings"
+ "time"
+
+ "github.com/USER/pipedrive-cli/internal/config"
+ "github.com/spf13/cobra"
+)
+
+func newAuthCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "auth",
+ Short: "Manage authentication",
+ }
+
+ cmd.AddCommand(newAuthLoginCmd(flags))
+ cmd.AddCommand(newAuthStatusCmd(flags))
+ cmd.AddCommand(newAuthLogoutCmd(flags))
+
+ return cmd
+}
+
+func newAuthLoginCmd(flags *rootFlags) *cobra.Command {
+ var clientID string
+ var clientSecret string
+ var port int
+
+ cmd := &cobra.Command{
+ Use: "login",
+ Short: "Authenticate via OAuth2",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if clientID == "" {
+ return fmt.Errorf("--client-id is required")
+ }
+
+ cfg, err := config.Load(flags.configPath)
+ if err != nil {
+ return err
+ }
+
+ stateBytes := make([]byte, 16)
+ if _, err := rand.Read(stateBytes); err != nil {
+ return fmt.Errorf("generating state: %w", err)
+ }
+ state := hex.EncodeToString(stateBytes)
+
+ listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
+ if err != nil {
+ return fmt.Errorf("starting callback server: %w", err)
+ }
+ defer listener.Close()
+
+ redirectURI := fmt.Sprintf("http://localhost:%d/callback", listener.Addr().(*net.TCPAddr).Port)
+
+ authURL := "https://oauth.pipedrive.com/oauth/authorize"
+ params := url.Values{
+ "client_id": {clientID},
+ "redirect_uri": {redirectURI},
+ "response_type": {"code"},
+ "state": {state},
+ "access_type": {"offline"},
+ "prompt": {"consent"},
+ }
+ scopes := []string{"activities:full", "activities:read", "admin", "base", "contact-fields:full", "contacts:full", "contacts:read", "deal-fields:full", "deals:full", "deals:read", "goals:full", "goals:read", "leads:full", "leads:read", "mail:full", "mail:read", "messengers-integration", "phone-integration", "product-fields:full", "products:full", "products:read", "projects:full", "projects:read", "recents:read", "search:read", "users:read", "video-calls", }
+ if len(scopes) > 0 {
+ params.Set("scope", strings.Join(scopes, " "))
+ }
+
+ fullURL := authURL + "?" + params.Encode()
+ fmt.Fprintf(os.Stderr, "Opening browser for authentication...\n")
+ fmt.Fprintf(os.Stderr, "If the browser doesn't open, visit:\n%s\n\n", fullURL)
+ openBrowser(fullURL)
+
+ codeCh := make(chan string, 1)
+ errCh := make(chan error, 1)
+
+ mux := http.NewServeMux()
+ mux.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) {
+ if r.URL.Query().Get("state") != state {
+ errCh <- fmt.Errorf("state mismatch")
+ http.Error(w, "State mismatch", http.StatusBadRequest)
+ return
+ }
+ if errMsg := r.URL.Query().Get("error"); errMsg != "" {
+ errCh <- fmt.Errorf("auth error: %s", errMsg)
+ http.Error(w, errMsg, http.StatusBadRequest)
+ return
+ }
+ code := r.URL.Query().Get("code")
+ if code == "" {
+ errCh <- fmt.Errorf("no code in callback")
+ http.Error(w, "No code", http.StatusBadRequest)
+ return
+ }
+ w.Header().Set("Content-Type", "text/html")
+ fmt.Fprint(w, "<html><body><h2>Authentication successful!</h2><p>You can close this tab.</p></body></html>")
+ codeCh <- code
+ })
+
+ server := &http.Server{Handler: mux}
+ go server.Serve(listener)
+
+ var code string
+ select {
+ case code = <-codeCh:
+ case err := <-errCh:
+ return err
+ case <-time.After(2 * time.Minute):
+ return fmt.Errorf("authentication timed out after 2 minutes")
+ }
+
+ server.Shutdown(context.Background())
+
+ tokenURL := "https://oauth.pipedrive.com/oauth/token"
+ tokenParams := url.Values{
+ "grant_type": {"authorization_code"},
+ "code": {code},
+ "redirect_uri": {redirectURI},
+ "client_id": {clientID},
+ }
+ if clientSecret != "" {
+ tokenParams.Set("client_secret", clientSecret)
+ }
+
+ resp, err := http.PostForm(tokenURL, tokenParams)
+ if err != nil {
+ return fmt.Errorf("exchanging code for token: %w", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode >= 400 {
+ var body map[string]any
+ if err := json.NewDecoder(resp.Body).Decode(&body); err == nil {
+ return fmt.Errorf("exchanging code for token: HTTP %d: %v", resp.StatusCode, body)
+ }
+ return fmt.Errorf("exchanging code for token: HTTP %d", resp.StatusCode)
+ }
+
+ var tokenResp struct {
+ AccessToken string `json:"access_token"`
+ RefreshToken string `json:"refresh_token"`
+ ExpiresIn int `json:"expires_in"`
+ TokenType string `json:"token_type"`
+ }
+ if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
+ return fmt.Errorf("parsing token response: %w", err)
+ }
+ if tokenResp.AccessToken == "" {
+ return fmt.Errorf("no access token in response")
+ }
+
+ expiry := time.Now().Add(time.Duration(tokenResp.ExpiresIn) * time.Second)
+ if err := cfg.SaveTokens(clientID, clientSecret, tokenResp.AccessToken, tokenResp.RefreshToken, expiry); err != nil {
+ return fmt.Errorf("saving tokens: %w", err)
+ }
+
+ fmt.Fprintf(os.Stderr, "%s Authentication successful! Token expires at %s\n", green("OK"), expiry.Format(time.RFC3339))
+ return nil
+ },
+ }
+
+ cmd.Flags().StringVar(&clientID, "client-id", os.Getenv("PIPEDRIVE_CLIENT_ID"), "OAuth2 client ID")
+ cmd.Flags().StringVar(&clientSecret, "client-secret", os.Getenv("PIPEDRIVE_CLIENT_SECRET"), "OAuth2 client secret")
+ cmd.Flags().IntVar(&port, "port", 8085, "Local callback server port")
+
+ return cmd
+}
+
+func newAuthStatusCmd(flags *rootFlags) *cobra.Command {
+ return &cobra.Command{
+ Use: "status",
+ Short: "Show authentication status",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ cfg, err := config.Load(flags.configPath)
+ if err != nil {
+ return err
+ }
+
+ w := cmd.OutOrStdout()
+ if cfg.AccessToken == "" {
+ fmt.Fprintf(w, " %s Not authenticated. Run 'auth login' to authenticate.\n", red("FAIL"))
+ return nil
+ }
+
+ if cfg.TokenExpiry.IsZero() {
+ fmt.Fprintf(w, " %s Authenticated (no expiry info)\n", green("OK"))
+ } else if time.Now().Before(cfg.TokenExpiry) {
+ fmt.Fprintf(w, " %s Authenticated (expires %s)\n", green("OK"), cfg.TokenExpiry.Format(time.RFC3339))
+ } else {
+ if cfg.RefreshToken != "" {
+ fmt.Fprintf(w, " %s Token expired (will auto-refresh on next request)\n", yellow("WARN"))
+ } else {
+ fmt.Fprintf(w, " %s Token expired. Run 'auth login' to re-authenticate.\n", red("FAIL"))
+ }
+ }
+
+ if cfg.AuthSource != "" {
+ fmt.Fprintf(w, " source: %s\n", cfg.AuthSource)
+ }
+ return nil
+ },
+ }
+}
+
+func newAuthLogoutCmd(flags *rootFlags) *cobra.Command {
+ return &cobra.Command{
+ Use: "logout",
+ Short: "Remove stored authentication tokens",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ cfg, err := config.Load(flags.configPath)
+ if err != nil {
+ return err
+ }
+ if err := cfg.ClearTokens(); err != nil {
+ return fmt.Errorf("clearing tokens: %w", err)
+ }
+ fmt.Fprintf(os.Stderr, "Logged out. Tokens removed.\n")
+ return nil
+ },
+ }
+}
+
+func openBrowser(url string) {
+ var cmd *exec.Cmd
+ switch runtime.GOOS {
+ case "darwin":
+ cmd = exec.Command("open", url)
+ case "linux":
+ cmd = exec.Command("xdg-open", url)
+ case "windows":
+ cmd = exec.Command("rundll32", "url.dll,FileProtocolHandler", url)
+ default:
+ return
+ }
+ cmd.Start()
+}
diff --git a/pipedrive-cli/internal/cli/billing.go b/pipedrive-cli/internal/cli/billing.go
new file mode 100644
index 00000000..e330c9df
--- /dev/null
+++ b/pipedrive-cli/internal/cli/billing.go
@@ -0,0 +1,51 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newBillingCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "billing",
+ Short: "Billing is responsible for handling your subscriptions, payments, plans and add-ons.",
+ }
+
+ cmd.AddCommand(newBillingGetCompanyAddonsCmd(flags))
+ return cmd
+}
+
+func newBillingGetCompanyAddonsCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-company-addons",
+ Aliases: []string{"list"},
+ Short: "Get all add-ons for a single company",
+ Example: " pipedrive-cli billing get-company-addons",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/billing/subscriptions/addons"
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/call-logs.go b/pipedrive-cli/internal/cli/call-logs.go
new file mode 100644
index 00000000..d30f2f47
--- /dev/null
+++ b/pipedrive-cli/internal/cli/call-logs.go
@@ -0,0 +1,223 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newCallLogsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "call-logs",
+ Short: "Call logs describe the outcome of a phone call managed by an integrated provider. Since these logs are also...",
+ }
+
+ cmd.AddCommand(newCallLogsAddCmd(flags))
+ cmd.AddCommand(newCallLogsDeleteCmd(flags))
+ cmd.AddCommand(newCallLogsGetCmd(flags))
+ cmd.AddCommand(newCallLogsGetUserCmd(flags))
+ cmd.AddCommand(newCallLogsRecordingsCmd(flags))
+ return cmd
+}
+
+func newCallLogsAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyActivityId int
+ var bodyDealId int
+ var bodyDuration string
+ var bodyEndTime string
+ var bodyFromPhoneNumber string
+ var bodyLeadId string
+ var bodyNote string
+ var bodyOrgId int
+ var bodyOutcome string
+ var bodyPersonId int
+ var bodyStartTime string
+ var bodySubject string
+ var bodyToPhoneNumber string
+ var bodyUserId int
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Add a call log",
+ Example: " pipedrive-cli call-logs add --end-time value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/callLogs"
+ body := map[string]any{}
+ if bodyActivityId != 0 {
+ body["activity_id"] = bodyActivityId
+ }
+ if bodyDealId != 0 {
+ body["deal_id"] = bodyDealId
+ }
+ if bodyDuration != "" {
+ body["duration"] = bodyDuration
+ }
+ if bodyEndTime != "" {
+ body["end_time"] = bodyEndTime
+ }
+ if bodyFromPhoneNumber != "" {
+ body["from_phone_number"] = bodyFromPhoneNumber
+ }
+ if bodyLeadId != "" {
+ body["lead_id"] = bodyLeadId
+ }
+ if bodyNote != "" {
+ body["note"] = bodyNote
+ }
+ if bodyOrgId != 0 {
+ body["org_id"] = bodyOrgId
+ }
+ if bodyOutcome != "" {
+ body["outcome"] = bodyOutcome
+ }
+ if bodyPersonId != 0 {
+ body["person_id"] = bodyPersonId
+ }
+ if bodyStartTime != "" {
+ body["start_time"] = bodyStartTime
+ }
+ if bodySubject != "" {
+ body["subject"] = bodySubject
+ }
+ if bodyToPhoneNumber != "" {
+ body["to_phone_number"] = bodyToPhoneNumber
+ }
+ if bodyUserId != 0 {
+ body["user_id"] = bodyUserId
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyActivityId, "activity-id", 0, "If specified, this activity will be converted into a call log, with the information provided. When this field is...")
+ cmd.Flags().IntVar(&bodyDealId, "deal-id", 0, "The ID of the deal this call is associated with. A call log can be associated with either a deal or a lead, but not...")
+ cmd.Flags().StringVar(&bodyDuration, "duration", "", "The duration of the call in seconds")
+ cmd.Flags().StringVar(&bodyEndTime, "end-time", "", "The date and time of the end of the call in UTC. Format: YYYY-MM-DD HH:MM:SS.")
+ _ = cmd.MarkFlagRequired("end-time")
+ cmd.Flags().StringVar(&bodyFromPhoneNumber, "from-phone-number", "", "The number that made the call")
+ cmd.Flags().StringVar(&bodyLeadId, "lead-id", "", "The ID of the lead in the UUID format this call is associated with. A call log can be associated with either a deal...")
+ cmd.Flags().StringVar(&bodyNote, "note", "", "The note for the call log in HTML format")
+ cmd.Flags().IntVar(&bodyOrgId, "org-id", 0, "The ID of the organization this call is associated with")
+ cmd.Flags().StringVar(&bodyOutcome, "outcome", "", "Describes the outcome of the call")
+ _ = cmd.MarkFlagRequired("outcome")
+ cmd.Flags().IntVar(&bodyPersonId, "person-id", 0, "The ID of the person this call is associated with")
+ cmd.Flags().StringVar(&bodyStartTime, "start-time", "", "The date and time of the start of the call in UTC. Format: YYYY-MM-DD HH:MM:SS.")
+ _ = cmd.MarkFlagRequired("start-time")
+ cmd.Flags().StringVar(&bodySubject, "subject", "", "The name of the activity this call is attached to")
+ cmd.Flags().StringVar(&bodyToPhoneNumber, "to-phone-number", "", "The number called")
+ _ = cmd.MarkFlagRequired("to-phone-number")
+ cmd.Flags().IntVar(&bodyUserId, "user-id", 0, "The ID of the owner of the call log. Please note that a user without account settings access cannot create call logs...")
+
+ return cmd
+}
+
+func newCallLogsDeleteCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete <id>",
+ Short: "Delete a call log",
+ Example: " pipedrive-cli call-logs delete <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/callLogs/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newCallLogsGetCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get <id>",
+ Short: "Get details of a call log",
+ Example: " pipedrive-cli call-logs get <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/callLogs/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newCallLogsGetUserCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-user",
+ Aliases: []string{"list"},
+ Short: "Get all call logs assigned to a particular user",
+ Example: " pipedrive-cli call-logs get-user",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/callLogs"
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "For pagination, the limit of entries to be returned. The upper limit is 50.")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/call-logs_recordings.go b/pipedrive-cli/internal/cli/call-logs_recordings.go
new file mode 100644
index 00000000..f87a64db
--- /dev/null
+++ b/pipedrive-cli/internal/cli/call-logs_recordings.go
@@ -0,0 +1,61 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newCallLogsRecordingsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "recordings",
+ Short: "Manage recordings",
+ }
+
+ cmd.AddCommand(newCallLogsRecordingsAddCallLogAudioFileCmd(flags))
+ return cmd
+}
+
+func newCallLogsRecordingsAddCallLogAudioFileCmd(flags *rootFlags) *cobra.Command {
+ var bodyFile string
+
+ cmd := &cobra.Command{
+ Use: "add-call-log-audio-file <id>",
+ Aliases: []string{"create"},
+ Short: "Attach an audio file to the call log",
+ Example: " pipedrive-cli call-logs recordings add-call-log-audio-file <id> --file value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/callLogs/{id}/recordings"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyFile != "" {
+ body["file"] = bodyFile
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyFile, "file", "", "Audio file supported by the HTML5 specification")
+ _ = cmd.MarkFlagRequired("file")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/channels.go b/pipedrive-cli/internal/cli/channels.go
new file mode 100644
index 00000000..f932f61d
--- /dev/null
+++ b/pipedrive-cli/internal/cli/channels.go
@@ -0,0 +1,188 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newChannelsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "channels",
+ Short: "Channels API allows you to integrate your existing messaging channels into Pipedrive through [Messaging app...",
+ }
+
+ cmd.AddCommand(newChannelsAddCmd(flags))
+ cmd.AddCommand(newChannelsDeleteCmd(flags))
+ cmd.AddCommand(newChannelsReceiveMessageCmd(flags))
+ cmd.AddCommand(newChannelsConversationsCmd(flags))
+ return cmd
+}
+
+func newChannelsAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyAvatarUrl string
+ var bodyName string
+ var bodyProviderChannelId string
+ var bodyProviderType string
+ var bodyTemplateSupport bool
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Add a channel",
+ Example: " pipedrive-cli channels add --name value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/channels"
+ body := map[string]any{}
+ if bodyAvatarUrl != "" {
+ body["avatar_url"] = bodyAvatarUrl
+ }
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ if bodyProviderChannelId != "" {
+ body["provider_channel_id"] = bodyProviderChannelId
+ }
+ if bodyProviderType != "" {
+ body["provider_type"] = bodyProviderType
+ }
+ if bodyTemplateSupport != false {
+ body["template_support"] = bodyTemplateSupport
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyAvatarUrl, "avatar-url", "", "The URL for an icon that represents your channel")
+ cmd.Flags().StringVar(&bodyName, "name", "", "The name of the channel")
+ _ = cmd.MarkFlagRequired("name")
+ cmd.Flags().StringVar(&bodyProviderChannelId, "provider-channel-id", "", "The channel ID")
+ _ = cmd.MarkFlagRequired("provider-channel-id")
+ cmd.Flags().StringVar(&bodyProviderType, "provider-type", "other", "It controls the icons (like the icon next to the conversation)")
+ cmd.Flags().BoolVar(&bodyTemplateSupport, "template-support", false, "If true, enables templates logic on UI. Requires getTemplates endpoint implemented. Find out more...")
+
+ return cmd
+}
+
+func newChannelsDeleteCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete <id>",
+ Short: "Delete a channel",
+ Example: " pipedrive-cli channels delete <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/channels/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newChannelsReceiveMessageCmd(flags *rootFlags) *cobra.Command {
+ var bodyChannelId string
+ var bodyConversationId string
+ var bodyConversationLink string
+ var bodyCreatedAt string
+ var bodyId string
+ var bodyMessage string
+ var bodyReplyBy string
+ var bodySenderId string
+ var bodyStatus string
+
+ cmd := &cobra.Command{
+ Use: "receive-message",
+ Short: "Receives an incoming message",
+ Example: " pipedrive-cli channels receive-message --channel-id value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/channels/messages/receive"
+ body := map[string]any{}
+ if bodyChannelId != "" {
+ body["channel_id"] = bodyChannelId
+ }
+ if bodyConversationId != "" {
+ body["conversation_id"] = bodyConversationId
+ }
+ if bodyConversationLink != "" {
+ body["conversation_link"] = bodyConversationLink
+ }
+ if bodyCreatedAt != "" {
+ body["created_at"] = bodyCreatedAt
+ }
+ if bodyId != "" {
+ body["id"] = bodyId
+ }
+ if bodyMessage != "" {
+ body["message"] = bodyMessage
+ }
+ if bodyReplyBy != "" {
+ body["reply_by"] = bodyReplyBy
+ }
+ if bodySenderId != "" {
+ body["sender_id"] = bodySenderId
+ }
+ if bodyStatus != "" {
+ body["status"] = bodyStatus
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyChannelId, "channel-id", "", "The channel ID as in the provider")
+ _ = cmd.MarkFlagRequired("channel-id")
+ cmd.Flags().StringVar(&bodyConversationId, "conversation-id", "", "The ID of the conversation")
+ _ = cmd.MarkFlagRequired("conversation-id")
+ cmd.Flags().StringVar(&bodyConversationLink, "conversation-link", "", "A URL that can open the conversation in the provider's side")
+ cmd.Flags().StringVar(&bodyCreatedAt, "created-at", "", "The date and time when the message was created in the provider, in UTC. Format: YYYY-MM-DD HH:MM")
+ _ = cmd.MarkFlagRequired("created-at")
+ cmd.Flags().StringVar(&bodyId, "id", "", "The ID of the message")
+ _ = cmd.MarkFlagRequired("id")
+ cmd.Flags().StringVar(&bodyMessage, "message", "", "The body of the message")
+ _ = cmd.MarkFlagRequired("message")
+ cmd.Flags().StringVar(&bodyReplyBy, "reply-by", "", "The date and time when the message can no longer receive a reply, in UTC. Format: YYYY-MM-DD HH:MM")
+ cmd.Flags().StringVar(&bodySenderId, "sender-id", "", "The ID of the provider's user that sent the message")
+ _ = cmd.MarkFlagRequired("sender-id")
+ cmd.Flags().StringVar(&bodyStatus, "status", "", "The status of the message")
+ _ = cmd.MarkFlagRequired("status")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/channels_conversations.go b/pipedrive-cli/internal/cli/channels_conversations.go
new file mode 100644
index 00000000..6d00311d
--- /dev/null
+++ b/pipedrive-cli/internal/cli/channels_conversations.go
@@ -0,0 +1,57 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newChannelsConversationsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "conversations",
+ Short: "Manage conversations",
+ }
+
+ cmd.AddCommand(newChannelsConversationsDeleteCmd(flags))
+ return cmd
+}
+
+func newChannelsConversationsDeleteCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete <channel-id> <conversation-id>",
+ Short: "Delete a conversation",
+ Example: " pipedrive-cli channels conversations delete <channel-id> <conversation-id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/channels/{channel-id}/conversations/{conversation-id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("channel-id is required"))
+ }
+ path = replacePathParam(path, "channel-id", args[0])
+ if len(args) < 2 {
+ return usageErr(fmt.Errorf("conversation-id is required"))
+ }
+ path = replacePathParam(path, "conversation-id", args[1])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/currencies.go b/pipedrive-cli/internal/cli/currencies.go
new file mode 100644
index 00000000..db79c24d
--- /dev/null
+++ b/pipedrive-cli/internal/cli/currencies.go
@@ -0,0 +1,56 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newCurrenciesCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "currencies",
+ Short: "Supported currencies which can be used to represent the monetary value of a deal, or a value of any monetary type...",
+ }
+
+ cmd.AddCommand(newCurrenciesGetCmd(flags))
+ return cmd
+}
+
+func newCurrenciesGetCmd(flags *rootFlags) *cobra.Command {
+ var flagTerm string
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all supported currencies",
+ Example: " pipedrive-cli currencies get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/currencies"
+ params := map[string]string{}
+ if flagTerm != "" {
+ params["term"] = fmt.Sprintf("%v", flagTerm)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagTerm, "term", "", "Optional search term that is searched for from currency's name and/or code")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/deal-fields.go b/pipedrive-cli/internal/cli/deal-fields.go
new file mode 100644
index 00000000..d98cc3a9
--- /dev/null
+++ b/pipedrive-cli/internal/cli/deal-fields.go
@@ -0,0 +1,235 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newDealFieldsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "deal-fields",
+ Short: "Deal fields represent the near-complete schema for a deal in the context of the company of the authorized user. Each...",
+ }
+
+ cmd.AddCommand(newDealFieldsAddCmd(flags))
+ cmd.AddCommand(newDealFieldsDeleteCmd(flags))
+ cmd.AddCommand(newDealFieldsDeleteDealfieldsCmd(flags))
+ cmd.AddCommand(newDealFieldsGetCmd(flags))
+ cmd.AddCommand(newDealFieldsGetDealfieldsCmd(flags))
+ cmd.AddCommand(newDealFieldsUpdateCmd(flags))
+ return cmd
+}
+
+func newDealFieldsAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyAddVisibleFlag bool
+ var bodyFieldType string
+ var bodyName string
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Add a new deal field",
+ Example: " pipedrive-cli deal-fields add --field-type value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/dealFields"
+ body := map[string]any{}
+ if bodyAddVisibleFlag != false {
+ body["add_visible_flag"] = bodyAddVisibleFlag
+ }
+ if bodyFieldType != "" {
+ body["field_type"] = bodyFieldType
+ }
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().BoolVar(&bodyAddVisibleFlag, "add-visible-flag", true, "Whether the field is available in the 'add new' modal or not (both in the web and mobile app)")
+ cmd.Flags().StringVar(&bodyFieldType, "field-type", "", "The type of the field<table><tr><th>Value</th><th>Description</th></tr><tr><td>`address`</td><td>Address...")
+ _ = cmd.MarkFlagRequired("field-type")
+ cmd.Flags().StringVar(&bodyName, "name", "", "The name of the field")
+ _ = cmd.MarkFlagRequired("name")
+
+ return cmd
+}
+
+func newDealFieldsDeleteCmd(flags *rootFlags) *cobra.Command {
+ var flagIds string
+
+ cmd := &cobra.Command{
+ Use: "delete",
+ Short: "Delete multiple deal fields in bulk",
+ Example: " pipedrive-cli deal-fields delete",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/dealFields"
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagIds, "ids", "", "The comma-separated field IDs to delete")
+ _ = cmd.MarkFlagRequired("ids")
+
+ return cmd
+}
+
+func newDealFieldsDeleteDealfieldsCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete-dealfields <id>",
+ Short: "Delete a deal field",
+ Example: " pipedrive-cli deal-fields delete-dealfields <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/dealFields/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newDealFieldsGetCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all deal fields",
+ Example: " pipedrive-cli deal-fields get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/dealFields"
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
+func newDealFieldsGetDealfieldsCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-dealfields <id>",
+ Short: "Get one deal field",
+ Example: " pipedrive-cli deal-fields get-dealfields <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/dealFields/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newDealFieldsUpdateCmd(flags *rootFlags) *cobra.Command {
+ var bodyAddVisibleFlag bool
+ var bodyName string
+
+ cmd := &cobra.Command{
+ Use: "update <id>",
+ Short: "Update a deal field",
+ Example: " pipedrive-cli deal-fields update <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/dealFields/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyAddVisibleFlag != false {
+ body["add_visible_flag"] = bodyAddVisibleFlag
+ }
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().BoolVar(&bodyAddVisibleFlag, "add-visible-flag", true, "Whether the field is available in 'add new' modal or not (both in web and mobile app)")
+ cmd.Flags().StringVar(&bodyName, "name", "", "The name of the field")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/deals.go b/pipedrive-cli/internal/cli/deals.go
new file mode 100644
index 00000000..44481232
--- /dev/null
+++ b/pipedrive-cli/internal/cli/deals.go
@@ -0,0 +1,355 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newDealsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "deals",
+ Short: "Deals represent ongoing, lost or won sales to an organization or to a person. Each deal has a monetary value and...",
+ }
+
+ cmd.AddCommand(newDealsGetArchivedCmd(flags))
+ cmd.AddCommand(newDealsGetArchivedSummaryCmd(flags))
+ cmd.AddCommand(newDealsGetArchivedTimelineCmd(flags))
+ cmd.AddCommand(newDealsGetSummaryCmd(flags))
+ cmd.AddCommand(newDealsGetTimelineCmd(flags))
+ cmd.AddCommand(newDealsChangelogCmd(flags))
+ cmd.AddCommand(newDealsDuplicateCmd(flags))
+ cmd.AddCommand(newDealsFilesCmd(flags))
+ cmd.AddCommand(newDealsFlowCmd(flags))
+ cmd.AddCommand(newDealsFollowersCmd(flags))
+ cmd.AddCommand(newDealsMailMessagesCmd(flags))
+ cmd.AddCommand(newDealsMergeCmd(flags))
+ cmd.AddCommand(newDealsParticipantsCmd(flags))
+ cmd.AddCommand(newDealsParticipantsChangelogCmd(flags))
+ cmd.AddCommand(newDealsPermittedUsersCmd(flags))
+ return cmd
+}
+
+func newDealsGetArchivedCmd(flags *rootFlags) *cobra.Command {
+ var flagUserId int
+ var flagFilterId int
+ var flagPersonId int
+ var flagOrgId int
+ var flagProductId int
+ var flagPipelineId int
+ var flagStageId int
+ var flagStatus string
+ var flagStart int
+ var flagLimit int
+ var flagSort string
+ var flagOwnedByYou float64
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-archived",
+ Aliases: []string{"list"},
+ Short: "Get all archived deals",
+ Example: " pipedrive-cli deals get-archived",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/archived"
+ data, err := paginatedGet(c, path, map[string]string{
+ "user_id": fmt.Sprintf("%v", flagUserId),
+ "filter_id": fmt.Sprintf("%v", flagFilterId),
+ "person_id": fmt.Sprintf("%v", flagPersonId),
+ "org_id": fmt.Sprintf("%v", flagOrgId),
+ "product_id": fmt.Sprintf("%v", flagProductId),
+ "pipeline_id": fmt.Sprintf("%v", flagPipelineId),
+ "stage_id": fmt.Sprintf("%v", flagStageId),
+ "status": fmt.Sprintf("%v", flagStatus),
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ "sort": fmt.Sprintf("%v", flagSort),
+ "owned_by_you": fmt.Sprintf("%v", flagOwnedByYou),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagUserId, "user-id", 0, "If supplied, only deals matching the given user will be returned. However, `filter_id` and `owned_by_you` takes...")
+ cmd.Flags().IntVar(&flagFilterId, "filter-id", 0, "The ID of the filter to use")
+ cmd.Flags().IntVar(&flagPersonId, "person-id", 0, "If supplied, only deals linked to the specified person are returned. If filter_id is provided, this is ignored.")
+ cmd.Flags().IntVar(&flagOrgId, "org-id", 0, "If supplied, only deals linked to the specified organization are returned. If filter_id is provided, this is ignored.")
+ cmd.Flags().IntVar(&flagProductId, "product-id", 0, "If supplied, only deals linked to the specified product are returned. If filter_id is provided, this is ignored.")
+ cmd.Flags().IntVar(&flagPipelineId, "pipeline-id", 0, "If supplied, only deals in the specified pipeline are returned. If filter_id is provided, this is ignored.")
+ cmd.Flags().IntVar(&flagStageId, "stage-id", 0, "If supplied, only deals in the specified stage are returned. If filter_id is provided, this is ignored.")
+ cmd.Flags().StringVar(&flagStatus, "status", "all_not_deleted", "Only fetch deals with a specific status. If omitted, all not deleted deals are returned. If set to deleted, deals...")
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().StringVar(&flagSort, "sort", "", "The field names and sorting mode separated by a comma (`field_name_1 ASC`, `field_name_2 DESC`). Only first-level...")
+ cmd.Flags().Float64Var(&flagOwnedByYou, "owned-by-you", 0.0, "When supplied, only deals owned by you are returned. However, `filter_id` takes precedence over `owned_by_you` when...")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
+func newDealsGetArchivedSummaryCmd(flags *rootFlags) *cobra.Command {
+ var flagStatus string
+ var flagFilterId int
+ var flagUserId int
+ var flagPipelineId int
+ var flagStageId int
+
+ cmd := &cobra.Command{
+ Use: "get-archived-summary",
+ Short: "Get archived deals summary",
+ Example: " pipedrive-cli deals get-archived-summary",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/summary/archived"
+ params := map[string]string{}
+ if flagStatus != "" {
+ params["status"] = fmt.Sprintf("%v", flagStatus)
+ }
+ if flagFilterId != 0 {
+ params["filter_id"] = fmt.Sprintf("%v", flagFilterId)
+ }
+ if flagUserId != 0 {
+ params["user_id"] = fmt.Sprintf("%v", flagUserId)
+ }
+ if flagPipelineId != 0 {
+ params["pipeline_id"] = fmt.Sprintf("%v", flagPipelineId)
+ }
+ if flagStageId != 0 {
+ params["stage_id"] = fmt.Sprintf("%v", flagStageId)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagStatus, "status", "", "Only fetch deals with a specific status. open = Open, won = Won, lost = Lost.")
+ cmd.Flags().IntVar(&flagFilterId, "filter-id", 0, "<code>user_id</code> will not be considered. Only deals matching the given filter will be returned.")
+ cmd.Flags().IntVar(&flagUserId, "user-id", 0, "Only deals matching the given user will be returned. `user_id` will not be considered if you use `filter_id`.")
+ cmd.Flags().IntVar(&flagPipelineId, "pipeline-id", 0, "Only deals within the given pipeline will be returned")
+ cmd.Flags().IntVar(&flagStageId, "stage-id", 0, "Only deals within the given stage will be returned")
+
+ return cmd
+}
+
+func newDealsGetArchivedTimelineCmd(flags *rootFlags) *cobra.Command {
+ var flagStartDate string
+ var flagInterval string
+ var flagAmount int
+ var flagFieldKey string
+ var flagUserId int
+ var flagPipelineId int
+ var flagFilterId int
+ var flagExcludeDeals float64
+ var flagTotalsConvertCurrency string
+
+ cmd := &cobra.Command{
+ Use: "get-archived-timeline",
+ Short: "Get archived deals timeline",
+ Example: " pipedrive-cli deals get-archived-timeline",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/timeline/archived"
+ params := map[string]string{}
+ if flagStartDate != "" {
+ params["start_date"] = fmt.Sprintf("%v", flagStartDate)
+ }
+ if flagInterval != "" {
+ params["interval"] = fmt.Sprintf("%v", flagInterval)
+ }
+ if flagAmount != 0 {
+ params["amount"] = fmt.Sprintf("%v", flagAmount)
+ }
+ if flagFieldKey != "" {
+ params["field_key"] = fmt.Sprintf("%v", flagFieldKey)
+ }
+ if flagUserId != 0 {
+ params["user_id"] = fmt.Sprintf("%v", flagUserId)
+ }
+ if flagPipelineId != 0 {
+ params["pipeline_id"] = fmt.Sprintf("%v", flagPipelineId)
+ }
+ if flagFilterId != 0 {
+ params["filter_id"] = fmt.Sprintf("%v", flagFilterId)
+ }
+ if flagExcludeDeals != 0.0 {
+ params["exclude_deals"] = fmt.Sprintf("%v", flagExcludeDeals)
+ }
+ if flagTotalsConvertCurrency != "" {
+ params["totals_convert_currency"] = fmt.Sprintf("%v", flagTotalsConvertCurrency)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagStartDate, "start-date", "", "The date when the first interval starts. Format: YYYY-MM-DD.")
+ _ = cmd.MarkFlagRequired("start-date")
+ cmd.Flags().StringVar(&flagInterval, "interval", "", "The type of the interval<table><tr><th>Value</th><th>Description</th></tr><tr><td>`day`</td><td>Day</td></tr><tr><td>...")
+ _ = cmd.MarkFlagRequired("interval")
+ cmd.Flags().IntVar(&flagAmount, "amount", 0, "The number of given intervals, starting from `start_date`, to fetch. E.g. 3 (months).")
+ _ = cmd.MarkFlagRequired("amount")
+ cmd.Flags().StringVar(&flagFieldKey, "field-key", "", "The date field key which deals will be retrieved from")
+ _ = cmd.MarkFlagRequired("field-key")
+ cmd.Flags().IntVar(&flagUserId, "user-id", 0, "If supplied, only deals matching the given user will be returned")
+ cmd.Flags().IntVar(&flagPipelineId, "pipeline-id", 0, "If supplied, only deals matching the given pipeline will be returned")
+ cmd.Flags().IntVar(&flagFilterId, "filter-id", 0, "If supplied, only deals matching the given filter will be returned")
+ cmd.Flags().Float64Var(&flagExcludeDeals, "exclude-deals", 0.0, "Whether to exclude deals list (1) or not (0). Note that when deals are excluded, the timeline summary (counts and...")
+ cmd.Flags().StringVar(&flagTotalsConvertCurrency, "totals-convert-currency", "", "The 3-letter currency code of any of the supported currencies. When supplied, `totals_converted` is returned per...")
+
+ return cmd
+}
+
+func newDealsGetSummaryCmd(flags *rootFlags) *cobra.Command {
+ var flagStatus string
+ var flagFilterId int
+ var flagUserId int
+ var flagPipelineId int
+ var flagStageId int
+
+ cmd := &cobra.Command{
+ Use: "get-summary",
+ Short: "Get deals summary",
+ Example: " pipedrive-cli deals get-summary",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/summary"
+ params := map[string]string{}
+ if flagStatus != "" {
+ params["status"] = fmt.Sprintf("%v", flagStatus)
+ }
+ if flagFilterId != 0 {
+ params["filter_id"] = fmt.Sprintf("%v", flagFilterId)
+ }
+ if flagUserId != 0 {
+ params["user_id"] = fmt.Sprintf("%v", flagUserId)
+ }
+ if flagPipelineId != 0 {
+ params["pipeline_id"] = fmt.Sprintf("%v", flagPipelineId)
+ }
+ if flagStageId != 0 {
+ params["stage_id"] = fmt.Sprintf("%v", flagStageId)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagStatus, "status", "", "Only fetch deals with a specific status. open = Open, won = Won, lost = Lost.")
+ cmd.Flags().IntVar(&flagFilterId, "filter-id", 0, "<code>user_id</code> will not be considered. Only deals matching the given filter will be returned.")
+ cmd.Flags().IntVar(&flagUserId, "user-id", 0, "Only deals matching the given user will be returned. `user_id` will not be considered if you use `filter_id`.")
+ cmd.Flags().IntVar(&flagPipelineId, "pipeline-id", 0, "Only deals within the given pipeline will be returned")
+ cmd.Flags().IntVar(&flagStageId, "stage-id", 0, "Only deals within the given stage will be returned")
+
+ return cmd
+}
+
+func newDealsGetTimelineCmd(flags *rootFlags) *cobra.Command {
+ var flagStartDate string
+ var flagInterval string
+ var flagAmount int
+ var flagFieldKey string
+ var flagUserId int
+ var flagPipelineId int
+ var flagFilterId int
+ var flagExcludeDeals float64
+ var flagTotalsConvertCurrency string
+
+ cmd := &cobra.Command{
+ Use: "get-timeline",
+ Short: "Get deals timeline",
+ Example: " pipedrive-cli deals get-timeline",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/timeline"
+ params := map[string]string{}
+ if flagStartDate != "" {
+ params["start_date"] = fmt.Sprintf("%v", flagStartDate)
+ }
+ if flagInterval != "" {
+ params["interval"] = fmt.Sprintf("%v", flagInterval)
+ }
+ if flagAmount != 0 {
+ params["amount"] = fmt.Sprintf("%v", flagAmount)
+ }
+ if flagFieldKey != "" {
+ params["field_key"] = fmt.Sprintf("%v", flagFieldKey)
+ }
+ if flagUserId != 0 {
+ params["user_id"] = fmt.Sprintf("%v", flagUserId)
+ }
+ if flagPipelineId != 0 {
+ params["pipeline_id"] = fmt.Sprintf("%v", flagPipelineId)
+ }
+ if flagFilterId != 0 {
+ params["filter_id"] = fmt.Sprintf("%v", flagFilterId)
+ }
+ if flagExcludeDeals != 0.0 {
+ params["exclude_deals"] = fmt.Sprintf("%v", flagExcludeDeals)
+ }
+ if flagTotalsConvertCurrency != "" {
+ params["totals_convert_currency"] = fmt.Sprintf("%v", flagTotalsConvertCurrency)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagStartDate, "start-date", "", "The date when the first interval starts. Format: YYYY-MM-DD.")
+ _ = cmd.MarkFlagRequired("start-date")
+ cmd.Flags().StringVar(&flagInterval, "interval", "", "The type of the interval<table><tr><th>Value</th><th>Description</th></tr><tr><td>`day`</td><td>Day</td></tr><tr><td>...")
+ _ = cmd.MarkFlagRequired("interval")
+ cmd.Flags().IntVar(&flagAmount, "amount", 0, "The number of given intervals, starting from `start_date`, to fetch. E.g. 3 (months).")
+ _ = cmd.MarkFlagRequired("amount")
+ cmd.Flags().StringVar(&flagFieldKey, "field-key", "", "The date field key which deals will be retrieved from")
+ _ = cmd.MarkFlagRequired("field-key")
+ cmd.Flags().IntVar(&flagUserId, "user-id", 0, "If supplied, only deals matching the given user will be returned")
+ cmd.Flags().IntVar(&flagPipelineId, "pipeline-id", 0, "If supplied, only deals matching the given pipeline will be returned")
+ cmd.Flags().IntVar(&flagFilterId, "filter-id", 0, "If supplied, only deals matching the given filter will be returned")
+ cmd.Flags().Float64Var(&flagExcludeDeals, "exclude-deals", 0.0, "Whether to exclude deals list (1) or not (0). Note that when deals are excluded, the timeline summary (counts and...")
+ cmd.Flags().StringVar(&flagTotalsConvertCurrency, "totals-convert-currency", "", "The 3-letter currency code of any of the supported currencies. When supplied, `totals_converted` is returned per...")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/deals_changelog.go b/pipedrive-cli/internal/cli/deals_changelog.go
new file mode 100644
index 00000000..901d8556
--- /dev/null
+++ b/pipedrive-cli/internal/cli/deals_changelog.go
@@ -0,0 +1,63 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newDealsChangelogCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "changelog",
+ Short: "Manage changelog",
+ }
+
+ cmd.AddCommand(newDealsChangelogGetDealCmd(flags))
+ return cmd
+}
+
+func newDealsChangelogGetDealCmd(flags *rootFlags) *cobra.Command {
+ var flagCursor string
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-deal <id>",
+ Aliases: []string{"get"},
+ Short: "List updates about deal field values",
+ Example: " pipedrive-cli deals changelog get-deal <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/{id}/changelog"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "cursor": fmt.Sprintf("%v", flagCursor),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "cursor", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagCursor, "cursor", "", "For pagination, the marker (an opaque string value) representing the first item on the next page")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/deals_duplicate.go b/pipedrive-cli/internal/cli/deals_duplicate.go
new file mode 100644
index 00000000..103dbcfe
--- /dev/null
+++ b/pipedrive-cli/internal/cli/deals_duplicate.go
@@ -0,0 +1,55 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newDealsDuplicateCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "duplicate",
+ Short: "Manage duplicate",
+ }
+
+ cmd.AddCommand(newDealsDuplicateDealCmd(flags))
+ return cmd
+}
+
+func newDealsDuplicateDealCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "deal <id>",
+ Aliases: []string{"create"},
+ Short: "Duplicate deal",
+ Example: " pipedrive-cli deals duplicate deal <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/{id}/duplicate"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/deals_files.go b/pipedrive-cli/internal/cli/deals_files.go
new file mode 100644
index 00000000..43254a08
--- /dev/null
+++ b/pipedrive-cli/internal/cli/deals_files.go
@@ -0,0 +1,66 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newDealsFilesCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "files",
+ Short: "Files are documents of any kind (images, spreadsheets, text files, etc.) that are uploaded to Pipedrive, and usually...",
+ }
+
+ cmd.AddCommand(newDealsFilesGetDealCmd(flags))
+ return cmd
+}
+
+func newDealsFilesGetDealCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagSort string
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-deal <id>",
+ Aliases: []string{"get"},
+ Short: "List files attached to a deal",
+ Example: " pipedrive-cli deals files get-deal <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/{id}/files"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ "sort": fmt.Sprintf("%v", flagSort),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page. Please note that a maximum value of 100 is allowed.")
+ cmd.Flags().StringVar(&flagSort, "sort", "", "Supported fields: `id`, `update_time`")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/deals_flow.go b/pipedrive-cli/internal/cli/deals_flow.go
new file mode 100644
index 00000000..0a6ec72b
--- /dev/null
+++ b/pipedrive-cli/internal/cli/deals_flow.go
@@ -0,0 +1,69 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newDealsFlowCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "flow",
+ Short: "Manage flow",
+ }
+
+ cmd.AddCommand(newDealsFlowGetDealUpdatesCmd(flags))
+ return cmd
+}
+
+func newDealsFlowGetDealUpdatesCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAllChanges string
+ var flagItems string
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-deal-updates <id>",
+ Aliases: []string{"get"},
+ Short: "List updates about a deal",
+ Example: " pipedrive-cli deals flow get-deal-updates <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/{id}/flow"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ "all_changes": fmt.Sprintf("%v", flagAllChanges),
+ "items": fmt.Sprintf("%v", flagItems),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().StringVar(&flagAllChanges, "all-changes", "", "Whether to show custom field updates or not. 1 = Include custom field changes. If omitted returns changes without...")
+ cmd.Flags().StringVar(&flagItems, "items", "", "A comma-separated string for filtering out item specific updates. (Possible values - call, activity,...")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/deals_followers.go b/pipedrive-cli/internal/cli/deals_followers.go
new file mode 100644
index 00000000..e7b2cd43
--- /dev/null
+++ b/pipedrive-cli/internal/cli/deals_followers.go
@@ -0,0 +1,128 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newDealsFollowersCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "followers",
+ Short: "Manage followers",
+ }
+
+ cmd.AddCommand(newDealsFollowersAddDealCmd(flags))
+ cmd.AddCommand(newDealsFollowersDeleteDealCmd(flags))
+ cmd.AddCommand(newDealsFollowersGetDealCmd(flags))
+ return cmd
+}
+
+func newDealsFollowersAddDealCmd(flags *rootFlags) *cobra.Command {
+ var bodyUserId int
+
+ cmd := &cobra.Command{
+ Use: "add-deal <id>",
+ Aliases: []string{"create"},
+ Short: "Add a follower to a deal",
+ Example: " pipedrive-cli deals followers add-deal <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/{id}/followers"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyUserId != 0 {
+ body["user_id"] = bodyUserId
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyUserId, "user-id", 0, "The ID of the user")
+ _ = cmd.MarkFlagRequired("user-id")
+
+ return cmd
+}
+
+func newDealsFollowersDeleteDealCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete-deal <id> <follower_id>",
+ Aliases: []string{"delete"},
+ Short: "Delete a follower from a deal",
+ Example: " pipedrive-cli deals followers delete-deal <id> <follower_id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/{id}/followers/{follower_id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ if len(args) < 2 {
+ return usageErr(fmt.Errorf("follower_id is required"))
+ }
+ path = replacePathParam(path, "follower_id", args[1])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newDealsFollowersGetDealCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-deal <id>",
+ Aliases: []string{"get"},
+ Short: "List followers of a deal",
+ Example: " pipedrive-cli deals followers get-deal <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/{id}/followers"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/deals_mail-messages.go b/pipedrive-cli/internal/cli/deals_mail-messages.go
new file mode 100644
index 00000000..34143615
--- /dev/null
+++ b/pipedrive-cli/internal/cli/deals_mail-messages.go
@@ -0,0 +1,63 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newDealsMailMessagesCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "mail-messages",
+ Short: "Manage mail messages",
+ }
+
+ cmd.AddCommand(newDealsMailMessagesGetDealCmd(flags))
+ return cmd
+}
+
+func newDealsMailMessagesGetDealCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-deal <id>",
+ Aliases: []string{"get"},
+ Short: "List mail messages associated with a deal",
+ Example: " pipedrive-cli deals mail-messages get-deal <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/{id}/mailMessages"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/deals_merge.go b/pipedrive-cli/internal/cli/deals_merge.go
new file mode 100644
index 00000000..24cc19ba
--- /dev/null
+++ b/pipedrive-cli/internal/cli/deals_merge.go
@@ -0,0 +1,61 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newDealsMergeCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "merge",
+ Short: "Manage merge",
+ }
+
+ cmd.AddCommand(newDealsMergeDealsCmd(flags))
+ return cmd
+}
+
+func newDealsMergeDealsCmd(flags *rootFlags) *cobra.Command {
+ var bodyMergeWithId int
+
+ cmd := &cobra.Command{
+ Use: "deals <id>",
+ Aliases: []string{"update"},
+ Short: "Merge two deals",
+ Example: " pipedrive-cli deals merge deals <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/{id}/merge"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyMergeWithId != 0 {
+ body["merge_with_id"] = bodyMergeWithId
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyMergeWithId, "merge-with-id", 0, "The ID of the deal that the deal will be merged with")
+ _ = cmd.MarkFlagRequired("merge-with-id")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/deals_participants-changelog.go b/pipedrive-cli/internal/cli/deals_participants-changelog.go
new file mode 100644
index 00000000..7b07a4ab
--- /dev/null
+++ b/pipedrive-cli/internal/cli/deals_participants-changelog.go
@@ -0,0 +1,63 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newDealsParticipantsChangelogCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "participants-changelog",
+ Short: "Manage participants changelog",
+ }
+
+ cmd.AddCommand(newDealsParticipantsChangelogGetDealCmd(flags))
+ return cmd
+}
+
+func newDealsParticipantsChangelogGetDealCmd(flags *rootFlags) *cobra.Command {
+ var flagLimit int
+ var flagCursor string
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-deal <id>",
+ Aliases: []string{"get"},
+ Short: "List updates about participants of a deal",
+ Example: " pipedrive-cli deals participants-changelog get-deal <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/{id}/participantsChangelog"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "limit": fmt.Sprintf("%v", flagLimit),
+ "cursor": fmt.Sprintf("%v", flagCursor),
+ }, flagAll, "cursor", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().StringVar(&flagCursor, "cursor", "", "For pagination, the marker (an opaque string value) representing the first item on the next page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/deals_participants.go b/pipedrive-cli/internal/cli/deals_participants.go
new file mode 100644
index 00000000..fbe6e167
--- /dev/null
+++ b/pipedrive-cli/internal/cli/deals_participants.go
@@ -0,0 +1,136 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newDealsParticipantsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "participants",
+ Short: "Manage participants",
+ }
+
+ cmd.AddCommand(newDealsParticipantsAddDealCmd(flags))
+ cmd.AddCommand(newDealsParticipantsDeleteDealCmd(flags))
+ cmd.AddCommand(newDealsParticipantsGetDealCmd(flags))
+ return cmd
+}
+
+func newDealsParticipantsAddDealCmd(flags *rootFlags) *cobra.Command {
+ var bodyPersonId int
+
+ cmd := &cobra.Command{
+ Use: "add-deal <id>",
+ Aliases: []string{"create"},
+ Short: "Add a participant to a deal",
+ Example: " pipedrive-cli deals participants add-deal <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/{id}/participants"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyPersonId != 0 {
+ body["person_id"] = bodyPersonId
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyPersonId, "person-id", 0, "The ID of the person")
+ _ = cmd.MarkFlagRequired("person-id")
+
+ return cmd
+}
+
+func newDealsParticipantsDeleteDealCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete-deal <id> <deal_participant_id>",
+ Aliases: []string{"delete"},
+ Short: "Delete a participant from a deal",
+ Example: " pipedrive-cli deals participants delete-deal <id> <deal_participant_id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/{id}/participants/{deal_participant_id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ if len(args) < 2 {
+ return usageErr(fmt.Errorf("deal_participant_id is required"))
+ }
+ path = replacePathParam(path, "deal_participant_id", args[1])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newDealsParticipantsGetDealCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-deal <id>",
+ Aliases: []string{"get"},
+ Short: "List participants of a deal",
+ Example: " pipedrive-cli deals participants get-deal <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/{id}/participants"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/deals_permitted-users.go b/pipedrive-cli/internal/cli/deals_permitted-users.go
new file mode 100644
index 00000000..badb8bbd
--- /dev/null
+++ b/pipedrive-cli/internal/cli/deals_permitted-users.go
@@ -0,0 +1,55 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newDealsPermittedUsersCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "permitted-users",
+ Short: "Manage permitted users",
+ }
+
+ cmd.AddCommand(newDealsPermittedUsersGetDealUsersCmd(flags))
+ return cmd
+}
+
+func newDealsPermittedUsersGetDealUsersCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-deal-users <id>",
+ Aliases: []string{"get"},
+ Short: "List permitted users",
+ Example: " pipedrive-cli deals permitted-users get-deal-users <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/deals/{id}/permittedUsers"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/doctor.go b/pipedrive-cli/internal/cli/doctor.go
new file mode 100644
index 00000000..423f1f05
--- /dev/null
+++ b/pipedrive-cli/internal/cli/doctor.go
@@ -0,0 +1,121 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/USER/pipedrive-cli/internal/config"
+ "github.com/spf13/cobra"
+)
+
+func newDoctorCmd(flags *rootFlags) *cobra.Command {
+ return &cobra.Command{
+ Use: "doctor",
+ Short: "Check CLI health",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ report := map[string]any{}
+
+ // Check config
+ cfg, err := config.Load(flags.configPath)
+ if err != nil {
+ report["config"] = fmt.Sprintf("error: %s", err)
+ } else {
+ report["config"] = "ok"
+ report["config_path"] = cfg.Path
+ report["base_url"] = cfg.BaseURL
+ }
+
+ // Check auth
+ if cfg != nil {
+ header := cfg.AuthHeader()
+ if header == "" {
+ report["auth"] = "not configured"
+ } else {
+ report["auth"] = "configured"
+ report["auth_source"] = cfg.AuthSource
+ }
+ }
+
+ // Check API connectivity
+ if cfg != nil && cfg.BaseURL != "" {
+ httpClient := &http.Client{Timeout: 5 * time.Second}
+
+ // Try common health-check paths in order
+ paths := []string{
+ "",
+ "/health",
+ "/healthz",
+ "/status",
+ "/ping",
+ }
+
+ reached := false
+ for _, p := range paths {
+ url := strings.TrimRight(cfg.BaseURL, "/") + p
+ resp, err := httpClient.Get(url)
+ if err != nil {
+ continue
+ }
+ resp.Body.Close()
+ if resp.StatusCode >= 200 && resp.StatusCode < 400 {
+ report["api"] = fmt.Sprintf("reachable (HTTP %d)", resp.StatusCode)
+ reached = true
+ break
+ }
+ }
+
+ if !reached {
+ // Fall back to reporting the base URL status
+ resp, err := httpClient.Get(cfg.BaseURL)
+ if err != nil {
+ report["api"] = fmt.Sprintf("unreachable: %s", err)
+ } else {
+ resp.Body.Close()
+ report["api"] = fmt.Sprintf("degraded (HTTP %d)", resp.StatusCode)
+ }
+ }
+ } else if cfg != nil && cfg.BaseURL == "" {
+ report["api"] = "not configured (set base_url in config file)"
+ }
+
+ report["version"] = version
+
+ if flags.asJSON {
+ return flags.printJSON(cmd, report)
+ }
+
+ // Human-readable output with color
+ w := cmd.OutOrStdout()
+ checkKeys := []struct{ key, label string }{
+ {"config", "Config"},
+ {"auth", "Auth"},
+ {"api", "API"},
+ }
+ for _, ck := range checkKeys {
+ v, ok := report[ck.key]
+ if !ok {
+ continue
+ }
+ s := fmt.Sprintf("%v", v)
+ indicator := green("OK")
+ if strings.Contains(s, "error") || strings.Contains(s, "not configured") || strings.Contains(s, "unreachable") {
+ indicator = red("FAIL")
+ } else if strings.Contains(s, "not ") {
+ indicator = yellow("WARN")
+ }
+ fmt.Fprintf(w, " %s %s: %s\n", indicator, ck.label, s)
+ }
+ // Print info keys without status indicator
+ for _, key := range []string{"config_path", "base_url", "auth_source", "version"} {
+ if v, ok := report[key]; ok {
+ fmt.Fprintf(w, " %s: %v\n", key, v)
+ }
+ }
+ return nil
+ },
+ }
+}
diff --git a/pipedrive-cli/internal/cli/files.go b/pipedrive-cli/internal/cli/files.go
new file mode 100644
index 00000000..5ed76560
--- /dev/null
+++ b/pipedrive-cli/internal/cli/files.go
@@ -0,0 +1,337 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newFilesCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "files",
+ Short: "Files are documents of any kind (images, spreadsheets, text files, etc.) that are uploaded to Pipedrive, and usually...",
+ }
+
+ cmd.AddCommand(newFilesAddCmd(flags))
+ cmd.AddCommand(newFilesAddAndLinkItCmd(flags))
+ cmd.AddCommand(newFilesDeleteCmd(flags))
+ cmd.AddCommand(newFilesGetCmd(flags))
+ cmd.AddCommand(newFilesGetIdCmd(flags))
+ cmd.AddCommand(newFilesLinkToItemCmd(flags))
+ cmd.AddCommand(newFilesUpdateCmd(flags))
+ cmd.AddCommand(newFilesDownloadCmd(flags))
+ return cmd
+}
+
+func newFilesAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyActivityId int
+ var bodyDealId int
+ var bodyFile string
+ var bodyLeadId string
+ var bodyOrgId int
+ var bodyPersonId int
+ var bodyProductId int
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Add file",
+ Example: " pipedrive-cli files add --file value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/files"
+ body := map[string]any{}
+ if bodyActivityId != 0 {
+ body["activity_id"] = bodyActivityId
+ }
+ if bodyDealId != 0 {
+ body["deal_id"] = bodyDealId
+ }
+ if bodyFile != "" {
+ body["file"] = bodyFile
+ }
+ if bodyLeadId != "" {
+ body["lead_id"] = bodyLeadId
+ }
+ if bodyOrgId != 0 {
+ body["org_id"] = bodyOrgId
+ }
+ if bodyPersonId != 0 {
+ body["person_id"] = bodyPersonId
+ }
+ if bodyProductId != 0 {
+ body["product_id"] = bodyProductId
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyActivityId, "activity-id", 0, "The ID of the activity to associate file(s) with")
+ cmd.Flags().IntVar(&bodyDealId, "deal-id", 0, "The ID of the deal to associate file(s) with")
+ cmd.Flags().StringVar(&bodyFile, "file", "", "A single file, supplied in the multipart/form-data encoding and contained within the given boundaries")
+ _ = cmd.MarkFlagRequired("file")
+ cmd.Flags().StringVar(&bodyLeadId, "lead-id", "", "The ID of the lead to associate file(s) with")
+ cmd.Flags().IntVar(&bodyOrgId, "org-id", 0, "The ID of the organization to associate file(s) with")
+ cmd.Flags().IntVar(&bodyPersonId, "person-id", 0, "The ID of the person to associate file(s) with")
+ cmd.Flags().IntVar(&bodyProductId, "product-id", 0, "The ID of the product to associate file(s) with")
+
+ return cmd
+}
+
+func newFilesAddAndLinkItCmd(flags *rootFlags) *cobra.Command {
+ var bodyFileType string
+ var bodyItemId int
+ var bodyItemType string
+ var bodyRemoteLocation string
+ var bodyTitle string
+
+ cmd := &cobra.Command{
+ Use: "add-and-link-it",
+ Short: "Create a remote file and link it to an item",
+ Example: " pipedrive-cli files add-and-link-it --file-type value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/files/remote"
+ body := map[string]any{}
+ if bodyFileType != "" {
+ body["file_type"] = bodyFileType
+ }
+ if bodyItemId != 0 {
+ body["item_id"] = bodyItemId
+ }
+ if bodyItemType != "" {
+ body["item_type"] = bodyItemType
+ }
+ if bodyRemoteLocation != "" {
+ body["remote_location"] = bodyRemoteLocation
+ }
+ if bodyTitle != "" {
+ body["title"] = bodyTitle
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyFileType, "file-type", "", "The file type")
+ _ = cmd.MarkFlagRequired("file-type")
+ cmd.Flags().IntVar(&bodyItemId, "item-id", 0, "The ID of the item to associate the file with")
+ _ = cmd.MarkFlagRequired("item-id")
+ cmd.Flags().StringVar(&bodyItemType, "item-type", "", "The item type")
+ _ = cmd.MarkFlagRequired("item-type")
+ cmd.Flags().StringVar(&bodyRemoteLocation, "remote-location", "", "The location type to send the file to. Only `googledrive` is supported at the moment.")
+ _ = cmd.MarkFlagRequired("remote-location")
+ cmd.Flags().StringVar(&bodyTitle, "title", "", "The title of the file")
+ _ = cmd.MarkFlagRequired("title")
+
+ return cmd
+}
+
+func newFilesDeleteCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete <id>",
+ Short: "Delete a file",
+ Example: " pipedrive-cli files delete <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/files/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newFilesGetCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagSort string
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all files",
+ Example: " pipedrive-cli files get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/files"
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ "sort": fmt.Sprintf("%v", flagSort),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page. Please note that a maximum value of 100 is allowed.")
+ cmd.Flags().StringVar(&flagSort, "sort", "", "Supported fields: `id`, `update_time`")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
+func newFilesGetIdCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-id <id>",
+ Short: "Get one file",
+ Example: " pipedrive-cli files get-id <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/files/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newFilesLinkToItemCmd(flags *rootFlags) *cobra.Command {
+ var bodyItemId int
+ var bodyItemType string
+ var bodyRemoteId string
+ var bodyRemoteLocation string
+
+ cmd := &cobra.Command{
+ Use: "link-to-item",
+ Short: "Link a remote file to an item",
+ Example: " pipedrive-cli files link-to-item --item-type value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/files/remoteLink"
+ body := map[string]any{}
+ if bodyItemId != 0 {
+ body["item_id"] = bodyItemId
+ }
+ if bodyItemType != "" {
+ body["item_type"] = bodyItemType
+ }
+ if bodyRemoteId != "" {
+ body["remote_id"] = bodyRemoteId
+ }
+ if bodyRemoteLocation != "" {
+ body["remote_location"] = bodyRemoteLocation
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyItemId, "item-id", 0, "The ID of the item to associate the file with")
+ _ = cmd.MarkFlagRequired("item-id")
+ cmd.Flags().StringVar(&bodyItemType, "item-type", "", "The item type")
+ _ = cmd.MarkFlagRequired("item-type")
+ cmd.Flags().StringVar(&bodyRemoteId, "remote-id", "", "The remote item ID")
+ _ = cmd.MarkFlagRequired("remote-id")
+ cmd.Flags().StringVar(&bodyRemoteLocation, "remote-location", "", "The location type to send the file to. Only `googledrive` is supported at the moment.")
+ _ = cmd.MarkFlagRequired("remote-location")
+
+ return cmd
+}
+
+func newFilesUpdateCmd(flags *rootFlags) *cobra.Command {
+ var bodyDescription string
+ var bodyName string
+
+ cmd := &cobra.Command{
+ Use: "update <id>",
+ Short: "Update file details",
+ Example: " pipedrive-cli files update <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/files/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyDescription != "" {
+ body["description"] = bodyDescription
+ }
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyDescription, "description", "", "The description of the file")
+ cmd.Flags().StringVar(&bodyName, "name", "", "The visible name of the file")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/files_download.go b/pipedrive-cli/internal/cli/files_download.go
new file mode 100644
index 00000000..3559ae62
--- /dev/null
+++ b/pipedrive-cli/internal/cli/files_download.go
@@ -0,0 +1,55 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newFilesDownloadCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "download",
+ Short: "Manage download",
+ }
+
+ cmd.AddCommand(newFilesDownloadFileCmd(flags))
+ return cmd
+}
+
+func newFilesDownloadFileCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "file <id>",
+ Aliases: []string{"get"},
+ Short: "Download one file",
+ Example: " pipedrive-cli files download file <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/files/{id}/download"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/filters.go b/pipedrive-cli/internal/cli/filters.go
new file mode 100644
index 00000000..0d0f4fdf
--- /dev/null
+++ b/pipedrive-cli/internal/cli/filters.go
@@ -0,0 +1,243 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newFiltersCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "filters",
+ Short: "Each filter is essentially a set of data validation conditions. A filter of the same kind can be applied when...",
+ }
+
+ cmd.AddCommand(newFiltersAddCmd(flags))
+ cmd.AddCommand(newFiltersDeleteCmd(flags))
+ cmd.AddCommand(newFiltersDeleteIdCmd(flags))
+ cmd.AddCommand(newFiltersGetCmd(flags))
+ cmd.AddCommand(newFiltersGetHelpersCmd(flags))
+ cmd.AddCommand(newFiltersGetIdCmd(flags))
+ cmd.AddCommand(newFiltersUpdateCmd(flags))
+ return cmd
+}
+
+func newFiltersAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyName string
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Add a new filter",
+ Example: " pipedrive-cli filters add --name value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/filters"
+ body := map[string]any{}
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyName, "name", "", "The name of the filter")
+ _ = cmd.MarkFlagRequired("name")
+
+ return cmd
+}
+
+func newFiltersDeleteCmd(flags *rootFlags) *cobra.Command {
+ var flagIds string
+
+ cmd := &cobra.Command{
+ Use: "delete",
+ Short: "Delete multiple filters in bulk",
+ Example: " pipedrive-cli filters delete",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/filters"
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagIds, "ids", "", "The comma-separated filter IDs to delete")
+ _ = cmd.MarkFlagRequired("ids")
+
+ return cmd
+}
+
+func newFiltersDeleteIdCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete-id <id>",
+ Short: "Delete a filter",
+ Example: " pipedrive-cli filters delete-id <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/filters/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newFiltersGetCmd(flags *rootFlags) *cobra.Command {
+ var flagType string
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all filters",
+ Example: " pipedrive-cli filters get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/filters"
+ params := map[string]string{}
+ if flagType != "" {
+ params["type"] = fmt.Sprintf("%v", flagType)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagType, "type", "", "The types of filters to fetch")
+
+ return cmd
+}
+
+func newFiltersGetHelpersCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-helpers",
+ Short: "Get all filter helpers",
+ Example: " pipedrive-cli filters get-helpers",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/filters/helpers"
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newFiltersGetIdCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-id <id>",
+ Short: "Get one filter",
+ Example: " pipedrive-cli filters get-id <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/filters/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newFiltersUpdateCmd(flags *rootFlags) *cobra.Command {
+ var bodyName string
+
+ cmd := &cobra.Command{
+ Use: "update <id>",
+ Short: "Update filter",
+ Example: " pipedrive-cli filters update <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/filters/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyName, "name", "", "The name of the filter")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/goals.go b/pipedrive-cli/internal/cli/goals.go
new file mode 100644
index 00000000..f97e1f03
--- /dev/null
+++ b/pipedrive-cli/internal/cli/goals.go
@@ -0,0 +1,227 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newGoalsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "goals",
+ Short: "Goals help your team meet your sales targets. There are three types of goals - company, team and user.",
+ }
+
+ cmd.AddCommand(newGoalsAddCmd(flags))
+ cmd.AddCommand(newGoalsDeleteCmd(flags))
+ cmd.AddCommand(newGoalsGetCmd(flags))
+ cmd.AddCommand(newGoalsUpdateCmd(flags))
+ cmd.AddCommand(newGoalsResultsCmd(flags))
+ return cmd
+}
+
+func newGoalsAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyInterval string
+ var bodyTitle string
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Add a new goal",
+ Example: " pipedrive-cli goals add --interval value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/goals"
+ body := map[string]any{}
+ if bodyInterval != "" {
+ body["interval"] = bodyInterval
+ }
+ if bodyTitle != "" {
+ body["title"] = bodyTitle
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyInterval, "interval", "", "The interval of the goal")
+ _ = cmd.MarkFlagRequired("interval")
+ cmd.Flags().StringVar(&bodyTitle, "title", "", "The title of the goal")
+
+ return cmd
+}
+
+func newGoalsDeleteCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete <id>",
+ Short: "Delete existing goal",
+ Example: " pipedrive-cli goals delete <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/goals/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newGoalsGetCmd(flags *rootFlags) *cobra.Command {
+ var flagTypeName string
+ var flagTitle string
+ var flagIsActive bool
+ var flagAssigneeId int
+ var flagAssigneeType string
+ var flagExpectedOutcomeTarget float64
+ var flagExpectedOutcomeTrackingMetric string
+ var flagExpectedOutcomeCurrencyId int
+ var flagTypeParamsPipelineId string
+ var flagTypeParamsStageId int
+ var flagTypeParamsActivityTypeId string
+ var flagPeriodStart string
+ var flagPeriodEnd string
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Find goals",
+ Example: " pipedrive-cli goals get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/goals/find"
+ params := map[string]string{}
+ if flagTypeName != "" {
+ params["type.name"] = fmt.Sprintf("%v", flagTypeName)
+ }
+ if flagTitle != "" {
+ params["title"] = fmt.Sprintf("%v", flagTitle)
+ }
+ if flagIsActive != false {
+ params["is_active"] = fmt.Sprintf("%v", flagIsActive)
+ }
+ if flagAssigneeId != 0 {
+ params["assignee.id"] = fmt.Sprintf("%v", flagAssigneeId)
+ }
+ if flagAssigneeType != "" {
+ params["assignee.type"] = fmt.Sprintf("%v", flagAssigneeType)
+ }
+ if flagExpectedOutcomeTarget != 0.0 {
+ params["expected_outcome.target"] = fmt.Sprintf("%v", flagExpectedOutcomeTarget)
+ }
+ if flagExpectedOutcomeTrackingMetric != "" {
+ params["expected_outcome.tracking_metric"] = fmt.Sprintf("%v", flagExpectedOutcomeTrackingMetric)
+ }
+ if flagExpectedOutcomeCurrencyId != 0 {
+ params["expected_outcome.currency_id"] = fmt.Sprintf("%v", flagExpectedOutcomeCurrencyId)
+ }
+ if flagTypeParamsPipelineId != "" {
+ params["type.params.pipeline_id"] = fmt.Sprintf("%v", flagTypeParamsPipelineId)
+ }
+ if flagTypeParamsStageId != 0 {
+ params["type.params.stage_id"] = fmt.Sprintf("%v", flagTypeParamsStageId)
+ }
+ if flagTypeParamsActivityTypeId != "" {
+ params["type.params.activity_type_id"] = fmt.Sprintf("%v", flagTypeParamsActivityTypeId)
+ }
+ if flagPeriodStart != "" {
+ params["period.start"] = fmt.Sprintf("%v", flagPeriodStart)
+ }
+ if flagPeriodEnd != "" {
+ params["period.end"] = fmt.Sprintf("%v", flagPeriodEnd)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagTypeName, "type-name", "", "The type of the goal. If provided, everyone's goals will be returned.")
+ cmd.Flags().StringVar(&flagTitle, "title", "", "The title of the goal")
+ cmd.Flags().BoolVar(&flagIsActive, "is-active", true, "Whether the goal is active or not")
+ cmd.Flags().IntVar(&flagAssigneeId, "assignee-id", 0, "The ID of the user who's goal to fetch. When omitted, only your goals will be returned.")
+ cmd.Flags().StringVar(&flagAssigneeType, "assignee-type", "", "The type of the goal's assignee. If provided, everyone's goals will be returned.")
+ cmd.Flags().Float64Var(&flagExpectedOutcomeTarget, "expected-outcome-target", 0.0, "The numeric value of the outcome. If provided, everyone's goals will be returned.")
+ cmd.Flags().StringVar(&flagExpectedOutcomeTrackingMetric, "expected-outcome-tracking-metric", "", "The tracking metric of the expected outcome of the goal. If provided, everyone's goals will be returned.")
+ cmd.Flags().IntVar(&flagExpectedOutcomeCurrencyId, "expected-outcome-currency-id", 0, "The numeric ID of the goal's currency. Only applicable to goals with `expected_outcome.tracking_metric` with value...")
+ cmd.Flags().StringVar(&flagTypeParamsPipelineId, "type-params-pipeline-id", "", "An array of pipeline IDs or `null` for all pipelines. If provided, everyone's goals will be returned.")
+ cmd.Flags().IntVar(&flagTypeParamsStageId, "type-params-stage-id", 0, "The ID of the stage. Applicable to only `deals_progressed` type of goals. If provided, everyone's goals will be...")
+ cmd.Flags().StringVar(&flagTypeParamsActivityTypeId, "type-params-activity-type-id", "", "An array of IDs or `null` for all activity types. Only applicable for `activities_completed` and/or...")
+ cmd.Flags().StringVar(&flagPeriodStart, "period-start", "", "The start date of the period for which to find goals. Date in format of YYYY-MM-DD. When `period.start` is provided,...")
+ cmd.Flags().StringVar(&flagPeriodEnd, "period-end", "", "The end date of the period for which to find goals. Date in format of YYYY-MM-DD.")
+
+ return cmd
+}
+
+func newGoalsUpdateCmd(flags *rootFlags) *cobra.Command {
+ var bodyInterval string
+ var bodyTitle string
+
+ cmd := &cobra.Command{
+ Use: "update <id>",
+ Short: "Update existing goal",
+ Example: " pipedrive-cli goals update <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/goals/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyInterval != "" {
+ body["interval"] = bodyInterval
+ }
+ if bodyTitle != "" {
+ body["title"] = bodyTitle
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyInterval, "interval", "", "The interval of the goal")
+ cmd.Flags().StringVar(&bodyTitle, "title", "", "The title of the goal")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/goals_results.go b/pipedrive-cli/internal/cli/goals_results.go
new file mode 100644
index 00000000..29d4461c
--- /dev/null
+++ b/pipedrive-cli/internal/cli/goals_results.go
@@ -0,0 +1,67 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newGoalsResultsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "results",
+ Short: "Manage results",
+ }
+
+ cmd.AddCommand(newGoalsResultsGetGoalCmd(flags))
+ return cmd
+}
+
+func newGoalsResultsGetGoalCmd(flags *rootFlags) *cobra.Command {
+ var flagPeriodStart string
+ var flagPeriodEnd string
+
+ cmd := &cobra.Command{
+ Use: "get-goal <id>",
+ Aliases: []string{"get"},
+ Short: "Get result of a goal",
+ Example: " pipedrive-cli goals results get-goal <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/goals/{id}/results"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ if flagPeriodStart != "" {
+ params["period.start"] = fmt.Sprintf("%v", flagPeriodStart)
+ }
+ if flagPeriodEnd != "" {
+ params["period.end"] = fmt.Sprintf("%v", flagPeriodEnd)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagPeriodStart, "period-start", "", "The start date of the period for which to find the goal's progress. Format: YYYY-MM-DD. This date must be the same...")
+ _ = cmd.MarkFlagRequired("period-start")
+ cmd.Flags().StringVar(&flagPeriodEnd, "period-end", "", "The end date of the period for which to find the goal's progress. Format: YYYY-MM-DD. This date must be the same or...")
+ _ = cmd.MarkFlagRequired("period-end")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/helpers.go b/pipedrive-cli/internal/cli/helpers.go
new file mode 100644
index 00000000..94b0ad8c
--- /dev/null
+++ b/pipedrive-cli/internal/cli/helpers.go
@@ -0,0 +1,357 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "sort"
+ "strings"
+ "text/tabwriter"
+
+ "github.com/mattn/go-isatty"
+)
+
+var As = errors.As
+
+// noColor is set by the --no-color flag
+var noColor bool
+
+func colorEnabled() bool {
+ if noColor {
+ return false
+ }
+ if os.Getenv("NO_COLOR") != "" {
+ return false
+ }
+ if os.Getenv("TERM") == "dumb" {
+ return false
+ }
+ return isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd())
+}
+
+func bold(s string) string {
+ if !colorEnabled() {
+ return s
+ }
+ return "\033[1m" + s + "\033[0m"
+}
+
+func green(s string) string {
+ if !colorEnabled() {
+ return s
+ }
+ return "\033[32m" + s + "\033[0m"
+}
+
+func red(s string) string {
+ if !colorEnabled() {
+ return s
+ }
+ return "\033[31m" + s + "\033[0m"
+}
+
+func yellow(s string) string {
+ if !colorEnabled() {
+ return s
+ }
+ return "\033[33m" + s + "\033[0m"
+}
+
+type cliError struct {
+ code int
+ err error
+}
+
+func (e *cliError) Error() string { return e.err.Error() }
+func (e *cliError) Unwrap() error { return e.err }
+
+func usageErr(err error) error { return &cliError{code: 2, err: err} }
+func notFoundErr(err error) error { return &cliError{code: 3, err: err} }
+func authErr(err error) error { return &cliError{code: 4, err: err} }
+func apiErr(err error) error { return &cliError{code: 5, err: err} }
+func configErr(err error) error { return &cliError{code: 10, err: err} }
+func rateLimitErr(err error) error { return &cliError{code: 7, err: err} }
+
+// classifyAPIError maps API errors to structured exit codes with actionable hints.
+func classifyAPIError(err error) error {
+ msg := err.Error()
+ switch {
+ case strings.Contains(msg, "HTTP 401") || strings.Contains(msg, "HTTP 403"):
+ return authErr(fmt.Errorf("%w\nhint: check your API credentials. Run 'pipedrive-cli doctor' to verify auth, or set the required environment variable", err))
+ case strings.Contains(msg, "HTTP 404"):
+ return notFoundErr(fmt.Errorf("%w\nhint: resource not found. Run the 'list' command to see available items", err))
+ case strings.Contains(msg, "HTTP 429"):
+ return rateLimitErr(err)
+ default:
+ return apiErr(err)
+ }
+}
+
+func truncate(s string, max int) string {
+ if len(s) <= max {
+ return s
+ }
+ if max <= 3 {
+ return s[:max]
+ }
+ return s[:max-3] + "..."
+}
+
+func firstNonEmpty(items ...string) string {
+ for _, s := range items {
+ if s != "" {
+ return s
+ }
+ }
+ return ""
+}
+
+func newTabWriter(w io.Writer) *tabwriter.Writer {
+ return tabwriter.NewWriter(w, 2, 4, 2, ' ', 0)
+}
+
+func replacePathParam(path, name, value string) string {
+ return strings.ReplaceAll(path, "{"+name+"}", value)
+}
+
+// paginatedGet fetches pages and concatenates array results.
+func paginatedGet(c interface {
+ Get(path string, params map[string]string) (json.RawMessage, error)
+}, path string, params map[string]string, fetchAll bool, cursorParam, nextCursorPath, hasMoreField string) (json.RawMessage, error) {
+ // Clean zero-value params
+ clean := map[string]string{}
+ for k, v := range params {
+ if v != "" && v != "0" && v != "false" {
+ clean[k] = v
+ }
+ }
+
+ if !fetchAll {
+ return c.Get(path, clean)
+ }
+
+ // Fetch all pages
+ var allItems []json.RawMessage
+ page := 0
+ for {
+ page++
+ fmt.Fprintf(os.Stderr, "fetching page %d...\n", page)
+
+ data, err := c.Get(path, clean)
+ if err != nil {
+ return nil, err
+ }
+
+ // Try to extract items array
+ var items []json.RawMessage
+ if json.Unmarshal(data, &items) == nil {
+ allItems = append(allItems, items...)
+ } else {
+ // Response is an object - look for array inside
+ var obj map[string]json.RawMessage
+ if json.Unmarshal(data, &obj) == nil {
+ // Try common data fields
+ for _, field := range []string{"data", "items", "results", "messages", "members", "values"} {
+ if arr, ok := obj[field]; ok {
+ var nested []json.RawMessage
+ if json.Unmarshal(arr, &nested) == nil {
+ allItems = append(allItems, nested...)
+ break
+ }
+ }
+ }
+
+ // Check for next cursor
+ if nextCursorPath != "" {
+ if tokenRaw, ok := obj[nextCursorPath]; ok {
+ var token string
+ if json.Unmarshal(tokenRaw, &token) == nil && token != "" {
+ clean[cursorParam] = token
+ continue
+ }
+ }
+ }
+
+ // Check has_more
+ if hasMoreField != "" {
+ if moreRaw, ok := obj[hasMoreField]; ok {
+ var more bool
+ if json.Unmarshal(moreRaw, &more) == nil && more {
+ continue
+ }
+ }
+ }
+ }
+ // No more pages
+ break
+ }
+
+ // For direct arrays, can't paginate without cursor
+ break
+ }
+
+ fmt.Fprintf(os.Stderr, "fetched %d items across %d pages\n", len(allItems), page)
+ result, _ := json.Marshal(allItems)
+ return json.RawMessage(result), nil
+}
+
+// selectFields is set from the --select flag; used by printOutputFiltered.
+var selectFieldsGlobal string
+
+// printOutputFiltered applies --select field filtering before rendering.
+func printOutputFiltered(w io.Writer, data json.RawMessage, asJSON bool, selectExpr string) error {
+ if selectExpr != "" {
+ data = filterFields(data, selectExpr)
+ }
+ return printOutput(w, data, asJSON)
+}
+
+// filterFields keeps only the specified comma-separated fields from JSON objects/arrays.
+func filterFields(data json.RawMessage, fields string) json.RawMessage {
+ wanted := map[string]bool{}
+ for _, f := range strings.Split(fields, ",") {
+ f = strings.TrimSpace(f)
+ if f != "" {
+ wanted[f] = true
+ }
+ }
+ if len(wanted) == 0 {
+ return data
+ }
+
+ // Try array of objects
+ var items []map[string]json.RawMessage
+ if json.Unmarshal(data, &items) == nil {
+ filtered := make([]map[string]json.RawMessage, len(items))
+ for i, item := range items {
+ m := map[string]json.RawMessage{}
+ for k, v := range item {
+ if wanted[k] {
+ m[k] = v
+ }
+ }
+ filtered[i] = m
+ }
+ out, _ := json.Marshal(filtered)
+ return out
+ }
+
+ // Try single object
+ var obj map[string]json.RawMessage
+ if json.Unmarshal(data, &obj) == nil {
+ m := map[string]json.RawMessage{}
+ for k, v := range obj {
+ if wanted[k] {
+ m[k] = v
+ }
+ }
+ out, _ := json.Marshal(m)
+ return out
+ }
+
+ return data
+}
+
+// printOutput auto-detects arrays and renders as tables, or prints raw JSON for objects.
+func printOutput(w io.Writer, data json.RawMessage, asJSON bool) error {
+ if asJSON {
+ enc := json.NewEncoder(w)
+ enc.SetIndent("", " ")
+ return enc.Encode(data)
+ }
+
+ // Try to detect if response is an array
+ var items []map[string]any
+ if err := json.Unmarshal(data, &items); err == nil && len(items) > 0 {
+ return printAutoTable(w, items)
+ }
+
+ // Single object - pretty print
+ var obj map[string]any
+ if err := json.Unmarshal(data, &obj); err == nil {
+ enc := json.NewEncoder(w)
+ enc.SetIndent("", " ")
+ return enc.Encode(obj)
+ }
+
+ // Fallback: print raw
+ fmt.Fprintln(w, string(data))
+ return nil
+}
+
+func printAutoTable(w io.Writer, items []map[string]any) error {
+ if len(items) == 0 {
+ return nil
+ }
+
+ // Collect headers from first item, prioritize common fields
+ priority := []string{"id", "name", "username", "title", "status", "type", "email", "description"}
+ headerSet := map[string]struct{}{}
+ for k := range items[0] {
+ headerSet[k] = struct{}{}
+ }
+
+ var headers []string
+ for _, p := range priority {
+ if _, ok := headerSet[p]; ok {
+ headers = append(headers, p)
+ delete(headerSet, p)
+ }
+ }
+ // Add remaining headers sorted
+ var rest []string
+ for k := range headerSet {
+ rest = append(rest, k)
+ }
+ sort.Strings(rest)
+ headers = append(headers, rest...)
+
+ // Limit to 6 columns max for readability
+ if len(headers) > 6 {
+ headers = headers[:6]
+ }
+
+ // Build rows
+ rows := make([][]string, 0, len(items))
+ for _, item := range items {
+ row := make([]string, len(headers))
+ for i, h := range headers {
+ v := item[h]
+ switch val := v.(type) {
+ case string:
+ row[i] = truncate(val, 40)
+ case float64:
+ if val == float64(int64(val)) {
+ row[i] = fmt.Sprintf("%d", int64(val))
+ } else {
+ row[i] = fmt.Sprintf("%g", val)
+ }
+ case bool:
+ row[i] = fmt.Sprintf("%t", val)
+ case nil:
+ row[i] = ""
+ default:
+ b, _ := json.Marshal(val)
+ row[i] = truncate(string(b), 40)
+ }
+ }
+ rows = append(rows, row)
+ }
+
+ // Print with tab alignment using tabwriter
+ tw := newTabWriter(w)
+ upperHeaders := make([]string, len(headers))
+ for i, h := range headers {
+ upperHeaders[i] = bold(strings.ToUpper(h))
+ }
+
+ fmt.Fprintln(tw, strings.Join(upperHeaders, "\t"))
+ for _, row := range rows {
+ fmt.Fprintln(tw, strings.Join(row, "\t"))
+ }
+ return tw.Flush()
+}
diff --git a/pipedrive-cli/internal/cli/lead-fields.go b/pipedrive-cli/internal/cli/lead-fields.go
new file mode 100644
index 00000000..09bdaddd
--- /dev/null
+++ b/pipedrive-cli/internal/cli/lead-fields.go
@@ -0,0 +1,59 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newLeadFieldsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "lead-fields",
+ Short: "Lead fields represent the near-complete schema for a lead in the context of the company of the authorized user. Each...",
+ }
+
+ cmd.AddCommand(newLeadFieldsGetCmd(flags))
+ return cmd
+}
+
+func newLeadFieldsGetCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all lead fields",
+ Example: " pipedrive-cli lead-fields get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/leadFields"
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/lead-labels.go b/pipedrive-cli/internal/cli/lead-labels.go
new file mode 100644
index 00000000..54f5ab04
--- /dev/null
+++ b/pipedrive-cli/internal/cli/lead-labels.go
@@ -0,0 +1,162 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newLeadLabelsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "lead-labels",
+ Short: "Lead labels allow you to visually categorize your leads. There are three default lead labels: hot, cold, and warm,...",
+ }
+
+ cmd.AddCommand(newLeadLabelsAddCmd(flags))
+ cmd.AddCommand(newLeadLabelsDeleteCmd(flags))
+ cmd.AddCommand(newLeadLabelsGetCmd(flags))
+ cmd.AddCommand(newLeadLabelsUpdateCmd(flags))
+ return cmd
+}
+
+func newLeadLabelsAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyColor string
+ var bodyName string
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Add a lead label",
+ Example: " pipedrive-cli lead-labels add --color value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/leadLabels"
+ body := map[string]any{}
+ if bodyColor != "" {
+ body["color"] = bodyColor
+ }
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyColor, "color", "", "The color of the label. Only a subset of colors can be used.")
+ _ = cmd.MarkFlagRequired("color")
+ cmd.Flags().StringVar(&bodyName, "name", "", "The name of the lead label")
+ _ = cmd.MarkFlagRequired("name")
+
+ return cmd
+}
+
+func newLeadLabelsDeleteCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete <id>",
+ Short: "Delete a lead label",
+ Example: " pipedrive-cli lead-labels delete <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/leadLabels/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newLeadLabelsGetCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all lead labels",
+ Example: " pipedrive-cli lead-labels get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/leadLabels"
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newLeadLabelsUpdateCmd(flags *rootFlags) *cobra.Command {
+ var bodyColor string
+ var bodyName string
+
+ cmd := &cobra.Command{
+ Use: "update <id>",
+ Short: "Update a lead label",
+ Example: " pipedrive-cli lead-labels update <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/leadLabels/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyColor != "" {
+ body["color"] = bodyColor
+ }
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ data, err := c.Patch(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyColor, "color", "", "The color of the label. Only a subset of colors can be used.")
+ cmd.Flags().StringVar(&bodyName, "name", "", "The name of the lead label")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/lead-sources.go b/pipedrive-cli/internal/cli/lead-sources.go
new file mode 100644
index 00000000..6392b2a6
--- /dev/null
+++ b/pipedrive-cli/internal/cli/lead-sources.go
@@ -0,0 +1,51 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newLeadSourcesCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "lead-sources",
+ Short: "A lead source indicates where your lead came from. Currently, these are the possible lead sources: `Manually...",
+ }
+
+ cmd.AddCommand(newLeadSourcesGetCmd(flags))
+ return cmd
+}
+
+func newLeadSourcesGetCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all lead sources",
+ Example: " pipedrive-cli lead-sources get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/leadSources"
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/leads.go b/pipedrive-cli/internal/cli/leads.go
new file mode 100644
index 00000000..da2aea4d
--- /dev/null
+++ b/pipedrive-cli/internal/cli/leads.go
@@ -0,0 +1,393 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newLeadsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "leads",
+ Short: "Leads are potential deals stored in Leads Inbox before they are archived or converted to a deal. Each lead needs to...",
+ }
+
+ cmd.AddCommand(newLeadsAddCmd(flags))
+ cmd.AddCommand(newLeadsDeleteCmd(flags))
+ cmd.AddCommand(newLeadsGetCmd(flags))
+ cmd.AddCommand(newLeadsGetArchivedCmd(flags))
+ cmd.AddCommand(newLeadsGetIdCmd(flags))
+ cmd.AddCommand(newLeadsSearchCmd(flags))
+ cmd.AddCommand(newLeadsUpdateCmd(flags))
+ cmd.AddCommand(newLeadsPermittedUsersCmd(flags))
+ return cmd
+}
+
+func newLeadsAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyChannel int
+ var bodyChannelId string
+ var bodyExpectedCloseDate string
+ var bodyOrganizationId int
+ var bodyOriginId string
+ var bodyOwnerId int
+ var bodyPersonId int
+ var bodyTitle string
+ var bodyWasSeen bool
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Add a lead",
+ Example: " pipedrive-cli leads add --title value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/leads"
+ body := map[string]any{}
+ if bodyChannel != 0 {
+ body["channel"] = bodyChannel
+ }
+ if bodyChannelId != "" {
+ body["channel_id"] = bodyChannelId
+ }
+ if bodyExpectedCloseDate != "" {
+ body["expected_close_date"] = bodyExpectedCloseDate
+ }
+ if bodyOrganizationId != 0 {
+ body["organization_id"] = bodyOrganizationId
+ }
+ if bodyOriginId != "" {
+ body["origin_id"] = bodyOriginId
+ }
+ if bodyOwnerId != 0 {
+ body["owner_id"] = bodyOwnerId
+ }
+ if bodyPersonId != 0 {
+ body["person_id"] = bodyPersonId
+ }
+ if bodyTitle != "" {
+ body["title"] = bodyTitle
+ }
+ if bodyWasSeen != false {
+ body["was_seen"] = bodyWasSeen
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyChannel, "channel", 0, "The ID of Marketing channel this lead was created from. Provided value must be one of the channels configured for...")
+ cmd.Flags().StringVar(&bodyChannelId, "channel-id", "", "The optional ID to further distinguish the Marketing channel. If omitted, `channel_id` will be set to null.")
+ cmd.Flags().StringVar(&bodyExpectedCloseDate, "expected-close-date", "", "The date of when the deal which will be created from the lead is expected to be closed. In ISO 8601 format: YYYY-MM-DD.")
+ cmd.Flags().IntVar(&bodyOrganizationId, "organization-id", 0, "The ID of an organization which this lead will be linked to. If the organization does not exist yet, it needs to be...")
+ cmd.Flags().StringVar(&bodyOriginId, "origin-id", "", "The optional ID to further distinguish the origin of the lead - e.g. Which API integration created this lead. If...")
+ cmd.Flags().IntVar(&bodyOwnerId, "owner-id", 0, "The ID of the user which will be the owner of the created lead. If not provided, the user making the request will be...")
+ cmd.Flags().IntVar(&bodyPersonId, "person-id", 0, "The ID of a person which this lead will be linked to. If the person does not exist yet, it needs to be created...")
+ cmd.Flags().StringVar(&bodyTitle, "title", "", "The name of the lead")
+ _ = cmd.MarkFlagRequired("title")
+ cmd.Flags().BoolVar(&bodyWasSeen, "was-seen", false, "A flag indicating whether the lead was seen by someone in the Pipedrive UI")
+
+ return cmd
+}
+
+func newLeadsDeleteCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete <id>",
+ Short: "Delete a lead",
+ Example: " pipedrive-cli leads delete <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/leads/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newLeadsGetCmd(flags *rootFlags) *cobra.Command {
+ var flagLimit int
+ var flagStart int
+ var flagOwnerId int
+ var flagPersonId int
+ var flagOrganizationId int
+ var flagFilterId int
+ var flagUpdatedSince string
+ var flagSort string
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all leads",
+ Example: " pipedrive-cli leads get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/leads"
+ data, err := paginatedGet(c, path, map[string]string{
+ "limit": fmt.Sprintf("%v", flagLimit),
+ "start": fmt.Sprintf("%v", flagStart),
+ "owner_id": fmt.Sprintf("%v", flagOwnerId),
+ "person_id": fmt.Sprintf("%v", flagPersonId),
+ "organization_id": fmt.Sprintf("%v", flagOrganizationId),
+ "filter_id": fmt.Sprintf("%v", flagFilterId),
+ "updated_since": fmt.Sprintf("%v", flagUpdatedSince),
+ "sort": fmt.Sprintf("%v", flagSort),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "For pagination, the limit of entries to be returned. If not provided, 100 items will be returned.")
+ cmd.Flags().IntVar(&flagStart, "start", 0, "For pagination, the position that represents the first result for the page")
+ cmd.Flags().IntVar(&flagOwnerId, "owner-id", 0, "If supplied, only leads matching the given user will be returned. However, `filter_id` takes precedence over...")
+ cmd.Flags().IntVar(&flagPersonId, "person-id", 0, "If supplied, only leads matching the given person will be returned. However, `filter_id` takes precedence over...")
+ cmd.Flags().IntVar(&flagOrganizationId, "organization-id", 0, "If supplied, only leads matching the given organization will be returned. However, `filter_id` takes precedence over...")
+ cmd.Flags().IntVar(&flagFilterId, "filter-id", 0, "The ID of the filter to use")
+ cmd.Flags().StringVar(&flagUpdatedSince, "updated-since", "", "If set, only leads with an `update_time` later than or equal to this time are returned. In ISO 8601 format, e.g....")
+ cmd.Flags().StringVar(&flagSort, "sort", "", "The field names and sorting mode separated by a comma (`field_name_1 ASC`, `field_name_2 DESC`). Only first-level...")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
+func newLeadsGetArchivedCmd(flags *rootFlags) *cobra.Command {
+ var flagLimit int
+ var flagStart int
+ var flagOwnerId int
+ var flagPersonId int
+ var flagOrganizationId int
+ var flagFilterId int
+ var flagSort string
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-archived",
+ Short: "Get all archived leads",
+ Example: " pipedrive-cli leads get-archived",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/leads/archived"
+ data, err := paginatedGet(c, path, map[string]string{
+ "limit": fmt.Sprintf("%v", flagLimit),
+ "start": fmt.Sprintf("%v", flagStart),
+ "owner_id": fmt.Sprintf("%v", flagOwnerId),
+ "person_id": fmt.Sprintf("%v", flagPersonId),
+ "organization_id": fmt.Sprintf("%v", flagOrganizationId),
+ "filter_id": fmt.Sprintf("%v", flagFilterId),
+ "sort": fmt.Sprintf("%v", flagSort),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "For pagination, the limit of entries to be returned. If not provided, 100 items will be returned.")
+ cmd.Flags().IntVar(&flagStart, "start", 0, "For pagination, the position that represents the first result for the page")
+ cmd.Flags().IntVar(&flagOwnerId, "owner-id", 0, "If supplied, only leads matching the given user will be returned. However, `filter_id` takes precedence over...")
+ cmd.Flags().IntVar(&flagPersonId, "person-id", 0, "If supplied, only leads matching the given person will be returned. However, `filter_id` takes precedence over...")
+ cmd.Flags().IntVar(&flagOrganizationId, "organization-id", 0, "If supplied, only leads matching the given organization will be returned. However, `filter_id` takes precedence over...")
+ cmd.Flags().IntVar(&flagFilterId, "filter-id", 0, "The ID of the filter to use")
+ cmd.Flags().StringVar(&flagSort, "sort", "", "The field names and sorting mode separated by a comma (`field_name_1 ASC`, `field_name_2 DESC`). Only first-level...")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
+func newLeadsGetIdCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-id <id>",
+ Short: "Get one lead",
+ Example: " pipedrive-cli leads get-id <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/leads/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newLeadsSearchCmd(flags *rootFlags) *cobra.Command {
+ var flagTerm string
+ var flagFields string
+ var flagExactMatch bool
+ var flagPersonId int
+ var flagOrganizationId int
+ var flagIncludeFields string
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "search",
+ Short: "Search leads",
+ Example: " pipedrive-cli leads search",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/leads/search"
+ data, err := paginatedGet(c, path, map[string]string{
+ "term": fmt.Sprintf("%v", flagTerm),
+ "fields": fmt.Sprintf("%v", flagFields),
+ "exact_match": fmt.Sprintf("%v", flagExactMatch),
+ "person_id": fmt.Sprintf("%v", flagPersonId),
+ "organization_id": fmt.Sprintf("%v", flagOrganizationId),
+ "include_fields": fmt.Sprintf("%v", flagIncludeFields),
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagTerm, "term", "", "The search term to look for. Minimum 2 characters (or 1 if using `exact_match`). Please note that the search term...")
+ _ = cmd.MarkFlagRequired("term")
+ cmd.Flags().StringVar(&flagFields, "fields", "", "A comma-separated string array. The fields to perform the search from. Defaults to all of them.")
+ cmd.Flags().BoolVar(&flagExactMatch, "exact-match", false, "When enabled, only full exact matches against the given term are returned. It is <b>not</b> case sensitive.")
+ cmd.Flags().IntVar(&flagPersonId, "person-id", 0, "Will filter leads by the provided person ID. The upper limit of found leads associated with the person is 2000.")
+ cmd.Flags().IntVar(&flagOrganizationId, "organization-id", 0, "Will filter leads by the provided organization ID. The upper limit of found leads associated with the organization...")
+ cmd.Flags().StringVar(&flagIncludeFields, "include-fields", "", "Supports including optional fields in the results which are not provided by default")
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start. Note that the pagination is based on main results and does not include related items when using...")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
+func newLeadsUpdateCmd(flags *rootFlags) *cobra.Command {
+ var bodyChannel int
+ var bodyChannelId string
+ var bodyExpectedCloseDate string
+ var bodyIsArchived bool
+ var bodyOrganizationId int
+ var bodyOwnerId int
+ var bodyPersonId int
+ var bodyTitle string
+ var bodyWasSeen bool
+
+ cmd := &cobra.Command{
+ Use: "update <id>",
+ Short: "Update a lead",
+ Example: " pipedrive-cli leads update <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/leads/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyChannel != 0 {
+ body["channel"] = bodyChannel
+ }
+ if bodyChannelId != "" {
+ body["channel_id"] = bodyChannelId
+ }
+ if bodyExpectedCloseDate != "" {
+ body["expected_close_date"] = bodyExpectedCloseDate
+ }
+ if bodyIsArchived != false {
+ body["is_archived"] = bodyIsArchived
+ }
+ if bodyOrganizationId != 0 {
+ body["organization_id"] = bodyOrganizationId
+ }
+ if bodyOwnerId != 0 {
+ body["owner_id"] = bodyOwnerId
+ }
+ if bodyPersonId != 0 {
+ body["person_id"] = bodyPersonId
+ }
+ if bodyTitle != "" {
+ body["title"] = bodyTitle
+ }
+ if bodyWasSeen != false {
+ body["was_seen"] = bodyWasSeen
+ }
+ data, err := c.Patch(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyChannel, "channel", 0, "The ID of Marketing channel this lead was created from. Provided value must be one of the channels configured for...")
+ cmd.Flags().StringVar(&bodyChannelId, "channel-id", "", "The optional ID to further distinguish the Marketing channel.")
+ cmd.Flags().StringVar(&bodyExpectedCloseDate, "expected-close-date", "", "The date of when the deal which will be created from the lead is expected to be closed. In ISO 8601 format: YYYY-MM-DD.")
+ cmd.Flags().BoolVar(&bodyIsArchived, "is-archived", false, "A flag indicating whether the lead is archived or not")
+ cmd.Flags().IntVar(&bodyOrganizationId, "organization-id", 0, "The ID of an organization which this lead will be linked to. If the organization does not exist yet, it needs to be...")
+ cmd.Flags().IntVar(&bodyOwnerId, "owner-id", 0, "The ID of the user which will be the owner of the created lead. If not provided, the user making the request will be...")
+ cmd.Flags().IntVar(&bodyPersonId, "person-id", 0, "The ID of a person which this lead will be linked to. If the person does not exist yet, it needs to be created...")
+ cmd.Flags().StringVar(&bodyTitle, "title", "", "The name of the lead")
+ cmd.Flags().BoolVar(&bodyWasSeen, "was-seen", false, "A flag indicating whether the lead was seen by someone in the Pipedrive UI")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/leads_permitted-users.go b/pipedrive-cli/internal/cli/leads_permitted-users.go
new file mode 100644
index 00000000..ebc4cdbb
--- /dev/null
+++ b/pipedrive-cli/internal/cli/leads_permitted-users.go
@@ -0,0 +1,55 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newLeadsPermittedUsersCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "permitted-users",
+ Short: "Manage permitted users",
+ }
+
+ cmd.AddCommand(newLeadsPermittedUsersGetLeadUsersCmd(flags))
+ return cmd
+}
+
+func newLeadsPermittedUsersGetLeadUsersCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-lead-users <id>",
+ Aliases: []string{"get"},
+ Short: "List permitted users",
+ Example: " pipedrive-cli leads permitted-users get-lead-users <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/leads/{id}/permittedUsers"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/legacy-teams.go b/pipedrive-cli/internal/cli/legacy-teams.go
new file mode 100644
index 00000000..f03ccdac
--- /dev/null
+++ b/pipedrive-cli/internal/cli/legacy-teams.go
@@ -0,0 +1,232 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newLegacyTeamsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "legacy-teams",
+ Short: "Legacy teams allow you to form groups of users withing the organization for more efficient management. Previously...",
+ }
+
+ cmd.AddCommand(newLegacyTeamsAddTeamCmd(flags))
+ cmd.AddCommand(newLegacyTeamsGetTeamCmd(flags))
+ cmd.AddCommand(newLegacyTeamsGetTeamsCmd(flags))
+ cmd.AddCommand(newLegacyTeamsGetUserTeamsCmd(flags))
+ cmd.AddCommand(newLegacyTeamsUpdateTeamCmd(flags))
+ cmd.AddCommand(newLegacyTeamsUsersCmd(flags))
+ return cmd
+}
+
+func newLegacyTeamsAddTeamCmd(flags *rootFlags) *cobra.Command {
+ var bodyDescription string
+ var bodyManagerId int
+ var bodyName string
+
+ cmd := &cobra.Command{
+ Use: "add-team",
+ Aliases: []string{"create"},
+ Short: "Add a new team",
+ Example: " pipedrive-cli legacy-teams add-team --name value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/legacyTeams"
+ body := map[string]any{}
+ if bodyDescription != "" {
+ body["description"] = bodyDescription
+ }
+ if bodyManagerId != 0 {
+ body["manager_id"] = bodyManagerId
+ }
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyDescription, "description", "", "The team description")
+ cmd.Flags().IntVar(&bodyManagerId, "manager-id", 0, "The team manager ID")
+ _ = cmd.MarkFlagRequired("manager-id")
+ cmd.Flags().StringVar(&bodyName, "name", "", "The team name")
+ _ = cmd.MarkFlagRequired("name")
+
+ return cmd
+}
+
+func newLegacyTeamsGetTeamCmd(flags *rootFlags) *cobra.Command {
+ var flagSkipUsers float64
+
+ cmd := &cobra.Command{
+ Use: "get-team <id>",
+ Aliases: []string{"get"},
+ Short: "Get a single team",
+ Example: " pipedrive-cli legacy-teams get-team <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/legacyTeams/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ if flagSkipUsers != 0.0 {
+ params["skip_users"] = fmt.Sprintf("%v", flagSkipUsers)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().Float64Var(&flagSkipUsers, "skip-users", 0.000000, "When enabled, the teams will not include IDs of member users")
+
+ return cmd
+}
+
+func newLegacyTeamsGetTeamsCmd(flags *rootFlags) *cobra.Command {
+ var flagOrderBy string
+ var flagSkipUsers float64
+
+ cmd := &cobra.Command{
+ Use: "get-teams",
+ Aliases: []string{"list"},
+ Short: "Get all teams",
+ Example: " pipedrive-cli legacy-teams get-teams",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/legacyTeams"
+ params := map[string]string{}
+ if flagOrderBy != "" {
+ params["order_by"] = fmt.Sprintf("%v", flagOrderBy)
+ }
+ if flagSkipUsers != 0.0 {
+ params["skip_users"] = fmt.Sprintf("%v", flagSkipUsers)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagOrderBy, "order-by", "id", "The field name to sort returned teams by")
+ cmd.Flags().Float64Var(&flagSkipUsers, "skip-users", 0.000000, "When enabled, the teams will not include IDs of member users")
+
+ return cmd
+}
+
+func newLegacyTeamsGetUserTeamsCmd(flags *rootFlags) *cobra.Command {
+ var flagOrderBy string
+ var flagSkipUsers float64
+
+ cmd := &cobra.Command{
+ Use: "get-user-teams <id>",
+ Short: "Get all teams of a user",
+ Example: " pipedrive-cli legacy-teams get-user-teams <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/legacyTeams/user/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ if flagOrderBy != "" {
+ params["order_by"] = fmt.Sprintf("%v", flagOrderBy)
+ }
+ if flagSkipUsers != 0.0 {
+ params["skip_users"] = fmt.Sprintf("%v", flagSkipUsers)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagOrderBy, "order-by", "id", "The field name to sort returned teams by")
+ cmd.Flags().Float64Var(&flagSkipUsers, "skip-users", 0.000000, "When enabled, the teams will not include IDs of member users")
+
+ return cmd
+}
+
+func newLegacyTeamsUpdateTeamCmd(flags *rootFlags) *cobra.Command {
+ var bodyDescription string
+ var bodyManagerId int
+ var bodyName string
+
+ cmd := &cobra.Command{
+ Use: "update-team <id>",
+ Aliases: []string{"update"},
+ Short: "Update a team",
+ Example: " pipedrive-cli legacy-teams update-team <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/legacyTeams/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyDescription != "" {
+ body["description"] = bodyDescription
+ }
+ if bodyManagerId != 0 {
+ body["manager_id"] = bodyManagerId
+ }
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyDescription, "description", "", "The team description")
+ cmd.Flags().IntVar(&bodyManagerId, "manager-id", 0, "The team manager ID")
+ cmd.Flags().StringVar(&bodyName, "name", "", "The team name")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/legacy-teams_users.go b/pipedrive-cli/internal/cli/legacy-teams_users.go
new file mode 100644
index 00000000..e5cdca3b
--- /dev/null
+++ b/pipedrive-cli/internal/cli/legacy-teams_users.go
@@ -0,0 +1,118 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newLegacyTeamsUsersCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "users",
+ Short: "Users are people with access to your Pipedrive account. A user may belong to one or many Pipedrive accounts, so...",
+ }
+
+ cmd.AddCommand(newLegacyTeamsUsersAddTeamCmd(flags))
+ cmd.AddCommand(newLegacyTeamsUsersDeleteTeamCmd(flags))
+ cmd.AddCommand(newLegacyTeamsUsersGetTeamCmd(flags))
+ return cmd
+}
+
+func newLegacyTeamsUsersAddTeamCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "add-team <id>",
+ Aliases: []string{"create"},
+ Short: "Add users to a team",
+ Example: " pipedrive-cli legacy-teams users add-team <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/legacyTeams/{id}/users"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newLegacyTeamsUsersDeleteTeamCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete-team <id>",
+ Aliases: []string{"delete"},
+ Short: "Delete users from a team",
+ Example: " pipedrive-cli legacy-teams users delete-team <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/legacyTeams/{id}/users"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newLegacyTeamsUsersGetTeamCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-team <id>",
+ Aliases: []string{"get"},
+ Short: "Get all users in a team",
+ Example: " pipedrive-cli legacy-teams users get-team <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/legacyTeams/{id}/users"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/mailbox.go b/pipedrive-cli/internal/cli/mailbox.go
new file mode 100644
index 00000000..4a387ab1
--- /dev/null
+++ b/pipedrive-cli/internal/cli/mailbox.go
@@ -0,0 +1,235 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newMailboxCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "mailbox",
+ Short: "Mailbox was designed to be the email control hub inside Pipedrive. Pipedrive supports all major providers (including...",
+ }
+
+ cmd.AddCommand(newMailboxDeleteMailThreadCmd(flags))
+ cmd.AddCommand(newMailboxGetMailMessageCmd(flags))
+ cmd.AddCommand(newMailboxGetMailThreadCmd(flags))
+ cmd.AddCommand(newMailboxGetMailThreadMessagesCmd(flags))
+ cmd.AddCommand(newMailboxGetMailThreadsCmd(flags))
+ cmd.AddCommand(newMailboxUpdateMailThreadDetailsCmd(flags))
+ return cmd
+}
+
+func newMailboxDeleteMailThreadCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete-mail-thread <id>",
+ Aliases: []string{"delete"},
+ Short: "Delete mail thread",
+ Example: " pipedrive-cli mailbox delete-mail-thread <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/mailbox/mailThreads/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newMailboxGetMailMessageCmd(flags *rootFlags) *cobra.Command {
+ var flagIncludeBody float64
+
+ cmd := &cobra.Command{
+ Use: "get-mail-message <id>",
+ Aliases: []string{"get"},
+ Short: "Get one mail message",
+ Example: " pipedrive-cli mailbox get-mail-message <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/mailbox/mailMessages/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ if flagIncludeBody != 0.0 {
+ params["include_body"] = fmt.Sprintf("%v", flagIncludeBody)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().Float64Var(&flagIncludeBody, "include-body", 0.000000, "Whether to include the full message body or not. `0` = Don't include, `1` = Include.")
+
+ return cmd
+}
+
+func newMailboxGetMailThreadCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-mail-thread <id>",
+ Short: "Get one mail thread",
+ Example: " pipedrive-cli mailbox get-mail-thread <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/mailbox/mailThreads/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newMailboxGetMailThreadMessagesCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-mail-thread-messages <id>",
+ Short: "Get all mail messages of mail thread",
+ Example: " pipedrive-cli mailbox get-mail-thread-messages <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/mailbox/mailThreads/{id}/mailMessages"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newMailboxGetMailThreadsCmd(flags *rootFlags) *cobra.Command {
+ var flagFolder string
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-mail-threads",
+ Aliases: []string{"list"},
+ Short: "Get mail threads",
+ Example: " pipedrive-cli mailbox get-mail-threads",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/mailbox/mailThreads"
+ data, err := paginatedGet(c, path, map[string]string{
+ "folder": fmt.Sprintf("%v", flagFolder),
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagFolder, "folder", "inbox", "The type of folder to fetch")
+ _ = cmd.MarkFlagRequired("folder")
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
+func newMailboxUpdateMailThreadDetailsCmd(flags *rootFlags) *cobra.Command {
+ var bodyDealId int
+ var bodyLeadId string
+
+ cmd := &cobra.Command{
+ Use: "update-mail-thread-details <id>",
+ Aliases: []string{"update"},
+ Short: "Update mail thread details",
+ Example: " pipedrive-cli mailbox update-mail-thread-details <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/mailbox/mailThreads/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyDealId != 0 {
+ body["deal_id"] = bodyDealId
+ }
+ if bodyLeadId != "" {
+ body["lead_id"] = bodyLeadId
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyDealId, "deal-id", 0, "The ID of the deal this thread is associated with")
+ cmd.Flags().StringVar(&bodyLeadId, "lead-id", "", "The ID of the lead this thread is associated with")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/meetings.go b/pipedrive-cli/internal/cli/meetings.go
new file mode 100644
index 00000000..df9f3162
--- /dev/null
+++ b/pipedrive-cli/internal/cli/meetings.go
@@ -0,0 +1,106 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newMeetingsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "meetings",
+ Short: "Meetings API allows integrating video calling apps into Pipedrive through [Video Calling App...",
+ }
+
+ cmd.AddCommand(newMeetingsDeleteUserProviderLinkCmd(flags))
+ cmd.AddCommand(newMeetingsSaveUserProviderLinkCmd(flags))
+ return cmd
+}
+
+func newMeetingsDeleteUserProviderLinkCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete-user-provider-link <id>",
+ Aliases: []string{"delete"},
+ Short: "Delete the link between a user and the installed video call integration",
+ Example: " pipedrive-cli meetings delete-user-provider-link <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/meetings/userProviderLinks/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newMeetingsSaveUserProviderLinkCmd(flags *rootFlags) *cobra.Command {
+ var bodyCompanyId int
+ var bodyMarketplaceClientId string
+ var bodyUserId int
+ var bodyUserProviderId string
+
+ cmd := &cobra.Command{
+ Use: "save-user-provider-link",
+ Aliases: []string{"create"},
+ Short: "Link a user with the installed video call integration",
+ Example: " pipedrive-cli meetings save-user-provider-link --marketplace-client-id value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/meetings/userProviderLinks"
+ body := map[string]any{}
+ if bodyCompanyId != 0 {
+ body["company_id"] = bodyCompanyId
+ }
+ if bodyMarketplaceClientId != "" {
+ body["marketplace_client_id"] = bodyMarketplaceClientId
+ }
+ if bodyUserId != 0 {
+ body["user_id"] = bodyUserId
+ }
+ if bodyUserProviderId != "" {
+ body["user_provider_id"] = bodyUserProviderId
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyCompanyId, "company-id", 0, "Pipedrive company ID")
+ _ = cmd.MarkFlagRequired("company-id")
+ cmd.Flags().StringVar(&bodyMarketplaceClientId, "marketplace-client-id", "", "Pipedrive Marketplace client ID of the installed integration")
+ _ = cmd.MarkFlagRequired("marketplace-client-id")
+ cmd.Flags().IntVar(&bodyUserId, "user-id", 0, "Pipedrive user ID")
+ _ = cmd.MarkFlagRequired("user-id")
+ cmd.Flags().StringVar(&bodyUserProviderId, "user-provider-id", "", "Unique identifier linking a user to the installed integration. Generated by the integration.")
+ _ = cmd.MarkFlagRequired("user-provider-id")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/note-fields.go b/pipedrive-cli/internal/cli/note-fields.go
new file mode 100644
index 00000000..98d77eef
--- /dev/null
+++ b/pipedrive-cli/internal/cli/note-fields.go
@@ -0,0 +1,51 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newNoteFieldsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "note-fields",
+ Short: "Note fields represent different fields that a note has.",
+ }
+
+ cmd.AddCommand(newNoteFieldsGetCmd(flags))
+ return cmd
+}
+
+func newNoteFieldsGetCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all note fields",
+ Example: " pipedrive-cli note-fields get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/noteFields"
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/notes.go b/pipedrive-cli/internal/cli/notes.go
new file mode 100644
index 00000000..79b51c84
--- /dev/null
+++ b/pipedrive-cli/internal/cli/notes.go
@@ -0,0 +1,306 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newNotesCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "notes",
+ Short: "Notes are pieces of textual (HTML-formatted) information that can be attached to deals, persons and organizations....",
+ }
+
+ cmd.AddCommand(newNotesAddCmd(flags))
+ cmd.AddCommand(newNotesDeleteCmd(flags))
+ cmd.AddCommand(newNotesGetCmd(flags))
+ cmd.AddCommand(newNotesGetIdCmd(flags))
+ cmd.AddCommand(newNotesUpdateCmd(flags))
+ cmd.AddCommand(newNotesCommentsCmd(flags))
+ return cmd
+}
+
+func newNotesAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyAddTime string
+ var bodyContent string
+ var bodyDealId int
+ var bodyLeadId string
+ var bodyOrgId int
+ var bodyPersonId int
+ var bodyProjectId int
+ var bodyUserId int
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Add a note",
+ Example: " pipedrive-cli notes add --content value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/notes"
+ body := map[string]any{}
+ if bodyAddTime != "" {
+ body["add_time"] = bodyAddTime
+ }
+ if bodyContent != "" {
+ body["content"] = bodyContent
+ }
+ if bodyDealId != 0 {
+ body["deal_id"] = bodyDealId
+ }
+ if bodyLeadId != "" {
+ body["lead_id"] = bodyLeadId
+ }
+ if bodyOrgId != 0 {
+ body["org_id"] = bodyOrgId
+ }
+ if bodyPersonId != 0 {
+ body["person_id"] = bodyPersonId
+ }
+ if bodyProjectId != 0 {
+ body["project_id"] = bodyProjectId
+ }
+ if bodyUserId != 0 {
+ body["user_id"] = bodyUserId
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyAddTime, "add-time", "", "The optional creation date & time of the note in UTC. Can be set in the past or in the future. Format: YYYY-MM-DD...")
+ cmd.Flags().StringVar(&bodyContent, "content", "", "The content of the note in HTML format. Subject to sanitization on the back-end.")
+ _ = cmd.MarkFlagRequired("content")
+ cmd.Flags().IntVar(&bodyDealId, "deal-id", 0, "The ID of the deal the note will be attached to. This property is required unless one of...")
+ cmd.Flags().StringVar(&bodyLeadId, "lead-id", "", "The ID of the lead the note will be attached to. This property is required unless one of...")
+ cmd.Flags().IntVar(&bodyOrgId, "org-id", 0, "The ID of the organization this note will be attached to. This property is required unless one of...")
+ cmd.Flags().IntVar(&bodyPersonId, "person-id", 0, "The ID of the person this note will be attached to. This property is required unless one of...")
+ cmd.Flags().IntVar(&bodyProjectId, "project-id", 0, "The ID of the project the note will be attached to. This property is required unless one of...")
+ cmd.Flags().IntVar(&bodyUserId, "user-id", 0, "The ID of the user who will be marked as the author of the note. Only an admin can change the author.")
+
+ return cmd
+}
+
+func newNotesDeleteCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete <id>",
+ Short: "Delete a note",
+ Example: " pipedrive-cli notes delete <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/notes/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newNotesGetCmd(flags *rootFlags) *cobra.Command {
+ var flagUserId int
+ var flagLeadId string
+ var flagDealId int
+ var flagPersonId int
+ var flagOrgId int
+ var flagProjectId int
+ var flagStart int
+ var flagLimit int
+ var flagSort string
+ var flagStartDate string
+ var flagEndDate string
+ var flagUpdatedSince string
+ var flagPinnedToLeadFlag float64
+ var flagPinnedToDealFlag float64
+ var flagPinnedToOrganizationFlag float64
+ var flagPinnedToPersonFlag float64
+ var flagPinnedToProjectFlag float64
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all notes",
+ Example: " pipedrive-cli notes get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/notes"
+ data, err := paginatedGet(c, path, map[string]string{
+ "user_id": fmt.Sprintf("%v", flagUserId),
+ "lead_id": fmt.Sprintf("%v", flagLeadId),
+ "deal_id": fmt.Sprintf("%v", flagDealId),
+ "person_id": fmt.Sprintf("%v", flagPersonId),
+ "org_id": fmt.Sprintf("%v", flagOrgId),
+ "project_id": fmt.Sprintf("%v", flagProjectId),
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ "sort": fmt.Sprintf("%v", flagSort),
+ "start_date": fmt.Sprintf("%v", flagStartDate),
+ "end_date": fmt.Sprintf("%v", flagEndDate),
+ "updated_since": fmt.Sprintf("%v", flagUpdatedSince),
+ "pinned_to_lead_flag": fmt.Sprintf("%v", flagPinnedToLeadFlag),
+ "pinned_to_deal_flag": fmt.Sprintf("%v", flagPinnedToDealFlag),
+ "pinned_to_organization_flag": fmt.Sprintf("%v", flagPinnedToOrganizationFlag),
+ "pinned_to_person_flag": fmt.Sprintf("%v", flagPinnedToPersonFlag),
+ "pinned_to_project_flag": fmt.Sprintf("%v", flagPinnedToProjectFlag),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagUserId, "user-id", 0, "The ID of the user whose notes to fetch. If omitted, notes by all users will be returned.")
+ cmd.Flags().StringVar(&flagLeadId, "lead-id", "", "The ID of the lead which notes to fetch. If omitted, notes about all leads will be returned.")
+ cmd.Flags().IntVar(&flagDealId, "deal-id", 0, "The ID of the deal which notes to fetch. If omitted, notes about all deals will be returned.")
+ cmd.Flags().IntVar(&flagPersonId, "person-id", 0, "The ID of the person whose notes to fetch. If omitted, notes about all persons will be returned.")
+ cmd.Flags().IntVar(&flagOrgId, "org-id", 0, "The ID of the organization which notes to fetch. If omitted, notes about all organizations will be returned.")
+ cmd.Flags().IntVar(&flagProjectId, "project-id", 0, "The ID of the project which notes to fetch. If omitted, notes about all projects will be returned.")
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().StringVar(&flagSort, "sort", "", "The field names and sorting mode separated by a comma (`field_name_1 ASC`, `field_name_2 DESC`). Only first-level...")
+ cmd.Flags().StringVar(&flagStartDate, "start-date", "", "The date in format of YYYY-MM-DD from which notes to fetch")
+ cmd.Flags().StringVar(&flagEndDate, "end-date", "", "The date in format of YYYY-MM-DD until which notes to fetch to")
+ cmd.Flags().StringVar(&flagUpdatedSince, "updated-since", "", "If set, only notes with an `update_time` later than or equal to this time are returned. In RFC3339 format, e.g....")
+ cmd.Flags().Float64Var(&flagPinnedToLeadFlag, "pinned-to-lead-flag", 0.0, "If set, the results are filtered by note to lead pinning state")
+ cmd.Flags().Float64Var(&flagPinnedToDealFlag, "pinned-to-deal-flag", 0.0, "If set, the results are filtered by note to deal pinning state")
+ cmd.Flags().Float64Var(&flagPinnedToOrganizationFlag, "pinned-to-organization-flag", 0.0, "If set, the results are filtered by note to organization pinning state")
+ cmd.Flags().Float64Var(&flagPinnedToPersonFlag, "pinned-to-person-flag", 0.0, "If set, the results are filtered by note to person pinning state")
+ cmd.Flags().Float64Var(&flagPinnedToProjectFlag, "pinned-to-project-flag", 0.0, "If set, the results are filtered by note to project pinning state")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
+func newNotesGetIdCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-id <id>",
+ Short: "Get one note",
+ Example: " pipedrive-cli notes get-id <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/notes/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newNotesUpdateCmd(flags *rootFlags) *cobra.Command {
+ var bodyAddTime string
+ var bodyContent string
+ var bodyDealId int
+ var bodyLeadId string
+ var bodyOrgId int
+ var bodyPersonId int
+ var bodyProjectId int
+ var bodyUserId int
+
+ cmd := &cobra.Command{
+ Use: "update <id>",
+ Short: "Update a note",
+ Example: " pipedrive-cli notes update <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/notes/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyAddTime != "" {
+ body["add_time"] = bodyAddTime
+ }
+ if bodyContent != "" {
+ body["content"] = bodyContent
+ }
+ if bodyDealId != 0 {
+ body["deal_id"] = bodyDealId
+ }
+ if bodyLeadId != "" {
+ body["lead_id"] = bodyLeadId
+ }
+ if bodyOrgId != 0 {
+ body["org_id"] = bodyOrgId
+ }
+ if bodyPersonId != 0 {
+ body["person_id"] = bodyPersonId
+ }
+ if bodyProjectId != 0 {
+ body["project_id"] = bodyProjectId
+ }
+ if bodyUserId != 0 {
+ body["user_id"] = bodyUserId
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyAddTime, "add-time", "", "The optional creation date & time of the note in UTC. Can be set in the past or in the future. Format: YYYY-MM-DD...")
+ cmd.Flags().StringVar(&bodyContent, "content", "", "The content of the note in HTML format. Subject to sanitization on the back-end.")
+ cmd.Flags().IntVar(&bodyDealId, "deal-id", 0, "The ID of the deal the note will be attached to")
+ cmd.Flags().StringVar(&bodyLeadId, "lead-id", "", "The ID of the lead the note will be attached to")
+ cmd.Flags().IntVar(&bodyOrgId, "org-id", 0, "The ID of the organization the note will be attached to")
+ cmd.Flags().IntVar(&bodyPersonId, "person-id", 0, "The ID of the person the note will be attached to")
+ cmd.Flags().IntVar(&bodyProjectId, "project-id", 0, "The ID of the project the note will be attached to")
+ cmd.Flags().IntVar(&bodyUserId, "user-id", 0, "The ID of the user who will be marked as the author of the note. Only an admin can change the author.")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/notes_comments.go b/pipedrive-cli/internal/cli/notes_comments.go
new file mode 100644
index 00000000..f2b1ccaa
--- /dev/null
+++ b/pipedrive-cli/internal/cli/notes_comments.go
@@ -0,0 +1,211 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newNotesCommentsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "comments",
+ Short: "Manage comments",
+ }
+
+ cmd.AddCommand(newNotesCommentsAddNoteCmd(flags))
+ cmd.AddCommand(newNotesCommentsDeleteCmd(flags))
+ cmd.AddCommand(newNotesCommentsGetCmd(flags))
+ cmd.AddCommand(newNotesCommentsGetNoteCmd(flags))
+ cmd.AddCommand(newNotesCommentsUpdateForNoteCmd(flags))
+ return cmd
+}
+
+func newNotesCommentsAddNoteCmd(flags *rootFlags) *cobra.Command {
+ var bodyContent string
+
+ cmd := &cobra.Command{
+ Use: "add-note <id>",
+ Aliases: []string{"create"},
+ Short: "Add a comment to a note",
+ Example: " pipedrive-cli notes comments add-note <id> --content value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/notes/{id}/comments"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyContent != "" {
+ body["content"] = bodyContent
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyContent, "content", "", "The content of the comment in HTML format. Subject to sanitization on the back-end.")
+ _ = cmd.MarkFlagRequired("content")
+
+ return cmd
+}
+
+func newNotesCommentsDeleteCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete <id> <commentId>",
+ Short: "Delete a comment related to a note",
+ Example: " pipedrive-cli notes comments delete <id> <commentId>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/notes/{id}/comments/{commentId}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ if len(args) < 2 {
+ return usageErr(fmt.Errorf("commentId is required"))
+ }
+ path = replacePathParam(path, "commentId", args[1])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newNotesCommentsGetCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get <id> <commentId>",
+ Short: "Get one comment",
+ Example: " pipedrive-cli notes comments get <id> <commentId>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/notes/{id}/comments/{commentId}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ if len(args) < 2 {
+ return usageErr(fmt.Errorf("commentId is required"))
+ }
+ path = replacePathParam(path, "commentId", args[1])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newNotesCommentsGetNoteCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-note <id>",
+ Short: "Get all comments for a note",
+ Example: " pipedrive-cli notes comments get-note <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/notes/{id}/comments"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
+func newNotesCommentsUpdateForNoteCmd(flags *rootFlags) *cobra.Command {
+ var bodyContent string
+
+ cmd := &cobra.Command{
+ Use: "update-for-note <id> <commentId>",
+ Aliases: []string{"update"},
+ Short: "Update a comment related to a note",
+ Example: " pipedrive-cli notes comments update-for-note <id> <commentId> --content value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/notes/{id}/comments/{commentId}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ if len(args) < 2 {
+ return usageErr(fmt.Errorf("commentId is required"))
+ }
+ path = replacePathParam(path, "commentId", args[1])
+ body := map[string]any{}
+ if bodyContent != "" {
+ body["content"] = bodyContent
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyContent, "content", "", "The content of the comment in HTML format. Subject to sanitization on the back-end.")
+ _ = cmd.MarkFlagRequired("content")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/oauth.go b/pipedrive-cli/internal/cli/oauth.go
new file mode 100644
index 00000000..8adb8e97
--- /dev/null
+++ b/pipedrive-cli/internal/cli/oauth.go
@@ -0,0 +1,148 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newOauthCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "oauth",
+ Short: "Using OAuth 2.0 is necessary for developing apps that are available in the Pipedrive Marketplace. Authorization via...",
+ }
+
+ cmd.AddCommand(newOauthAuthorizeCmd(flags))
+ cmd.AddCommand(newOauthGetTokensCmd(flags))
+ cmd.AddCommand(newOauthRefreshTokensCmd(flags))
+ return cmd
+}
+
+func newOauthAuthorizeCmd(flags *rootFlags) *cobra.Command {
+ var flagClientId string
+ var flagRedirectUri string
+ var flagState string
+
+ cmd := &cobra.Command{
+ Use: "authorize",
+ Aliases: []string{"list"},
+ Short: "Requesting authorization",
+ Example: " pipedrive-cli oauth authorize",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/oauth/authorize"
+ params := map[string]string{}
+ if flagClientId != "" {
+ params["client_id"] = fmt.Sprintf("%v", flagClientId)
+ }
+ if flagRedirectUri != "" {
+ params["redirect_uri"] = fmt.Sprintf("%v", flagRedirectUri)
+ }
+ if flagState != "" {
+ params["state"] = fmt.Sprintf("%v", flagState)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagClientId, "client-id", "", "The client ID provided to you by the Pipedrive Marketplace when you register your app")
+ _ = cmd.MarkFlagRequired("client-id")
+ cmd.Flags().StringVar(&flagRedirectUri, "redirect-uri", "", "The callback URL you provided when you registered your app. Authorization code will be sent to that URL (if it...")
+ _ = cmd.MarkFlagRequired("redirect-uri")
+ cmd.Flags().StringVar(&flagState, "state", "", "You may pass any random string as the state parameter and the same string will be returned to your app after a user...")
+
+ return cmd
+}
+
+func newOauthGetTokensCmd(flags *rootFlags) *cobra.Command {
+ var bodyCode string
+ var bodyGrantType string
+ var bodyRedirectUri string
+
+ cmd := &cobra.Command{
+ Use: "get-tokens",
+ Aliases: []string{"create"},
+ Short: "Getting the tokens",
+ Example: " pipedrive-cli oauth get-tokens",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/oauth/token"
+ body := map[string]any{}
+ if bodyCode != "" {
+ body["code"] = bodyCode
+ }
+ if bodyGrantType != "" {
+ body["grant_type"] = bodyGrantType
+ }
+ if bodyRedirectUri != "" {
+ body["redirect_uri"] = bodyRedirectUri
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyCode, "code", "", "The authorization code that you received after the user confirmed app installation")
+ cmd.Flags().StringVar(&bodyGrantType, "grant-type", "authorization_code", "Since you are trying to exchange an authorization code for a pair of tokens, you must use the value 'authorization_code'")
+ cmd.Flags().StringVar(&bodyRedirectUri, "redirect-uri", "", "The callback URL you provided when you registered your app")
+
+ return cmd
+}
+
+func newOauthRefreshTokensCmd(flags *rootFlags) *cobra.Command {
+ var bodyGrantType string
+ var bodyRefreshToken string
+
+ cmd := &cobra.Command{
+ Use: "refresh-tokens",
+ Short: "Refreshing the tokens",
+ Example: " pipedrive-cli oauth refresh-tokens",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/oauth/token/"
+ body := map[string]any{}
+ if bodyGrantType != "" {
+ body["grant_type"] = bodyGrantType
+ }
+ if bodyRefreshToken != "" {
+ body["refresh_token"] = bodyRefreshToken
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyGrantType, "grant-type", "refresh_token", "Since you are to refresh your access_token, you must use the value 'refresh_token'")
+ cmd.Flags().StringVar(&bodyRefreshToken, "refresh-token", "", "The refresh token that you received after you exchanged the authorization code")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/organization-fields.go b/pipedrive-cli/internal/cli/organization-fields.go
new file mode 100644
index 00000000..35f7de1a
--- /dev/null
+++ b/pipedrive-cli/internal/cli/organization-fields.go
@@ -0,0 +1,235 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newOrganizationFieldsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "organization-fields",
+ Short: "Organization fields represent the near-complete schema for an organization in the context of the company of the...",
+ }
+
+ cmd.AddCommand(newOrganizationFieldsAddCmd(flags))
+ cmd.AddCommand(newOrganizationFieldsDeleteCmd(flags))
+ cmd.AddCommand(newOrganizationFieldsDeleteOrganizationfieldsCmd(flags))
+ cmd.AddCommand(newOrganizationFieldsGetCmd(flags))
+ cmd.AddCommand(newOrganizationFieldsGetOrganizationfieldsCmd(flags))
+ cmd.AddCommand(newOrganizationFieldsUpdateCmd(flags))
+ return cmd
+}
+
+func newOrganizationFieldsAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyAddVisibleFlag bool
+ var bodyFieldType string
+ var bodyName string
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Add a new organization field",
+ Example: " pipedrive-cli organization-fields add --field-type value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizationFields"
+ body := map[string]any{}
+ if bodyAddVisibleFlag != false {
+ body["add_visible_flag"] = bodyAddVisibleFlag
+ }
+ if bodyFieldType != "" {
+ body["field_type"] = bodyFieldType
+ }
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().BoolVar(&bodyAddVisibleFlag, "add-visible-flag", true, "Whether the field is available in the 'add new' modal or not (both in the web and mobile app)")
+ cmd.Flags().StringVar(&bodyFieldType, "field-type", "", "The type of the field<table><tr><th>Value</th><th>Description</th></tr><tr><td>`address`</td><td>Address...")
+ _ = cmd.MarkFlagRequired("field-type")
+ cmd.Flags().StringVar(&bodyName, "name", "", "The name of the field")
+ _ = cmd.MarkFlagRequired("name")
+
+ return cmd
+}
+
+func newOrganizationFieldsDeleteCmd(flags *rootFlags) *cobra.Command {
+ var flagIds string
+
+ cmd := &cobra.Command{
+ Use: "delete",
+ Short: "Delete multiple organization fields in bulk",
+ Example: " pipedrive-cli organization-fields delete",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizationFields"
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagIds, "ids", "", "The comma-separated field IDs to delete")
+ _ = cmd.MarkFlagRequired("ids")
+
+ return cmd
+}
+
+func newOrganizationFieldsDeleteOrganizationfieldsCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete-organizationfields <id>",
+ Short: "Delete an organization field",
+ Example: " pipedrive-cli organization-fields delete-organizationfields <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizationFields/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newOrganizationFieldsGetCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all organization fields",
+ Example: " pipedrive-cli organization-fields get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizationFields"
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
+func newOrganizationFieldsGetOrganizationfieldsCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-organizationfields <id>",
+ Short: "Get one organization field",
+ Example: " pipedrive-cli organization-fields get-organizationfields <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizationFields/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newOrganizationFieldsUpdateCmd(flags *rootFlags) *cobra.Command {
+ var bodyAddVisibleFlag bool
+ var bodyName string
+
+ cmd := &cobra.Command{
+ Use: "update <id>",
+ Short: "Update an organization field",
+ Example: " pipedrive-cli organization-fields update <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizationFields/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyAddVisibleFlag != false {
+ body["add_visible_flag"] = bodyAddVisibleFlag
+ }
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().BoolVar(&bodyAddVisibleFlag, "add-visible-flag", true, "Whether the field is available in 'add new' modal or not (both in web and mobile app)")
+ cmd.Flags().StringVar(&bodyName, "name", "", "The name of the field")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/organization-relationships.go b/pipedrive-cli/internal/cli/organization-relationships.go
new file mode 100644
index 00000000..8d39eec6
--- /dev/null
+++ b/pipedrive-cli/internal/cli/organization-relationships.go
@@ -0,0 +1,225 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newOrganizationRelationshipsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "organization-relationships",
+ Short: "Organization relationships represent how different organizations are related to each other. The relationship can be...",
+ }
+
+ cmd.AddCommand(newOrganizationRelationshipsAddCmd(flags))
+ cmd.AddCommand(newOrganizationRelationshipsDeleteCmd(flags))
+ cmd.AddCommand(newOrganizationRelationshipsGetCmd(flags))
+ cmd.AddCommand(newOrganizationRelationshipsGetOrganizationrelationshipsCmd(flags))
+ cmd.AddCommand(newOrganizationRelationshipsUpdateCmd(flags))
+ return cmd
+}
+
+func newOrganizationRelationshipsAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyOrgId int
+ var bodyRelLinkedOrgId int
+ var bodyRelOwnerOrgId int
+ var bodyType string
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Create an organization relationship",
+ Example: " pipedrive-cli organization-relationships add --type value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizationRelationships"
+ body := map[string]any{}
+ if bodyOrgId != 0 {
+ body["org_id"] = bodyOrgId
+ }
+ if bodyRelLinkedOrgId != 0 {
+ body["rel_linked_org_id"] = bodyRelLinkedOrgId
+ }
+ if bodyRelOwnerOrgId != 0 {
+ body["rel_owner_org_id"] = bodyRelOwnerOrgId
+ }
+ if bodyType != "" {
+ body["type"] = bodyType
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyOrgId, "org-id", 0, "The ID of the base organization for the returned calculated values")
+ cmd.Flags().IntVar(&bodyRelLinkedOrgId, "rel-linked-org-id", 0, "The linked organization in the relationship. If type is `parent`, then the linked organization is the daughter.")
+ _ = cmd.MarkFlagRequired("rel-linked-org-id")
+ cmd.Flags().IntVar(&bodyRelOwnerOrgId, "rel-owner-org-id", 0, "The owner of the relationship. If type is `parent`, then the owner is the parent and the linked organization is the...")
+ _ = cmd.MarkFlagRequired("rel-owner-org-id")
+ cmd.Flags().StringVar(&bodyType, "type", "", "The type of organization relationship")
+ _ = cmd.MarkFlagRequired("type")
+
+ return cmd
+}
+
+func newOrganizationRelationshipsDeleteCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete <id>",
+ Short: "Delete an organization relationship",
+ Example: " pipedrive-cli organization-relationships delete <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizationRelationships/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newOrganizationRelationshipsGetCmd(flags *rootFlags) *cobra.Command {
+ var flagOrgId int
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all relationships for organization",
+ Example: " pipedrive-cli organization-relationships get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizationRelationships"
+ params := map[string]string{}
+ if flagOrgId != 0 {
+ params["org_id"] = fmt.Sprintf("%v", flagOrgId)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagOrgId, "org-id", 0, "The ID of the organization to get relationships for")
+ _ = cmd.MarkFlagRequired("org-id")
+
+ return cmd
+}
+
+func newOrganizationRelationshipsGetOrganizationrelationshipsCmd(flags *rootFlags) *cobra.Command {
+ var flagOrgId int
+
+ cmd := &cobra.Command{
+ Use: "get-organizationrelationships <id>",
+ Short: "Get one organization relationship",
+ Example: " pipedrive-cli organization-relationships get-organizationrelationships <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizationRelationships/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ if flagOrgId != 0 {
+ params["org_id"] = fmt.Sprintf("%v", flagOrgId)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagOrgId, "org-id", 0, "The ID of the base organization for the returned calculated values")
+
+ return cmd
+}
+
+func newOrganizationRelationshipsUpdateCmd(flags *rootFlags) *cobra.Command {
+ var bodyOrgId int
+ var bodyRelLinkedOrgId int
+ var bodyRelOwnerOrgId int
+ var bodyType string
+
+ cmd := &cobra.Command{
+ Use: "update <id>",
+ Short: "Update an organization relationship",
+ Example: " pipedrive-cli organization-relationships update <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizationRelationships/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyOrgId != 0 {
+ body["org_id"] = bodyOrgId
+ }
+ if bodyRelLinkedOrgId != 0 {
+ body["rel_linked_org_id"] = bodyRelLinkedOrgId
+ }
+ if bodyRelOwnerOrgId != 0 {
+ body["rel_owner_org_id"] = bodyRelOwnerOrgId
+ }
+ if bodyType != "" {
+ body["type"] = bodyType
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyOrgId, "org-id", 0, "The ID of the base organization for the returned calculated values")
+ cmd.Flags().IntVar(&bodyRelLinkedOrgId, "rel-linked-org-id", 0, "The linked organization in this relationship. If type is `parent`, then the linked organization is the daughter.")
+ cmd.Flags().IntVar(&bodyRelOwnerOrgId, "rel-owner-org-id", 0, "The owner of this relationship. If type is `parent`, then the owner is the parent and the linked organization is the...")
+ cmd.Flags().StringVar(&bodyType, "type", "", "The type of organization relationship")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/organizations.go b/pipedrive-cli/internal/cli/organizations.go
new file mode 100644
index 00000000..57ad85dc
--- /dev/null
+++ b/pipedrive-cli/internal/cli/organizations.go
@@ -0,0 +1,30 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newOrganizationsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "organizations",
+ Short: "Organizations are companies and other kinds of organizations you are making deals with. Persons can be associated...",
+ }
+
+ cmd.AddCommand(newOrganizationsChangelogCmd(flags))
+ cmd.AddCommand(newOrganizationsFilesCmd(flags))
+ cmd.AddCommand(newOrganizationsFlowCmd(flags))
+ cmd.AddCommand(newOrganizationsFollowersCmd(flags))
+ cmd.AddCommand(newOrganizationsMailMessagesCmd(flags))
+ cmd.AddCommand(newOrganizationsMergeCmd(flags))
+ cmd.AddCommand(newOrganizationsPermittedUsersCmd(flags))
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/organizations_changelog.go b/pipedrive-cli/internal/cli/organizations_changelog.go
new file mode 100644
index 00000000..4cafa5fe
--- /dev/null
+++ b/pipedrive-cli/internal/cli/organizations_changelog.go
@@ -0,0 +1,63 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newOrganizationsChangelogCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "changelog",
+ Short: "Manage changelog",
+ }
+
+ cmd.AddCommand(newOrganizationsChangelogGetOrganizationCmd(flags))
+ return cmd
+}
+
+func newOrganizationsChangelogGetOrganizationCmd(flags *rootFlags) *cobra.Command {
+ var flagCursor string
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-organization <id>",
+ Aliases: []string{"get"},
+ Short: "List updates about organization field values",
+ Example: " pipedrive-cli organizations changelog get-organization <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizations/{id}/changelog"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "cursor": fmt.Sprintf("%v", flagCursor),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "cursor", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagCursor, "cursor", "", "For pagination, the marker (an opaque string value) representing the first item on the next page")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/organizations_files.go b/pipedrive-cli/internal/cli/organizations_files.go
new file mode 100644
index 00000000..837bb0de
--- /dev/null
+++ b/pipedrive-cli/internal/cli/organizations_files.go
@@ -0,0 +1,66 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newOrganizationsFilesCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "files",
+ Short: "Files are documents of any kind (images, spreadsheets, text files, etc.) that are uploaded to Pipedrive, and usually...",
+ }
+
+ cmd.AddCommand(newOrganizationsFilesGetOrganizationCmd(flags))
+ return cmd
+}
+
+func newOrganizationsFilesGetOrganizationCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagSort string
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-organization <id>",
+ Aliases: []string{"get"},
+ Short: "List files attached to an organization",
+ Example: " pipedrive-cli organizations files get-organization <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizations/{id}/files"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ "sort": fmt.Sprintf("%v", flagSort),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page. Please note that a maximum value of 100 is allowed.")
+ cmd.Flags().StringVar(&flagSort, "sort", "", "Supported fields: `id`, `update_time`")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/organizations_flow.go b/pipedrive-cli/internal/cli/organizations_flow.go
new file mode 100644
index 00000000..1b5d7d90
--- /dev/null
+++ b/pipedrive-cli/internal/cli/organizations_flow.go
@@ -0,0 +1,69 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newOrganizationsFlowCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "flow",
+ Short: "Manage flow",
+ }
+
+ cmd.AddCommand(newOrganizationsFlowGetOrganizationUpdatesCmd(flags))
+ return cmd
+}
+
+func newOrganizationsFlowGetOrganizationUpdatesCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAllChanges string
+ var flagItems string
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-organization-updates <id>",
+ Aliases: []string{"get"},
+ Short: "List updates about an organization",
+ Example: " pipedrive-cli organizations flow get-organization-updates <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizations/{id}/flow"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ "all_changes": fmt.Sprintf("%v", flagAllChanges),
+ "items": fmt.Sprintf("%v", flagItems),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().StringVar(&flagAllChanges, "all-changes", "", "Whether to show custom field updates or not. 1 = Include custom field changes. If omitted, returns changes without...")
+ cmd.Flags().StringVar(&flagItems, "items", "", "A comma-separated string for filtering out item specific updates. (Possible values - activity, plannedActivity,...")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/organizations_followers.go b/pipedrive-cli/internal/cli/organizations_followers.go
new file mode 100644
index 00000000..15c23d5a
--- /dev/null
+++ b/pipedrive-cli/internal/cli/organizations_followers.go
@@ -0,0 +1,128 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newOrganizationsFollowersCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "followers",
+ Short: "Manage followers",
+ }
+
+ cmd.AddCommand(newOrganizationsFollowersAddOrganizationCmd(flags))
+ cmd.AddCommand(newOrganizationsFollowersDeleteOrganizationCmd(flags))
+ cmd.AddCommand(newOrganizationsFollowersGetOrganizationCmd(flags))
+ return cmd
+}
+
+func newOrganizationsFollowersAddOrganizationCmd(flags *rootFlags) *cobra.Command {
+ var bodyUserId int
+
+ cmd := &cobra.Command{
+ Use: "add-organization <id>",
+ Aliases: []string{"create"},
+ Short: "Add a follower to an organization",
+ Example: " pipedrive-cli organizations followers add-organization <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizations/{id}/followers"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyUserId != 0 {
+ body["user_id"] = bodyUserId
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyUserId, "user-id", 0, "The ID of the user")
+ _ = cmd.MarkFlagRequired("user-id")
+
+ return cmd
+}
+
+func newOrganizationsFollowersDeleteOrganizationCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete-organization <id> <follower_id>",
+ Aliases: []string{"delete"},
+ Short: "Delete a follower from an organization",
+ Example: " pipedrive-cli organizations followers delete-organization <id> <follower_id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizations/{id}/followers/{follower_id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ if len(args) < 2 {
+ return usageErr(fmt.Errorf("follower_id is required"))
+ }
+ path = replacePathParam(path, "follower_id", args[1])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newOrganizationsFollowersGetOrganizationCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-organization <id>",
+ Aliases: []string{"get"},
+ Short: "List followers of an organization",
+ Example: " pipedrive-cli organizations followers get-organization <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizations/{id}/followers"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/organizations_mail-messages.go b/pipedrive-cli/internal/cli/organizations_mail-messages.go
new file mode 100644
index 00000000..4e1da589
--- /dev/null
+++ b/pipedrive-cli/internal/cli/organizations_mail-messages.go
@@ -0,0 +1,63 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newOrganizationsMailMessagesCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "mail-messages",
+ Short: "Manage mail messages",
+ }
+
+ cmd.AddCommand(newOrganizationsMailMessagesGetOrganizationCmd(flags))
+ return cmd
+}
+
+func newOrganizationsMailMessagesGetOrganizationCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-organization <id>",
+ Aliases: []string{"get"},
+ Short: "List mail messages associated with an organization",
+ Example: " pipedrive-cli organizations mail-messages get-organization <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizations/{id}/mailMessages"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/organizations_merge.go b/pipedrive-cli/internal/cli/organizations_merge.go
new file mode 100644
index 00000000..9d64e949
--- /dev/null
+++ b/pipedrive-cli/internal/cli/organizations_merge.go
@@ -0,0 +1,61 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newOrganizationsMergeCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "merge",
+ Short: "Manage merge",
+ }
+
+ cmd.AddCommand(newOrganizationsMergeOrganizationsCmd(flags))
+ return cmd
+}
+
+func newOrganizationsMergeOrganizationsCmd(flags *rootFlags) *cobra.Command {
+ var bodyMergeWithId int
+
+ cmd := &cobra.Command{
+ Use: "organizations <id>",
+ Aliases: []string{"update"},
+ Short: "Merge two organizations",
+ Example: " pipedrive-cli organizations merge organizations <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizations/{id}/merge"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyMergeWithId != 0 {
+ body["merge_with_id"] = bodyMergeWithId
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyMergeWithId, "merge-with-id", 0, "The ID of the organization that the organization will be merged with")
+ _ = cmd.MarkFlagRequired("merge-with-id")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/organizations_permitted-users.go b/pipedrive-cli/internal/cli/organizations_permitted-users.go
new file mode 100644
index 00000000..4d17ba42
--- /dev/null
+++ b/pipedrive-cli/internal/cli/organizations_permitted-users.go
@@ -0,0 +1,55 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newOrganizationsPermittedUsersCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "permitted-users",
+ Short: "Manage permitted users",
+ }
+
+ cmd.AddCommand(newOrganizationsPermittedUsersGetOrganizationUsersCmd(flags))
+ return cmd
+}
+
+func newOrganizationsPermittedUsersGetOrganizationUsersCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-organization-users <id>",
+ Aliases: []string{"get"},
+ Short: "List permitted users",
+ Example: " pipedrive-cli organizations permitted-users get-organization-users <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/organizations/{id}/permittedUsers"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/permission-sets.go b/pipedrive-cli/internal/cli/permission-sets.go
new file mode 100644
index 00000000..e359b7f0
--- /dev/null
+++ b/pipedrive-cli/internal/cli/permission-sets.go
@@ -0,0 +1,88 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newPermissionSetsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "permission-sets",
+ Short: "Permission sets define what users in the account can do: which actions they are allowed to perform and which...",
+ }
+
+ cmd.AddCommand(newPermissionSetsGetCmd(flags))
+ cmd.AddCommand(newPermissionSetsGetPermissionsetsCmd(flags))
+ cmd.AddCommand(newPermissionSetsAssignmentsCmd(flags))
+ return cmd
+}
+
+func newPermissionSetsGetCmd(flags *rootFlags) *cobra.Command {
+ var flagApp string
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all permission sets",
+ Example: " pipedrive-cli permission-sets get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/permissionSets"
+ params := map[string]string{}
+ if flagApp != "" {
+ params["app"] = fmt.Sprintf("%v", flagApp)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagApp, "app", "", "The app to filter the permission sets by")
+
+ return cmd
+}
+
+func newPermissionSetsGetPermissionsetsCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-permissionsets <id>",
+ Short: "Get one permission set",
+ Example: " pipedrive-cli permission-sets get-permissionsets <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/permissionSets/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/permission-sets_assignments.go b/pipedrive-cli/internal/cli/permission-sets_assignments.go
new file mode 100644
index 00000000..6d2bfc05
--- /dev/null
+++ b/pipedrive-cli/internal/cli/permission-sets_assignments.go
@@ -0,0 +1,63 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newPermissionSetsAssignmentsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "assignments",
+ Short: "Manage assignments",
+ }
+
+ cmd.AddCommand(newPermissionSetsAssignmentsGetPermissionSetCmd(flags))
+ return cmd
+}
+
+func newPermissionSetsAssignmentsGetPermissionSetCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-permission-set <id>",
+ Aliases: []string{"get"},
+ Short: "List permission set assignments",
+ Example: " pipedrive-cli permission-sets assignments get-permission-set <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/permissionSets/{id}/assignments"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/person-fields.go b/pipedrive-cli/internal/cli/person-fields.go
new file mode 100644
index 00000000..eb896ab6
--- /dev/null
+++ b/pipedrive-cli/internal/cli/person-fields.go
@@ -0,0 +1,235 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newPersonFieldsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "person-fields",
+ Short: "Person fields represent the near-complete schema for a person in the context of the company of the authorized user....",
+ }
+
+ cmd.AddCommand(newPersonFieldsAddCmd(flags))
+ cmd.AddCommand(newPersonFieldsDeleteCmd(flags))
+ cmd.AddCommand(newPersonFieldsDeletePersonfieldsCmd(flags))
+ cmd.AddCommand(newPersonFieldsGetCmd(flags))
+ cmd.AddCommand(newPersonFieldsGetPersonfieldsCmd(flags))
+ cmd.AddCommand(newPersonFieldsUpdateCmd(flags))
+ return cmd
+}
+
+func newPersonFieldsAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyAddVisibleFlag bool
+ var bodyFieldType string
+ var bodyName string
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Add a new person field",
+ Example: " pipedrive-cli person-fields add --field-type value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/personFields"
+ body := map[string]any{}
+ if bodyAddVisibleFlag != false {
+ body["add_visible_flag"] = bodyAddVisibleFlag
+ }
+ if bodyFieldType != "" {
+ body["field_type"] = bodyFieldType
+ }
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().BoolVar(&bodyAddVisibleFlag, "add-visible-flag", true, "Whether the field is available in the 'add new' modal or not (both in the web and mobile app)")
+ cmd.Flags().StringVar(&bodyFieldType, "field-type", "", "The type of the field<table><tr><th>Value</th><th>Description</th></tr><tr><td>`address`</td><td>Address...")
+ _ = cmd.MarkFlagRequired("field-type")
+ cmd.Flags().StringVar(&bodyName, "name", "", "The name of the field")
+ _ = cmd.MarkFlagRequired("name")
+
+ return cmd
+}
+
+func newPersonFieldsDeleteCmd(flags *rootFlags) *cobra.Command {
+ var flagIds string
+
+ cmd := &cobra.Command{
+ Use: "delete",
+ Short: "Delete multiple person fields in bulk",
+ Example: " pipedrive-cli person-fields delete",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/personFields"
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagIds, "ids", "", "The comma-separated field IDs to delete")
+ _ = cmd.MarkFlagRequired("ids")
+
+ return cmd
+}
+
+func newPersonFieldsDeletePersonfieldsCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete-personfields <id>",
+ Short: "Delete a person field",
+ Example: " pipedrive-cli person-fields delete-personfields <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/personFields/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newPersonFieldsGetCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all person fields",
+ Example: " pipedrive-cli person-fields get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/personFields"
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
+func newPersonFieldsGetPersonfieldsCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-personfields <id>",
+ Short: "Get one person field",
+ Example: " pipedrive-cli person-fields get-personfields <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/personFields/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newPersonFieldsUpdateCmd(flags *rootFlags) *cobra.Command {
+ var bodyAddVisibleFlag bool
+ var bodyName string
+
+ cmd := &cobra.Command{
+ Use: "update <id>",
+ Short: "Update a person field",
+ Example: " pipedrive-cli person-fields update <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/personFields/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyAddVisibleFlag != false {
+ body["add_visible_flag"] = bodyAddVisibleFlag
+ }
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().BoolVar(&bodyAddVisibleFlag, "add-visible-flag", true, "Whether the field is available in 'add new' modal or not (both in web and mobile app)")
+ cmd.Flags().StringVar(&bodyName, "name", "", "The name of the field")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/persons.go b/pipedrive-cli/internal/cli/persons.go
new file mode 100644
index 00000000..acb456c3
--- /dev/null
+++ b/pipedrive-cli/internal/cli/persons.go
@@ -0,0 +1,32 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newPersonsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "persons",
+ Short: "Persons are your contacts, the customers you are doing deals with. Each person can belong to an organization....",
+ }
+
+ cmd.AddCommand(newPersonsChangelogCmd(flags))
+ cmd.AddCommand(newPersonsFilesCmd(flags))
+ cmd.AddCommand(newPersonsFlowCmd(flags))
+ cmd.AddCommand(newPersonsFollowersCmd(flags))
+ cmd.AddCommand(newPersonsMailMessagesCmd(flags))
+ cmd.AddCommand(newPersonsMergeCmd(flags))
+ cmd.AddCommand(newPersonsPermittedUsersCmd(flags))
+ cmd.AddCommand(newPersonsPictureCmd(flags))
+ cmd.AddCommand(newPersonsProductsCmd(flags))
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/persons_changelog.go b/pipedrive-cli/internal/cli/persons_changelog.go
new file mode 100644
index 00000000..a0fcd8a2
--- /dev/null
+++ b/pipedrive-cli/internal/cli/persons_changelog.go
@@ -0,0 +1,63 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newPersonsChangelogCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "changelog",
+ Short: "Manage changelog",
+ }
+
+ cmd.AddCommand(newPersonsChangelogGetPersonCmd(flags))
+ return cmd
+}
+
+func newPersonsChangelogGetPersonCmd(flags *rootFlags) *cobra.Command {
+ var flagCursor string
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-person <id>",
+ Aliases: []string{"get"},
+ Short: "List updates about person field values",
+ Example: " pipedrive-cli persons changelog get-person <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/persons/{id}/changelog"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "cursor": fmt.Sprintf("%v", flagCursor),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "cursor", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagCursor, "cursor", "", "For pagination, the marker (an opaque string value) representing the first item on the next page")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/persons_files.go b/pipedrive-cli/internal/cli/persons_files.go
new file mode 100644
index 00000000..e98c2015
--- /dev/null
+++ b/pipedrive-cli/internal/cli/persons_files.go
@@ -0,0 +1,66 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newPersonsFilesCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "files",
+ Short: "Files are documents of any kind (images, spreadsheets, text files, etc.) that are uploaded to Pipedrive, and usually...",
+ }
+
+ cmd.AddCommand(newPersonsFilesGetPersonCmd(flags))
+ return cmd
+}
+
+func newPersonsFilesGetPersonCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagSort string
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-person <id>",
+ Aliases: []string{"get"},
+ Short: "List files attached to a person",
+ Example: " pipedrive-cli persons files get-person <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/persons/{id}/files"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ "sort": fmt.Sprintf("%v", flagSort),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page. Please note that a maximum value of 100 is allowed.")
+ cmd.Flags().StringVar(&flagSort, "sort", "", "Supported fields: `id`, `update_time`")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/persons_flow.go b/pipedrive-cli/internal/cli/persons_flow.go
new file mode 100644
index 00000000..bc19c21b
--- /dev/null
+++ b/pipedrive-cli/internal/cli/persons_flow.go
@@ -0,0 +1,69 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newPersonsFlowCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "flow",
+ Short: "Manage flow",
+ }
+
+ cmd.AddCommand(newPersonsFlowGetPersonUpdatesCmd(flags))
+ return cmd
+}
+
+func newPersonsFlowGetPersonUpdatesCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAllChanges string
+ var flagItems string
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-person-updates <id>",
+ Aliases: []string{"get"},
+ Short: "List updates about a person",
+ Example: " pipedrive-cli persons flow get-person-updates <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/persons/{id}/flow"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ "all_changes": fmt.Sprintf("%v", flagAllChanges),
+ "items": fmt.Sprintf("%v", flagItems),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().StringVar(&flagAllChanges, "all-changes", "", "Whether to show custom field updates or not. 1 = Include custom field changes. If omitted returns changes without...")
+ cmd.Flags().StringVar(&flagItems, "items", "", "A comma-separated string for filtering out item specific updates. (Possible values - call, activity,...")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/persons_followers.go b/pipedrive-cli/internal/cli/persons_followers.go
new file mode 100644
index 00000000..ee2d9f18
--- /dev/null
+++ b/pipedrive-cli/internal/cli/persons_followers.go
@@ -0,0 +1,128 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newPersonsFollowersCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "followers",
+ Short: "Manage followers",
+ }
+
+ cmd.AddCommand(newPersonsFollowersAddPersonCmd(flags))
+ cmd.AddCommand(newPersonsFollowersDeletePersonCmd(flags))
+ cmd.AddCommand(newPersonsFollowersGetPersonCmd(flags))
+ return cmd
+}
+
+func newPersonsFollowersAddPersonCmd(flags *rootFlags) *cobra.Command {
+ var bodyUserId int
+
+ cmd := &cobra.Command{
+ Use: "add-person <id>",
+ Aliases: []string{"create"},
+ Short: "Add a follower to a person",
+ Example: " pipedrive-cli persons followers add-person <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/persons/{id}/followers"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyUserId != 0 {
+ body["user_id"] = bodyUserId
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyUserId, "user-id", 0, "The ID of the user")
+ _ = cmd.MarkFlagRequired("user-id")
+
+ return cmd
+}
+
+func newPersonsFollowersDeletePersonCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete-person <id> <follower_id>",
+ Aliases: []string{"delete"},
+ Short: "Delete a follower from a person",
+ Example: " pipedrive-cli persons followers delete-person <id> <follower_id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/persons/{id}/followers/{follower_id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ if len(args) < 2 {
+ return usageErr(fmt.Errorf("follower_id is required"))
+ }
+ path = replacePathParam(path, "follower_id", args[1])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newPersonsFollowersGetPersonCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-person <id>",
+ Aliases: []string{"get"},
+ Short: "List followers of a person",
+ Example: " pipedrive-cli persons followers get-person <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/persons/{id}/followers"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/persons_mail-messages.go b/pipedrive-cli/internal/cli/persons_mail-messages.go
new file mode 100644
index 00000000..c74db33a
--- /dev/null
+++ b/pipedrive-cli/internal/cli/persons_mail-messages.go
@@ -0,0 +1,63 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newPersonsMailMessagesCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "mail-messages",
+ Short: "Manage mail messages",
+ }
+
+ cmd.AddCommand(newPersonsMailMessagesGetPersonCmd(flags))
+ return cmd
+}
+
+func newPersonsMailMessagesGetPersonCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-person <id>",
+ Aliases: []string{"get"},
+ Short: "List mail messages associated with a person",
+ Example: " pipedrive-cli persons mail-messages get-person <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/persons/{id}/mailMessages"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/persons_merge.go b/pipedrive-cli/internal/cli/persons_merge.go
new file mode 100644
index 00000000..ffa9dfc1
--- /dev/null
+++ b/pipedrive-cli/internal/cli/persons_merge.go
@@ -0,0 +1,61 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newPersonsMergeCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "merge",
+ Short: "Manage merge",
+ }
+
+ cmd.AddCommand(newPersonsMergePersonsCmd(flags))
+ return cmd
+}
+
+func newPersonsMergePersonsCmd(flags *rootFlags) *cobra.Command {
+ var bodyMergeWithId int
+
+ cmd := &cobra.Command{
+ Use: "persons <id>",
+ Aliases: []string{"update"},
+ Short: "Merge two persons",
+ Example: " pipedrive-cli persons merge persons <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/persons/{id}/merge"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyMergeWithId != 0 {
+ body["merge_with_id"] = bodyMergeWithId
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyMergeWithId, "merge-with-id", 0, "The ID of the person that will not be overwritten. This person’s data will be prioritized in case of conflict with...")
+ _ = cmd.MarkFlagRequired("merge-with-id")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/persons_permitted-users.go b/pipedrive-cli/internal/cli/persons_permitted-users.go
new file mode 100644
index 00000000..959506b6
--- /dev/null
+++ b/pipedrive-cli/internal/cli/persons_permitted-users.go
@@ -0,0 +1,55 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newPersonsPermittedUsersCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "permitted-users",
+ Short: "Manage permitted users",
+ }
+
+ cmd.AddCommand(newPersonsPermittedUsersGetPersonUsersCmd(flags))
+ return cmd
+}
+
+func newPersonsPermittedUsersGetPersonUsersCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-person-users <id>",
+ Aliases: []string{"get"},
+ Short: "List permitted users",
+ Example: " pipedrive-cli persons permitted-users get-person-users <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/persons/{id}/permittedUsers"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/persons_picture.go b/pipedrive-cli/internal/cli/persons_picture.go
new file mode 100644
index 00000000..159cf60e
--- /dev/null
+++ b/pipedrive-cli/internal/cli/persons_picture.go
@@ -0,0 +1,112 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newPersonsPictureCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "picture",
+ Short: "Manage picture",
+ }
+
+ cmd.AddCommand(newPersonsPictureAddPersonCmd(flags))
+ cmd.AddCommand(newPersonsPictureDeletePersonCmd(flags))
+ return cmd
+}
+
+func newPersonsPictureAddPersonCmd(flags *rootFlags) *cobra.Command {
+ var bodyCropHeight int
+ var bodyCropWidth int
+ var bodyCropX int
+ var bodyCropY int
+ var bodyFile string
+
+ cmd := &cobra.Command{
+ Use: "add-person <id>",
+ Aliases: []string{"create"},
+ Short: "Add person picture",
+ Example: " pipedrive-cli persons picture add-person <id> --file value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/persons/{id}/picture"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyCropHeight != 0 {
+ body["crop_height"] = bodyCropHeight
+ }
+ if bodyCropWidth != 0 {
+ body["crop_width"] = bodyCropWidth
+ }
+ if bodyCropX != 0 {
+ body["crop_x"] = bodyCropX
+ }
+ if bodyCropY != 0 {
+ body["crop_y"] = bodyCropY
+ }
+ if bodyFile != "" {
+ body["file"] = bodyFile
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyCropHeight, "crop-height", 0, "The height of the cropping area (in pixels)")
+ cmd.Flags().IntVar(&bodyCropWidth, "crop-width", 0, "The width of the cropping area (in pixels)")
+ cmd.Flags().IntVar(&bodyCropX, "crop-x", 0, "X coordinate to where start cropping form (in pixels)")
+ cmd.Flags().IntVar(&bodyCropY, "crop-y", 0, "Y coordinate to where start cropping form (in pixels)")
+ cmd.Flags().StringVar(&bodyFile, "file", "", "One image supplied in the multipart/form-data encoding")
+ _ = cmd.MarkFlagRequired("file")
+
+ return cmd
+}
+
+func newPersonsPictureDeletePersonCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete-person <id>",
+ Aliases: []string{"delete"},
+ Short: "Delete person picture",
+ Example: " pipedrive-cli persons picture delete-person <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/persons/{id}/picture"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/persons_products.go b/pipedrive-cli/internal/cli/persons_products.go
new file mode 100644
index 00000000..3fb850af
--- /dev/null
+++ b/pipedrive-cli/internal/cli/persons_products.go
@@ -0,0 +1,63 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newPersonsProductsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "products",
+ Short: "Products are the goods or services you are dealing with. Each product can have N different price points - firstly,...",
+ }
+
+ cmd.AddCommand(newPersonsProductsGetPersonCmd(flags))
+ return cmd
+}
+
+func newPersonsProductsGetPersonCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-person <id>",
+ Aliases: []string{"get"},
+ Short: "List products associated with a person",
+ Example: " pipedrive-cli persons products get-person <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/persons/{id}/products"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/pipelines.go b/pipedrive-cli/internal/cli/pipelines.go
new file mode 100644
index 00000000..deae489f
--- /dev/null
+++ b/pipedrive-cli/internal/cli/pipelines.go
@@ -0,0 +1,26 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newPipelinesCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "pipelines",
+ Short: "Pipelines are essentially ordered collections of stages.",
+ }
+
+ cmd.AddCommand(newPipelinesConversionStatisticsCmd(flags))
+ cmd.AddCommand(newPipelinesDealsCmd(flags))
+ cmd.AddCommand(newPipelinesMovementStatisticsCmd(flags))
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/pipelines_conversion-statistics.go b/pipedrive-cli/internal/cli/pipelines_conversion-statistics.go
new file mode 100644
index 00000000..b8514d93
--- /dev/null
+++ b/pipedrive-cli/internal/cli/pipelines_conversion-statistics.go
@@ -0,0 +1,72 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newPipelinesConversionStatisticsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "conversion-statistics",
+ Short: "Manage conversion statistics",
+ }
+
+ cmd.AddCommand(newPipelinesConversionStatisticsGetPipelineCmd(flags))
+ return cmd
+}
+
+func newPipelinesConversionStatisticsGetPipelineCmd(flags *rootFlags) *cobra.Command {
+ var flagStartDate string
+ var flagEndDate string
+ var flagUserId int
+
+ cmd := &cobra.Command{
+ Use: "get-pipeline <id>",
+ Aliases: []string{"get"},
+ Short: "Get deals conversion rates in pipeline",
+ Example: " pipedrive-cli pipelines conversion-statistics get-pipeline <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/pipelines/{id}/conversion_statistics"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ if flagStartDate != "" {
+ params["start_date"] = fmt.Sprintf("%v", flagStartDate)
+ }
+ if flagEndDate != "" {
+ params["end_date"] = fmt.Sprintf("%v", flagEndDate)
+ }
+ if flagUserId != 0 {
+ params["user_id"] = fmt.Sprintf("%v", flagUserId)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagStartDate, "start-date", "", "The start of the period. Date in format of YYYY-MM-DD.")
+ _ = cmd.MarkFlagRequired("start-date")
+ cmd.Flags().StringVar(&flagEndDate, "end-date", "", "The end of the period. Date in format of YYYY-MM-DD.")
+ _ = cmd.MarkFlagRequired("end-date")
+ cmd.Flags().IntVar(&flagUserId, "user-id", 0, "The ID of the user who's pipeline metrics statistics to fetch. If omitted, the authorized user will be used.")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/pipelines_deals.go b/pipedrive-cli/internal/cli/pipelines_deals.go
new file mode 100644
index 00000000..6ece9a19
--- /dev/null
+++ b/pipedrive-cli/internal/cli/pipelines_deals.go
@@ -0,0 +1,81 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newPipelinesDealsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "deals",
+ Short: "Deals represent ongoing, lost or won sales to an organization or to a person. Each deal has a monetary value and...",
+ }
+
+ cmd.AddCommand(newPipelinesDealsGetPipelineCmd(flags))
+ return cmd
+}
+
+func newPipelinesDealsGetPipelineCmd(flags *rootFlags) *cobra.Command {
+ var flagFilterId int
+ var flagUserId int
+ var flagEveryone float64
+ var flagStageId int
+ var flagStart int
+ var flagLimit int
+ var flagGetSummary float64
+ var flagTotalsConvertCurrency string
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-pipeline <id>",
+ Aliases: []string{"get"},
+ Short: "Get deals in a pipeline",
+ Example: " pipedrive-cli pipelines deals get-pipeline <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/pipelines/{id}/deals"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "filter_id": fmt.Sprintf("%v", flagFilterId),
+ "user_id": fmt.Sprintf("%v", flagUserId),
+ "everyone": fmt.Sprintf("%v", flagEveryone),
+ "stage_id": fmt.Sprintf("%v", flagStageId),
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ "get_summary": fmt.Sprintf("%v", flagGetSummary),
+ "totals_convert_currency": fmt.Sprintf("%v", flagTotalsConvertCurrency),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagFilterId, "filter-id", 0, "If supplied, only deals matching the given filter will be returned")
+ cmd.Flags().IntVar(&flagUserId, "user-id", 0, "If supplied, `filter_id` will not be considered and only deals owned by the given user will be returned. If omitted,...")
+ cmd.Flags().Float64Var(&flagEveryone, "everyone", 0.0, "If supplied, `filter_id` and `user_id` will not be considered – instead, deals owned by everyone will be returned")
+ cmd.Flags().IntVar(&flagStageId, "stage-id", 0, "If supplied, only deals within the given stage will be returned")
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().Float64Var(&flagGetSummary, "get-summary", 0.0, "Whether to include a summary of the pipeline in the `additional_data` or not")
+ cmd.Flags().StringVar(&flagTotalsConvertCurrency, "totals-convert-currency", "", "The 3-letter currency code of any of the supported currencies. When supplied, `per_stages_converted` is returned...")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/pipelines_movement-statistics.go b/pipedrive-cli/internal/cli/pipelines_movement-statistics.go
new file mode 100644
index 00000000..5a271565
--- /dev/null
+++ b/pipedrive-cli/internal/cli/pipelines_movement-statistics.go
@@ -0,0 +1,72 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newPipelinesMovementStatisticsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "movement-statistics",
+ Short: "Manage movement statistics",
+ }
+
+ cmd.AddCommand(newPipelinesMovementStatisticsGetPipelineCmd(flags))
+ return cmd
+}
+
+func newPipelinesMovementStatisticsGetPipelineCmd(flags *rootFlags) *cobra.Command {
+ var flagStartDate string
+ var flagEndDate string
+ var flagUserId int
+
+ cmd := &cobra.Command{
+ Use: "get-pipeline <id>",
+ Aliases: []string{"get"},
+ Short: "Get deals movements in pipeline",
+ Example: " pipedrive-cli pipelines movement-statistics get-pipeline <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/pipelines/{id}/movement_statistics"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ if flagStartDate != "" {
+ params["start_date"] = fmt.Sprintf("%v", flagStartDate)
+ }
+ if flagEndDate != "" {
+ params["end_date"] = fmt.Sprintf("%v", flagEndDate)
+ }
+ if flagUserId != 0 {
+ params["user_id"] = fmt.Sprintf("%v", flagUserId)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagStartDate, "start-date", "", "The start of the period. Date in format of YYYY-MM-DD.")
+ _ = cmd.MarkFlagRequired("start-date")
+ cmd.Flags().StringVar(&flagEndDate, "end-date", "", "The end of the period. Date in format of YYYY-MM-DD.")
+ _ = cmd.MarkFlagRequired("end-date")
+ cmd.Flags().IntVar(&flagUserId, "user-id", 0, "The ID of the user who's pipeline statistics to fetch. If omitted, the authorized user will be used.")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/product-fields.go b/pipedrive-cli/internal/cli/product-fields.go
new file mode 100644
index 00000000..26a75d54
--- /dev/null
+++ b/pipedrive-cli/internal/cli/product-fields.go
@@ -0,0 +1,225 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newProductFieldsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "product-fields",
+ Short: "Product fields represent the near-complete schema for a product in the context of the company of the authorized...",
+ }
+
+ cmd.AddCommand(newProductFieldsAddCmd(flags))
+ cmd.AddCommand(newProductFieldsDeleteCmd(flags))
+ cmd.AddCommand(newProductFieldsDeleteProductfieldsCmd(flags))
+ cmd.AddCommand(newProductFieldsGetCmd(flags))
+ cmd.AddCommand(newProductFieldsGetProductfieldsCmd(flags))
+ cmd.AddCommand(newProductFieldsUpdateCmd(flags))
+ return cmd
+}
+
+func newProductFieldsAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyFieldType string
+ var bodyName string
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Add a new product field",
+ Example: " pipedrive-cli product-fields add --field-type value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/productFields"
+ body := map[string]any{}
+ if bodyFieldType != "" {
+ body["field_type"] = bodyFieldType
+ }
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyFieldType, "field-type", "", "The type of the field<table><tr><th>Value</th><th>Description</th></tr><tr><td>`varchar`</td><td>Text (up to 255...")
+ _ = cmd.MarkFlagRequired("field-type")
+ cmd.Flags().StringVar(&bodyName, "name", "", "The name of the field")
+ _ = cmd.MarkFlagRequired("name")
+
+ return cmd
+}
+
+func newProductFieldsDeleteCmd(flags *rootFlags) *cobra.Command {
+ var flagIds string
+
+ cmd := &cobra.Command{
+ Use: "delete",
+ Short: "Delete multiple product fields in bulk",
+ Example: " pipedrive-cli product-fields delete",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/productFields"
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagIds, "ids", "", "The comma-separated field IDs to delete")
+ _ = cmd.MarkFlagRequired("ids")
+
+ return cmd
+}
+
+func newProductFieldsDeleteProductfieldsCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete-productfields <id>",
+ Short: "Delete a product field",
+ Example: " pipedrive-cli product-fields delete-productfields <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/productFields/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newProductFieldsGetCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all product fields",
+ Example: " pipedrive-cli product-fields get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/productFields"
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
+func newProductFieldsGetProductfieldsCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-productfields <id>",
+ Short: "Get one product field",
+ Example: " pipedrive-cli product-fields get-productfields <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/productFields/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newProductFieldsUpdateCmd(flags *rootFlags) *cobra.Command {
+ var bodyName string
+
+ cmd := &cobra.Command{
+ Use: "update <id>",
+ Short: "Update a product field",
+ Example: " pipedrive-cli product-fields update <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/productFields/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyName, "name", "", "The name of the field")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/products.go b/pipedrive-cli/internal/cli/products.go
new file mode 100644
index 00000000..bde2ec8c
--- /dev/null
+++ b/pipedrive-cli/internal/cli/products.go
@@ -0,0 +1,27 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newProductsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "products",
+ Short: "Products are the goods or services you are dealing with. Each product can have N different price points - firstly,...",
+ }
+
+ cmd.AddCommand(newProductsDealsCmd(flags))
+ cmd.AddCommand(newProductsFilesCmd(flags))
+ cmd.AddCommand(newProductsFollowersCmd(flags))
+ cmd.AddCommand(newProductsPermittedUsersCmd(flags))
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/products_deals.go b/pipedrive-cli/internal/cli/products_deals.go
new file mode 100644
index 00000000..88051e7c
--- /dev/null
+++ b/pipedrive-cli/internal/cli/products_deals.go
@@ -0,0 +1,66 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newProductsDealsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "deals",
+ Short: "Deals represent ongoing, lost or won sales to an organization or to a person. Each deal has a monetary value and...",
+ }
+
+ cmd.AddCommand(newProductsDealsGetProductCmd(flags))
+ return cmd
+}
+
+func newProductsDealsGetProductCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagStatus string
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-product <id>",
+ Aliases: []string{"get"},
+ Short: "Get deals where a product is attached to",
+ Example: " pipedrive-cli products deals get-product <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/products/{id}/deals"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ "status": fmt.Sprintf("%v", flagStatus),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().StringVar(&flagStatus, "status", "all_not_deleted", "Only fetch deals with a specific status. If omitted, all not deleted deals are returned. If set to deleted, deals...")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/products_files.go b/pipedrive-cli/internal/cli/products_files.go
new file mode 100644
index 00000000..d1490019
--- /dev/null
+++ b/pipedrive-cli/internal/cli/products_files.go
@@ -0,0 +1,66 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newProductsFilesCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "files",
+ Short: "Files are documents of any kind (images, spreadsheets, text files, etc.) that are uploaded to Pipedrive, and usually...",
+ }
+
+ cmd.AddCommand(newProductsFilesGetProductCmd(flags))
+ return cmd
+}
+
+func newProductsFilesGetProductCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagSort string
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-product <id>",
+ Aliases: []string{"get"},
+ Short: "List files attached to a product",
+ Example: " pipedrive-cli products files get-product <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/products/{id}/files"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ "sort": fmt.Sprintf("%v", flagSort),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page. Please note that a maximum value of 100 is allowed.")
+ cmd.Flags().StringVar(&flagSort, "sort", "", "Supported fields: `id`, `update_time`")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/products_followers.go b/pipedrive-cli/internal/cli/products_followers.go
new file mode 100644
index 00000000..a8ddb0a0
--- /dev/null
+++ b/pipedrive-cli/internal/cli/products_followers.go
@@ -0,0 +1,136 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newProductsFollowersCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "followers",
+ Short: "Manage followers",
+ }
+
+ cmd.AddCommand(newProductsFollowersAddProductCmd(flags))
+ cmd.AddCommand(newProductsFollowersDeleteProductCmd(flags))
+ cmd.AddCommand(newProductsFollowersGetProductCmd(flags))
+ return cmd
+}
+
+func newProductsFollowersAddProductCmd(flags *rootFlags) *cobra.Command {
+ var bodyUserId int
+
+ cmd := &cobra.Command{
+ Use: "add-product <id>",
+ Aliases: []string{"create"},
+ Short: "Add a follower to a product",
+ Example: " pipedrive-cli products followers add-product <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/products/{id}/followers"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyUserId != 0 {
+ body["user_id"] = bodyUserId
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyUserId, "user-id", 0, "The ID of the user")
+ _ = cmd.MarkFlagRequired("user-id")
+
+ return cmd
+}
+
+func newProductsFollowersDeleteProductCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete-product <id> <follower_id>",
+ Aliases: []string{"delete"},
+ Short: "Delete a follower from a product",
+ Example: " pipedrive-cli products followers delete-product <id> <follower_id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/products/{id}/followers/{follower_id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ if len(args) < 2 {
+ return usageErr(fmt.Errorf("follower_id is required"))
+ }
+ path = replacePathParam(path, "follower_id", args[1])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newProductsFollowersGetProductCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-product <id>",
+ Aliases: []string{"get"},
+ Short: "List followers of a product",
+ Example: " pipedrive-cli products followers get-product <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/products/{id}/followers"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/products_permitted-users.go b/pipedrive-cli/internal/cli/products_permitted-users.go
new file mode 100644
index 00000000..34e5e9a9
--- /dev/null
+++ b/pipedrive-cli/internal/cli/products_permitted-users.go
@@ -0,0 +1,55 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newProductsPermittedUsersCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "permitted-users",
+ Short: "Manage permitted users",
+ }
+
+ cmd.AddCommand(newProductsPermittedUsersGetProductUsersCmd(flags))
+ return cmd
+}
+
+func newProductsPermittedUsersGetProductUsersCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-product-users <id>",
+ Aliases: []string{"get"},
+ Short: "List permitted users",
+ Example: " pipedrive-cli products permitted-users get-product-users <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/products/{id}/permittedUsers"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/project-templates.go b/pipedrive-cli/internal/cli/project-templates.go
new file mode 100644
index 00000000..8b203f9f
--- /dev/null
+++ b/pipedrive-cli/internal/cli/project-templates.go
@@ -0,0 +1,90 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newProjectTemplatesCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "project-templates",
+ Short: "Project templates allow you to have reusable and dynamic structure to simplify creation of a project. Project...",
+ }
+
+ cmd.AddCommand(newProjectTemplatesGetCmd(flags))
+ cmd.AddCommand(newProjectTemplatesGetProjecttemplatesCmd(flags))
+ return cmd
+}
+
+func newProjectTemplatesGetCmd(flags *rootFlags) *cobra.Command {
+ var flagCursor string
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all project templates",
+ Example: " pipedrive-cli project-templates get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/projectTemplates"
+ data, err := paginatedGet(c, path, map[string]string{
+ "cursor": fmt.Sprintf("%v", flagCursor),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "cursor", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagCursor, "cursor", "", "For pagination, the marker (an opaque string value) representing the first item on the next page")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "For pagination, the limit of entries to be returned. If not provided, up to 500 items will be returned.")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
+func newProjectTemplatesGetProjecttemplatesCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-projecttemplates <id>",
+ Short: "Get details of a template",
+ Example: " pipedrive-cli project-templates get-projecttemplates <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/projectTemplates/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/projects.go b/pipedrive-cli/internal/cli/projects.go
new file mode 100644
index 00000000..ae6992c6
--- /dev/null
+++ b/pipedrive-cli/internal/cli/projects.go
@@ -0,0 +1,424 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newProjectsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "projects",
+ Short: "Projects represent ongoing, completed or canceled projects attached to an organization, person or to deals. Each...",
+ }
+
+ cmd.AddCommand(newProjectsAddCmd(flags))
+ cmd.AddCommand(newProjectsDeleteCmd(flags))
+ cmd.AddCommand(newProjectsGetCmd(flags))
+ cmd.AddCommand(newProjectsGetBoardCmd(flags))
+ cmd.AddCommand(newProjectsGetBoardsCmd(flags))
+ cmd.AddCommand(newProjectsGetIdCmd(flags))
+ cmd.AddCommand(newProjectsGetPhaseCmd(flags))
+ cmd.AddCommand(newProjectsGetPhasesCmd(flags))
+ cmd.AddCommand(newProjectsUpdateCmd(flags))
+ cmd.AddCommand(newProjectsActivitiesCmd(flags))
+ cmd.AddCommand(newProjectsArchiveCmd(flags))
+ cmd.AddCommand(newProjectsGroupsCmd(flags))
+ cmd.AddCommand(newProjectsPlanCmd(flags))
+ cmd.AddCommand(newProjectsTasksCmd(flags))
+ return cmd
+}
+
+func newProjectsAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyBoardId float64
+ var bodyDescription string
+ var bodyEndDate string
+ var bodyOrgId float64
+ var bodyOwnerId float64
+ var bodyPersonId float64
+ var bodyPhaseId float64
+ var bodyStartDate string
+ var bodyStatus string
+ var bodyTemplateId float64
+ var bodyTitle string
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Add a project",
+ Example: " pipedrive-cli projects add --title value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/projects"
+ body := map[string]any{}
+ if bodyBoardId != 0.0 {
+ body["board_id"] = bodyBoardId
+ }
+ if bodyDescription != "" {
+ body["description"] = bodyDescription
+ }
+ if bodyEndDate != "" {
+ body["end_date"] = bodyEndDate
+ }
+ if bodyOrgId != 0.0 {
+ body["org_id"] = bodyOrgId
+ }
+ if bodyOwnerId != 0.0 {
+ body["owner_id"] = bodyOwnerId
+ }
+ if bodyPersonId != 0.0 {
+ body["person_id"] = bodyPersonId
+ }
+ if bodyPhaseId != 0.0 {
+ body["phase_id"] = bodyPhaseId
+ }
+ if bodyStartDate != "" {
+ body["start_date"] = bodyStartDate
+ }
+ if bodyStatus != "" {
+ body["status"] = bodyStatus
+ }
+ if bodyTemplateId != 0.0 {
+ body["template_id"] = bodyTemplateId
+ }
+ if bodyTitle != "" {
+ body["title"] = bodyTitle
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().Float64Var(&bodyBoardId, "board-id", 0.0, "The ID of the board this project is associated with")
+ cmd.Flags().StringVar(&bodyDescription, "description", "", "The description of the project")
+ cmd.Flags().StringVar(&bodyEndDate, "end-date", "", "The end date of the project. Format: YYYY-MM-DD.")
+ cmd.Flags().Float64Var(&bodyOrgId, "org-id", 0.0, "The ID of the organization this project is associated with")
+ cmd.Flags().Float64Var(&bodyOwnerId, "owner-id", 0.0, "The ID of a project owner")
+ cmd.Flags().Float64Var(&bodyPersonId, "person-id", 0.0, "The ID of the person this project is associated with")
+ cmd.Flags().Float64Var(&bodyPhaseId, "phase-id", 0.0, "The ID of the phase this project is associated with")
+ cmd.Flags().StringVar(&bodyStartDate, "start-date", "", "The start date of the project. Format: YYYY-MM-DD.")
+ cmd.Flags().StringVar(&bodyStatus, "status", "", "The status of the project")
+ cmd.Flags().Float64Var(&bodyTemplateId, "template-id", 0.0, "The ID of the template the project will be based on")
+ cmd.Flags().StringVar(&bodyTitle, "title", "", "The title of the project")
+ _ = cmd.MarkFlagRequired("title")
+
+ return cmd
+}
+
+func newProjectsDeleteCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete <id>",
+ Short: "Delete a project",
+ Example: " pipedrive-cli projects delete <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/projects/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newProjectsGetCmd(flags *rootFlags) *cobra.Command {
+ var flagCursor string
+ var flagLimit int
+ var flagFilterId int
+ var flagStatus string
+ var flagPhaseId int
+ var flagIncludeArchived bool
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all projects",
+ Example: " pipedrive-cli projects get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/projects"
+ data, err := paginatedGet(c, path, map[string]string{
+ "cursor": fmt.Sprintf("%v", flagCursor),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ "filter_id": fmt.Sprintf("%v", flagFilterId),
+ "status": fmt.Sprintf("%v", flagStatus),
+ "phase_id": fmt.Sprintf("%v", flagPhaseId),
+ "include_archived": fmt.Sprintf("%v", flagIncludeArchived),
+ }, flagAll, "cursor", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagCursor, "cursor", "", "For pagination, the marker (an opaque string value) representing the first item on the next page")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "For pagination, the limit of entries to be returned. If not provided, 100 items will be returned.")
+ cmd.Flags().IntVar(&flagFilterId, "filter-id", 0, "The ID of the filter to use")
+ cmd.Flags().StringVar(&flagStatus, "status", "", "If supplied, includes only projects with the specified statuses. Possible values are `open`, `completed`, `canceled`...")
+ cmd.Flags().IntVar(&flagPhaseId, "phase-id", 0, "If supplied, only projects in specified phase are returned")
+ cmd.Flags().BoolVar(&flagIncludeArchived, "include-archived", false, "If supplied with `true` then archived projects are also included in the response. By default only not archived...")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
+func newProjectsGetBoardCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-board <id>",
+ Short: "Get details of a board",
+ Example: " pipedrive-cli projects get-board <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/projects/boards/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newProjectsGetBoardsCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-boards",
+ Short: "Get all project boards",
+ Example: " pipedrive-cli projects get-boards",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/projects/boards"
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newProjectsGetIdCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-id <id>",
+ Short: "Get details of a project",
+ Example: " pipedrive-cli projects get-id <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/projects/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newProjectsGetPhaseCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-phase <id>",
+ Short: "Get details of a phase",
+ Example: " pipedrive-cli projects get-phase <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/projects/phases/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newProjectsGetPhasesCmd(flags *rootFlags) *cobra.Command {
+ var flagBoardId int
+
+ cmd := &cobra.Command{
+ Use: "get-phases",
+ Short: "Get project phases",
+ Example: " pipedrive-cli projects get-phases",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/projects/phases"
+ params := map[string]string{}
+ if flagBoardId != 0 {
+ params["board_id"] = fmt.Sprintf("%v", flagBoardId)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagBoardId, "board-id", 0, "ID of the board for which phases are requested")
+ _ = cmd.MarkFlagRequired("board-id")
+
+ return cmd
+}
+
+func newProjectsUpdateCmd(flags *rootFlags) *cobra.Command {
+ var bodyBoardId float64
+ var bodyDescription string
+ var bodyEndDate string
+ var bodyOrgId float64
+ var bodyOwnerId float64
+ var bodyPersonId float64
+ var bodyPhaseId float64
+ var bodyStartDate string
+ var bodyStatus string
+ var bodyTitle string
+
+ cmd := &cobra.Command{
+ Use: "update <id>",
+ Short: "Update a project",
+ Example: " pipedrive-cli projects update <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/projects/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyBoardId != 0.0 {
+ body["board_id"] = bodyBoardId
+ }
+ if bodyDescription != "" {
+ body["description"] = bodyDescription
+ }
+ if bodyEndDate != "" {
+ body["end_date"] = bodyEndDate
+ }
+ if bodyOrgId != 0.0 {
+ body["org_id"] = bodyOrgId
+ }
+ if bodyOwnerId != 0.0 {
+ body["owner_id"] = bodyOwnerId
+ }
+ if bodyPersonId != 0.0 {
+ body["person_id"] = bodyPersonId
+ }
+ if bodyPhaseId != 0.0 {
+ body["phase_id"] = bodyPhaseId
+ }
+ if bodyStartDate != "" {
+ body["start_date"] = bodyStartDate
+ }
+ if bodyStatus != "" {
+ body["status"] = bodyStatus
+ }
+ if bodyTitle != "" {
+ body["title"] = bodyTitle
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().Float64Var(&bodyBoardId, "board-id", 0.0, "The ID of the board this project is associated with")
+ cmd.Flags().StringVar(&bodyDescription, "description", "", "The description of the project")
+ cmd.Flags().StringVar(&bodyEndDate, "end-date", "", "The end date of the project. Format: YYYY-MM-DD.")
+ cmd.Flags().Float64Var(&bodyOrgId, "org-id", 0.0, "The ID of the organization this project is associated with")
+ cmd.Flags().Float64Var(&bodyOwnerId, "owner-id", 0.0, "The ID of a project owner")
+ cmd.Flags().Float64Var(&bodyPersonId, "person-id", 0.0, "The ID of the person this project is associated with")
+ cmd.Flags().Float64Var(&bodyPhaseId, "phase-id", 0.0, "The ID of the phase this project is associated with")
+ cmd.Flags().StringVar(&bodyStartDate, "start-date", "", "The start date of the project. Format: YYYY-MM-DD.")
+ cmd.Flags().StringVar(&bodyStatus, "status", "", "The status of the project")
+ cmd.Flags().StringVar(&bodyTitle, "title", "", "The title of the project")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/projects_activities.go b/pipedrive-cli/internal/cli/projects_activities.go
new file mode 100644
index 00000000..8bd451bb
--- /dev/null
+++ b/pipedrive-cli/internal/cli/projects_activities.go
@@ -0,0 +1,55 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newProjectsActivitiesCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "activities",
+ Short: "Activities are appointments/tasks/events on a calendar that can be associated with a deal, a lead, a person and an...",
+ }
+
+ cmd.AddCommand(newProjectsActivitiesGetProjectCmd(flags))
+ return cmd
+}
+
+func newProjectsActivitiesGetProjectCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-project <id>",
+ Aliases: []string{"get"},
+ Short: "Returns project activities",
+ Example: " pipedrive-cli projects activities get-project <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/projects/{id}/activities"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/projects_archive.go b/pipedrive-cli/internal/cli/projects_archive.go
new file mode 100644
index 00000000..acb41b53
--- /dev/null
+++ b/pipedrive-cli/internal/cli/projects_archive.go
@@ -0,0 +1,55 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newProjectsArchiveCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "archive",
+ Short: "Manage archive",
+ }
+
+ cmd.AddCommand(newProjectsArchiveProjectCmd(flags))
+ return cmd
+}
+
+func newProjectsArchiveProjectCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "project <id>",
+ Aliases: []string{"create"},
+ Short: "Archive a project",
+ Example: " pipedrive-cli projects archive project <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/projects/{id}/archive"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/projects_groups.go b/pipedrive-cli/internal/cli/projects_groups.go
new file mode 100644
index 00000000..fa620d40
--- /dev/null
+++ b/pipedrive-cli/internal/cli/projects_groups.go
@@ -0,0 +1,55 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newProjectsGroupsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "groups",
+ Short: "Manage groups",
+ }
+
+ cmd.AddCommand(newProjectsGroupsGetProjectCmd(flags))
+ return cmd
+}
+
+func newProjectsGroupsGetProjectCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-project <id>",
+ Aliases: []string{"get"},
+ Short: "Returns project groups",
+ Example: " pipedrive-cli projects groups get-project <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/projects/{id}/groups"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/projects_plan.go b/pipedrive-cli/internal/cli/projects_plan.go
new file mode 100644
index 00000000..94775d11
--- /dev/null
+++ b/pipedrive-cli/internal/cli/projects_plan.go
@@ -0,0 +1,146 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newProjectsPlanCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "plan",
+ Short: "Manage plan",
+ }
+
+ cmd.AddCommand(newProjectsPlanGetProjectCmd(flags))
+ cmd.AddCommand(newProjectsPlanPutProjectActivityCmd(flags))
+ cmd.AddCommand(newProjectsPlanPutProjectTaskCmd(flags))
+ return cmd
+}
+
+func newProjectsPlanGetProjectCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-project <id>",
+ Aliases: []string{"get"},
+ Short: "Returns project plan",
+ Example: " pipedrive-cli projects plan get-project <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/projects/{id}/plan"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newProjectsPlanPutProjectActivityCmd(flags *rootFlags) *cobra.Command {
+ var bodyGroupId float64
+ var bodyPhaseId float64
+
+ cmd := &cobra.Command{
+ Use: "put-project-activity <id> <activityId>",
+ Aliases: []string{"update"},
+ Short: "Update activity in project plan",
+ Example: " pipedrive-cli projects plan put-project-activity <id> <activityId>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/projects/{id}/plan/activities/{activityId}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ if len(args) < 2 {
+ return usageErr(fmt.Errorf("activityId is required"))
+ }
+ path = replacePathParam(path, "activityId", args[1])
+ body := map[string]any{}
+ if bodyGroupId != 0.0 {
+ body["group_id"] = bodyGroupId
+ }
+ if bodyPhaseId != 0.0 {
+ body["phase_id"] = bodyPhaseId
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().Float64Var(&bodyGroupId, "group-id", 0.0, "The ID of a group on a project board")
+ cmd.Flags().Float64Var(&bodyPhaseId, "phase-id", 0.0, "The ID of a phase on a project board")
+
+ return cmd
+}
+
+func newProjectsPlanPutProjectTaskCmd(flags *rootFlags) *cobra.Command {
+ var bodyGroupId float64
+ var bodyPhaseId float64
+
+ cmd := &cobra.Command{
+ Use: "put-project-task <id> <taskId>",
+ Short: "Update task in project plan",
+ Example: " pipedrive-cli projects plan put-project-task <id> <taskId>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/projects/{id}/plan/tasks/{taskId}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ if len(args) < 2 {
+ return usageErr(fmt.Errorf("taskId is required"))
+ }
+ path = replacePathParam(path, "taskId", args[1])
+ body := map[string]any{}
+ if bodyGroupId != 0.0 {
+ body["group_id"] = bodyGroupId
+ }
+ if bodyPhaseId != 0.0 {
+ body["phase_id"] = bodyPhaseId
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().Float64Var(&bodyGroupId, "group-id", 0.0, "The ID of a group on a project board")
+ cmd.Flags().Float64Var(&bodyPhaseId, "phase-id", 0.0, "The ID of a phase on a project board")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/projects_tasks.go b/pipedrive-cli/internal/cli/projects_tasks.go
new file mode 100644
index 00000000..e116b943
--- /dev/null
+++ b/pipedrive-cli/internal/cli/projects_tasks.go
@@ -0,0 +1,55 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newProjectsTasksCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "tasks",
+ Short: "Tasks represent actions that need to be completed and must be associated with a project. Tasks have an optional due...",
+ }
+
+ cmd.AddCommand(newProjectsTasksGetProjectCmd(flags))
+ return cmd
+}
+
+func newProjectsTasksGetProjectCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-project <id>",
+ Aliases: []string{"get"},
+ Short: "Returns project tasks",
+ Example: " pipedrive-cli projects tasks get-project <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/projects/{id}/tasks"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/recents.go b/pipedrive-cli/internal/cli/recents.go
new file mode 100644
index 00000000..75554188
--- /dev/null
+++ b/pipedrive-cli/internal/cli/recents.go
@@ -0,0 +1,66 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newRecentsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "recents",
+ Short: "Recent changes across all item types in Pipedrive (deals, persons, etc).",
+ }
+
+ cmd.AddCommand(newRecentsGetCmd(flags))
+ return cmd
+}
+
+func newRecentsGetCmd(flags *rootFlags) *cobra.Command {
+ var flagSinceTimestamp string
+ var flagItems string
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get recents",
+ Example: " pipedrive-cli recents get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/recents"
+ data, err := paginatedGet(c, path, map[string]string{
+ "since_timestamp": fmt.Sprintf("%v", flagSinceTimestamp),
+ "items": fmt.Sprintf("%v", flagItems),
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagSinceTimestamp, "since-timestamp", "", "The timestamp in UTC. Format: YYYY-MM-DD HH:MM:SS.")
+ _ = cmd.MarkFlagRequired("since-timestamp")
+ cmd.Flags().StringVar(&flagItems, "items", "", "Multiple selection of item types to include in the query (optional)")
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/roles.go b/pipedrive-cli/internal/cli/roles.go
new file mode 100644
index 00000000..fb12704e
--- /dev/null
+++ b/pipedrive-cli/internal/cli/roles.go
@@ -0,0 +1,203 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newRolesCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "roles",
+ Short: "Roles are a part of the Visibility groups’ feature that allow the admin user to categorize other users and dictate...",
+ }
+
+ cmd.AddCommand(newRolesAddCmd(flags))
+ cmd.AddCommand(newRolesDeleteCmd(flags))
+ cmd.AddCommand(newRolesGetCmd(flags))
+ cmd.AddCommand(newRolesGetIdCmd(flags))
+ cmd.AddCommand(newRolesUpdateCmd(flags))
+ cmd.AddCommand(newRolesAssignmentsCmd(flags))
+ cmd.AddCommand(newRolesPipelinesCmd(flags))
+ cmd.AddCommand(newRolesSettingsCmd(flags))
+ return cmd
+}
+
+func newRolesAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyName string
+ var bodyParentRoleId int
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Add a role",
+ Example: " pipedrive-cli roles add --name value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/roles"
+ body := map[string]any{}
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ if bodyParentRoleId != 0 {
+ body["parent_role_id"] = bodyParentRoleId
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyName, "name", "", "The name of the role")
+ _ = cmd.MarkFlagRequired("name")
+ cmd.Flags().IntVar(&bodyParentRoleId, "parent-role-id", 0, "The ID of the parent role")
+
+ return cmd
+}
+
+func newRolesDeleteCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete <id>",
+ Short: "Delete a role",
+ Example: " pipedrive-cli roles delete <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/roles/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newRolesGetCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all roles",
+ Example: " pipedrive-cli roles get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/roles"
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
+func newRolesGetIdCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-id <id>",
+ Short: "Get one role",
+ Example: " pipedrive-cli roles get-id <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/roles/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newRolesUpdateCmd(flags *rootFlags) *cobra.Command {
+ var bodyName string
+ var bodyParentRoleId int
+
+ cmd := &cobra.Command{
+ Use: "update <id>",
+ Short: "Update role details",
+ Example: " pipedrive-cli roles update <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/roles/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ if bodyParentRoleId != 0 {
+ body["parent_role_id"] = bodyParentRoleId
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyName, "name", "", "The name of the role")
+ cmd.Flags().IntVar(&bodyParentRoleId, "parent-role-id", 0, "The ID of the parent role")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/roles_assignments.go b/pipedrive-cli/internal/cli/roles_assignments.go
new file mode 100644
index 00000000..c5692773
--- /dev/null
+++ b/pipedrive-cli/internal/cli/roles_assignments.go
@@ -0,0 +1,135 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newRolesAssignmentsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "assignments",
+ Short: "Manage assignments",
+ }
+
+ cmd.AddCommand(newRolesAssignmentsAddRoleCmd(flags))
+ cmd.AddCommand(newRolesAssignmentsDeleteRoleCmd(flags))
+ cmd.AddCommand(newRolesAssignmentsGetRoleCmd(flags))
+ return cmd
+}
+
+func newRolesAssignmentsAddRoleCmd(flags *rootFlags) *cobra.Command {
+ var bodyUserId int
+
+ cmd := &cobra.Command{
+ Use: "add-role <id>",
+ Aliases: []string{"create"},
+ Short: "Add role assignment",
+ Example: " pipedrive-cli roles assignments add-role <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/roles/{id}/assignments"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyUserId != 0 {
+ body["user_id"] = bodyUserId
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyUserId, "user-id", 0, "The ID of the user")
+ _ = cmd.MarkFlagRequired("user-id")
+
+ return cmd
+}
+
+func newRolesAssignmentsDeleteRoleCmd(flags *rootFlags) *cobra.Command {
+ var bodyUserId int
+
+ cmd := &cobra.Command{
+ Use: "delete-role <id>",
+ Aliases: []string{"delete"},
+ Short: "Delete a role assignment",
+ Example: " pipedrive-cli roles assignments delete-role <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/roles/{id}/assignments"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&bodyUserId, "user-id", 0, "The ID of the user")
+ _ = cmd.MarkFlagRequired("user-id")
+
+ return cmd
+}
+
+func newRolesAssignmentsGetRoleCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-role <id>",
+ Aliases: []string{"get"},
+ Short: "List role assignments",
+ Example: " pipedrive-cli roles assignments get-role <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/roles/{id}/assignments"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/roles_pipelines.go b/pipedrive-cli/internal/cli/roles_pipelines.go
new file mode 100644
index 00000000..65b8ef5d
--- /dev/null
+++ b/pipedrive-cli/internal/cli/roles_pipelines.go
@@ -0,0 +1,92 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newRolesPipelinesCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "pipelines",
+ Short: "Pipelines are essentially ordered collections of stages.",
+ }
+
+ cmd.AddCommand(newRolesPipelinesGetRoleCmd(flags))
+ cmd.AddCommand(newRolesPipelinesUpdateRoleCmd(flags))
+ return cmd
+}
+
+func newRolesPipelinesGetRoleCmd(flags *rootFlags) *cobra.Command {
+ var flagVisible bool
+
+ cmd := &cobra.Command{
+ Use: "get-role <id>",
+ Aliases: []string{"get"},
+ Short: "List pipeline visibility for a role",
+ Example: " pipedrive-cli roles pipelines get-role <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/roles/{id}/pipelines"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ if flagVisible != false {
+ params["visible"] = fmt.Sprintf("%v", flagVisible)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().BoolVar(&flagVisible, "visible", true, "Whether to return the visible or hidden pipelines for the role")
+
+ return cmd
+}
+
+func newRolesPipelinesUpdateRoleCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "update-role <id>",
+ Aliases: []string{"update"},
+ Short: "Update pipeline visibility for a role",
+ Example: " pipedrive-cli roles pipelines update-role <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/roles/{id}/pipelines"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/roles_settings.go b/pipedrive-cli/internal/cli/roles_settings.go
new file mode 100644
index 00000000..e8e690af
--- /dev/null
+++ b/pipedrive-cli/internal/cli/roles_settings.go
@@ -0,0 +1,99 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newRolesSettingsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "settings",
+ Short: "Manage settings",
+ }
+
+ cmd.AddCommand(newRolesSettingsAddOrUpdateRoleCmd(flags))
+ cmd.AddCommand(newRolesSettingsGetRoleCmd(flags))
+ return cmd
+}
+
+func newRolesSettingsAddOrUpdateRoleCmd(flags *rootFlags) *cobra.Command {
+ var bodySettingKey string
+ var bodyValue int
+
+ cmd := &cobra.Command{
+ Use: "add-or-update-role <id>",
+ Aliases: []string{"create"},
+ Short: "Add or update role setting",
+ Example: " pipedrive-cli roles settings add-or-update-role <id> --setting-key value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/roles/{id}/settings"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodySettingKey != "" {
+ body["setting_key"] = bodySettingKey
+ }
+ if bodyValue != 0 {
+ body["value"] = bodyValue
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodySettingKey, "setting-key", "", "Setting key")
+ _ = cmd.MarkFlagRequired("setting-key")
+ cmd.Flags().IntVar(&bodyValue, "value", 0, "Possible values for the `default_visibility` setting depending on the subscription plan:<br> <table...")
+ _ = cmd.MarkFlagRequired("value")
+
+ return cmd
+}
+
+func newRolesSettingsGetRoleCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-role <id>",
+ Aliases: []string{"get"},
+ Short: "List role settings",
+ Example: " pipedrive-cli roles settings get-role <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/roles/{id}/settings"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/root.go b/pipedrive-cli/internal/cli/root.go
new file mode 100644
index 00000000..3f34f5cb
--- /dev/null
+++ b/pipedrive-cli/internal/cli/root.go
@@ -0,0 +1,153 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "encoding/json"
+ "fmt"
+ "text/tabwriter"
+ "time"
+
+ "github.com/USER/pipedrive-cli/internal/client"
+ "github.com/USER/pipedrive-cli/internal/config"
+ "github.com/spf13/cobra"
+)
+
+var version = "1.0.0"
+
+type rootFlags struct {
+ asJSON bool
+ plain bool
+ quiet bool
+ dryRun bool
+ selectFields string
+ configPath string
+ timeout time.Duration
+}
+
+func Execute() error {
+ var flags rootFlags
+
+ rootCmd := &cobra.Command{
+ Use: "pipedrive-cli",
+ Short: "",
+ SilenceUsage: true,
+ SilenceErrors: true,
+ Version: version,
+ }
+ rootCmd.SetVersionTemplate("pipedrive-cli {{ .Version }}\n")
+
+ rootCmd.PersistentFlags().BoolVar(&flags.asJSON, "json", false, "Output as JSON")
+ rootCmd.PersistentFlags().BoolVar(&flags.plain, "plain", false, "Output as plain tab-separated text")
+ rootCmd.PersistentFlags().BoolVar(&flags.quiet, "quiet", false, "Bare output, one value per line")
+ rootCmd.PersistentFlags().StringVar(&flags.configPath, "config", "", "Config file path")
+ rootCmd.PersistentFlags().DurationVar(&flags.timeout, "timeout", 30*time.Second, "Request timeout")
+ rootCmd.PersistentFlags().BoolVar(&flags.dryRun, "dry-run", false, "Show request without sending")
+ rootCmd.PersistentFlags().StringVar(&flags.selectFields, "select", "", "Comma-separated fields to include in output (e.g. --select id,name,status)")
+ rootCmd.PersistentFlags().BoolVar(&noColor, "no-color", false, "Disable colored output")
+ rootCmd.AddCommand(newActivityFieldsCmd(&flags))
+ rootCmd.AddCommand(newActivityTypesCmd(&flags))
+ rootCmd.AddCommand(newBillingCmd(&flags))
+ rootCmd.AddCommand(newCallLogsCmd(&flags))
+ rootCmd.AddCommand(newChannelsCmd(&flags))
+ rootCmd.AddCommand(newCurrenciesCmd(&flags))
+ rootCmd.AddCommand(newDealFieldsCmd(&flags))
+ rootCmd.AddCommand(newDealsCmd(&flags))
+ rootCmd.AddCommand(newFilesCmd(&flags))
+ rootCmd.AddCommand(newFiltersCmd(&flags))
+ rootCmd.AddCommand(newGoalsCmd(&flags))
+ rootCmd.AddCommand(newLeadFieldsCmd(&flags))
+ rootCmd.AddCommand(newLeadLabelsCmd(&flags))
+ rootCmd.AddCommand(newLeadSourcesCmd(&flags))
+ rootCmd.AddCommand(newLeadsCmd(&flags))
+ rootCmd.AddCommand(newLegacyTeamsCmd(&flags))
+ rootCmd.AddCommand(newMailboxCmd(&flags))
+ rootCmd.AddCommand(newMeetingsCmd(&flags))
+ rootCmd.AddCommand(newNoteFieldsCmd(&flags))
+ rootCmd.AddCommand(newNotesCmd(&flags))
+ rootCmd.AddCommand(newOauthCmd(&flags))
+ rootCmd.AddCommand(newOrganizationFieldsCmd(&flags))
+ rootCmd.AddCommand(newOrganizationRelationshipsCmd(&flags))
+ rootCmd.AddCommand(newOrganizationsCmd(&flags))
+ rootCmd.AddCommand(newPermissionSetsCmd(&flags))
+ rootCmd.AddCommand(newPersonFieldsCmd(&flags))
+ rootCmd.AddCommand(newPersonsCmd(&flags))
+ rootCmd.AddCommand(newPipelinesCmd(&flags))
+ rootCmd.AddCommand(newProductFieldsCmd(&flags))
+ rootCmd.AddCommand(newProductsCmd(&flags))
+ rootCmd.AddCommand(newProjectTemplatesCmd(&flags))
+ rootCmd.AddCommand(newProjectsCmd(&flags))
+ rootCmd.AddCommand(newRecentsCmd(&flags))
+ rootCmd.AddCommand(newRolesCmd(&flags))
+ rootCmd.AddCommand(newStagesCmd(&flags))
+ rootCmd.AddCommand(newTasksCmd(&flags))
+ rootCmd.AddCommand(newUserConnectionsCmd(&flags))
+ rootCmd.AddCommand(newUserSettingsCmd(&flags))
+ rootCmd.AddCommand(newUsersCmd(&flags))
+ rootCmd.AddCommand(newWebhooksCmd(&flags))
+ rootCmd.AddCommand(newDoctorCmd(&flags))
+ rootCmd.AddCommand(newAuthCmd(&flags))
+ rootCmd.AddCommand(newVersionCliCmd())
+
+ return rootCmd.Execute()
+}
+
+func ExitCode(err error) int {
+ var codeErr *cliError
+ if As(err, &codeErr) {
+ return codeErr.code
+ }
+ return 1
+}
+
+func (f *rootFlags) newClient() (*client.Client, error) {
+ cfg, err := config.Load(f.configPath)
+ if err != nil {
+ return nil, configErr(err)
+ }
+ c := client.New(cfg, f.timeout)
+ c.DryRun = f.dryRun
+ return c, nil
+}
+
+func (f *rootFlags) printJSON(w *cobra.Command, v any) error {
+ enc := json.NewEncoder(w.OutOrStdout())
+ enc.SetIndent("", " ")
+ return enc.Encode(v)
+}
+
+func (f *rootFlags) printTable(w *cobra.Command, headers []string, rows [][]string) error {
+ if f.asJSON {
+ return fmt.Errorf("use printJSON for JSON output")
+ }
+ tw := tabwriter.NewWriter(w.OutOrStdout(), 2, 4, 2, ' ', 0)
+ header := ""
+ for i, h := range headers {
+ if i > 0 {
+ header += "\t"
+ }
+ header += h
+ }
+ fmt.Fprintln(tw, header)
+ for _, row := range rows {
+ line := ""
+ for i, cell := range row {
+ if i > 0 {
+ line += "\t"
+ }
+ line += cell
+ }
+ fmt.Fprintln(tw, line)
+ }
+ return tw.Flush()
+}
+
+func newVersionCliCmd() *cobra.Command {
+ return &cobra.Command{
+ Use: "version",
+ Short: "Print version",
+ Run: func(cmd *cobra.Command, args []string) {
+ fmt.Printf("pipedrive-cli %s\n", version)
+ },
+ }
+}
diff --git a/pipedrive-cli/internal/cli/stages.go b/pipedrive-cli/internal/cli/stages.go
new file mode 100644
index 00000000..74948d05
--- /dev/null
+++ b/pipedrive-cli/internal/cli/stages.go
@@ -0,0 +1,24 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newStagesCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "stages",
+ Short: "Stage is a logical component of a pipeline, and essentially a bucket that can hold a number of deals. In the context...",
+ }
+
+ cmd.AddCommand(newStagesDealsCmd(flags))
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/stages_deals.go b/pipedrive-cli/internal/cli/stages_deals.go
new file mode 100644
index 00000000..5b01faef
--- /dev/null
+++ b/pipedrive-cli/internal/cli/stages_deals.go
@@ -0,0 +1,72 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newStagesDealsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "deals",
+ Short: "Deals represent ongoing, lost or won sales to an organization or to a person. Each deal has a monetary value and...",
+ }
+
+ cmd.AddCommand(newStagesDealsGetStageCmd(flags))
+ return cmd
+}
+
+func newStagesDealsGetStageCmd(flags *rootFlags) *cobra.Command {
+ var flagFilterId int
+ var flagUserId int
+ var flagEveryone float64
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-stage <id>",
+ Aliases: []string{"get"},
+ Short: "Get deals in a stage",
+ Example: " pipedrive-cli stages deals get-stage <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/stages/{id}/deals"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "filter_id": fmt.Sprintf("%v", flagFilterId),
+ "user_id": fmt.Sprintf("%v", flagUserId),
+ "everyone": fmt.Sprintf("%v", flagEveryone),
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagFilterId, "filter-id", 0, "If supplied, only deals matching the given filter will be returned")
+ cmd.Flags().IntVar(&flagUserId, "user-id", 0, "If supplied, `filter_id` will not be considered and only deals owned by the given user will be returned. If omitted,...")
+ cmd.Flags().Float64Var(&flagEveryone, "everyone", 0.0, "If supplied, `filter_id` and `user_id` will not be considered – instead, deals owned by everyone will be returned")
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/tasks.go b/pipedrive-cli/internal/cli/tasks.go
new file mode 100644
index 00000000..79937ff9
--- /dev/null
+++ b/pipedrive-cli/internal/cli/tasks.go
@@ -0,0 +1,253 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newTasksCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "tasks",
+ Short: "Tasks represent actions that need to be completed and must be associated with a project. Tasks have an optional due...",
+ }
+
+ cmd.AddCommand(newTasksAddCmd(flags))
+ cmd.AddCommand(newTasksDeleteCmd(flags))
+ cmd.AddCommand(newTasksGetCmd(flags))
+ cmd.AddCommand(newTasksGetIdCmd(flags))
+ cmd.AddCommand(newTasksUpdateCmd(flags))
+ return cmd
+}
+
+func newTasksAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyAssigneeId float64
+ var bodyDescription string
+ var bodyDueDate string
+ var bodyParentTaskId float64
+ var bodyProjectId float64
+ var bodyTitle string
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Add a task",
+ Example: " pipedrive-cli tasks add --title value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/tasks"
+ body := map[string]any{}
+ if bodyAssigneeId != 0.0 {
+ body["assignee_id"] = bodyAssigneeId
+ }
+ if bodyDescription != "" {
+ body["description"] = bodyDescription
+ }
+ if bodyDueDate != "" {
+ body["due_date"] = bodyDueDate
+ }
+ if bodyParentTaskId != 0.0 {
+ body["parent_task_id"] = bodyParentTaskId
+ }
+ if bodyProjectId != 0.0 {
+ body["project_id"] = bodyProjectId
+ }
+ if bodyTitle != "" {
+ body["title"] = bodyTitle
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().Float64Var(&bodyAssigneeId, "assignee-id", 0.0, "The ID of the user assigned to the task. When the `assignee_id` field is updated, the `assignee_ids` field value...")
+ cmd.Flags().StringVar(&bodyDescription, "description", "", "The description of the task")
+ cmd.Flags().StringVar(&bodyDueDate, "due-date", "", "The due date of the task. Format: YYYY-MM-DD.")
+ cmd.Flags().Float64Var(&bodyParentTaskId, "parent-task-id", 0.0, "The ID of a parent task. Can not be ID of a task which is already a subtask.")
+ cmd.Flags().Float64Var(&bodyProjectId, "project-id", 0.0, "The ID of a project")
+ _ = cmd.MarkFlagRequired("project-id")
+ cmd.Flags().StringVar(&bodyTitle, "title", "", "The title of the task")
+ _ = cmd.MarkFlagRequired("title")
+
+ return cmd
+}
+
+func newTasksDeleteCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete <id>",
+ Short: "Delete a task",
+ Example: " pipedrive-cli tasks delete <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/tasks/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newTasksGetCmd(flags *rootFlags) *cobra.Command {
+ var flagCursor string
+ var flagLimit int
+ var flagAssigneeId int
+ var flagProjectId int
+ var flagParentTaskId int
+ var flagDone float64
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all tasks",
+ Example: " pipedrive-cli tasks get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/tasks"
+ data, err := paginatedGet(c, path, map[string]string{
+ "cursor": fmt.Sprintf("%v", flagCursor),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ "assignee_id": fmt.Sprintf("%v", flagAssigneeId),
+ "project_id": fmt.Sprintf("%v", flagProjectId),
+ "parent_task_id": fmt.Sprintf("%v", flagParentTaskId),
+ "done": fmt.Sprintf("%v", flagDone),
+ }, flagAll, "cursor", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagCursor, "cursor", "", "For pagination, the marker (an opaque string value) representing the first item on the next page")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "For pagination, the limit of entries to be returned. If not provided, up to 500 items will be returned.")
+ cmd.Flags().IntVar(&flagAssigneeId, "assignee-id", 0, "If supplied, only tasks that are assigned to this user are returned")
+ cmd.Flags().IntVar(&flagProjectId, "project-id", 0, "If supplied, only tasks that are assigned to this project are returned")
+ cmd.Flags().IntVar(&flagParentTaskId, "parent-task-id", 0, "If `null` is supplied then only parent tasks are returned. If integer is supplied then only subtasks of a specific...")
+ cmd.Flags().Float64Var(&flagDone, "done", 0.0, "Whether the task is done or not. `0` = Not done, `1` = Done. If not omitted then returns both done and not done tasks.")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
+func newTasksGetIdCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-id <id>",
+ Short: "Get details of a task",
+ Example: " pipedrive-cli tasks get-id <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/tasks/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newTasksUpdateCmd(flags *rootFlags) *cobra.Command {
+ var bodyAssigneeId float64
+ var bodyDescription string
+ var bodyDueDate string
+ var bodyParentTaskId float64
+ var bodyProjectId float64
+ var bodyTitle string
+
+ cmd := &cobra.Command{
+ Use: "update <id>",
+ Short: "Update a task",
+ Example: " pipedrive-cli tasks update <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/tasks/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyAssigneeId != 0.0 {
+ body["assignee_id"] = bodyAssigneeId
+ }
+ if bodyDescription != "" {
+ body["description"] = bodyDescription
+ }
+ if bodyDueDate != "" {
+ body["due_date"] = bodyDueDate
+ }
+ if bodyParentTaskId != 0.0 {
+ body["parent_task_id"] = bodyParentTaskId
+ }
+ if bodyProjectId != 0.0 {
+ body["project_id"] = bodyProjectId
+ }
+ if bodyTitle != "" {
+ body["title"] = bodyTitle
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().Float64Var(&bodyAssigneeId, "assignee-id", 0.0, "The ID of the user assigned to the task. When the `assignee_id` field is updated, the `assignee_ids` field value...")
+ cmd.Flags().StringVar(&bodyDescription, "description", "", "The description of the task")
+ cmd.Flags().StringVar(&bodyDueDate, "due-date", "", "The due date of the task. Format: YYYY-MM-DD.")
+ cmd.Flags().Float64Var(&bodyParentTaskId, "parent-task-id", 0.0, "The ID of a parent task. Can not be ID of a task which is already a subtask.")
+ cmd.Flags().Float64Var(&bodyProjectId, "project-id", 0.0, "The ID of the project this task is associated with")
+ cmd.Flags().StringVar(&bodyTitle, "title", "", "The title of the task")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/user-connections.go b/pipedrive-cli/internal/cli/user-connections.go
new file mode 100644
index 00000000..66baf366
--- /dev/null
+++ b/pipedrive-cli/internal/cli/user-connections.go
@@ -0,0 +1,51 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newUserConnectionsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "user-connections",
+ Short: "Manage user connections.",
+ }
+
+ cmd.AddCommand(newUserConnectionsGetCmd(flags))
+ return cmd
+}
+
+func newUserConnectionsGetCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all user connections",
+ Example: " pipedrive-cli user-connections get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/userConnections"
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/user-settings.go b/pipedrive-cli/internal/cli/user-settings.go
new file mode 100644
index 00000000..e4412e8b
--- /dev/null
+++ b/pipedrive-cli/internal/cli/user-settings.go
@@ -0,0 +1,51 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newUserSettingsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "user-settings",
+ Short: "View user settings.",
+ }
+
+ cmd.AddCommand(newUserSettingsGetCmd(flags))
+ return cmd
+}
+
+func newUserSettingsGetCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "List settings of an authorized user",
+ Example: " pipedrive-cli user-settings get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/userSettings"
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/users.go b/pipedrive-cli/internal/cli/users.go
new file mode 100644
index 00000000..d8858408
--- /dev/null
+++ b/pipedrive-cli/internal/cli/users.go
@@ -0,0 +1,227 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newUsersCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "users",
+ Short: "Users are people with access to your Pipedrive account. A user may belong to one or many Pipedrive accounts, so...",
+ }
+
+ cmd.AddCommand(newUsersAddCmd(flags))
+ cmd.AddCommand(newUsersFindByNameCmd(flags))
+ cmd.AddCommand(newUsersGetCmd(flags))
+ cmd.AddCommand(newUsersGetCurrentCmd(flags))
+ cmd.AddCommand(newUsersGetIdCmd(flags))
+ cmd.AddCommand(newUsersUpdateCmd(flags))
+ cmd.AddCommand(newUsersFollowersCmd(flags))
+ cmd.AddCommand(newUsersPermissionsCmd(flags))
+ cmd.AddCommand(newUsersRoleAssignmentsCmd(flags))
+ cmd.AddCommand(newUsersRoleSettingsCmd(flags))
+ return cmd
+}
+
+func newUsersAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyActiveFlag bool
+ var bodyEmail string
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Add a new user",
+ Example: " pipedrive-cli users add --email value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/users"
+ body := map[string]any{}
+ if bodyActiveFlag != false {
+ body["active_flag"] = bodyActiveFlag
+ }
+ if bodyEmail != "" {
+ body["email"] = bodyEmail
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().BoolVar(&bodyActiveFlag, "active-flag", true, "Whether the user is active or not. `false` = Not activated, `true` = Activated")
+ cmd.Flags().StringVar(&bodyEmail, "email", "", "The email of the user")
+ _ = cmd.MarkFlagRequired("email")
+
+ return cmd
+}
+
+func newUsersFindByNameCmd(flags *rootFlags) *cobra.Command {
+ var flagTerm string
+ var flagSearchByEmail float64
+
+ cmd := &cobra.Command{
+ Use: "find-by-name",
+ Aliases: []string{"list"},
+ Short: "Find users by name",
+ Example: " pipedrive-cli users find-by-name",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/users/find"
+ params := map[string]string{}
+ if flagTerm != "" {
+ params["term"] = fmt.Sprintf("%v", flagTerm)
+ }
+ if flagSearchByEmail != 0.0 {
+ params["search_by_email"] = fmt.Sprintf("%v", flagSearchByEmail)
+ }
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&flagTerm, "term", "", "The search term to look for")
+ _ = cmd.MarkFlagRequired("term")
+ cmd.Flags().Float64Var(&flagSearchByEmail, "search-by-email", 0.000000, "When enabled, the term will only be matched against email addresses of users. Default: `false`.")
+
+ return cmd
+}
+
+func newUsersGetCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Short: "Get all users",
+ Example: " pipedrive-cli users get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/users"
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newUsersGetCurrentCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-current",
+ Short: "Get current user data",
+ Example: " pipedrive-cli users get-current",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/users/me"
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newUsersGetIdCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-id <id>",
+ Short: "Get one user",
+ Example: " pipedrive-cli users get-id <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/users/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newUsersUpdateCmd(flags *rootFlags) *cobra.Command {
+ var bodyActiveFlag bool
+
+ cmd := &cobra.Command{
+ Use: "update <id>",
+ Short: "Update user details",
+ Example: " pipedrive-cli users update <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/users/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ body := map[string]any{}
+ if bodyActiveFlag != false {
+ body["active_flag"] = bodyActiveFlag
+ }
+ data, err := c.Put(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().BoolVar(&bodyActiveFlag, "active-flag", false, "Whether the user is active or not. `false` = Not activated, `true` = Activated")
+ _ = cmd.MarkFlagRequired("active-flag")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/users_followers.go b/pipedrive-cli/internal/cli/users_followers.go
new file mode 100644
index 00000000..9f607c16
--- /dev/null
+++ b/pipedrive-cli/internal/cli/users_followers.go
@@ -0,0 +1,55 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newUsersFollowersCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "followers",
+ Short: "Manage followers",
+ }
+
+ cmd.AddCommand(newUsersFollowersGetUserCmd(flags))
+ return cmd
+}
+
+func newUsersFollowersGetUserCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-user <id>",
+ Aliases: []string{"get"},
+ Short: "List followers of a user",
+ Example: " pipedrive-cli users followers get-user <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/users/{id}/followers"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/users_permissions.go b/pipedrive-cli/internal/cli/users_permissions.go
new file mode 100644
index 00000000..96ef0ed3
--- /dev/null
+++ b/pipedrive-cli/internal/cli/users_permissions.go
@@ -0,0 +1,55 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newUsersPermissionsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "permissions",
+ Short: "Manage permissions",
+ }
+
+ cmd.AddCommand(newUsersPermissionsGetUserCmd(flags))
+ return cmd
+}
+
+func newUsersPermissionsGetUserCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-user <id>",
+ Aliases: []string{"get"},
+ Short: "List user permissions",
+ Example: " pipedrive-cli users permissions get-user <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/users/{id}/permissions"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/users_role-assignments.go b/pipedrive-cli/internal/cli/users_role-assignments.go
new file mode 100644
index 00000000..d40b95cf
--- /dev/null
+++ b/pipedrive-cli/internal/cli/users_role-assignments.go
@@ -0,0 +1,63 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newUsersRoleAssignmentsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "role-assignments",
+ Short: "Manage role assignments",
+ }
+
+ cmd.AddCommand(newUsersRoleAssignmentsGetUserCmd(flags))
+ return cmd
+}
+
+func newUsersRoleAssignmentsGetUserCmd(flags *rootFlags) *cobra.Command {
+ var flagStart int
+ var flagLimit int
+ var flagAll bool
+
+ cmd := &cobra.Command{
+ Use: "get-user <id>",
+ Aliases: []string{"get"},
+ Short: "List role assignments",
+ Example: " pipedrive-cli users role-assignments get-user <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/users/{id}/roleAssignments"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := paginatedGet(c, path, map[string]string{
+ "start": fmt.Sprintf("%v", flagStart),
+ "limit": fmt.Sprintf("%v", flagLimit),
+ }, flagAll, "", "", "")
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().IntVar(&flagStart, "start", 0, "Pagination start")
+ cmd.Flags().IntVar(&flagLimit, "limit", 0, "Items shown per page")
+ cmd.Flags().BoolVar(&flagAll, "all", false, "Fetch all pages")
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/users_role-settings.go b/pipedrive-cli/internal/cli/users_role-settings.go
new file mode 100644
index 00000000..d09f852f
--- /dev/null
+++ b/pipedrive-cli/internal/cli/users_role-settings.go
@@ -0,0 +1,55 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newUsersRoleSettingsCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "role-settings",
+ Short: "Manage role settings",
+ }
+
+ cmd.AddCommand(newUsersRoleSettingsGetUserCmd(flags))
+ return cmd
+}
+
+func newUsersRoleSettingsGetUserCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get-user <id>",
+ Aliases: []string{"get"},
+ Short: "List user role settings",
+ Example: " pipedrive-cli users role-settings get-user <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/users/{id}/roleSettings"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/cli/webhooks.go b/pipedrive-cli/internal/cli/webhooks.go
new file mode 100644
index 00000000..7c6bed97
--- /dev/null
+++ b/pipedrive-cli/internal/cli/webhooks.go
@@ -0,0 +1,153 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+var _ = strings.ReplaceAll // ensure import
+var _ = fmt.Sprintf // ensure import
+
+func newWebhooksCmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "webhooks",
+ Short: "See <a href='https://pipedrive.readme.io/docs/guide-for-webhooks-v2?ref=api_reference' target='_blank' rel='noopener...",
+ }
+
+ cmd.AddCommand(newWebhooksAddCmd(flags))
+ cmd.AddCommand(newWebhooksDeleteCmd(flags))
+ cmd.AddCommand(newWebhooksGetCmd(flags))
+ return cmd
+}
+
+func newWebhooksAddCmd(flags *rootFlags) *cobra.Command {
+ var bodyEventAction string
+ var bodyEventObject string
+ var bodyHttpAuthPassword string
+ var bodyHttpAuthUser string
+ var bodyName string
+ var bodySubscriptionUrl string
+ var bodyUserId int
+ var bodyVersion string
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Aliases: []string{"create"},
+ Short: "Create a new Webhook",
+ Example: " pipedrive-cli webhooks add --event-action value",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/webhooks"
+ body := map[string]any{}
+ if bodyEventAction != "" {
+ body["event_action"] = bodyEventAction
+ }
+ if bodyEventObject != "" {
+ body["event_object"] = bodyEventObject
+ }
+ if bodyHttpAuthPassword != "" {
+ body["http_auth_password"] = bodyHttpAuthPassword
+ }
+ if bodyHttpAuthUser != "" {
+ body["http_auth_user"] = bodyHttpAuthUser
+ }
+ if bodyName != "" {
+ body["name"] = bodyName
+ }
+ if bodySubscriptionUrl != "" {
+ body["subscription_url"] = bodySubscriptionUrl
+ }
+ if bodyUserId != 0 {
+ body["user_id"] = bodyUserId
+ }
+ if bodyVersion != "" {
+ body["version"] = bodyVersion
+ }
+ data, err := c.Post(path, body)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+ cmd.Flags().StringVar(&bodyEventAction, "event-action", "", "The type of action to receive notifications about. Wildcard will match all supported actions.")
+ _ = cmd.MarkFlagRequired("event-action")
+ cmd.Flags().StringVar(&bodyEventObject, "event-object", "", "The type of object to receive notifications about. Wildcard will match all supported objects.")
+ _ = cmd.MarkFlagRequired("event-object")
+ cmd.Flags().StringVar(&bodyHttpAuthPassword, "http-auth-password", "", "The HTTP basic auth password of the subscription URL endpoint (if required)")
+ cmd.Flags().StringVar(&bodyHttpAuthUser, "http-auth-user", "", "The HTTP basic auth username of the subscription URL endpoint (if required)")
+ cmd.Flags().StringVar(&bodyName, "name", "", "The webhook's name")
+ _ = cmd.MarkFlagRequired("name")
+ cmd.Flags().StringVar(&bodySubscriptionUrl, "subscription-url", "", "A full, valid, publicly accessible URL which determines where to send the notifications. Please note that you cannot...")
+ _ = cmd.MarkFlagRequired("subscription-url")
+ cmd.Flags().IntVar(&bodyUserId, "user-id", 0, "The ID of the user that this webhook will be authorized with. You have the option to use a different user's...")
+ cmd.Flags().StringVar(&bodyVersion, "version", "2.0", "The webhook's version. NB! Webhooks v2 is the default from March 17th, 2025. See <a...")
+
+ return cmd
+}
+
+func newWebhooksDeleteCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "delete <id>",
+ Short: "Delete existing Webhook",
+ Example: " pipedrive-cli webhooks delete <id>",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/webhooks/{id}"
+ if len(args) < 1 {
+ return usageErr(fmt.Errorf("id is required"))
+ }
+ path = replacePathParam(path, "id", args[0])
+ data, err := c.Delete(path)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
+func newWebhooksGetCmd(flags *rootFlags) *cobra.Command {
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Aliases: []string{"list"},
+ Short: "Get all Webhooks",
+ Example: " pipedrive-cli webhooks get",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ c, err := flags.newClient()
+ if err != nil {
+ return err
+ }
+
+ path := "/webhooks"
+ params := map[string]string{}
+ data, err := c.Get(path, params)
+ if err != nil {
+ return classifyAPIError(err)
+ }
+
+ return printOutput(cmd.OutOrStdout(), data, flags.asJSON)
+ },
+ }
+
+ return cmd
+}
+
diff --git a/pipedrive-cli/internal/client/client.go b/pipedrive-cli/internal/client/client.go
new file mode 100644
index 00000000..3cc9bc59
--- /dev/null
+++ b/pipedrive-cli/internal/client/client.go
@@ -0,0 +1,300 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package client
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "math"
+ "net/http"
+ "net/url"
+ "os"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/USER/pipedrive-cli/internal/config"
+)
+
+type Client struct {
+ BaseURL string
+ Config *config.Config
+ HTTPClient *http.Client
+ DryRun bool
+}
+
+// APIError carries HTTP status information for structured exit codes.
+type APIError struct {
+ Method string
+ Path string
+ StatusCode int
+ Body string
+}
+
+func (e *APIError) Error() string {
+ return fmt.Sprintf("%s %s returned HTTP %d: %s", e.Method, e.Path, e.StatusCode, e.Body)
+}
+
+func New(cfg *config.Config, timeout time.Duration) *Client {
+ return &Client{
+ BaseURL: strings.TrimRight(cfg.BaseURL, "/"),
+ Config: cfg,
+ HTTPClient: &http.Client{Timeout: timeout},
+ }
+}
+
+func (c *Client) Get(path string, params map[string]string) (json.RawMessage, error) {
+ return c.do("GET", path, params, nil)
+}
+
+func (c *Client) Post(path string, body any) (json.RawMessage, error) {
+ return c.do("POST", path, nil, body)
+}
+
+func (c *Client) Delete(path string) (json.RawMessage, error) {
+ return c.do("DELETE", path, nil, nil)
+}
+
+func (c *Client) Put(path string, body any) (json.RawMessage, error) {
+ return c.do("PUT", path, nil, body)
+}
+
+func (c *Client) Patch(path string, body any) (json.RawMessage, error) {
+ return c.do("PATCH", path, nil, body)
+}
+
+func (c *Client) do(method, path string, params map[string]string, body any) (json.RawMessage, error) {
+ url := c.BaseURL + path
+
+ var bodyBytes []byte
+ if body != nil {
+ b, err := json.Marshal(body)
+ if err != nil {
+ return nil, fmt.Errorf("marshaling body: %w", err)
+ }
+ bodyBytes = b
+ }
+
+ // Build the request for dry-run display or actual execution
+ if c.DryRun {
+ return c.dryRun(method, url, params, bodyBytes)
+ }
+
+ const maxRetries = 3
+ var lastErr error
+
+ for attempt := 0; attempt <= maxRetries; attempt++ {
+ var bodyReader io.Reader
+ if bodyBytes != nil {
+ bodyReader = strings.NewReader(string(bodyBytes))
+ }
+
+ req, err := http.NewRequest(method, url, bodyReader)
+ if err != nil {
+ return nil, fmt.Errorf("creating request: %w", err)
+ }
+
+ authHeader, err := c.authHeader()
+ if err != nil {
+ return nil, err
+ }
+ if authHeader != "" {
+ req.Header.Set("Authorization", authHeader)
+ }
+ if bodyBytes != nil {
+ req.Header.Set("Content-Type", "application/json")
+ }
+ req.Header.Set("User-Agent", "pipedrive-cli/1.0.0")
+
+ if params != nil {
+ q := req.URL.Query()
+ for k, v := range params {
+ if v != "" {
+ q.Set(k, v)
+ }
+ }
+ req.URL.RawQuery = q.Encode()
+ }
+
+ resp, err := c.HTTPClient.Do(req)
+ if err != nil {
+ lastErr = fmt.Errorf("%s %s: %w", method, path, err)
+ continue
+ }
+
+ respBody, err := io.ReadAll(resp.Body)
+ resp.Body.Close()
+ if err != nil {
+ return nil, fmt.Errorf("reading response: %w", err)
+ }
+
+ // Success
+ if resp.StatusCode < 400 {
+ return json.RawMessage(respBody), nil
+ }
+
+ apiErr := &APIError{
+ Method: method,
+ Path: path,
+ StatusCode: resp.StatusCode,
+ Body: truncateBody(respBody),
+ }
+
+ // Rate limited - wait and retry
+ if resp.StatusCode == 429 && attempt < maxRetries {
+ wait := retryAfter(resp)
+ fmt.Fprintf(os.Stderr, "rate limited, waiting %s (attempt %d/%d)\n", wait, attempt+1, maxRetries)
+ time.Sleep(wait)
+ lastErr = apiErr
+ continue
+ }
+
+ // Server error - retry with backoff
+ if resp.StatusCode >= 500 && attempt < maxRetries {
+ wait := time.Duration(math.Pow(2, float64(attempt))) * time.Second
+ fmt.Fprintf(os.Stderr, "server error %d, retrying in %s (attempt %d/%d)\n", resp.StatusCode, wait, attempt+1, maxRetries)
+ time.Sleep(wait)
+ lastErr = apiErr
+ continue
+ }
+
+ // Client error or retries exhausted - return the error
+ return nil, apiErr
+ }
+
+ return nil, lastErr
+}
+
+func (c *Client) dryRun(method, url string, params map[string]string, body []byte) (json.RawMessage, error) {
+ fmt.Fprintf(os.Stderr, "%s %s\n", method, url)
+ if params != nil {
+ for k, v := range params {
+ if v != "" {
+ fmt.Fprintf(os.Stderr, " ?%s=%s\n", k, v)
+ }
+ }
+ }
+ authHeader, err := c.authHeader()
+ if err != nil {
+ return nil, err
+ }
+ if authHeader != "" {
+ // Mask token for safety
+ auth := authHeader
+ if len(auth) > 20 {
+ auth = auth[:15] + "..."
+ }
+ fmt.Fprintf(os.Stderr, " Authorization: %s\n", auth)
+ }
+ if body != nil {
+ var pretty json.RawMessage
+ if json.Unmarshal(body, &pretty) == nil {
+ enc := json.NewEncoder(os.Stderr)
+ enc.SetIndent(" ", " ")
+ fmt.Fprintf(os.Stderr, " Body:\n")
+ enc.Encode(pretty)
+ }
+ }
+ fmt.Fprintf(os.Stderr, "\n(dry run - no request sent)\n")
+ return json.RawMessage(`{"dry_run": true}`), nil
+}
+
+func (c *Client) authHeader() (string, error) {
+ if c.Config == nil {
+ return "", nil
+ }
+ if c.Config.AccessToken != "" && !c.Config.TokenExpiry.IsZero() && time.Now().After(c.Config.TokenExpiry) && c.Config.RefreshToken != "" {
+ if err := c.refreshAccessToken(); err != nil {
+ return "", err
+ }
+ }
+ return c.Config.AuthHeader(), nil
+}
+
+func (c *Client) refreshAccessToken() error {
+ if c.Config == nil {
+ return nil
+ }
+ if c.Config.RefreshToken == "" {
+ return nil
+ }
+
+ tokenURL := "https://oauth.pipedrive.com/oauth/token"
+ if tokenURL == "" {
+ return nil
+ }
+
+ params := url.Values{
+ "grant_type": {"refresh_token"},
+ "refresh_token": {c.Config.RefreshToken},
+ "client_id": {c.Config.ClientID},
+ }
+ if c.Config.ClientSecret != "" {
+ params.Set("client_secret", c.Config.ClientSecret)
+ }
+
+ resp, err := c.HTTPClient.PostForm(tokenURL, params)
+ if err != nil {
+ return fmt.Errorf("refreshing access token: %w", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode >= 400 {
+ body, _ := io.ReadAll(resp.Body)
+ return fmt.Errorf("refreshing access token: HTTP %d: %s", resp.StatusCode, truncateBody(body))
+ }
+
+ var tokenResp struct {
+ AccessToken string `json:"access_token"`
+ RefreshToken string `json:"refresh_token"`
+ ExpiresIn int `json:"expires_in"`
+ }
+ if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
+ return fmt.Errorf("parsing refresh response: %w", err)
+ }
+ if tokenResp.AccessToken == "" {
+ return fmt.Errorf("refreshing access token: no access token in response")
+ }
+
+ refreshToken := c.Config.RefreshToken
+ if tokenResp.RefreshToken != "" {
+ refreshToken = tokenResp.RefreshToken
+ }
+
+ expiry := time.Time{}
+ if tokenResp.ExpiresIn > 0 {
+ expiry = time.Now().Add(time.Duration(tokenResp.ExpiresIn) * time.Second)
+ }
+
+ if err := c.Config.SaveTokens(c.Config.ClientID, c.Config.ClientSecret, tokenResp.AccessToken, refreshToken, expiry); err != nil {
+ return fmt.Errorf("saving refreshed token: %w", err)
+ }
+
+ return nil
+}
+
+func retryAfter(resp *http.Response) time.Duration {
+ header := resp.Header.Get("Retry-After")
+ if header == "" {
+ return 5 * time.Second
+ }
+ if seconds, err := strconv.Atoi(header); err == nil {
+ return time.Duration(seconds) * time.Second
+ }
+ if t, err := http.ParseTime(header); err == nil {
+ wait := time.Until(t)
+ if wait > 0 {
+ return wait
+ }
+ }
+ return 5 * time.Second
+}
+
+func truncateBody(b []byte) string {
+ s := string(b)
+ if len(s) > 200 {
+ return s[:200] + "..."
+ }
+ return s
+}
diff --git a/pipedrive-cli/internal/config/config.go b/pipedrive-cli/internal/config/config.go
new file mode 100644
index 00000000..4f73daea
--- /dev/null
+++ b/pipedrive-cli/internal/config/config.go
@@ -0,0 +1,104 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package config
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "strings"
+ "time"
+
+ "github.com/pelletier/go-toml/v2"
+)
+
+type Config struct {
+ BaseURL string `toml:"base_url"`
+ AuthHeaderVal string `toml:"auth_header"`
+ AuthSource string `toml:"-"`
+ AccessToken string `toml:"access_token"`
+ RefreshToken string `toml:"refresh_token"`
+ TokenExpiry time.Time `toml:"token_expiry"`
+ ClientID string `toml:"client_id"`
+ ClientSecret string `toml:"client_secret"`
+ Path string `toml:"-"`
+ PipedriveToken string `toml:"token"`
+}
+
+func Load(configPath string) (*Config, error) {
+ cfg := &Config{
+ BaseURL: "https://api.pipedrive.com/v1",
+ }
+
+ // Resolve config path
+ path := configPath
+ if path == "" {
+ path = os.Getenv("PIPEDRIVE_CONFIG")
+ }
+ if path == "" {
+ home, _ := os.UserHomeDir()
+ path = filepath.Join(home, ".config", "pipedrive-cli", "config.toml")
+ }
+ cfg.Path = path
+
+ // Try to load config file
+ data, err := os.ReadFile(path)
+ if err == nil {
+ if err := toml.Unmarshal(data, cfg); err != nil {
+ return nil, fmt.Errorf("parsing config %s: %w", path, err)
+ }
+ }
+
+ // Env var overrides
+ if v := os.Getenv("PIPEDRIVE_TOKEN"); v != "" {
+ cfg.PipedriveToken = v
+ cfg.AuthSource = "env:PIPEDRIVE_TOKEN"
+ }
+
+ return cfg, nil
+}
+
+func (c *Config) AuthHeader() string {
+ if c.AuthHeaderVal != "" {
+ return c.AuthHeaderVal
+ }
+ if c.AccessToken != "" {
+ c.AuthSource = "oauth2"
+ return "Bearer " + c.AccessToken
+ }
+ if c.PipedriveToken != "" {
+ return "Bearer " + c.PipedriveToken
+ }
+ return ""
+}
+
+func (c *Config) SaveTokens(clientID, clientSecret, accessToken, refreshToken string, expiry time.Time) error {
+ c.ClientID = clientID
+ c.ClientSecret = clientSecret
+ c.AccessToken = accessToken
+ c.RefreshToken = refreshToken
+ c.TokenExpiry = expiry
+ return c.save()
+}
+
+func (c *Config) ClearTokens() error {
+ c.AccessToken = ""
+ c.RefreshToken = ""
+ c.TokenExpiry = time.Time{}
+ return c.save()
+}
+
+func (c *Config) save() error {
+ dir := filepath.Dir(c.Path)
+ if err := os.MkdirAll(dir, 0o700); err != nil {
+ return fmt.Errorf("creating config dir: %w", err)
+ }
+ data, err := toml.Marshal(c)
+ if err != nil {
+ return fmt.Errorf("marshaling config: %w", err)
+ }
+ return os.WriteFile(c.Path, data, 0o600)
+}
+
+// Ensure strings import is used
+var _ = strings.ReplaceAll
diff --git a/pipedrive-cli/internal/types/types.go b/pipedrive-cli/internal/types/types.go
new file mode 100644
index 00000000..fedfa25e
--- /dev/null
+++ b/pipedrive-cli/internal/types/types.go
@@ -0,0 +1,4 @@
+// Code generated by CLI Printing Press. DO NOT EDIT.
+
+package types
+
← 66bc4ea8 feat(catalog): generate Plaid CLI from official OpenAPI spec
·
back to Cli Printing Press
·
docs: overnight hardening results - 10/10 gauntlet, 30 tests 5e0f4714 →