@ikatec/digisac-api-sdk 4.4.0 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/apis/cards/CardsApi.cjs +70 -0
  2. package/dist/apis/cards/CardsApi.cjs.map +1 -1
  3. package/dist/apis/cards/CardsApi.d.ts +53 -1
  4. package/dist/apis/cards/CardsApi.d.ts.map +1 -1
  5. package/dist/apis/cards/CardsApi.mjs +70 -0
  6. package/dist/apis/cards/CardsApi.mjs.map +1 -1
  7. package/dist/apis/cards/types.d.ts +84 -0
  8. package/dist/apis/cards/types.d.ts.map +1 -1
  9. package/dist/apis/kanbanBoards/types.d.ts +33 -4
  10. package/dist/apis/kanbanBoards/types.d.ts.map +1 -1
  11. package/dist/apis/kanbanCards/KanbanCardsApi.cjs +8 -0
  12. package/dist/apis/kanbanCards/KanbanCardsApi.cjs.map +1 -1
  13. package/dist/apis/kanbanCards/KanbanCardsApi.d.ts +7 -1
  14. package/dist/apis/kanbanCards/KanbanCardsApi.d.ts.map +1 -1
  15. package/dist/apis/kanbanCards/KanbanCardsApi.mjs +8 -0
  16. package/dist/apis/kanbanCards/KanbanCardsApi.mjs.map +1 -1
  17. package/dist/apis/kanbanCards/types.d.ts +17 -5
  18. package/dist/apis/kanbanCards/types.d.ts.map +1 -1
  19. package/dist/apis/kanbanColumns/KanbanColumnsApi.cjs +9 -0
  20. package/dist/apis/kanbanColumns/KanbanColumnsApi.cjs.map +1 -1
  21. package/dist/apis/kanbanColumns/KanbanColumnsApi.d.ts +8 -1
  22. package/dist/apis/kanbanColumns/KanbanColumnsApi.d.ts.map +1 -1
  23. package/dist/apis/kanbanColumns/KanbanColumnsApi.mjs +9 -0
  24. package/dist/apis/kanbanColumns/KanbanColumnsApi.mjs.map +1 -1
  25. package/dist/apis/kanbanColumns/types.d.ts +14 -3
  26. package/dist/apis/kanbanColumns/types.d.ts.map +1 -1
  27. package/dist/apis/messages/MessagesApi.cjs +4 -1
  28. package/dist/apis/messages/MessagesApi.cjs.map +1 -1
  29. package/dist/apis/messages/MessagesApi.d.ts +5 -2
  30. package/dist/apis/messages/MessagesApi.d.ts.map +1 -1
  31. package/dist/apis/messages/MessagesApi.mjs +4 -1
  32. package/dist/apis/messages/MessagesApi.mjs.map +1 -1
  33. package/dist/apis/messages/types.d.ts +13 -0
  34. package/dist/apis/messages/types.d.ts.map +1 -1
  35. package/dist/apis/pipeline/PipelineApi.cjs +133 -0
  36. package/dist/apis/pipeline/PipelineApi.cjs.map +1 -1
  37. package/dist/apis/pipeline/PipelineApi.d.ts +102 -1
  38. package/dist/apis/pipeline/PipelineApi.d.ts.map +1 -1
  39. package/dist/apis/pipeline/PipelineApi.mjs +133 -0
  40. package/dist/apis/pipeline/PipelineApi.mjs.map +1 -1
  41. package/dist/apis/pipeline/types.d.ts +164 -0
  42. package/dist/apis/pipeline/types.d.ts.map +1 -1
  43. package/dist/apis/tags/TagsApi.cjs +3 -2
  44. package/dist/apis/tags/TagsApi.cjs.map +1 -1
  45. package/dist/apis/tags/TagsApi.d.ts +6 -5
  46. package/dist/apis/tags/TagsApi.d.ts.map +1 -1
  47. package/dist/apis/tags/TagsApi.mjs +3 -2
  48. package/dist/apis/tags/TagsApi.mjs.map +1 -1
  49. package/dist/apis/tags/types.d.ts +5 -0
  50. package/dist/apis/tags/types.d.ts.map +1 -1
  51. package/dist/apis/users/types.d.ts +21 -3
  52. package/dist/apis/users/types.d.ts.map +1 -1
  53. package/package.json +1 -1
  54. package/src/apis/cards/CardsApi.test.ts +128 -0
  55. package/src/apis/cards/CardsApi.ts +124 -1
  56. package/src/apis/cards/types.ts +81 -0
  57. package/src/apis/kanbanBoards/types.ts +36 -4
  58. package/src/apis/kanbanCards/KanbanCardsApi.test.ts +46 -0
  59. package/src/apis/kanbanCards/KanbanCardsApi.ts +23 -1
  60. package/src/apis/kanbanCards/types.ts +18 -5
  61. package/src/apis/kanbanColumns/KanbanColumnsApi.test.ts +46 -0
  62. package/src/apis/kanbanColumns/KanbanColumnsApi.ts +24 -1
  63. package/src/apis/kanbanColumns/types.ts +15 -3
  64. package/src/apis/me/MeApi.test.ts +3 -3
  65. package/src/apis/messages/MessagesApi.test.ts +11 -0
  66. package/src/apis/messages/MessagesApi.ts +6 -3
  67. package/src/apis/messages/types.ts +13 -0
  68. package/src/apis/payloads.test-d.ts +30 -0
  69. package/src/apis/pipeline/PipelineApi.test.ts +193 -0
  70. package/src/apis/pipeline/PipelineApi.ts +274 -1
  71. package/src/apis/pipeline/types.ts +162 -0
  72. package/src/apis/tags/TagsApi.test.ts +5 -0
  73. package/src/apis/tags/TagsApi.ts +8 -6
  74. package/src/apis/tags/types.ts +6 -0
  75. package/src/apis/users/UsersApi.test.ts +3 -3
  76. package/src/apis/users/types.ts +23 -3
