featurebase-node 0.15.0 → 0.15.2
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.
- package/CHANGELOG.md +8 -0
- package/client.d.mts +8 -2
- package/client.d.mts.map +1 -1
- package/client.d.ts +8 -2
- package/client.d.ts.map +1 -1
- package/client.js +6 -0
- package/client.js.map +1 -1
- package/client.mjs +6 -0
- package/client.mjs.map +1 -1
- package/package.json +1 -1
- package/resources/audit-logs.d.mts +2 -2
- package/resources/audit-logs.d.mts.map +1 -1
- package/resources/audit-logs.d.ts +2 -2
- package/resources/audit-logs.d.ts.map +1 -1
- package/resources/changelogs/changelogs.d.mts +1166 -6
- package/resources/changelogs/changelogs.d.mts.map +1 -1
- package/resources/changelogs/changelogs.d.ts +1166 -6
- package/resources/changelogs/changelogs.d.ts.map +1 -1
- package/resources/changelogs/changelogs.js +53 -3
- package/resources/changelogs/changelogs.js.map +1 -1
- package/resources/changelogs/changelogs.mjs +53 -3
- package/resources/changelogs/changelogs.mjs.map +1 -1
- package/resources/changelogs/index.d.mts +1 -1
- package/resources/changelogs/index.d.mts.map +1 -1
- package/resources/changelogs/index.d.ts +1 -1
- package/resources/changelogs/index.d.ts.map +1 -1
- package/resources/changelogs/index.js.map +1 -1
- package/resources/changelogs/index.mjs.map +1 -1
- package/resources/conversation-attributes.d.mts +5 -0
- package/resources/conversation-attributes.d.mts.map +1 -1
- package/resources/conversation-attributes.d.ts +5 -0
- package/resources/conversation-attributes.d.ts.map +1 -1
- package/resources/feedback/comments.d.mts +4 -2
- package/resources/feedback/comments.d.mts.map +1 -1
- package/resources/feedback/comments.d.ts +4 -2
- package/resources/feedback/comments.d.ts.map +1 -1
- package/resources/feedback/custom-fields.d.mts +12 -0
- package/resources/feedback/custom-fields.d.mts.map +1 -1
- package/resources/feedback/custom-fields.d.ts +12 -0
- package/resources/feedback/custom-fields.d.ts.map +1 -1
- package/resources/feedback/posts/index.d.mts +1 -0
- package/resources/feedback/posts/index.d.mts.map +1 -1
- package/resources/feedback/posts/index.d.ts +1 -0
- package/resources/feedback/posts/index.d.ts.map +1 -1
- package/resources/feedback/posts/index.js +3 -1
- package/resources/feedback/posts/index.js.map +1 -1
- package/resources/feedback/posts/index.mjs +1 -0
- package/resources/feedback/posts/index.mjs.map +1 -1
- package/resources/feedback/posts/insights.d.mts +254 -0
- package/resources/feedback/posts/insights.d.mts.map +1 -0
- package/resources/feedback/posts/insights.d.ts +254 -0
- package/resources/feedback/posts/insights.d.ts.map +1 -0
- package/resources/feedback/posts/insights.js +269 -0
- package/resources/feedback/posts/insights.js.map +1 -0
- package/resources/feedback/posts/insights.mjs +265 -0
- package/resources/feedback/posts/insights.mjs.map +1 -0
- package/resources/feedback/posts/posts.d.mts +647 -20
- package/resources/feedback/posts/posts.d.mts.map +1 -1
- package/resources/feedback/posts/posts.d.ts +647 -20
- package/resources/feedback/posts/posts.d.ts.map +1 -1
- package/resources/feedback/posts/posts.js +199 -7
- package/resources/feedback/posts/posts.js.map +1 -1
- package/resources/feedback/posts/posts.mjs +199 -7
- package/resources/feedback/posts/posts.mjs.map +1 -1
- package/resources/index.d.mts +2 -1
- package/resources/index.d.mts.map +1 -1
- package/resources/index.d.ts +2 -1
- package/resources/index.d.ts.map +1 -1
- package/resources/index.js +3 -1
- package/resources/index.js.map +1 -1
- package/resources/index.mjs +1 -0
- package/resources/index.mjs.map +1 -1
- package/resources/reports.d.mts +101 -19
- package/resources/reports.d.mts.map +1 -1
- package/resources/reports.d.ts +101 -19
- package/resources/reports.d.ts.map +1 -1
- package/resources/reports.js +15 -8
- package/resources/reports.js.map +1 -1
- package/resources/reports.mjs +15 -8
- package/resources/reports.mjs.map +1 -1
- package/resources/support/conversations/conversations.d.mts +22 -1
- package/resources/support/conversations/conversations.d.mts.map +1 -1
- package/resources/support/conversations/conversations.d.ts +22 -1
- package/resources/support/conversations/conversations.d.ts.map +1 -1
- package/resources/support/conversations/conversations.js.map +1 -1
- package/resources/support/conversations/conversations.mjs.map +1 -1
- package/resources/support/tickets/tickets.d.mts +9 -5
- package/resources/support/tickets/tickets.d.mts.map +1 -1
- package/resources/support/tickets/tickets.d.ts +9 -5
- package/resources/support/tickets/tickets.d.ts.map +1 -1
- package/resources/support/tickets/tickets.js.map +1 -1
- package/resources/support/tickets/tickets.mjs.map +1 -1
- package/resources/training-data/files.d.mts +292 -0
- package/resources/training-data/files.d.mts.map +1 -0
- package/resources/training-data/files.d.ts +292 -0
- package/resources/training-data/files.d.ts.map +1 -0
- package/resources/training-data/files.js +171 -0
- package/resources/training-data/files.js.map +1 -0
- package/resources/training-data/files.mjs +167 -0
- package/resources/training-data/files.mjs.map +1 -0
- package/resources/training-data/index.d.mts +4 -0
- package/resources/training-data/index.d.mts.map +1 -0
- package/resources/training-data/index.d.ts +4 -0
- package/resources/training-data/index.d.ts.map +1 -0
- package/resources/training-data/index.js +11 -0
- package/resources/training-data/index.js.map +1 -0
- package/resources/training-data/index.mjs +5 -0
- package/resources/training-data/index.mjs.map +1 -0
- package/resources/training-data/qna.d.mts +370 -0
- package/resources/training-data/qna.d.mts.map +1 -0
- package/resources/training-data/qna.d.ts +370 -0
- package/resources/training-data/qna.d.ts.map +1 -0
- package/resources/training-data/qna.js +177 -0
- package/resources/training-data/qna.js.map +1 -0
- package/resources/training-data/qna.mjs +173 -0
- package/resources/training-data/qna.mjs.map +1 -0
- package/resources/training-data/training-data.d.mts +442 -0
- package/resources/training-data/training-data.d.mts.map +1 -0
- package/resources/training-data/training-data.d.ts +442 -0
- package/resources/training-data/training-data.d.ts.map +1 -0
- package/resources/training-data/training-data.js +105 -0
- package/resources/training-data/training-data.js.map +1 -0
- package/resources/training-data/training-data.mjs +100 -0
- package/resources/training-data/training-data.mjs.map +1 -0
- package/resources/training-data.d.mts +2 -0
- package/resources/training-data.d.mts.map +1 -0
- package/resources/training-data.d.ts +2 -0
- package/resources/training-data.d.ts.map +1 -0
- package/resources/training-data.js +6 -0
- package/resources/training-data.js.map +1 -0
- package/resources/training-data.mjs +3 -0
- package/resources/training-data.mjs.map +1 -0
- package/src/client.ts +22 -0
- package/src/resources/audit-logs.ts +12 -0
- package/src/resources/changelogs/changelogs.ts +2003 -51
- package/src/resources/changelogs/index.ts +1 -0
- package/src/resources/conversation-attributes.ts +6 -0
- package/src/resources/feedback/comments.ts +4 -2
- package/src/resources/feedback/custom-fields.ts +15 -0
- package/src/resources/feedback/posts/index.ts +7 -0
- package/src/resources/feedback/posts/insights.ts +340 -0
- package/src/resources/feedback/posts/posts.ts +764 -20
- package/src/resources/index.ts +8 -0
- package/src/resources/reports.ts +160 -19
- package/src/resources/support/conversations/conversations.ts +27 -1
- package/src/resources/support/tickets/tickets.ts +9 -5
- package/src/resources/training-data/files.ts +431 -0
- package/src/resources/training-data/index.ts +31 -0
- package/src/resources/training-data/qna.ts +514 -0
- package/src/resources/training-data/training-data.ts +603 -0
- package/src/resources/training-data.ts +3 -0
- package/src/version.ts +1 -1
- package/version.d.mts +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.mjs +1 -1
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
import { APIResource } from '../../../core/resource';
|
|
4
4
|
import * as PostsAPI from './posts';
|
|
5
5
|
import * as PostStatusesAPI from '../post-statuses';
|
|
6
|
+
import * as InsightsAPI from './insights';
|
|
7
|
+
import {
|
|
8
|
+
InsightConvertToPostParams,
|
|
9
|
+
InsightLinkParams,
|
|
10
|
+
InsightListParams,
|
|
11
|
+
InsightUnlinkParams,
|
|
12
|
+
Insights,
|
|
13
|
+
} from './insights';
|
|
6
14
|
import * as VotersAPI from './voters';
|
|
7
15
|
import {
|
|
8
16
|
VoterAddParams,
|
|
@@ -26,17 +34,29 @@ import { path } from '../../../internal/utils/path';
|
|
|
26
34
|
*/
|
|
27
35
|
export class Posts extends APIResource {
|
|
28
36
|
voters: VotersAPI.Voters = new VotersAPI.Voters(this._client);
|
|
37
|
+
insights: InsightsAPI.Insights = new InsightsAPI.Insights(this._client);
|
|
29
38
|
|
|
30
39
|
/**
|
|
31
40
|
* Creates a new post (feedback submission) in the specified board.
|
|
32
41
|
*
|
|
33
42
|
* ### Required Fields
|
|
34
43
|
*
|
|
35
|
-
* - `title` - Post title (minimum 2 characters)
|
|
36
|
-
*
|
|
44
|
+
* - `title` - Post title (minimum 2 characters). Required unless `intakeMode` is
|
|
45
|
+
* `feedback`; see "Intake mode" below.
|
|
37
46
|
*
|
|
38
47
|
* ### Optional Fields
|
|
39
48
|
*
|
|
49
|
+
* - `boardId` - Board ID to create the post in. Omit to use the organization's
|
|
50
|
+
* default board.
|
|
51
|
+
* - `intakeMode` - What the text is: `request` (default) or `feedback`. See
|
|
52
|
+
* "Intake mode" below.
|
|
53
|
+
* - `source` - Where the request came from:
|
|
54
|
+
* `{ channel, externalId, url?, conversationId?, label? }`. See "Provenance and
|
|
55
|
+
* idempotency" below.
|
|
56
|
+
* - `attachTo` - Id of an existing open request this post belongs with. The new
|
|
57
|
+
* post stays a post. See "attachTo, or link-insight?" below.
|
|
58
|
+
* - `internal` - Store this request on the hidden internal board (never
|
|
59
|
+
* portal-visible). Cannot be combined with `boardId`.
|
|
40
60
|
* - `content` - Post content in HTML format
|
|
41
61
|
* - `tags` - Array of tag names to attach
|
|
42
62
|
* - `statusId` - Status ID to set (defaults to board's default status)
|
|
@@ -62,20 +82,155 @@ export class Posts extends APIResource {
|
|
|
62
82
|
*
|
|
63
83
|
* Resolution priority: `id` > `userId` > `email` > authenticated user
|
|
64
84
|
*
|
|
85
|
+
* ### Intake mode
|
|
86
|
+
*
|
|
87
|
+
* `intakeMode` is the caller's declared intent, and the ONE field that selects how
|
|
88
|
+
* the post is processed. `author` and `source` only describe where the text came
|
|
89
|
+
* from; they never select the path.
|
|
90
|
+
*
|
|
91
|
+
* - `request` (default, and the behaviour of every call that does not send the
|
|
92
|
+
* field): a finished request. Stored exactly as supplied — no AI claim
|
|
93
|
+
* extraction, no rewrite — whoever the author is. Featurebase may still link
|
|
94
|
+
* existing customer evidence TO the new request in the background; that never
|
|
95
|
+
* modifies it.
|
|
96
|
+
* - `feedback`: raw customer feedback (a Slack message, a call note, a survey
|
|
97
|
+
* answer). Processed exactly like a post written on the portal: organized into a
|
|
98
|
+
* request when the workspace's "Organize submissions" lane is on, otherwise its
|
|
99
|
+
* claims are extracted and matched against existing requests. The workspace's
|
|
100
|
+
* Autopilot dial, plan, AI budget, moderation and spam settings all apply, and
|
|
101
|
+
* the post is processed even when it is filed under the API key's own user.
|
|
102
|
+
* `statusId` and `eta` are rejected in this mode (400): raw feedback carries no
|
|
103
|
+
* decision yet. Feedback creates are rate-limited per workspace more strictly
|
|
104
|
+
* than requests (429 with `Retry-After`).
|
|
105
|
+
*
|
|
106
|
+
* At most 5 requests organized from one submission notify the team (admin
|
|
107
|
+
* notifications, mentions, Slack, Discord and tracker pushes); the rest are
|
|
108
|
+
* created silently — still revealed, published and returned in
|
|
109
|
+
* `processing.results` — and still fire the `post.created` webhook.
|
|
110
|
+
*
|
|
111
|
+
* In `feedback` mode `title` is optional: raw text rarely has one. Omit it (or
|
|
112
|
+
* send it blank) and the first line of `content` becomes the title, cut to 120
|
|
113
|
+
* characters. `content` is then required — an empty title and an empty content
|
|
114
|
+
* together are rejected with a 400 on `content`. In `request` mode `title` stays
|
|
115
|
+
* required, minimum 2 characters.
|
|
116
|
+
*
|
|
117
|
+
* #### How much text a feedback create may carry
|
|
118
|
+
*
|
|
119
|
+
* Feedback text is read whole or not at all: up to the limit of its
|
|
120
|
+
* `source.channel` it is read in full, from the first line to the last; anything
|
|
121
|
+
* longer is rejected (400 on `content`) instead of being trimmed, and the error
|
|
122
|
+
* message states the limit and the length that was sent.
|
|
123
|
+
*
|
|
124
|
+
* | `source.channel` | Limit (characters) | Sized for |
|
|
125
|
+
* | ------------------ | ------------------ | -------------------------- |
|
|
126
|
+
* | `call` | 120,000 | a two-hour call transcript |
|
|
127
|
+
* | `email` | 60,000 | a long email thread |
|
|
128
|
+
* | `api` | 60,000 | a document or an export |
|
|
129
|
+
* | `slack`, `discord` | 30,000 | a thread or channel export |
|
|
130
|
+
*
|
|
131
|
+
* Text sent without a `source.channel` gets the `api` limit. The limits are the
|
|
132
|
+
* same for every workspace.
|
|
133
|
+
*
|
|
134
|
+
* The count is of plain text: the title and the content with its HTML markup
|
|
135
|
+
* removed. Workspaces that do not process feedback at all (the AI is switched off)
|
|
136
|
+
* have no limit — the text is stored exactly as sent. To send more, split it and
|
|
137
|
+
* give each part its own `source.externalId`.
|
|
138
|
+
*
|
|
139
|
+
* Long text takes longer. A short message is processed in seconds; a long one is
|
|
140
|
+
* read in parts, one after the other, and every ask it produces is then matched
|
|
141
|
+
* and filed in turn — allow tens of minutes for a two-hour transcript. An ask that
|
|
142
|
+
* comes up more than once in the same text is reported once. One submission yields
|
|
143
|
+
* at most 30 requests: when the text holds more separate asks than that, the 29
|
|
144
|
+
* strongest become requests as usual and the rest are listed — one line each, the
|
|
145
|
+
* ask and the customer's own words — in a single request held for a teammate.
|
|
146
|
+
* Where the workspace does not organize submissions, at most 50 asks are captured
|
|
147
|
+
* from one submission; the rest of a longer text is not read.
|
|
148
|
+
*
|
|
149
|
+
* Long feedback is rate-limited on its own: at most 20 submissions per workspace
|
|
150
|
+
* per hour may be longer than a single reading pass (about 16,000 characters where
|
|
151
|
+
* the workspace organizes submissions, otherwise 6,000 — 24,000 for a `call`).
|
|
152
|
+
* Past that the create answers 429 with `Retry-After`; shorter feedback is not
|
|
153
|
+
* affected.
|
|
154
|
+
*
|
|
155
|
+
* The response reports what happened in `intakeMode` and `processing`:
|
|
156
|
+
* `processing.status` is `queued` when an AI run was enqueued (its result lands on
|
|
157
|
+
* the post asynchronously), `skipped` with a `reason` when nothing was enqueued
|
|
158
|
+
* (`request_mode`, `autopilot_off`, `pipeline_paused`, `support_board`,
|
|
159
|
+
* `spam_held`, `staff_authored`, …), or `existing` on an idempotent replay. To
|
|
160
|
+
* read where the feedback ended up afterwards, fetch the post with
|
|
161
|
+
* `GET /v2/posts/{id}`.
|
|
162
|
+
*
|
|
163
|
+
* ### Provenance and idempotency
|
|
164
|
+
*
|
|
165
|
+
* `source` records where a request came from and makes the create idempotent:
|
|
166
|
+
*
|
|
167
|
+
* - `source.externalId` is the stable id of the message or record in your system.
|
|
168
|
+
* Sending the same `(channel, externalId)` twice returns the post created the
|
|
169
|
+
* first time, unchanged, with `deduped: true` — the first delivery always wins.
|
|
170
|
+
* - Ids are stored namespaced as `api:<externalId>`, so they can never collide
|
|
171
|
+
* with ids Featurebase writes itself.
|
|
172
|
+
* - `feedback`, `widget` and `support` are reserved for posts authored on the
|
|
173
|
+
* portal, the widget and the inbox, and are rejected with a 400.
|
|
174
|
+
* - With `source` and no `author`, the post is attributed to a guest named after
|
|
175
|
+
* `source.label` (or the channel), because a relayed request belongs to the
|
|
176
|
+
* customer who said it — not to the API key that carried it.
|
|
177
|
+
*
|
|
178
|
+
* ### attachTo, or link-insight?
|
|
179
|
+
*
|
|
180
|
+
* Both attach something to a request that already exists, and they do different
|
|
181
|
+
* things.
|
|
182
|
+
*
|
|
183
|
+
* `attachTo` records that the NEW post belongs with an existing request. **The
|
|
184
|
+
* post stays a post**: it keeps `kind: 'issue'`, it is still returned by
|
|
185
|
+
* `GET /v2/posts` and `GET /v2/posts/{id}`, it keeps its own votes, and its author
|
|
186
|
+
* does **not** become a supporter of the target — nothing about the target changes
|
|
187
|
+
* except that it now counts this post among the posts linked to it. The link is
|
|
188
|
+
* silent: no notification, no ack to the author. The post does **not** appear in
|
|
189
|
+
* `GET /v2/posts/{targetId}/insights` — that endpoint lists insights, and this is
|
|
190
|
+
* a post.
|
|
191
|
+
*
|
|
192
|
+
* `POST /v2/posts/{id}/link-insight` does the opposite: it files the post as a
|
|
193
|
+
* **quote** under the request. The post becomes an insight, leaves the posts
|
|
194
|
+
* resource (`GET /v2/posts/{id}` answers 404 afterwards), appears in
|
|
195
|
+
* `GET /v2/posts/{targetId}/insights`, and its author is rolled up as a supporter
|
|
196
|
+
* of the request.
|
|
197
|
+
*
|
|
198
|
+
* So: two customers asking for the same thing, and you want both to keep their own
|
|
199
|
+
* request row → `attachTo`. A sentence a customer said that is evidence for a
|
|
200
|
+
* request you already track → create the post, then call `link-insight` on it.
|
|
201
|
+
* Both take the same kind of target: an open request in this workspace.
|
|
202
|
+
*
|
|
203
|
+
* `attachTo` cannot be combined with `intakeMode: 'feedback'` (400
|
|
204
|
+
* `invalid_parameter` on `attachTo`): `attachTo` says where the text belongs, and
|
|
205
|
+
* `feedback` mode asks Featurebase to decide that for every ask the text contains.
|
|
206
|
+
* Pick one.
|
|
207
|
+
*
|
|
208
|
+
* The link is made AFTER the post is written, so an unusable target is a **422
|
|
209
|
+
* that says the post was created** — it is not rolled back. The target is refused
|
|
210
|
+
* when it does not exist in this workspace, is not a request (an insight or a
|
|
211
|
+
* record), was merged into another request, is a processed submission, is still
|
|
212
|
+
* awaiting moderation, is held as spam, or is the new post itself.
|
|
213
|
+
*
|
|
65
214
|
* ### Backdating (Imports)
|
|
66
215
|
*
|
|
67
216
|
* - `createdAt` - Override creation date for importing historical data
|
|
68
217
|
*
|
|
69
218
|
* ### Response
|
|
70
219
|
*
|
|
71
|
-
*
|
|
220
|
+
* - **201** - the post was created. Returns the post object with all fields
|
|
221
|
+
* populated, plus `intakeMode` and `processing`.
|
|
222
|
+
* - **200** - a post already existed for this
|
|
223
|
+
* `(source.channel, source.externalId)`. Returns that post unchanged, with
|
|
224
|
+
* `deduped: true` and `processing.status: 'existing'`. A replay is answered from
|
|
225
|
+
* the existing post and never links anything a second time, whatever `attachTo`
|
|
226
|
+
* says.
|
|
227
|
+
* - **422** - `attachTo` named a request that cannot carry evidence (missing,
|
|
228
|
+
* merged, atomized, held for moderation or spam, not a request, or the post
|
|
229
|
+
* itself). **The post was still created**; the error message says so.
|
|
72
230
|
*
|
|
73
231
|
* @example
|
|
74
232
|
* ```ts
|
|
75
|
-
* const post = await client.feedback.posts.create(
|
|
76
|
-
* boardId: '507f1f77bcf86cd799439011',
|
|
77
|
-
* title: 'Add dark mode support',
|
|
78
|
-
* });
|
|
233
|
+
* const post = await client.feedback.posts.create();
|
|
79
234
|
* ```
|
|
80
235
|
*/
|
|
81
236
|
create(params: PostCreateParams, options?: RequestOptions): APIPromise<Post> {
|
|
@@ -106,6 +261,46 @@ export class Posts extends APIResource {
|
|
|
106
261
|
* - Engagement metrics
|
|
107
262
|
* - Custom field values
|
|
108
263
|
*
|
|
264
|
+
* ### Feedback processing
|
|
265
|
+
*
|
|
266
|
+
* For a post created with `intakeMode: 'feedback'`, the response also carries
|
|
267
|
+
* `processing`, which says how far Featurebase has got with the text and what it
|
|
268
|
+
* made of it. It is absent on every other post, and on the list endpoint.
|
|
269
|
+
*
|
|
270
|
+
* `processing.status`:
|
|
271
|
+
*
|
|
272
|
+
* - `queued` - the text was accepted and no result has landed yet
|
|
273
|
+
* - `processing` - Featurebase is organizing the submission right now
|
|
274
|
+
* - `complete` - it is done; `results` lists what came out of it
|
|
275
|
+
* - `needs_review` - it is done, and a teammate still has to decide something
|
|
276
|
+
* - `skipped` - nothing ran, and nothing will; `reason` says why (the same reason
|
|
277
|
+
* the create returned, for example `autopilot_off`). The post is stored exactly
|
|
278
|
+
* as it was sent.
|
|
279
|
+
*
|
|
280
|
+
* `processing.results` is present in workspaces that organize submissions, once
|
|
281
|
+
* the run has finished: one entry per ask found in the text, in the order they
|
|
282
|
+
* appear. Each entry has the ask's `title` and its `outcome`:
|
|
283
|
+
*
|
|
284
|
+
* - `request` - the ask became a request of its own
|
|
285
|
+
* - `attached` - it was added as evidence to a request that already existed
|
|
286
|
+
* - `held` - it became a request waiting for a teammate to publish it
|
|
287
|
+
* - `question` - it asked something; no request was created and a teammate answers
|
|
288
|
+
* it
|
|
289
|
+
*
|
|
290
|
+
* `postId` and `postTitle` name the request the ask became or was attached to.
|
|
291
|
+
* They are absent for a `question`, and absent when that request is not readable
|
|
292
|
+
* through this API.
|
|
293
|
+
*
|
|
294
|
+
* `held` results carry a `reason` code saying what the teammate still has to
|
|
295
|
+
* decide: `too_many_topics` (the submission held more separate asks than one
|
|
296
|
+
* submission can become requests, so this request lists the ones that did not
|
|
297
|
+
* fit), `uncertain`, `custom_fields` or `processing_failed` (the AI could not
|
|
298
|
+
* rewrite the text, or could not check the ask against existing requests, so a
|
|
299
|
+
* teammate confirms it). No other outcome carries it.
|
|
300
|
+
*
|
|
301
|
+
* Workspaces that do not organize submissions report `status` only: there the post
|
|
302
|
+
* you sent IS the request, so there is no separate result to list.
|
|
303
|
+
*
|
|
109
304
|
* @example
|
|
110
305
|
* ```ts
|
|
111
306
|
* const post = await client.feedback.posts.retrieve(
|
|
@@ -228,6 +423,8 @@ export class Posts extends APIResource {
|
|
|
228
423
|
* - `tags` - Filter by tag names (can be comma-separated or repeated)
|
|
229
424
|
* - `q` - Search query for title/content
|
|
230
425
|
* - `inReview` - Include posts pending moderation
|
|
426
|
+
* - `kind` - `issue` (default: work items) or `record`; insights are never served
|
|
427
|
+
* by this resource — use `/v2/insights`
|
|
231
428
|
*
|
|
232
429
|
* ### Sorting
|
|
233
430
|
*
|
|
@@ -579,6 +776,13 @@ export interface Post {
|
|
|
579
776
|
|
|
580
777
|
access: PostAccess;
|
|
581
778
|
|
|
779
|
+
/**
|
|
780
|
+
* When kind is 'insight', where exactly the insight points back into its origin:
|
|
781
|
+
* an insight source record with character ranges into its fullText, or the native
|
|
782
|
+
* conversation/message/comment/post ids.
|
|
783
|
+
*/
|
|
784
|
+
anchor: Post.Anchor | null;
|
|
785
|
+
|
|
582
786
|
/**
|
|
583
787
|
* ID of the admin assigned to this post, null if unassigned
|
|
584
788
|
*/
|
|
@@ -618,11 +822,23 @@ export interface Post {
|
|
|
618
822
|
|
|
619
823
|
features: PostFeatures;
|
|
620
824
|
|
|
825
|
+
/**
|
|
826
|
+
* When kind is 'insight', the triage grouping key (source record id, conversation
|
|
827
|
+
* id, origin post id, or the insight's own id for singletons). Legacy insights may
|
|
828
|
+
* be null and group as singletons.
|
|
829
|
+
*/
|
|
830
|
+
groupKey: string | null;
|
|
831
|
+
|
|
621
832
|
/**
|
|
622
833
|
* Whether the post is pending moderation review
|
|
623
834
|
*/
|
|
624
835
|
inReview: boolean;
|
|
625
836
|
|
|
837
|
+
/**
|
|
838
|
+
* Provenance of an insight: which channel it came from and how it was captured.
|
|
839
|
+
*/
|
|
840
|
+
insightSource: Post.InsightSource | null;
|
|
841
|
+
|
|
626
842
|
/**
|
|
627
843
|
* Third-party integration links associated with this post
|
|
628
844
|
*/
|
|
@@ -633,6 +849,27 @@ export interface Post {
|
|
|
633
849
|
*/
|
|
634
850
|
isPinned: boolean;
|
|
635
851
|
|
|
852
|
+
/**
|
|
853
|
+
* Discriminates an actionable work item ('issue') from a customer submission whose
|
|
854
|
+
* claims were extracted into insights ('record' — not a work item). Defaults to
|
|
855
|
+
* 'issue' for all pre-existing posts. Default list responses return issues only;
|
|
856
|
+
* pass kind='record' to opt in. Raw signal ('insight') is never returned by the
|
|
857
|
+
* posts resource — insights are served by /v2/insights.
|
|
858
|
+
*/
|
|
859
|
+
kind: 'issue' | 'insight' | 'record';
|
|
860
|
+
|
|
861
|
+
/**
|
|
862
|
+
* Number of insights linked to this issue as supporting evidence. Only meaningful
|
|
863
|
+
* when kind is 'issue'.
|
|
864
|
+
*/
|
|
865
|
+
linkedInsightCount: number;
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* When kind is 'insight', the ID of the issue this insight supports. Null when the
|
|
869
|
+
* insight is unlinked or when kind is 'issue'.
|
|
870
|
+
*/
|
|
871
|
+
linkedIssueId: string | null;
|
|
872
|
+
|
|
636
873
|
/**
|
|
637
874
|
* Object type identifier
|
|
638
875
|
*/
|
|
@@ -643,6 +880,12 @@ export interface Post {
|
|
|
643
880
|
*/
|
|
644
881
|
opportunityAmount: number | null;
|
|
645
882
|
|
|
883
|
+
/**
|
|
884
|
+
* True when the issue is hidden from portal/public surfaces. Missing stored values
|
|
885
|
+
* are returned as false.
|
|
886
|
+
*/
|
|
887
|
+
portalHidden: boolean;
|
|
888
|
+
|
|
646
889
|
/**
|
|
647
890
|
* Full URL to view the post
|
|
648
891
|
*/
|
|
@@ -674,9 +917,82 @@ export interface Post {
|
|
|
674
917
|
* Total number of upvotes
|
|
675
918
|
*/
|
|
676
919
|
upvotes: number;
|
|
920
|
+
|
|
921
|
+
/**
|
|
922
|
+
* Present and true only on POST /v2/posts, when the request carried a
|
|
923
|
+
* `source.externalId` that already had a post. The existing post is returned
|
|
924
|
+
* unchanged with HTTP 200; a newly created post returns HTTP 201 without this
|
|
925
|
+
* field.
|
|
926
|
+
*/
|
|
927
|
+
deduped?: true;
|
|
928
|
+
|
|
929
|
+
/**
|
|
930
|
+
* Present only on POST /v2/posts: the `intakeMode` the post was processed under
|
|
931
|
+
* ('request' when the request named none). On an idempotent replay
|
|
932
|
+
* (`deduped: true`) this is the mode the post was ORIGINALLY created with.
|
|
933
|
+
*/
|
|
934
|
+
intakeMode?: 'request' | 'feedback';
|
|
935
|
+
|
|
936
|
+
/**
|
|
937
|
+
* On POST /v2/posts — `queued`: a processing run (claim extraction or the Organize
|
|
938
|
+
* rewrite) was enqueued and its result lands asynchronously on the post.
|
|
939
|
+
* `skipped`: nothing was enqueued; `reason` says which gate decided
|
|
940
|
+
* ('request_mode' for every intakeMode: 'request' create). `existing`: the create
|
|
941
|
+
* was an idempotent replay and the post was not processed again. On GET
|
|
942
|
+
* /v2/posts/{id} this field is present only for posts created with
|
|
943
|
+
* `intakeMode: 'feedback'` and reports how far that processing has got ('queued',
|
|
944
|
+
* 'processing', 'complete', 'needs_review', or 'skipped' with the same `reason`
|
|
945
|
+
* the create returned), with `results` listing what was made of the submission
|
|
946
|
+
* once the run has finished.
|
|
947
|
+
*/
|
|
948
|
+
processing?: Post.Processing;
|
|
677
949
|
}
|
|
678
950
|
|
|
679
951
|
export namespace Post {
|
|
952
|
+
/**
|
|
953
|
+
* When kind is 'insight', where exactly the insight points back into its origin:
|
|
954
|
+
* an insight source record with character ranges into its fullText, or the native
|
|
955
|
+
* conversation/message/comment/post ids.
|
|
956
|
+
*/
|
|
957
|
+
export interface Anchor {
|
|
958
|
+
commentId?: string | null;
|
|
959
|
+
|
|
960
|
+
conversationId?: string | null;
|
|
961
|
+
|
|
962
|
+
messageId?: string | null;
|
|
963
|
+
|
|
964
|
+
ranges?: Array<Anchor.Range> | null;
|
|
965
|
+
|
|
966
|
+
sourceRecordId?: string | null;
|
|
967
|
+
|
|
968
|
+
submissionId?: string | null;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
export namespace Anchor {
|
|
972
|
+
export interface Range {
|
|
973
|
+
end: number;
|
|
974
|
+
|
|
975
|
+
start: number;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
/**
|
|
980
|
+
* Provenance of an insight: which channel it came from and how it was captured.
|
|
981
|
+
*/
|
|
982
|
+
export interface InsightSource {
|
|
983
|
+
channel: 'slack' | 'discord' | 'email' | 'support' | 'widget' | 'call' | 'api' | 'feedback';
|
|
984
|
+
|
|
985
|
+
capturedBy?: 'manual' | 'auto' | 'ai' | 'api' | null;
|
|
986
|
+
|
|
987
|
+
conversationId?: string | null;
|
|
988
|
+
|
|
989
|
+
externalId?: string | null;
|
|
990
|
+
|
|
991
|
+
sourceLabel?: string | null;
|
|
992
|
+
|
|
993
|
+
url?: string | null;
|
|
994
|
+
}
|
|
995
|
+
|
|
680
996
|
/**
|
|
681
997
|
* Third-party integration links associated with this post
|
|
682
998
|
*/
|
|
@@ -841,6 +1157,107 @@ export namespace Post {
|
|
|
841
1157
|
objectType: 'Opportunity' | 'Case';
|
|
842
1158
|
}
|
|
843
1159
|
}
|
|
1160
|
+
|
|
1161
|
+
/**
|
|
1162
|
+
* On POST /v2/posts — `queued`: a processing run (claim extraction or the Organize
|
|
1163
|
+
* rewrite) was enqueued and its result lands asynchronously on the post.
|
|
1164
|
+
* `skipped`: nothing was enqueued; `reason` says which gate decided
|
|
1165
|
+
* ('request_mode' for every intakeMode: 'request' create). `existing`: the create
|
|
1166
|
+
* was an idempotent replay and the post was not processed again. On GET
|
|
1167
|
+
* /v2/posts/{id} this field is present only for posts created with
|
|
1168
|
+
* `intakeMode: 'feedback'` and reports how far that processing has got ('queued',
|
|
1169
|
+
* 'processing', 'complete', 'needs_review', or 'skipped' with the same `reason`
|
|
1170
|
+
* the create returned), with `results` listing what was made of the submission
|
|
1171
|
+
* once the run has finished.
|
|
1172
|
+
*/
|
|
1173
|
+
export interface Processing {
|
|
1174
|
+
/**
|
|
1175
|
+
* 'queued' = an AI run was enqueued and has not landed yet; 'processing' = the run
|
|
1176
|
+
* is working on the submission; 'complete' = it finished and `results` lists what
|
|
1177
|
+
* it produced; 'needs_review' = it finished and a teammate still has to decide
|
|
1178
|
+
* something; 'skipped' = nothing was enqueued (see `reason`); 'existing' =
|
|
1179
|
+
* idempotent replay, not processed again.
|
|
1180
|
+
*/
|
|
1181
|
+
status: 'queued' | 'processing' | 'complete' | 'needs_review' | 'skipped' | 'existing';
|
|
1182
|
+
|
|
1183
|
+
/**
|
|
1184
|
+
* Why processing was skipped. 'request_mode' = intakeMode was 'request' (the
|
|
1185
|
+
* default); 'autopilot_off' = the workspace's Autopilot dial is off or its plan
|
|
1186
|
+
* does not include it; 'pipeline_paused' = the platform paused AI processing (it
|
|
1187
|
+
* resumes automatically); 'support_board' / 'spam_held' / 'staff_authored' /
|
|
1188
|
+
* 'no_content' = the post did not qualify; 'source_too_long' = the text was over
|
|
1189
|
+
* the length limit when the run read it (a create that long is normally refused
|
|
1190
|
+
* with a 400 first); 'extraction_failed' = the AI could not read the text after
|
|
1191
|
+
* repeated attempts; nothing was written, and opening the post in Triage runs the
|
|
1192
|
+
* analysis again.
|
|
1193
|
+
*/
|
|
1194
|
+
reason?:
|
|
1195
|
+
| 'request_mode'
|
|
1196
|
+
| 'autopilot_off'
|
|
1197
|
+
| 'insights_disabled'
|
|
1198
|
+
| 'pipeline_paused'
|
|
1199
|
+
| 'support_board'
|
|
1200
|
+
| 'spam_held'
|
|
1201
|
+
| 'staff_authored'
|
|
1202
|
+
| 'not_a_post'
|
|
1203
|
+
| 'no_board'
|
|
1204
|
+
| 'no_id'
|
|
1205
|
+
| 'no_content'
|
|
1206
|
+
| 'source_too_long'
|
|
1207
|
+
| 'extraction_failed'
|
|
1208
|
+
| 'hook_error';
|
|
1209
|
+
|
|
1210
|
+
/**
|
|
1211
|
+
* What the workspace's "Organize submissions" lane made of this submission, one
|
|
1212
|
+
* entry per ask it found, in the order they appear in the text. Present on GET
|
|
1213
|
+
* /v2/posts/{id} for posts created with `intakeMode: 'feedback'` once the run has
|
|
1214
|
+
* finished. Absent while the run is still working, and absent for workspaces that
|
|
1215
|
+
* do not organize submissions — there the post itself is the request.
|
|
1216
|
+
*/
|
|
1217
|
+
results?: Array<Processing.Result>;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
export namespace Processing {
|
|
1221
|
+
export interface Result {
|
|
1222
|
+
/**
|
|
1223
|
+
* 'request' = the ask became a request of its own; 'attached' = it was added as
|
|
1224
|
+
* evidence to a request that already existed; 'held' = it became a request that is
|
|
1225
|
+
* waiting for a teammate to publish it; 'question' = it asked something and no
|
|
1226
|
+
* request was created, so a teammate answers it.
|
|
1227
|
+
*/
|
|
1228
|
+
outcome: 'attached' | 'request' | 'question' | 'held';
|
|
1229
|
+
|
|
1230
|
+
/**
|
|
1231
|
+
* The ask, as it was written up.
|
|
1232
|
+
*/
|
|
1233
|
+
title: string;
|
|
1234
|
+
|
|
1235
|
+
/**
|
|
1236
|
+
* The request this ask became, or was attached to. Absent for a question, and
|
|
1237
|
+
* absent when the request is not readable through this API (for example a ticket
|
|
1238
|
+
* board).
|
|
1239
|
+
*/
|
|
1240
|
+
postId?: string;
|
|
1241
|
+
|
|
1242
|
+
/**
|
|
1243
|
+
* Title of `postId`.
|
|
1244
|
+
*/
|
|
1245
|
+
postTitle?: string;
|
|
1246
|
+
|
|
1247
|
+
/**
|
|
1248
|
+
* Why a 'held' result is waiting for a teammate. Only on a 'held' result, and only
|
|
1249
|
+
* one of these codes: 'too_many_topics' = the submission held more separate asks
|
|
1250
|
+
* than one submission can become requests, so this one request lists the asks that
|
|
1251
|
+
* did not fit, one line each in the customer's words; 'uncertain' = the ask was
|
|
1252
|
+
* too vague to file without a person; 'custom_fields' = the board requires custom
|
|
1253
|
+
* fields this submission did not carry; 'processing_failed' = the AI could not
|
|
1254
|
+
* rewrite the text (the request then holds the original words) or could not check
|
|
1255
|
+
* this ask against existing requests, so a teammate confirms it is not a
|
|
1256
|
+
* duplicate.
|
|
1257
|
+
*/
|
|
1258
|
+
reason?: 'too_many_topics' | 'uncertain' | 'custom_fields' | 'processing_failed';
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
844
1261
|
}
|
|
845
1262
|
|
|
846
1263
|
export interface PostAccess {
|
|
@@ -995,6 +1412,13 @@ export namespace PostSearchResponse {
|
|
|
995
1412
|
|
|
996
1413
|
access: PostsAPI.PostAccess;
|
|
997
1414
|
|
|
1415
|
+
/**
|
|
1416
|
+
* When kind is 'insight', where exactly the insight points back into its origin:
|
|
1417
|
+
* an insight source record with character ranges into its fullText, or the native
|
|
1418
|
+
* conversation/message/comment/post ids.
|
|
1419
|
+
*/
|
|
1420
|
+
anchor: Data.Anchor | null;
|
|
1421
|
+
|
|
998
1422
|
/**
|
|
999
1423
|
* ID of the admin assigned to this post, null if unassigned
|
|
1000
1424
|
*/
|
|
@@ -1034,11 +1458,23 @@ export namespace PostSearchResponse {
|
|
|
1034
1458
|
|
|
1035
1459
|
features: PostsAPI.PostFeatures;
|
|
1036
1460
|
|
|
1461
|
+
/**
|
|
1462
|
+
* When kind is 'insight', the triage grouping key (source record id, conversation
|
|
1463
|
+
* id, origin post id, or the insight's own id for singletons). Legacy insights may
|
|
1464
|
+
* be null and group as singletons.
|
|
1465
|
+
*/
|
|
1466
|
+
groupKey: string | null;
|
|
1467
|
+
|
|
1037
1468
|
/**
|
|
1038
1469
|
* Whether the post is pending moderation review
|
|
1039
1470
|
*/
|
|
1040
1471
|
inReview: boolean;
|
|
1041
1472
|
|
|
1473
|
+
/**
|
|
1474
|
+
* Provenance of an insight: which channel it came from and how it was captured.
|
|
1475
|
+
*/
|
|
1476
|
+
insightSource: Data.InsightSource | null;
|
|
1477
|
+
|
|
1042
1478
|
/**
|
|
1043
1479
|
* Third-party integration links associated with this post
|
|
1044
1480
|
*/
|
|
@@ -1049,6 +1485,27 @@ export namespace PostSearchResponse {
|
|
|
1049
1485
|
*/
|
|
1050
1486
|
isPinned: boolean;
|
|
1051
1487
|
|
|
1488
|
+
/**
|
|
1489
|
+
* Discriminates an actionable work item ('issue') from a customer submission whose
|
|
1490
|
+
* claims were extracted into insights ('record' — not a work item). Defaults to
|
|
1491
|
+
* 'issue' for all pre-existing posts. Default list responses return issues only;
|
|
1492
|
+
* pass kind='record' to opt in. Raw signal ('insight') is never returned by the
|
|
1493
|
+
* posts resource — insights are served by /v2/insights.
|
|
1494
|
+
*/
|
|
1495
|
+
kind: 'issue' | 'insight' | 'record';
|
|
1496
|
+
|
|
1497
|
+
/**
|
|
1498
|
+
* Number of insights linked to this issue as supporting evidence. Only meaningful
|
|
1499
|
+
* when kind is 'issue'.
|
|
1500
|
+
*/
|
|
1501
|
+
linkedInsightCount: number;
|
|
1502
|
+
|
|
1503
|
+
/**
|
|
1504
|
+
* When kind is 'insight', the ID of the issue this insight supports. Null when the
|
|
1505
|
+
* insight is unlinked or when kind is 'issue'.
|
|
1506
|
+
*/
|
|
1507
|
+
linkedIssueId: string | null;
|
|
1508
|
+
|
|
1052
1509
|
/**
|
|
1053
1510
|
* Object type identifier
|
|
1054
1511
|
*/
|
|
@@ -1059,6 +1516,12 @@ export namespace PostSearchResponse {
|
|
|
1059
1516
|
*/
|
|
1060
1517
|
opportunityAmount: number | null;
|
|
1061
1518
|
|
|
1519
|
+
/**
|
|
1520
|
+
* True when the issue is hidden from portal/public surfaces. Missing stored values
|
|
1521
|
+
* are returned as false.
|
|
1522
|
+
*/
|
|
1523
|
+
portalHidden: boolean;
|
|
1524
|
+
|
|
1062
1525
|
/**
|
|
1063
1526
|
* Full URL to view the post
|
|
1064
1527
|
*/
|
|
@@ -1090,9 +1553,82 @@ export namespace PostSearchResponse {
|
|
|
1090
1553
|
* Total number of upvotes
|
|
1091
1554
|
*/
|
|
1092
1555
|
upvotes: number;
|
|
1556
|
+
|
|
1557
|
+
/**
|
|
1558
|
+
* Present and true only on POST /v2/posts, when the request carried a
|
|
1559
|
+
* `source.externalId` that already had a post. The existing post is returned
|
|
1560
|
+
* unchanged with HTTP 200; a newly created post returns HTTP 201 without this
|
|
1561
|
+
* field.
|
|
1562
|
+
*/
|
|
1563
|
+
deduped?: true;
|
|
1564
|
+
|
|
1565
|
+
/**
|
|
1566
|
+
* Present only on POST /v2/posts: the `intakeMode` the post was processed under
|
|
1567
|
+
* ('request' when the request named none). On an idempotent replay
|
|
1568
|
+
* (`deduped: true`) this is the mode the post was ORIGINALLY created with.
|
|
1569
|
+
*/
|
|
1570
|
+
intakeMode?: 'request' | 'feedback';
|
|
1571
|
+
|
|
1572
|
+
/**
|
|
1573
|
+
* On POST /v2/posts — `queued`: a processing run (claim extraction or the Organize
|
|
1574
|
+
* rewrite) was enqueued and its result lands asynchronously on the post.
|
|
1575
|
+
* `skipped`: nothing was enqueued; `reason` says which gate decided
|
|
1576
|
+
* ('request_mode' for every intakeMode: 'request' create). `existing`: the create
|
|
1577
|
+
* was an idempotent replay and the post was not processed again. On GET
|
|
1578
|
+
* /v2/posts/{id} this field is present only for posts created with
|
|
1579
|
+
* `intakeMode: 'feedback'` and reports how far that processing has got ('queued',
|
|
1580
|
+
* 'processing', 'complete', 'needs_review', or 'skipped' with the same `reason`
|
|
1581
|
+
* the create returned), with `results` listing what was made of the submission
|
|
1582
|
+
* once the run has finished.
|
|
1583
|
+
*/
|
|
1584
|
+
processing?: Data.Processing;
|
|
1093
1585
|
}
|
|
1094
1586
|
|
|
1095
1587
|
export namespace Data {
|
|
1588
|
+
/**
|
|
1589
|
+
* When kind is 'insight', where exactly the insight points back into its origin:
|
|
1590
|
+
* an insight source record with character ranges into its fullText, or the native
|
|
1591
|
+
* conversation/message/comment/post ids.
|
|
1592
|
+
*/
|
|
1593
|
+
export interface Anchor {
|
|
1594
|
+
commentId?: string | null;
|
|
1595
|
+
|
|
1596
|
+
conversationId?: string | null;
|
|
1597
|
+
|
|
1598
|
+
messageId?: string | null;
|
|
1599
|
+
|
|
1600
|
+
ranges?: Array<Anchor.Range> | null;
|
|
1601
|
+
|
|
1602
|
+
sourceRecordId?: string | null;
|
|
1603
|
+
|
|
1604
|
+
submissionId?: string | null;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
export namespace Anchor {
|
|
1608
|
+
export interface Range {
|
|
1609
|
+
end: number;
|
|
1610
|
+
|
|
1611
|
+
start: number;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
/**
|
|
1616
|
+
* Provenance of an insight: which channel it came from and how it was captured.
|
|
1617
|
+
*/
|
|
1618
|
+
export interface InsightSource {
|
|
1619
|
+
channel: 'slack' | 'discord' | 'email' | 'support' | 'widget' | 'call' | 'api' | 'feedback';
|
|
1620
|
+
|
|
1621
|
+
capturedBy?: 'manual' | 'auto' | 'ai' | 'api' | null;
|
|
1622
|
+
|
|
1623
|
+
conversationId?: string | null;
|
|
1624
|
+
|
|
1625
|
+
externalId?: string | null;
|
|
1626
|
+
|
|
1627
|
+
sourceLabel?: string | null;
|
|
1628
|
+
|
|
1629
|
+
url?: string | null;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1096
1632
|
/**
|
|
1097
1633
|
* Third-party integration links associated with this post
|
|
1098
1634
|
*/
|
|
@@ -1257,31 +1793,136 @@ export namespace PostSearchResponse {
|
|
|
1257
1793
|
objectType: 'Opportunity' | 'Case';
|
|
1258
1794
|
}
|
|
1259
1795
|
}
|
|
1796
|
+
|
|
1797
|
+
/**
|
|
1798
|
+
* On POST /v2/posts — `queued`: a processing run (claim extraction or the Organize
|
|
1799
|
+
* rewrite) was enqueued and its result lands asynchronously on the post.
|
|
1800
|
+
* `skipped`: nothing was enqueued; `reason` says which gate decided
|
|
1801
|
+
* ('request_mode' for every intakeMode: 'request' create). `existing`: the create
|
|
1802
|
+
* was an idempotent replay and the post was not processed again. On GET
|
|
1803
|
+
* /v2/posts/{id} this field is present only for posts created with
|
|
1804
|
+
* `intakeMode: 'feedback'` and reports how far that processing has got ('queued',
|
|
1805
|
+
* 'processing', 'complete', 'needs_review', or 'skipped' with the same `reason`
|
|
1806
|
+
* the create returned), with `results` listing what was made of the submission
|
|
1807
|
+
* once the run has finished.
|
|
1808
|
+
*/
|
|
1809
|
+
export interface Processing {
|
|
1810
|
+
/**
|
|
1811
|
+
* 'queued' = an AI run was enqueued and has not landed yet; 'processing' = the run
|
|
1812
|
+
* is working on the submission; 'complete' = it finished and `results` lists what
|
|
1813
|
+
* it produced; 'needs_review' = it finished and a teammate still has to decide
|
|
1814
|
+
* something; 'skipped' = nothing was enqueued (see `reason`); 'existing' =
|
|
1815
|
+
* idempotent replay, not processed again.
|
|
1816
|
+
*/
|
|
1817
|
+
status: 'queued' | 'processing' | 'complete' | 'needs_review' | 'skipped' | 'existing';
|
|
1818
|
+
|
|
1819
|
+
/**
|
|
1820
|
+
* Why processing was skipped. 'request_mode' = intakeMode was 'request' (the
|
|
1821
|
+
* default); 'autopilot_off' = the workspace's Autopilot dial is off or its plan
|
|
1822
|
+
* does not include it; 'pipeline_paused' = the platform paused AI processing (it
|
|
1823
|
+
* resumes automatically); 'support_board' / 'spam_held' / 'staff_authored' /
|
|
1824
|
+
* 'no_content' = the post did not qualify; 'source_too_long' = the text was over
|
|
1825
|
+
* the length limit when the run read it (a create that long is normally refused
|
|
1826
|
+
* with a 400 first); 'extraction_failed' = the AI could not read the text after
|
|
1827
|
+
* repeated attempts; nothing was written, and opening the post in Triage runs the
|
|
1828
|
+
* analysis again.
|
|
1829
|
+
*/
|
|
1830
|
+
reason?:
|
|
1831
|
+
| 'request_mode'
|
|
1832
|
+
| 'autopilot_off'
|
|
1833
|
+
| 'insights_disabled'
|
|
1834
|
+
| 'pipeline_paused'
|
|
1835
|
+
| 'support_board'
|
|
1836
|
+
| 'spam_held'
|
|
1837
|
+
| 'staff_authored'
|
|
1838
|
+
| 'not_a_post'
|
|
1839
|
+
| 'no_board'
|
|
1840
|
+
| 'no_id'
|
|
1841
|
+
| 'no_content'
|
|
1842
|
+
| 'source_too_long'
|
|
1843
|
+
| 'extraction_failed'
|
|
1844
|
+
| 'hook_error';
|
|
1845
|
+
|
|
1846
|
+
/**
|
|
1847
|
+
* What the workspace's "Organize submissions" lane made of this submission, one
|
|
1848
|
+
* entry per ask it found, in the order they appear in the text. Present on GET
|
|
1849
|
+
* /v2/posts/{id} for posts created with `intakeMode: 'feedback'` once the run has
|
|
1850
|
+
* finished. Absent while the run is still working, and absent for workspaces that
|
|
1851
|
+
* do not organize submissions — there the post itself is the request.
|
|
1852
|
+
*/
|
|
1853
|
+
results?: Array<Processing.Result>;
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
export namespace Processing {
|
|
1857
|
+
export interface Result {
|
|
1858
|
+
/**
|
|
1859
|
+
* 'request' = the ask became a request of its own; 'attached' = it was added as
|
|
1860
|
+
* evidence to a request that already existed; 'held' = it became a request that is
|
|
1861
|
+
* waiting for a teammate to publish it; 'question' = it asked something and no
|
|
1862
|
+
* request was created, so a teammate answers it.
|
|
1863
|
+
*/
|
|
1864
|
+
outcome: 'attached' | 'request' | 'question' | 'held';
|
|
1865
|
+
|
|
1866
|
+
/**
|
|
1867
|
+
* The ask, as it was written up.
|
|
1868
|
+
*/
|
|
1869
|
+
title: string;
|
|
1870
|
+
|
|
1871
|
+
/**
|
|
1872
|
+
* The request this ask became, or was attached to. Absent for a question, and
|
|
1873
|
+
* absent when the request is not readable through this API (for example a ticket
|
|
1874
|
+
* board).
|
|
1875
|
+
*/
|
|
1876
|
+
postId?: string;
|
|
1877
|
+
|
|
1878
|
+
/**
|
|
1879
|
+
* Title of `postId`.
|
|
1880
|
+
*/
|
|
1881
|
+
postTitle?: string;
|
|
1882
|
+
|
|
1883
|
+
/**
|
|
1884
|
+
* Why a 'held' result is waiting for a teammate. Only on a 'held' result, and only
|
|
1885
|
+
* one of these codes: 'too_many_topics' = the submission held more separate asks
|
|
1886
|
+
* than one submission can become requests, so this one request lists the asks that
|
|
1887
|
+
* did not fit, one line each in the customer's words; 'uncertain' = the ask was
|
|
1888
|
+
* too vague to file without a person; 'custom_fields' = the board requires custom
|
|
1889
|
+
* fields this submission did not carry; 'processing_failed' = the AI could not
|
|
1890
|
+
* rewrite the text (the request then holds the original words) or could not check
|
|
1891
|
+
* this ask against existing requests, so a teammate confirms it is not a
|
|
1892
|
+
* duplicate.
|
|
1893
|
+
*/
|
|
1894
|
+
reason?: 'too_many_topics' | 'uncertain' | 'custom_fields' | 'processing_failed';
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1260
1897
|
}
|
|
1261
1898
|
}
|
|
1262
1899
|
|
|
1263
1900
|
export interface PostCreateParams {
|
|
1264
1901
|
/**
|
|
1265
|
-
* Body param:
|
|
1902
|
+
* Body param: Admin ID to assign this post to
|
|
1266
1903
|
*/
|
|
1267
|
-
|
|
1904
|
+
assigneeId?: string;
|
|
1268
1905
|
|
|
1269
1906
|
/**
|
|
1270
|
-
* Body param:
|
|
1907
|
+
* Body param: Id of an existing open request this post is evidence for. The post
|
|
1908
|
+
* is created, then linked.
|
|
1271
1909
|
*/
|
|
1272
|
-
|
|
1910
|
+
attachTo?: string;
|
|
1273
1911
|
|
|
1274
1912
|
/**
|
|
1275
|
-
* Body param:
|
|
1913
|
+
* Body param: Author to attribute the post to. If not provided, uses the
|
|
1914
|
+
* authenticated user — unless `source` is given, in which case a guest author is
|
|
1915
|
+
* synthesised from `source.label` (or the channel name), because a relayed request
|
|
1916
|
+
* belongs to the customer who said it. Supports multiple identification methods:
|
|
1917
|
+
* id (Featurebase ID), userId (external SSO ID), or email.
|
|
1276
1918
|
*/
|
|
1277
|
-
|
|
1919
|
+
author?: TicketsAPI.AuthorInput;
|
|
1278
1920
|
|
|
1279
1921
|
/**
|
|
1280
|
-
* Body param:
|
|
1281
|
-
*
|
|
1282
|
-
* ID), userId (external SSO ID), or email.
|
|
1922
|
+
* Body param: Board ID to create the post in. Omit to use the default board of the
|
|
1923
|
+
* organization.
|
|
1283
1924
|
*/
|
|
1284
|
-
|
|
1925
|
+
boardId?: string;
|
|
1285
1926
|
|
|
1286
1927
|
/**
|
|
1287
1928
|
* Body param: Whether comments are enabled on this post
|
|
@@ -1289,7 +1930,9 @@ export interface PostCreateParams {
|
|
|
1289
1930
|
commentsEnabled?: boolean | null;
|
|
1290
1931
|
|
|
1291
1932
|
/**
|
|
1292
|
-
* Body param: Post content (HTML)
|
|
1933
|
+
* Body param: Post content (HTML). Required when `intakeMode` is 'feedback' and no
|
|
1934
|
+
* title is given. In 'feedback' mode its plain text is limited by `source.channel`
|
|
1935
|
+
* (see `intakeMode`); longer content is rejected with a 400.
|
|
1293
1936
|
*/
|
|
1294
1937
|
content?: string;
|
|
1295
1938
|
|
|
@@ -1315,6 +1958,23 @@ export interface PostCreateParams {
|
|
|
1315
1958
|
*/
|
|
1316
1959
|
inReview?: boolean | null;
|
|
1317
1960
|
|
|
1961
|
+
/**
|
|
1962
|
+
* Body param: What the text is. 'request' (default): a finished request — stored
|
|
1963
|
+
* exactly as supplied, no AI claim extraction, regardless of author. 'feedback':
|
|
1964
|
+
* raw customer feedback — processed like a portal post (organized into a request,
|
|
1965
|
+
* or its claims extracted and matched against existing requests) under the
|
|
1966
|
+
* workspace's Autopilot dial, plan, AI budget and moderation settings. In
|
|
1967
|
+
* 'feedback' mode `title` is optional (the first line of `content` becomes it),
|
|
1968
|
+
* `statusId` and `eta` are rejected (400) because raw feedback has no decision
|
|
1969
|
+
* yet, and text is read in full up to the limit of its `source.channel` — 120,000
|
|
1970
|
+
* characters of plain text for 'call' (a two-hour transcript), 60,000 for 'email'
|
|
1971
|
+
* and 'api', 30,000 for 'slack' and 'discord'; without a `source.channel` the
|
|
1972
|
+
* 'api' limit applies — while anything longer is rejected (400) rather than
|
|
1973
|
+
* trimmed. Long text takes tens of minutes rather than seconds to process, and one
|
|
1974
|
+
* submission yields at most 30 requests.
|
|
1975
|
+
*/
|
|
1976
|
+
intakeMode?: 'request' | 'feedback';
|
|
1977
|
+
|
|
1318
1978
|
/**
|
|
1319
1979
|
* Body param: Push the created post to third-party integrations configured on your
|
|
1320
1980
|
* organization. Each integration must be explicitly set to true to trigger;
|
|
@@ -1322,6 +1982,12 @@ export interface PostCreateParams {
|
|
|
1322
1982
|
*/
|
|
1323
1983
|
integrations?: PostCreateParams.Integrations;
|
|
1324
1984
|
|
|
1985
|
+
/**
|
|
1986
|
+
* Body param: Create this request on the internal board. Never visible on the
|
|
1987
|
+
* portal.
|
|
1988
|
+
*/
|
|
1989
|
+
internal?: boolean;
|
|
1990
|
+
|
|
1325
1991
|
/**
|
|
1326
1992
|
* Body param: Whether to send email notifications to admins when this post is
|
|
1327
1993
|
* created. When true, admins will receive the same email notifications as when a
|
|
@@ -1329,6 +1995,20 @@ export interface PostCreateParams {
|
|
|
1329
1995
|
*/
|
|
1330
1996
|
notifyAdmins?: boolean;
|
|
1331
1997
|
|
|
1998
|
+
/**
|
|
1999
|
+
* Body param: When true, hides the issue from portal/public surfaces. Omitted or
|
|
2000
|
+
* false is visible.
|
|
2001
|
+
*/
|
|
2002
|
+
portalHidden?: boolean;
|
|
2003
|
+
|
|
2004
|
+
/**
|
|
2005
|
+
* Body param: Provenance of this request, and the idempotency key for the create.
|
|
2006
|
+
* With `source` and no `author`, the post is attributed to a guest named after
|
|
2007
|
+
* `label` (or the channel) so it belongs to the customer who said it, not to the
|
|
2008
|
+
* API key.
|
|
2009
|
+
*/
|
|
2010
|
+
source?: PostCreateParams.Source;
|
|
2011
|
+
|
|
1332
2012
|
/**
|
|
1333
2013
|
* Body param: Status ID to set
|
|
1334
2014
|
*/
|
|
@@ -1339,6 +2019,13 @@ export interface PostCreateParams {
|
|
|
1339
2019
|
*/
|
|
1340
2020
|
tags?: string | Array<string>;
|
|
1341
2021
|
|
|
2022
|
+
/**
|
|
2023
|
+
* Body param: Post title. Required unless `intakeMode` is 'feedback', where raw
|
|
2024
|
+
* customer text rarely has one: omit it (or send it blank) and the first line of
|
|
2025
|
+
* `content` becomes the title, cut to 120 characters.
|
|
2026
|
+
*/
|
|
2027
|
+
title?: string;
|
|
2028
|
+
|
|
1342
2029
|
/**
|
|
1343
2030
|
* Body param: Initial upvotes count. Defaults to 1 (post author is automatically
|
|
1344
2031
|
* added as voter). Use 0 to create a post without any votes.
|
|
@@ -1396,6 +2083,45 @@ export namespace PostCreateParams {
|
|
|
1396
2083
|
*/
|
|
1397
2084
|
slack?: boolean;
|
|
1398
2085
|
}
|
|
2086
|
+
|
|
2087
|
+
/**
|
|
2088
|
+
* Provenance of this request, and the idempotency key for the create. With
|
|
2089
|
+
* `source` and no `author`, the post is attributed to a guest named after `label`
|
|
2090
|
+
* (or the channel) so it belongs to the customer who said it, not to the API key.
|
|
2091
|
+
*/
|
|
2092
|
+
export interface Source {
|
|
2093
|
+
/**
|
|
2094
|
+
* Channel the request arrived on. 'feedback', 'widget' and 'support' are reserved
|
|
2095
|
+
* for posts authored on the portal, the widget and the inbox, and are rejected
|
|
2096
|
+
* with a 400. With `intakeMode: 'feedback'` the channel also sets how much text is
|
|
2097
|
+
* read: 'call' 120,000 characters, 'email' and 'api' 60,000, 'slack' and 'discord'
|
|
2098
|
+
* 30,000.
|
|
2099
|
+
*/
|
|
2100
|
+
channel: 'slack' | 'discord' | 'email' | 'support' | 'widget' | 'call' | 'api' | 'feedback';
|
|
2101
|
+
|
|
2102
|
+
/**
|
|
2103
|
+
* Stable id of the message/record in the source system. Sending the same (channel,
|
|
2104
|
+
* externalId) twice returns the post created the first time instead of a duplicate
|
|
2105
|
+
* (HTTP 200 with `deduped: true`). Stored namespaced as `api:<externalId>`.
|
|
2106
|
+
*/
|
|
2107
|
+
externalId: string;
|
|
2108
|
+
|
|
2109
|
+
/**
|
|
2110
|
+
* Id of the support conversation this request came from
|
|
2111
|
+
*/
|
|
2112
|
+
conversationId?: string;
|
|
2113
|
+
|
|
2114
|
+
/**
|
|
2115
|
+
* Display name of the specific source. Also names the guest author when no
|
|
2116
|
+
* `author` is given.
|
|
2117
|
+
*/
|
|
2118
|
+
label?: string;
|
|
2119
|
+
|
|
2120
|
+
/**
|
|
2121
|
+
* Deep link back to the original message/record
|
|
2122
|
+
*/
|
|
2123
|
+
url?: string;
|
|
2124
|
+
}
|
|
1399
2125
|
}
|
|
1400
2126
|
|
|
1401
2127
|
export interface PostRetrieveParams {
|
|
@@ -1414,8 +2140,10 @@ export interface PostUpdateParams {
|
|
|
1414
2140
|
|
|
1415
2141
|
/**
|
|
1416
2142
|
* Body param: Author to attribute the post to. If not provided, uses the
|
|
1417
|
-
* authenticated user
|
|
1418
|
-
*
|
|
2143
|
+
* authenticated user — unless `source` is given, in which case a guest author is
|
|
2144
|
+
* synthesised from `source.label` (or the channel name), because a relayed request
|
|
2145
|
+
* belongs to the customer who said it. Supports multiple identification methods:
|
|
2146
|
+
* id (Featurebase ID), userId (external SSO ID), or email.
|
|
1419
2147
|
*/
|
|
1420
2148
|
author?: TicketsAPI.AuthorInput;
|
|
1421
2149
|
|
|
@@ -1507,6 +2235,13 @@ export interface PostListParams extends CursorPageParams {
|
|
|
1507
2235
|
*/
|
|
1508
2236
|
inReview?: boolean | null;
|
|
1509
2237
|
|
|
2238
|
+
/**
|
|
2239
|
+
* Query param: Filter by submission kind. Omitted or 'issue' returns work items
|
|
2240
|
+
* only. Pass 'record' for customer submissions whose claims were extracted into
|
|
2241
|
+
* insights. Insights are never served by this resource — use /v2/insights.
|
|
2242
|
+
*/
|
|
2243
|
+
kind?: 'issue' | 'record';
|
|
2244
|
+
|
|
1510
2245
|
/**
|
|
1511
2246
|
* Query param: Search query to filter posts by title/content
|
|
1512
2247
|
*/
|
|
@@ -1645,6 +2380,7 @@ export interface PostUnmergeParams {
|
|
|
1645
2380
|
}
|
|
1646
2381
|
|
|
1647
2382
|
Posts.Voters = Voters;
|
|
2383
|
+
Posts.Insights = Insights;
|
|
1648
2384
|
|
|
1649
2385
|
export declare namespace Posts {
|
|
1650
2386
|
export {
|
|
@@ -1678,4 +2414,12 @@ export declare namespace Posts {
|
|
|
1678
2414
|
type VoterAddParams as VoterAddParams,
|
|
1679
2415
|
type VoterRemoveParams as VoterRemoveParams,
|
|
1680
2416
|
};
|
|
2417
|
+
|
|
2418
|
+
export {
|
|
2419
|
+
Insights as Insights,
|
|
2420
|
+
type InsightListParams as InsightListParams,
|
|
2421
|
+
type InsightConvertToPostParams as InsightConvertToPostParams,
|
|
2422
|
+
type InsightLinkParams as InsightLinkParams,
|
|
2423
|
+
type InsightUnlinkParams as InsightUnlinkParams,
|
|
2424
|
+
};
|
|
1681
2425
|
}
|