@@ -45,6 +45,17 @@ const message: Message = {
45
45
  obfuscated: false,
46
46
  reactionParentMessageId: null,
47
47
  hsmId: null,
48
+ isFromBot: false,
49
+ accountId: 'acc-1',
50
+ serviceId: 'svc-1',
51
+ contactId: 'ctt-1',
52
+ fromId: null,
53
+ toId: 'ctt-1',
54
+ userId: 'usr-1',
55
+ ticketId: 'tkt-1',
56
+ ticketUserId: 'usr-1',
57
+ ticketDepartmentId: 'dep-1',
58
+ quotedMessageId: null,
48
59
  createdAt: '2024-01-01T00:00:00Z',
49
60
  updatedAt: '2024-01-01T00:00:00Z',
50
61
  deletedAt: null,
@@ -101,9 +101,12 @@ export class MessagesApi extends BaseCrudApi<Message, CreateMessagePayload, Upda
101
101
  )
102
102
  }
103
103
 
104
- /** Triggers an AI-generated summary for the conversation associated with the given message. */
105
- summarize(id: string, headers?: Record<string, string>): Promise<void> {
106
- return this.client.post<void>(`${this.basePath}/${id}/summarize`, undefined, headers)
104
+ /**
105
+ * Triggers an AI-generated summary for the conversation associated with the given message.
106
+ * Resolves to `'OK'`.
107
+ */
108
+ summarize(id: string, headers?: Record<string, string>): Promise<string> {
109
+ return this.client.post<string>(`${this.basePath}/${id}/summarize`, undefined, headers)
107
110
  }
108
111
 
109
112
  /** Checks whether a message is out of the visible range (i.e. there are more than `limit` messages after it). */
@@ -113,6 +113,19 @@ export type Message = {
113
113
  transcribeError?: boolean
114
114
  reactionParentMessageId: string | null
115
115
  hsmId: string | null
116
+ isFromBot: boolean
117
+ accountId: string
118
+ serviceId: string
119
+ contactId: string
120
+ /** The contact that sent the message; `null` when it is from the account. */
121
+ fromId: string | null
122
+ toId: string | null
123
+ /** The user that sent the message; `null` for a received one. */
124
+ userId: string | null
125
+ ticketId: string | null
126
+ ticketUserId: string | null
127
+ ticketDepartmentId: string | null
128
+ quotedMessageId: string | null
116
129
  createdAt: string
117
130
  updatedAt: string
118
131
  deletedAt: string | null
@@ -1,6 +1,9 @@
1
1
  import { expectError } from 'tsd'
2
2
  import type { ApiClient } from '../core/ApiClient'
3
+ import { CardsApi } from './cards/CardsApi'
3
4
  import { ContactsApi } from './contacts/ContactsApi'
5
+ import { KanbanColumnsApi } from './kanbanColumns/KanbanColumnsApi'
6
+ import { PipelineApi } from './pipeline/PipelineApi'
4
7
  import { PersonalAccessTokensApi } from './personalAccessTokens/PersonalAccessTokensApi'
5
8
  import { RolesApi } from './roles/RolesApi'
6
9
  import { TagsApi } from './tags/TagsApi'
@@ -63,3 +66,30 @@ const tags = new TagsApi(client)
63
66
  tags.attachContacts('t-1', { where: { id: { $in: ['c-1', 'c-2'] } } })
64
67
  expectError(tags.attachContacts('t-1', {}))
65
68
  expectError(tags.detachContacts('t-1', { include: ['tags'] }))
69
+
70
+ // ── pipelines: moving the cards of a deleted status needs the target ─
71
+
72
+ const pipelines = new PipelineApi(client)
73
+ pipelines.deleteStatus('st-1', { action: 'move-to-another', newStatusId: 'st-2' })
74
+ pipelines.deleteStatus('st-1', { action: 'keep-without-status' })
75
+ expectError(pipelines.deleteStatus('st-1', { action: 'move-to-another' }))
76
+ expectError(pipelines.createAutomation({ pipelineId: 'p-1', type: 'email' }))
77
+ expectError(pipelines.deleteStage('s-1', { typeAction: 'archive' }))
78
+
79
+ // ── cards: getCards is not scoped by the backend and only answers the attributes asked ─
80
+
81
+ const cards = new CardsApi(client)
82
+ cards.getCards({
83
+ where: { accountId: 'a-1', pipelineId: 'p-1' },
84
+ attributes: ['id', 'title'],
85
+ order: [['contact.name', 'ASC']],
86
+ })
87
+ expectError(cards.getCards({ where: { pipelineId: 'p-1' }, attributes: ['id'] }))
88
+ expectError(cards.getCards({ where: { accountId: 'a-1' } }))
89
+ expectError(cards.saveComment({ comment: 'no card nor id' }))
90
+
91
+ // ── kanban columns: the backend computes the position ───────────────
92
+
93
+ const columns = new KanbanColumnsApi(client)
94
+ columns.reorder('col-1', { beforeColumnId: 'col-0', afterColumnId: 'col-2' })
95
+ expectError(columns.reorder('col-1', { position: 'M' }))
@@ -0,0 +1,193 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+ import type { ApiClient } from '../../core/ApiClient'
3
+ import { PipelineApi } from './PipelineApi'
4
+
5
+ // ── Mock client factory ──────────────────────────────────────────────
6
+
7
+ function createMockClient(): ApiClient {
8
+ return {
9
+ setAccessToken: vi.fn().mockReturnThis(),
10
+ request: vi.fn(),
11
+ get: vi.fn(),
12
+ post: vi.fn(),
13
+ put: vi.fn(),
14
+ patch: vi.fn(),
15
+ delete: vi.fn(),
16
+ }
17
+ }
18
+
19
+ const headers = { 'X-Custom': 'value' }
20
+
21
+ // ── Tests ────────────────────────────────────────────────────────────
22
+
23
+ describe('PipelineApi', () => {
24
+ let client: ReturnType<typeof createMockClient>
25
+ let api: PipelineApi
26
+
27
+ beforeEach(() => {
28
+ client = createMockClient()
29
+ api = new PipelineApi(client)
30
+ })
31
+
32
+ describe('stages', () => {
33
+ const stage = { name: 'Proposta', pipelineId: 'p1', position: 2 }
34
+
35
+ it('createStage calls client.post with /pipelines/stage and body', async () => {
36
+ vi.mocked(client.post).mockResolvedValue({ id: 's1', ...stage })
37
+ const result = await api.createStage(stage)
38
+ expect(client.post).toHaveBeenCalledWith('/pipelines/stage', stage, undefined)
39
+ expect(result).toEqual({ id: 's1', ...stage })
40
+ })
41
+
42
+ it('createStage resolves to the refusal code the backend answers with 200', async () => {
43
+ vi.mocked(client.post).mockResolvedValue('STAGES_LIMIT')
44
+ await expect(api.createStage(stage)).resolves.toBe('STAGES_LIMIT')
45
+ })
46
+
47
+ it('updateStage calls client.put with /pipelines/stage/:id and body', async () => {
48
+ const body = { ...stage, id: 's1', statuses: [{ id: 'st1', name: 'Novo', position: 1 }] }
49
+ await api.updateStage('s1', body, headers)
50
+ expect(client.put).toHaveBeenCalledWith('/pipelines/stage/s1', body, headers)
51
+ })
52
+
53
+ it('deleteStage calls client.request with DELETE and the destination of the cards', async () => {
54
+ vi.mocked(client.request).mockResolvedValue('MESSAGE_STAGE_DELETED')
55
+ const body = { typeAction: 'move' as const, idNewStage: 's2', user: { id: 'u1' } }
56
+ const result = await api.deleteStage('s1', body)
57
+ expect(client.request).toHaveBeenCalledWith('DELETE', '/pipelines/stage/s1', body, undefined)
58
+ expect(result).toBe('MESSAGE_STAGE_DELETED')
59
+ })
60
+
61
+ it('deleteStage sends an empty body by default', async () => {
62
+ await api.deleteStage('s1')
63
+ expect(client.request).toHaveBeenCalledWith('DELETE', '/pipelines/stage/s1', {}, undefined)
64
+ })
65
+
66
+ it('getStageTotals calls client.post with /pipelines/stage-totals/:id and the filters', async () => {
67
+ const filters = { nameTitle: 'Acme', createdFrom: '01/09/2026' }
68
+ await api.getStageTotals('s1', filters)
69
+ expect(client.post).toHaveBeenCalledWith('/pipelines/stage-totals/s1', filters, undefined)
70
+ })
71
+
72
+ it('getStageTotals sends no filter by default', async () => {
73
+ await api.getStageTotals('s1')
74
+ expect(client.post).toHaveBeenCalledWith('/pipelines/stage-totals/s1', {}, undefined)
75
+ })
76
+ })
77
+
78
+ describe('statuses', () => {
79
+ it('getStatuses calls client.get with /pipelines/statuses/:pipelineId', async () => {
80
+ vi.mocked(client.get).mockResolvedValue([{ id: 'st1', name: 'Novo' }])
81
+ const result = await api.getStatuses('p1', headers)
82
+ expect(client.get).toHaveBeenCalledWith('/pipelines/statuses/p1', headers)
83
+ expect(result).toEqual([{ id: 'st1', name: 'Novo' }])
84
+ })
85
+
86
+ it('getStatus calls client.get with /pipelines/status/:id', async () => {
87
+ await api.getStatus('st1')
88
+ expect(client.get).toHaveBeenCalledWith('/pipelines/status/st1', undefined)
89
+ })
90
+
91
+ it('deleteStatus calls client.post with /pipelines/delete-status/:id and the action', async () => {
92
+ vi.mocked(client.post).mockResolvedValue('MESSAGE_STATUS_DELETED')
93
+ const body = { action: 'move-to-another' as const, newStatusId: 'st2' }
94
+ const result = await api.deleteStatus('st1', body)
95
+ expect(client.post).toHaveBeenCalledWith('/pipelines/delete-status/st1', body, undefined)
96
+ expect(result).toBe('MESSAGE_STATUS_DELETED')
97
+ })
98
+
99
+ it('renameStatus posts only newStatusName to the delete-status route', async () => {
100
+ vi.mocked(client.post).mockResolvedValue('MESSAGE_STATUS_RENAMED')
101
+ const result = await api.renameStatus('st1', 'Qualificado', headers)
102
+ expect(client.post).toHaveBeenCalledWith(
103
+ '/pipelines/delete-status/st1',
104
+ { newStatusName: 'Qualificado' },
105
+ headers,
106
+ )
107
+ expect(result).toBe('MESSAGE_STATUS_RENAMED')
108
+ })
109
+ })
110
+
111
+ describe('automations', () => {
112
+ const body = {
113
+ pipelineId: 'p1',
114
+ type: 'notification' as const,
115
+ config: { notify: 'high' as const },
116
+ }
117
+
118
+ it('createAutomation calls client.post with /pipelines/automations and body', async () => {
119
+ await api.createAutomation(body)
120
+ expect(client.post).toHaveBeenCalledWith('/pipelines/automations', body, undefined)
121
+ })
122
+
123
+ it('updateAutomation calls client.put with /pipelines/automations/:id and body', async () => {
124
+ await api.updateAutomation('a1', body, headers)
125
+ expect(client.put).toHaveBeenCalledWith('/pipelines/automations/a1', body, headers)
126
+ })
127
+
128
+ it('deleteAutomation calls client.delete with /pipelines/automations/:id', async () => {
129
+ await api.deleteAutomation('a1')
130
+ expect(client.delete).toHaveBeenCalledWith('/pipelines/automations/a1', undefined)
131
+ })
132
+
133
+ it('getAutomation calls client.get with /pipelines/automations/:pipelineId', async () => {
134
+ vi.mocked(client.get).mockResolvedValue([])
135
+ const result = await api.getAutomation('p1')
136
+ expect(client.get).toHaveBeenCalledWith('/pipelines/automations/p1', undefined)
137
+ expect(result).toEqual([])
138
+ })
139
+ })
140
+
141
+ describe('pipeline actions', () => {
142
+ it('duplicate calls client.post with /pipelines/duplicate/:pipelineId and no body', async () => {
143
+ await api.duplicate('p1', headers)
144
+ expect(client.post).toHaveBeenCalledWith('/pipelines/duplicate/p1', undefined, headers)
145
+ })
146
+
147
+ it('archive posts archive: true to /pipelines/:id/archive', async () => {
148
+ await api.archive('p1')
149
+ expect(client.post).toHaveBeenCalledWith(
150
+ '/pipelines/p1/archive',
151
+ { archive: true },
152
+ undefined,
153
+ )
154
+ })
155
+
156
+ it('unarchive posts archive: false to /pipelines/:id/archive', async () => {
157
+ await api.unarchive('p1')
158
+ expect(client.post).toHaveBeenCalledWith(
159
+ '/pipelines/p1/archive',
160
+ { archive: false },
161
+ undefined,
162
+ )
163
+ })
164
+
165
+ it('exportCsv calls client.post with /pipelines/:id/export and resolves to the CSV text', async () => {
166
+ vi.mocked(client.post).mockResolvedValue('Funil;\n')
167
+ const body = { createdAtInit: '2026-09-01 00:00:00', createdAtFinal: '2026-09-30 23:59:59' }
168
+ const result = await api.exportCsv('p1', body)
169
+ expect(client.post).toHaveBeenCalledWith('/pipelines/p1/export', body, undefined)
170
+ expect(result).toBe('Funil;\n')
171
+ })
172
+
173
+ it('getManyWithTotals serializes the query on /pipelines/withTotals', async () => {
174
+ await api.getManyWithTotals({ archive: true })
175
+ const expected = `/pipelines/withTotals?query=${encodeURIComponent(JSON.stringify({ archive: true }))}`
176
+ expect(client.get).toHaveBeenCalledWith(expected, undefined)
177
+ })
178
+
179
+ it('getManyWithTotals sends no query string without a query', async () => {
180
+ await api.getManyWithTotals()
181
+ expect(client.get).toHaveBeenCalledWith('/pipelines/withTotals', undefined)
182
+ })
183
+ })
184
+
185
+ describe('error propagation', () => {
186
+ it('propagates errors from createStage', async () => {
187
+ vi.mocked(client.post).mockRejectedValue(new Error('Validation failed'))
188
+ await expect(api.createStage({ name: 'x', pipelineId: 'p1', position: 1 })).rejects.toThrow(
189
+ 'Validation failed',
190
+ )
191
+ })
192
+ })
193
+ })
@@ -1,6 +1,28 @@
1
1
  import type { ApiClient } from '../../core/ApiClient'
2
2
  import { BaseCrudApi } from '../../core/BaseCrudApi'
3
- import type { Pipeline, CreatePipelinePayload, UpdatePipelinePayload } from './types'
3
+ import type {
4
+ CreatePipelineAutomationPayload,
5
+ CreatePipelinePayload,
6
+ CreatePipelineStagePayload,
7
+ DeletePipelineStagePayload,
8
+ DeletePipelineStageResult,
9
+ DeletePipelineStatusPayload,
10
+ ExportPipelinePayload,
11
+ Pipeline,
12
+ PipelineAutomation,
13
+ PipelineRecord,
14
+ PipelineStage,
15
+ PipelineStageRefusal,
16
+ PipelineStageStatusWithCount,
17
+ PipelineStageTotals,
18
+ PipelineStageTotalsFilters,
19
+ PipelineStatusRef,
20
+ PipelinesWithTotals,
21
+ PipelinesWithTotalsQuery,
22
+ UpdatePipelineAutomationPayload,
23
+ UpdatePipelinePayload,
24
+ UpdatePipelineStagePayload,
25
+ } from './types'
4
26
 
5
27
  export class PipelineApi extends BaseCrudApi<
6
28
  Pipeline,
@@ -10,4 +32,255 @@ export class PipelineApi extends BaseCrudApi<
10
32
  constructor(client: ApiClient) {
11
33
  super(client, '/pipelines')
12
34
  }
35
+
36
+ /**
37
+ * Adds a stage (with its statuses and reasons) to a pipeline. Resolves to the stage as stored,
38
+ * without the statuses/reasons, or to a refusal code with 200: `'STAGES_LIMIT'` (the pipeline
39
+ * already has 10 stages) or `'STAGE_ALREADY_EXIST'` (same name).
40
+ * @permissions pipelines.update
41
+ */
42
+ createStage(
43
+ body: CreatePipelineStagePayload,
44
+ headers?: Record<string, string>,
45
+ ): Promise<PipelineStage | PipelineStageRefusal> {
46
+ return this.client.post<PipelineStage | PipelineStageRefusal, CreatePipelineStagePayload>(
47
+ `${this.basePath}/stage`,
48
+ body,
49
+ headers,
50
+ )
51
+ }
52
+
53
+ /**
54
+ * Updates a stage. `statuses` and `reasons` replace the whole set: items with `id` are kept
55
+ * and updated, items without it are created and the missing ones are deleted — omitting the
56
+ * lists deletes every status and reason of the stage. Resolves to the stage as stored, or to
57
+ * `'STAGE_ALREADY_EXIST'`.
58
+ * @permissions pipelines.update
59
+ */
60
+ updateStage(
61
+ id: string,
62
+ body: UpdatePipelineStagePayload,
63
+ headers?: Record<string, string>,
64
+ ): Promise<PipelineStage | 'STAGE_ALREADY_EXIST'> {
65
+ return this.client.put<PipelineStage | 'STAGE_ALREADY_EXIST', UpdatePipelineStagePayload>(
66
+ `${this.basePath}/stage/${id}`,
67
+ body,
68
+ headers,
69
+ )
70
+ }
71
+
72
+ /**
73
+ * Deletes a stage and moves its cards (see {@link DeletePipelineStagePayload}). Resolves to
74
+ * `'MESSAGE_STAGE_DELETED'`, or to `'PIPELINES_MIN_STAGES'` (nothing deleted) when the pipeline
75
+ * has only 2 stages. The backend also serves this under `PUT /pipelines/delete-stage/{id}`.
76
+ * @permissions pipelines.update
77
+ */
78
+ deleteStage(
79
+ id: string,
80
+ body: DeletePipelineStagePayload = {},
81
+ headers?: Record<string, string>,
82
+ ): Promise<DeletePipelineStageResult> {
83
+ return this.client.request<DeletePipelineStageResult, DeletePipelineStagePayload>(
84
+ 'DELETE',
85
+ `${this.basePath}/stage/${id}`,
86
+ body,
87
+ headers,
88
+ )
89
+ }
90
+
91
+ /**
92
+ * Lists the statuses of every stage of a pipeline (`[]` for an unknown pipeline).
93
+ * @permissions pipelines.view
94
+ */
95
+ getStatuses(pipelineId: string, headers?: Record<string, string>): Promise<PipelineStatusRef[]> {
96
+ return this.client.get<PipelineStatusRef[]>(`${this.basePath}/statuses/${pipelineId}`, headers)
97
+ }
98
+
99
+ /**
100
+ * Gets a stage status with the number of cards using it. An unknown id resolves to
101
+ * `{ cardsCount: 0 }` with 200, not to an error.
102
+ * @permissions pipelines.view
103
+ */
104
+ getStatus(
105
+ id: string,
106
+ headers?: Record<string, string>,
107
+ ): Promise<PipelineStageStatusWithCount | { cardsCount: 0 }> {
108
+ return this.client.get<PipelineStageStatusWithCount | { cardsCount: 0 }>(
109
+ `${this.basePath}/status/${id}`,
110
+ headers,
111
+ )
112
+ }
113
+
114
+ /**
115
+ * Deletes a stage status, keeping its cards without status or moving them to another one.
116
+ * Resolves to `'MESSAGE_STATUS_DELETED'`.
117
+ * @permissions pipelines.view
118
+ */
119
+ deleteStatus(
120
+ id: string,
121
+ body: DeletePipelineStatusPayload,
122
+ headers?: Record<string, string>,
123
+ ): Promise<'MESSAGE_STATUS_DELETED'> {
124
+ return this.client.post<'MESSAGE_STATUS_DELETED', DeletePipelineStatusPayload>(
125
+ `${this.basePath}/delete-status/${id}`,
126
+ body,
127
+ headers,
128
+ )
129
+ }
130
+
131
+ /**
132
+ * Renames a stage status — same route as {@link deleteStatus}, without an `action`.
133
+ * Resolves to `'MESSAGE_STATUS_RENAMED'`; an empty name fails with 500.
134
+ * @permissions pipelines.view
135
+ */
136
+ renameStatus(
137
+ id: string,
138
+ newStatusName: string,
139
+ headers?: Record<string, string>,
140
+ ): Promise<'MESSAGE_STATUS_RENAMED'> {
141
+ return this.client.post<'MESSAGE_STATUS_RENAMED', { newStatusName: string }>(
142
+ `${this.basePath}/delete-status/${id}`,
143
+ { newStatusName },
144
+ headers,
145
+ )
146
+ }
147
+
148
+ /**
149
+ * Creates an automation of a pipeline. Resolves to the automation as stored.
150
+ * @permissions pipelines.update
151
+ */
152
+ createAutomation(
153
+ body: CreatePipelineAutomationPayload,
154
+ headers?: Record<string, string>,
155
+ ): Promise<PipelineAutomation> {
156
+ return this.client.post<PipelineAutomation, CreatePipelineAutomationPayload>(
157
+ `${this.basePath}/automations`,
158
+ body,
159
+ headers,
160
+ )
161
+ }
162
+
163
+ /**
164
+ * Updates an automation. Resolves to the automation as stored.
165
+ * @permissions pipelines.update
166
+ */
167
+ updateAutomation(
168
+ id: string,
169
+ body: UpdatePipelineAutomationPayload,
170
+ headers?: Record<string, string>,
171
+ ): Promise<PipelineAutomation> {
172
+ return this.client.put<PipelineAutomation, UpdatePipelineAutomationPayload>(
173
+ `${this.basePath}/automations/${id}`,
174
+ body,
175
+ headers,
176
+ )
177
+ }
178
+
179
+ /**
180
+ * Deletes an automation. Resolves with no content; an unknown id fails with 500.
181
+ * @permissions pipelines.update
182
+ */
183
+ deleteAutomation(id: string, headers?: Record<string, string>): Promise<void> {
184
+ return this.client.delete<void>(`${this.basePath}/automations/${id}`, headers)
185
+ }
186
+
187
+ /**
188
+ * Gets the automation of a pipeline — a single object (the first one found), or `[]` when
189
+ * the pipeline has none.
190
+ * @permissions pipelines.view
191
+ */
192
+ getAutomation(
193
+ pipelineId: string,
194
+ headers?: Record<string, string>,
195
+ ): Promise<PipelineAutomation | []> {
196
+ return this.client.get<PipelineAutomation | []>(
197
+ `${this.basePath}/automations/${pipelineId}`,
198
+ headers,
199
+ )
200
+ }
201
+
202
+ /**
203
+ * Copies a pipeline as `"<name> (copy)"`, with its stages, statuses, reasons and automations
204
+ * (not its departments). Resolves to the new pipeline as stored, without the stages.
205
+ * @permissions pipelines.view
206
+ */
207
+ duplicate(pipelineId: string, headers?: Record<string, string>): Promise<PipelineRecord> {
208
+ return this.client.post<PipelineRecord>(
209
+ `${this.basePath}/duplicate/${pipelineId}`,
210
+ undefined,
211
+ headers,
212
+ )
213
+ }
214
+
215
+ /**
216
+ * Archives a pipeline. Resolves to the pipeline with its stages and their card totals.
217
+ * @permissions pipelines.update
218
+ */
219
+ archive(id: string, headers?: Record<string, string>): Promise<Pipeline> {
220
+ return this.client.post<Pipeline, { archive: boolean }>(
221
+ `${this.basePath}/${id}/archive`,
222
+ { archive: true },
223
+ headers,
224
+ )
225
+ }
226
+
227
+ /**
228
+ * Restores an archived pipeline. Resolves to the pipeline with its stages and their totals.
229
+ * @permissions pipelines.update
230
+ */
231
+ unarchive(id: string, headers?: Record<string, string>): Promise<Pipeline> {
232
+ return this.client.post<Pipeline, { archive: boolean }>(
233
+ `${this.basePath}/${id}/archive`,
234
+ { archive: false },
235
+ headers,
236
+ )
237
+ }
238
+
239
+ /**
240
+ * Exports the cards of a pipeline as CSV text (`;` as the delimiter): a summary block
241
+ * followed by one row per card.
242
+ * @permissions pipelines.view
243
+ */
244
+ exportCsv(
245
+ id: string,
246
+ body: ExportPipelinePayload = {},
247
+ headers?: Record<string, string>,
248
+ ): Promise<string> {
249
+ return this.client.post<string, ExportPipelinePayload>(
250
+ `${this.basePath}/${id}/export`,
251
+ body,
252
+ headers,
253
+ )
254
+ }
255
+
256
+ /**
257
+ * Lists the pipelines of the account with their stages and card totals. Not paginated.
258
+ * @permissions pipelines.view
259
+ */
260
+ getManyWithTotals(
261
+ query?: PipelinesWithTotalsQuery,
262
+ headers?: Record<string, string>,
263
+ ): Promise<PipelinesWithTotals> {
264
+ return this.client.get<PipelinesWithTotals>(
265
+ `${this.basePath}/withTotals${this.toQueryString(query)}`,
266
+ headers,
267
+ )
268
+ }
269
+
270
+ /**
271
+ * Gets the card totals of a stage, optionally filtered like the board. Resolves to `null`
272
+ * for an unknown stage.
273
+ * @permissions pipelines.update OR pipelines.opportunity.update
274
+ */
275
+ getStageTotals(
276
+ stageId: string,
277
+ filters: PipelineStageTotalsFilters = {},
278
+ headers?: Record<string, string>,
279
+ ): Promise<PipelineStageTotals | null> {
280
+ return this.client.post<PipelineStageTotals | null, PipelineStageTotalsFilters>(
281
+ `${this.basePath}/stage-totals/${stageId}`,
282
+ filters,
283
+ headers,
284
+ )
285
+ }
13
286
  }