FastComments.com

API живих коментарів


API FastComments

FastComments надає API для взаємодії з багатьма ресурсами. Створюйте інтеграції з нашою платформою або навіть створюйте власних клієнтів!

У цій документації ви знайдете всі підтримувані ресурси API, задокументовані з їх типами запитів та відповідей.

Для корпоративних клієнтів весь доступ до API фіксується в журналі аудиту.

Згенеровані SDK

FastComments тепер генерує Специфікація API з нашого коду (це ще не завершено, але включає багато API).

Тепер у нас також є SDK для популярних мов:

Аутентифікація

API аутентифікується шляхом передачі вашого api key як заголовка X-API-KEY або параметра запиту API_KEY. Вам також знадобиться ваш tenantId для здійснення викликів API. Його можна отримати на тій же сторінці, що й ваш api key.

Примітка щодо безпеки

Ці маршрути призначені для виклику з сервера. НЕ ВИКОРИСТОВУЙТЕ їх у браузері. Це розкриє ваш API-ключ — це надасть повний доступ до вашого облікового запису будь-кому, хто зможе переглянути вихідний код сторінки!

Варіант аутентифікації 1 — Заголовки

  • Header: X-API-KEY
  • Header: X-TENANT-ID

Варіант аутентифікації 2 — Параметри запиту

  • Query Param: API_KEY
  • Query Param: tenantId

Варіант аутентифікації 3 — OAuth Bearer Token

  • Header: Authorization: Bearer fcat_...

Треті сторони, такі як Zapier та клієнти MCP server, отримують токен через OAuth замість API-ключа. Цей токен працює на кожному кінцевому пункті тут. Орендар передбачений токеном, тому tenantId є необов’язковим, але має відповідати токену, якщо вказаний. Запити GET потребують області read, а всі інші методи — області write. Повний процес, включаючи реєстрацію клієнта, PKCE, оновлення та відкликання, задокументовано в розділі Авторизація OAuth. Відкриття починається за адресою https://fastcomments.com/.well-known/oauth-authorization-server.

Читання власних записів

FastComments забезпечує активну‑активну доступність. Запити з вашого дата‑центру маршрутизуються до найближчого пункту присутності до вас. Це автоматично, і зазвичай ви можете спостерігати семантику «читати‑те‑запис». Якщо ви хочете бути впевненими, що читаєте власні записи, ви можете прив’язати ваші запити до певного регіону, використовуючи цей регіон як хост API (хоча зазвичай це не потрібно для більшості інтеграцій):

  • gdc-oregon.fastcomments.com
  • gdc-virginia.fastcomments.com
  • gdc-singapore.fastcomments.com
  • gdc-falkenstein2.fastcomments.com
  • gdc-sao-paulo.fastcomments.com
  • eudc-helsinki2.fastcomments.com
  • eudc-limburg.fastcomments.com
  • eudc-france.fastcomments.com

Зверніть увагу, що якщо ви це робите, можливо, захочете визначити резервний варіант, оскільки раніше ми деактивували вузли входу і використовуємо нові назви для перемикання.


Структура журналу аудиту Internal Link

An AuditLog is an object that represents an audited event for tenants that have access to this feature.

The structure for the AuditLog object is as follows:

Структура AuditLog
Copy Copy
1
2interface AuditLog {
3 id: string;
4 /** Who performed the event. **/
5 userId?: string;
6 username?: string;
7 resourceName: string;
8 crudType: 'c' | 'r' | 'u' | 'd' | 'login';
9 from: string;
10 url?: string;
11 ip?: string;
12 /** The browser that performed the event, when it came from one. **/
13 ua?: string;
14 /** A hash of the session the event came from, for correlating one person's actions. Never the session itself. **/
15 sIdHashed?: string;
16 when: string;
17 description?: string;
18 serverStartDate: string;
19 /** The id of the object the event was performed on, as opposed to who performed it. **/
20 targetId?: string;
21 /** A human-readable label for that object, e.g. "jsmith (jsmith@example.com)". **/
22 targetLabel?: string;
23 objectDetails?: object;
24}
25

targetId і targetLabel описують, на що була виконана подія; userId і username описують, хто її виконав. Для оновлень objectDetails.changes містить карту {field: {from, to}}, що показує, що саме змінилося.

Журнал аудиту є незмінним. Його також не можна записувати вручну. FastComments.com може вирішувати, коли записувати в журнал аудиту. Однак ви можете читати його за допомогою цього API.

Події в журналі аудиту видаляються через два роки.

Структура коментаря Internal Link

Об'єкт Comment представляє собою коментар, залишений користувачем.

Відношення між батьківськими та дочірніми коментарями визначається через parentId.

Структура об'єкта Comment виглядає так:

Структура об’єкта Comment
Copy Copy
1
2interface Comment {
3 /** READONLY: Встановлено true, якщо антиспам-движок визначив коментар як спам. **/
4 aiDeterminedSpam?: boolean
5 /** Чи схвалено показ коментаря. Встановлюється в true при збереженні коментаря, інакше він буде прихований. **/
6 approved?: boolean
7 /** Аватар користувача. **/
8 avatarSrc?: string
9 /** Дочірні коментарі. Не заповнюється в усіх сценаріях. Використовується, коли через API встановлено asTree = true. **/
10 children: Comment[]
11 /** Сирий (необроблений) текст коментаря. **/
12 comment: string
13 /** READONLY: Коментар розпарсовано в HTML. **/
14 commentHTML?: string
15 /** Електронна адреса коментатора. Обов'язкова, якщо анонімні коментарі вимкнені. **/
16 commenterEmail?: string
17 /** Посилання коментатора (наприклад, їхній блог). **/
18 commenterLink?: string
19 /** Ім'я коментатора. Завжди обов'язкове. Якщо недоступне, вкажіть щось на кшталт "Anonymous". **/
20 commenterName: string
21 /** Дата створення коментаря, у форматі UTC epoch. **/
22 date: number
23 /** Мітка для відображення коментаря - наприклад "Admin", "Moderator", або щось на кшталт "VIP User". **/
24 displayLabel?: string
25 /** Домен, на якому опубліковано коментар. **/
26 domain?: string
27 /** READONLY: Кількість разів, коли коментар було позначено. **/
28 flagCount?: number
29 /** Хештеги (#...), написані в коментарі та успішно розпарсені. Ви також можете вручну додавати хештеги для запитів, але вони не відобразяться в тексті коментаря автоматично. **/
30 hashTags?: CommentHashTag[]
31 /** READONLY: Чи містить коментар зображення? **/
32 hasImages?: boolean
33 /** READONLY: Чи містить коментар посилання? **/
34 hasLinks?: boolean
35 /** READONLY: Унікальний id коментаря. **/
36 id: string
37 /** Лише при створенні! Це хешується для збереження. **/
38 ip?: string
39 /** READONLY: Чи заблокував поточний користувач автора цього коментаря? **/
40 isBlocked?: boolean
41 /** READONLY: Чи автор коментаря є адміном? Встановлюється автоматично на основі userId. **/
42 isByAdmin?: boolean
43 /** READONLY: Чи автор коментаря є модератором? Встановлюється автоматично на основі userId. **/
44 isByModerator?: boolean
45 /** Встановити true, якщо коментар було м'яко видалено (була залишена тимчасова заміна через інші налаштування). **/
46 isDeleted?: boolean
47 /** Встановити true, якщо акаунт користувача було видалено і коментар потрібно було зберегти. **/
48 isDeletedUser?: boolean
49 /** READONLY: Чи було позначено (flagged) поточним увійденим користувачем (contextUserId)? **/
50 isFlagged?: boolean
51 /** Чи закріплено коментар? **/
52 isPinned?: boolean
53 /** Чи заблоковано коментар? Якщо true, ніхто (включно з модераторами) не може відповідати, редагувати або видаляти його, поки його не розблокують. **/
54 isLocked?: boolean
55 /** Чи є коментар спамом? **/
56 isSpam?: boolean
57 /** READONLY: Чи проголосовано проти цього коментаря поточним користувачем (contextUserId)? **/
58 isVotedDown?: boolean
59 /** READONLY: Чи проголосовано за цей коментар поточним користувачем (contextUserId)? **/
60 isVotedUp?: boolean
61 /** Локаль коментаря. Якщо не вказано, буде визначено із HTTP-заголовка Accept-Language. **/
62 locale?: 'de_de' | 'en_us' | 'es_es' | 'fr_fr' | 'it_it' | 'ja_jp' | 'ko_kr' | 'pl_pl' | 'pt_br' | 'ru_ru' | 'tr_tr' | 'zh_cn' | 'zh_tw'
63 /** READONLY: @згадки, написані в коментарі та успішно розпарсені. **/
64 mentions?: CommentUserMention[]
65 /** Опціональні метадані, пов'язані з коментарем. **/
66 meta?: Record<string, string | number | boolean>
67 /** Необов'язковий список id груп модерації, пов'язаних з цим коментарем. **/
68 moderationGroupIds?: string[]|null
69 /** READONLY: id об'єкта голосу, що відповідає голосу поточного користувача (contextUserId) за цей коментар. **/
70 myVoteId?: string
71 /** Чи було надіслано повідомлення про цей коментар коментаторам. Щоб запобігти надсиланню сповіщень під час імпорту, встановіть це в true. **/
72 notificationSentForParent?: boolean
73 /** Чи було надіслано повідомлення про цей коментар користувачам tenant. Щоб запобігти надсиланню сповіщень під час імпорту, встановіть це в true. **/
74 notificationSentForParentTenant?: boolean
75 /** Заголовок сторінки, на якій був цей коментар. **/
76 pageTitle?: string
77 /** Якщо ми відповідаємо на коментар, це ID коментаря, на який відповідаємо. **/
78 parentId?: string|null
79 /** Чи позначено коментар як переглянутий. **/
80 reviewed: boolean
81 /** id орендатора (tenant), до якого належить коментар. **/
82 tenantId: string
83 /** Користувач, який написав коментар. Створюється автоматично при збереженні коментаря з ім'ям/емейлом. **/
84 userId?: string|null
85 /** URL місця, де видно цей коментар, наприклад запис блогу. **/
86 url: string
87 /** "Очищена" версія urlId, який ви передали. Під час збереження ви вказуєте це поле, але при отриманні коментаря воно буде "очищене" і ваше оригінальне значення переміщено до "urlIdRaw". **/
88 urlId: string
89 /** READONLY: Початковий urlId, який ви передавали. **/
90 urlIdRaw?: string
91 /** Чи верифіковано користувача та цей коментар? **/
92 verified: boolean
93 /** Кількість голосів за. **/
94 votesUp?: number
95 /** Кількість голосів проти. **/
96 votesDown?: number
97 /** "Карма" коментаря (= votes up - votes down). **/
98 votes?: number
99}
100

Деякі з цих полів позначено як READONLY — вони повертаються API, але не можуть бути встановлені.

Структура тексту коментаря

Коментарі пишуться у фірмовому діалекті markdown від FastComments — це просто markdown плюс традиційні bbcode-стиль теги для зображень, як-от [img]path[/img].

Текст зберігається у двох полях. Текст, введений користувачем, зберігається без змін у полі comment. Він рендериться та зберігається в полі commentHTML.

Дозволені HTML-теги: b, u, i, strike, pre, span, code, img, a, strong, ul, ol, li, and br.

Рекомендується рендерити HTML, оскільки це дуже невелика підмножина HTML, тож створити рендерер досить просто. Існує кілька бібліотек для React Native і Flutter, наприклад, які можуть у цьому допомогти.

Ви можете обрати рендеринг ненормалізованого значення поля comment. Приклад парсера тут..

Приклад парсера також можна налаштувати для роботи з HTML і перетворення HTML-тегів у очікувані елементи для відображення на вашій платформі.

Тегування

Коли користувачів тегують у коментарі, інформація зберігається в списку mentions. Кожен об'єкт у цьому списку має таку структуру.

Об’єкт згадок коментаря
Copy CopyRun External Link
1
2interface CommentUserMention {
3 /** id користувача. Для SSO-користувачів тут буде префікс вашого tenant id. **/
4 id: string
5 /** Фінальний текст @згадки, включно з символом @. **/
6 tag: string
7 /** Оригінальний текст @згадки, включно з символом @. **/
8 rawTag: string
9 /** Тип користувача, який було згадано. user = обліковий запис FastComments.com. sso = SSOUser. **/
10 type: 'user'|'sso'
11 /** Якщо користувач відмовився від сповіщень, це все одно буде встановлено в true. **/
12 sent: boolean
13}
14

Хештеги

Коли хештеги використовуються та успішно розпарсуються, інформація зберігається в списку hashTags. Кожен об'єкт у цьому списку має таку структуру. Хештеги також можна додавати вручну до масиву hashTags коментаря для запитів, якщо встановлено retain.

Об’єкт хештегу коментаря
Copy CopyRun External Link
1
2interface CommentHashTag {
3 /** id хештегу. **/
4 id: string
5 /** Фінальний текст #хештегу, включно зі символом #. **/
6 tag: string
7 /** Якщо хештег пов’язано з кастомним URL, він буде вказаний. **/
8 url?: string
9 /** Чи потрібно зберігати хештег, навіть якщо він не присутній у тексті коментаря при оновленні. Корисно для тегування коментарів без зміни тексту коментаря. **/
10 retain?: boolean
11}
12

Структура шаблону електронної пошти Internal Link

Об'єкт EmailTemplate представляє конфігурацію для користувацького шаблону електронного листа для тенанта.

Система обиратиме шаблон електронного листа для використання за допомогою:

  • Ідентифікатора типу, який ми називаємо emailTemplateId. Це константи.
  • domain. Спочатку ми намагатимемося знайти шаблон для домену, до якого прив'язаний пов'язаний об'єкт (наприклад, Comment), і якщо відповідність не знайдена, тоді ми спробуємо знайти шаблон, де domain дорівнює null або *.

Структура об'єкта EmailTemplate виглядає так:

Структура шаблону електронного листа
Copy Copy
1
2interface EmailTemplate {
3 id: string
4 tenantId: string
5 emailTemplateId: string
6 displayName: string
7 /** ТІЛЬКИ ДЛЯ ЧИТАННЯ **/
8 createdAt: string
9 /** ТІЛЬКИ ДЛЯ ЧИТАННЯ **/
10 updatedAt: string
11 /** ТІЛЬКИ ДЛЯ ЧИТАННЯ **/
12 updatedByUserId: string
13 /** Домен, з яким має бути пов’язаний шаблон. **/
14 domain?: string | '*' | null
15 /** Вміст шаблону електронного листа в синтаксисі EJS. **/
16 ejs: string
17 /** Мапа перевизначених ключів перекладу на значення для кожної підтримуваної локалі. **/
18 translationOverridesByLocale: Record<string, Record<string, string>>
19 /** Об'єкт, який представляє контекст рендерингу шаблону. **/
20 testData: object
21}
22

Примітки

  • Дійсні значення emailTemplateId можна отримати з кінцевої точки /definitions.
  • Кінцева точка /definitions також містить стандартні переклади та тестові дані.
  • Шаблони не збережуться, якщо структура або тестові дані недійсні.

Структура публікації у стрічці Internal Link

A FeedPost object represents a post in a FastComments feed. A feed is a stream of posts with their own comment threads, rendered by the Feed widget. Every post has an author, optional rich content, media, and links, and can be tagged so that a feed can be filtered.

Об’єкт FeedPost представляє пост у стрічці FastComments. Стрічка — це потік постів зі своїми власними гілками коментарів, які відображаються за допомогою віджету Feed. Кожен пост має автора, необов’язковий багатий вміст, медіа та посилання, і може бути позначений тегами, щоб стрічку можна було фільтрувати.

The structure for the FeedPost object is as follows:

Структура об’єкта FeedPost виглядає наступним чином:

Структура FeedPost
Copy Copy
1
2interface FeedPost {
3 /** READONLY **/
4 _id: string
5 /** READONLY **/
6 tenantId: string
7 title?: string
8 /** Ідентифікатор користувача FastComments або SSO, який створив пост. **/
9 fromUserId?: string
10 /** Заповнюється з даних користувача, якщо не встановлено. **/
11 fromUserDisplayName?: string | null
12 /** READONLY. Заповнюється з даних користувача. **/
13 fromUserAvatar?: string | null
14 /** Використовується для фільтрації стрічки. **/
15 tags?: string[]
16 /** Вага сортування в межах стрічки. Вищі значення сортуються першими. **/
17 weight?: number
18 /** Пари ключ/значення довільного формату для вашого використання. **/
19 meta?: Record<string, string>
20 /** Очищений HTML. **/
21 contentHTML?: string
22 media?: FeedPostMediaItem[]
23 links?: FeedPostLink[]
24 /** READONLY **/
25 createdAt: string
26 /** READONLY. Reaction type to count. **/
27 reacts?: Record<string, number>
28 /** READONLY **/
29 commentCount?: number | null
30}
31
32interface FeedPostMediaItem {
33 title?: string
34 /** Куди посилається медіа‑елемент при кліку. **/
35 linkUrl?: string
36 /** Один запис на кожну варіацію. Віджет вибирає найкращий варіант. **/
37 sizes: FeedPostMediaItemAsset[]
38}
39
40interface FeedPostMediaItemAsset {
41 w: number
42 h: number
43 src: string
44}
45
46interface FeedPostLink {
47 /** Текст посилання, наприклад "Sign up now". **/
48 text?: string
49 /** Заголовок, що відображається разом з посиланням. **/
50 title?: string
51 /** Опис, що відображається разом з посиланням. **/
52 description?: string
53 url?: string
54}
55

Notes:

Примітки:

  • Деякі з цих полів позначені READONLY — вони повертаються API, але не можуть бути встановлені.
  • Коментарі до поста є звичайними коментарями, у яких urlId має вигляд post: + _id поста. Використовуйте це значення з Comment API, щоб читати або створювати коментарі до поста.

Структура хештегу Internal Link

Об'єкт HashTag представляє тег, який може залишити користувач. Хештеги можуть використовуватися для зв'язування з зовнішнім вмістом або для об'єднання пов'язаних коментарів.

Структура об'єкта HashTag виглядає так:

Структура HashTag
Copy Copy
1
2interface HashTag {
3 /** Повинно починатися з символу "#" або іншого бажаного символу. **/
4 tag: string
5 /** Необов'язковий URL, на який може вказувати хештег. Замість фільтрації коментарів за хештегом, інтерфейс перенаправить на цей URL при натисканні. **/
6 url?: string
7 /** ТІЛЬКИ ДЛЯ ЧИТАННЯ **/
8 createdAt: string
9}
10

Notes:

  • In some API endpoints you will see that the hashtag is used in the URL. Remember to URI-Encoded values. For example, # should instead be represented as %23.
  • Some of these fields are marked READONLY - these are returned by the API but cannot be set.

Структура кількості сповіщень Internal Link

Об'єкт NotificationCount представляє собою кількість непрочитаних сповіщень та метадані для користувача.

Якщо немає непрочитаних сповіщень, для користувача не існуватиме NotificationCount.

NotificationCount об'єкти створюються автоматично і не можуть бути створені через API. Термін їх дії закінчується через один рік.

Ви можете очистити кількість непрочитаних сповіщень користувача, видаливши його NotificationCount.

Структура об'єкта NotificationCount виглядає так:

Структура NotificationCount
Copy Copy
1
2interface NotificationCount {
3 id: string // ідентифікатор користувача
4 count: number
5 createdAt: string // рядок дати
6 expireAt: string // рядок дати
7}
8

Структура сповіщення Internal Link

Об'єкт Notification представляє сповіщення для користувача.

Об'єкти Notification створюються автоматично і не можуть бути створені через API. Вони також закінчують термін дії через один рік. Сповіщення не можна видалити. Однак їх можна оновити, встановивши viewed в false, і можна виконувати запити за viewed.

Користувач також може відмовитись від сповіщень для конкретного коментаря, встановивши optedOut у сповіщенні в true. Ви можете знову підписатися, встановивши його в false.

Існують різні типи сповіщень — перевіряйте relatedObjectType і type.

Способи створення сповіщень досить гнучкі і можуть бути викликані багатьма сценаріями (див. NotificationType).

На сьогодні наявність Notification фактично не означає, що електронний лист надсилається або має бути надісланий. Швидше за все, сповіщення використовуються для стрічки сповіщень та пов'язаних інтеграцій.

Структура об'єкта Notification виглядає так:

Структура Notification
Copy Copy
1
2enum NotificationObjectType {
3 Comment = 0,
4 Profile = 1,
5 Tenant = 2
6}
7
8enum NotificationType {
9 /** Якщо хтось відповів вам. **/
10 RepliedToMe = 0,
11 /** Якщо хтось відповів будь-де в треді (навіть нащадки нащадків) треда, в якому ви коментували. **/
12 RepliedTransientChild = 1,
13 /** Якщо за ваш коментар проголосували. **/
14 VotedMyComment = 2,
15 /** Якщо на корені сторінки, на яку ви підписані, залишено новий коментар. **/
16 SubscriptionReplyRoot = 3,
17 /** Якщо хтось прокоментував ваш профіль. **/
18 CommentedOnProfile = 4,
19 /** Якщо у вас є приватне повідомлення (DM). **/
20 DirectMessage = 5,
21 /** TrialLimits призначено лише для користувачів tenant. **/
22 TrialLimits = 6,
23 /** Якщо вас згадали за допомогою @. **/
24 Mentioned = 7
25}
26
27interface Notification {
28 id: string
29 tenantId: string
30 /** With SSO, the user id is in the format `<tenant id>:<user id>`. **/
31 userId?: string
32 /** When working with SSO, you only have to worry about `userId`. **/
33 anonUserId?: string
34 /** urlId is almost always defined. It is only optional for tenant-level notifications, which are infrequent. **/
35 urlId?: string
36 /** URL is cached for quick navigation to the source of the notification. **/
37 url?: string
38 /** Page Title is cached for quick reading of notification source. **/
39 pageTitle?: string
40 relatedObjectType: NotificationObjectType
41 /** For example, comment id. **/
42 relatedObjectId: string
43 viewed: boolean
44 createdAt: string // рядок дати
45 type: NotificationType
46 fromCommentId?: string
47 fromVoteId?: string
48 /** fromUserName and fromUserAvatarSrc are cached here for quick displaying of the notification. They are updated when the user is updated. **/
49 fromUserName: string
50 fromUserId: string
51 fromUserAvatarSrc?: string
52 /** Set this to true to stop getting notifications for this object. **/
53 optedOut?: boolean
54}
55

Структура сторінки Internal Link


Об'єкт Page представляє сторінку, якій можуть належати багато коментарів. Це відношення визначається urlId.

Об'єкт Page зберігає інформацію, таку як заголовок сторінки, кількість коментарів та urlId.

Структура об'єкта Page виглядає так:

Структура сторінки
Copy Copy
1
2interface Page {
3 id: string
4 urlId: string
5 url: string
6 title?: string
7 createdAt: string
8 commentCount: number
9 rootCommentCount: number
10 /** Якщо встановити це в null, усі користувачі SSO зможуть бачити сторінку. Порожній список означає, що вона закрита для всіх користувачів. **/
11 accessibleByGroupIds?: string[] | null
12 /** Чи закрита ця сторінка для нових коментарів? **/
13 isClosed?: boolean
14}
15

Структура опитування Internal Link

A Poll прикріплюється до коментаря, а не є окремим об’єктом. Він створюється разом з коментарем
(див. POST /api/v1/comments), або додається до існуючого коментаря пізніше за допомогою PUT /api/v1/polls/:commentId.

Кількість голосів зберігається безпосередньо в опитуванні, тому читання опитування дає вам результати без необхідності підсумовувати їх. Окремі голоси, що стоять за цими підрахунками, є об’єктами PollVote.

Кожен варіант має id, який генерується під час створення опитування. Цей id використовується для подачі голосу, зміни мітки варіанту та збереження варіанту (разом з його голосами) під час PUT опитування з доданими або видаленими варіантами. Це єдиний безпечний спосіб посилання на варіант — ніколи не використовуйте його позицію у списку.

Структура опитування
Copy Copy
1
2interface CommentPollOption {
3 id: string
4 label: string
5 votes: number
6}
7
8interface CommentPoll {
9 question: string
10 options: CommentPollOption[]
11 totalVotes: number
12 /** When set and in the past, the poll is closed and no longer accepts votes. **/
13 closesAt?: string | null
14 /** 0 anonymous (the default), 1 admins and moderators, 2 everyone. Absent means anonymous. **/
15 privacy?: 0 | 1 | 2 | null
16 /** When true, the counts are hidden from anyone who has not voted yet. Absent means false. **/
17 requireVoteToSeeResults?: boolean | null
18}
19

Обмеження

  • Питання є обов’язковим і має максимум 200 символів.
  • Опитування має від 2 до 10 варіантів.
  • Мітка варіанту є обов’язковою, має максимум 100 символів і повинна бути унікальною в межах опитування (без урахування регістру).
  • closesAt має бути в майбутньому під час створення опитування. Щоб закрити опитування негайно, виконайте PATCH з датою в минулому.

Налаштування сайту

Опитування підкоряються конфігурації вашого сайту, яку можна змінити під Customize Widget:

  • Опитування мають бути ввімкнені, перш ніж можна створити опитування, інакше API відповість polls-disabled.
  • Голосування може бути обмежене лише зареєстрованими користувачами; у цьому випадку голос, надісланий лише з anonUserId, буде відхилений з помилкою poll-login-required.

Структура голосу в опитуванні Internal Link

A PollVote — це відповідь однієї особи на опитування. Підрахунки, що показуються безпосередньо в опитуванні, синхронізовані з цими даними, тому вони потрібні лише тоді, коли ви хочете знати хто за що проголосував, а не загальні підсумки.

У виборця може бути не більше одного голосу в одному опитуванні. Повторне голосування переміщує його існуючий голос до нової опції замість додавання другого, а updatedAt фіксує, коли це сталося.

voterId — це userId, коли виборець був увійшов, і anonUserId в іншому випадку.

Структура PollVote
Copy Copy
1
2interface PollVote {
3 id: string
4 tenantId: string
5 commentId: string
6 urlId: string
7 /** userId, коли виборець був увійшов, інакше anonUserId. **/
8 voterId: string
9 optionId: string
10 createdAt: string
11 /** Коли виборець востаннє перемістив свій голос до іншої опції. **/
12 updatedAt?: string
13}
14

Приватність

Налаштування privacy опитування застосовується до цього API так само, як і у віджеті коментарів:

  • Anonymous (за замовчуванням): ніхто не може бачити, як хтось проголосував, тому голоси не можуть бути прочитані. GET /api/v1/poll-votes та GET /api/v1/poll-votes/:id відповідають poll-anonymous. Підрахунки опитування все ще доступні через GET /api/v1/polls/:commentId.
  • Admins and moderators: ваш API‑ключ належить адміністратору вашого сайту, тому він може читати голоси.
  • Everyone: голоси можна читати.

Приватність опитування можна звузити, але не розширити, після того як у ньому з'являться голоси.

Структура події очікуючого вебхука Internal Link

Об'єкт PendingWebhookEvent представляє подію вебхука, яка знаходиться в черзі та очікує виконання.

PendingWebhookEvent об'єкти створюються автоматично і не можуть бути створені вручну через API. Їх термін дії також закінчується через один рік. Їх можна видалити, що видаляє завдання з черги.

Існують різні типи подій — перевіряйте eventType (OutboundSyncEventType) і type (OutboundSyncType).

Поширений випадок використання цього API — реалізація власного моніторингу. Можливо, ви захочете періодично викликати ендпоінт /count щоб опитувати кількість невиконаних завдань за заданими фільтрами.

Структура об'єкта PendingWebhookEvent має такий вигляд:

Структура PendingWebhookEvent
Copy Copy
1
2enum OutboundSyncEventType {
3 Create: 0,
4 Delete: 1,
5 Update: 2
6}
7
8enum OutboundSyncType {
9 /** Синхронізація, специфічна для WordPress. **/
10 WP: 0,
11 Webhook: 1
12}
13
14interface PendingWebhookEvent {
15 id: string
16 /** Ідентифікатор коментаря, пов'язаний із подією. **/
17 commentId: string
18 /** Об'єкт коментаря для події на момент її виникнення. Ми почали додавати їх у листопаді 2023 року. **/
19 comment: Comment
20 /** Зовнішній ідентифікатор, який може бути пов'язаний із коментарем. **/
21 externalId: string | null
22 createdAt: Date
23 tenantId: string
24 attemptCount: number
25 /** Встановлюється перед першою спробою та після кожної невдачі. **/
26 nextAttemptAt: Date
27 /** Чи є це подія створення, видалення або оновлення... **/
28 eventType: OutboundSyncEventType
29 /** Тип синхронізації для виконання (WordPress, виклик API тощо). **/
30 type: OutboundSyncType
31 /** Домен, який відповідав коментарю. Ми використовуємо цей домен для вибору API-ключа. **/
32 domain: string
33 /** Остання помилка, яка сталася. Цей тип не має строгої типізації і є "дампом" того, що трапилось. Зазвичай містить об'єкт зі статусним кодом, тілом і мапою заголовків. **/
34 lastError: object | null
35}
36

Структура SSO користувача Internal Link

FastComments надає просте у використанні SSO-рішення. Оновлення інформації користувача за допомогою інтеграції на основі HMAC таке ж просте, як завантаження сторінки користувачем з оновленим payload.

Однак може бути бажано керувати користувачем поза цим потоком, щоб покращити послідовність вашого застосунку.

SSO User API надає спосіб CRUD-операцій над об'єктами, які ми називаємо SSOUsers. Ці об'єкти відрізняються від звичайних Users і зберігаються окремо заради типобезпеки.

The structure for the SSOUser object is as follows:

Структура SSOUser
Copy Copy
1
2interface SSOUser {
3 id: string
4 username: string
5 email?: string
6 websiteUrl?: string
7 signUpDate: number
8 createdFromUrlId?: string
9 loginCount?: number
10 avatarSrc?: string
11 optedInNotifications?: boolean
12 optedInSubscriptionNotifications?: boolean
13 displayLabel?: string
14 displayName?: string
15 isAccountOwner?: boolean // Права адміністратора - SSO-користувачі з цим прапором тарифікуються як SSO-адміністратори (окремо від звичайних SSO-користувачів)
16 isAdminAdmin?: boolean // Права адміністратора - SSO-користувачі з цим прапором тарифікуються як SSO-адміністратори (окремо від звичайних SSO-користувачів)
17 isCommentModeratorAdmin?: boolean // Права модератора - SSO-користувачі з цим прапором тарифікуються як SSO-модератори (окремо від звичайних SSO-користувачів)
18 /** Якщо null, контроль доступу не буде застосований до користувача. Якщо порожній список, цей користувач не зможе бачити жодних сторінок або використовувати @mention інших користувачів. **/
19 groupIds?: string[] | null
20 createdFromSimpleSSO?: boolean
21 /** Не дозволяти іншим користувачам бачити активність цього користувача, включно з коментарями, у його профілі. За замовчуванням true для забезпечення захищених профілів. **/
22 isProfileActivityPrivate?: boolean
23 /** Не дозволяти іншим користувачам залишати коментарі в профілі цього користувача або бачити наявні коментарі профілю. За замовчуванням false. **/
24 isProfileCommentsPrivate?: boolean
25 /** Не дозволяти іншим користувачам надсилати цьому користувачу приватні повідомлення. За замовчуванням false. **/
26 isProfileDMDisabled?: boolean
27 karma?: number
28 /** Необов'язкова конфігурація значків користувача. **/
29 badgeConfig?: {
30 /** Масив ID значків для призначення користувачу. Обмежено 30 значками. Порядок зберігається. Це глобальні значки, видимі на всіх сторінках. **/
31 badgeIds: string[]
32 /** Масив ID значків, обмежених поточною сторінкою (urlId). Ці значки відображаються лише на сторінці, де вони були призначені. **/
33 pageBadgeIds?: string[]
34 /** Якщо true, замінює всі існуючі відображувані значки на надані. Глобальні та сторінково-обмежені значки переоприділяються незалежно. Якщо false, додає до наявних значків. **/
35 override?: boolean
36 /** Якщо true, оновлює властивості відображення значків згідно з конфігурацією орендаря. **/
37 update?: boolean
38 }
39}
40

Білінг для SSO-користувачів

SSO-користувачів тарифікують по-різному залежно від їхніх прапорців дозволів:

  • Regular SSO Users: Користувачі без прав адміністратора або модератора тарифікуються як звичайні SSO-користувачі
  • SSO Admins: Користувачі з прапорцями isAccountOwner або isAdminAdmin тарифікуються окремо як SSO Admins (такий же тариф, як для звичайних адмінів орендаря)
  • SSO Moderators: Користувачі з прапорцем isCommentModeratorAdmin тарифікуються окремо як SSO Moderators (такий же тариф, як для звичайних модераторів)

Важливо: Щоб запобігти подвійній оплаті, система автоматично видаляє дублікати SSO-користувачів у порівнянні зі звичайними користувачами орендаря та модераторами за адресою електронної пошти. Якщо SSO-користувач має ту ж саму електронну пошту, що й звичайний користувач орендаря або модератор, за нього не буде стягнено плату двічі.

Контроль доступу

Користувачів можна розбити на групи. Саме для цього служить поле groupIds, і воно необов'язкове.

@Mentions

За замовчуванням @mentions використовуватиме username для пошуку інших sso-користувачів при введенні символу @. Якщо використовується displayName, то результати, що відповідають username, будуть проігноровані, коли є збіг по displayName, і результати пошуку @mention використовуватимуть displayName.

Підписки

У FastComments користувачі можуть підписатися на сторінку, клацнувши значок дзвінка у віджеті коментарів і натиснувши Subscribe.

Для звичайного користувача ми надсилаємо їм електронні листи з повідомленнями на основі його налаштувань повідомлень.

Для SSO-користувачів ми розділили це для зворотної сумісності. Користувачі отримуватимуть ці додаткові електронні листи з повідомленнями про підписку лише якщо ви встановите optedInSubscriptionNotifications в true.

Значки

Ви можете призначати значки SSO-користувачам за допомогою властивості badgeConfig. Значки — це візуальні індикатори, які з'являються поруч із іменем користувача в коментарях.

  • badgeIds - Масив ID значків для призначення користувачу. Це глобальні значки, видимі на всіх сторінках. Повинні бути дійсними ID значків, створеними у вашому обліковому записі FastComments. Обмежено 30 значками.
  • pageBadgeIds - Необов'язковий масив ID значків, обмежених поточною сторінкою (urlId). Ці значки відображаються лише на сторінці, де вони були призначені. Різні сторінки можуть мати різні сторінково-обмежені значки для одного й того ж користувача.
  • override - Якщо true, всі існуючі відображувані значки будуть замінені на надані. Глобальні та сторінково-обмежені значки переоприділяються незалежно — переоприділення глобальних значків не впливає на сторінково-обмежені, і навпаки. Якщо false або не вказано, надані значки будуть додані до наявних.
  • update - Якщо true, властивості відображення значків будуть оновлюватися з конфігурації орендаря щоразу, коли користувач входить в систему.

Структура підписки Internal Link

Об'єкт Subscription представляє підписку для користувача.

Subscription objects are created when a user clicks the notification bell in the comment widget and clicks "Підписатися на цю сторінку".

Підписки також можна створювати через API.

Наявність об'єкта Subscription призводить до створення об'єктів Notification і надсилання електронних листів, коли на корені пов'язаної сторінки, для якої призначена підписка, з'являються нові коментарі. Надсилання електронних листів залежить від типу користувача. Для звичайних користувачів це залежить від optedInNotifications. Для SSO-користувачів це залежить від optedInSubscriptionNotifications. Зверніть увагу, що деякі застосунки можуть не мати поняття веб-доступної сторінки; у такому випадку просто встановіть urlId в id елемента, на який ви підписуєтесь (те ж значення urlId, яке ви передали б віджету коментарів).

Структура об'єкта Subscription виглядає так:

Структура Subscription
Copy Copy
1
2interface Subscription {
3 id: string
4 tenantId: string
5 /** У SSO ідентифікатор користувача має формат `<tenant id>:<user id>`. **/
6 userId: string
7 anonUserId?: string
8 urlId: string
9 url?: string
10 pageTitle?: string
11 createdAt: string // рядок дати
12}
13

Структура щоденного використання орендаря Internal Link

Об'єкт TenantDailyUsage представляє використання для орендаря за конкретний день. Якщо для певного орендаря в певний день не було активності, у цей день не буде об'єкта TenantDailyUsage.

Об'єкт TenantDailyUsage не є в режимі реального часу і може відставати від фактичного використання на декілька хвилин.

Структура об'єкта TenantDailyUsage має такий вигляд:

Структура TenantDailyUsage
Copy Copy
1
2export interface TenantDailyUsage {
3 yearNumber: number
4 monthNumber: number
5 dayNumber: number
6 commentFetchCount?: number
7 commentCreateCount?: number
8 conversationCreateCount?: number
9 voteCount?: number
10 accountCreatedCount?: number
11 userMentionSearch?: number
12 hashTagSearch?: number
13 gifSearchTrending?: number
14 gifSearch?: number
15 apiCreditsUsed?: number
16 createdAt: string
17 billed: boolean
18 /** Ігнорується для білінгу. **/
19 ignored: boolean
20}
21

Структура орендаря Internal Link

Tenant визначає клієнта FastComments.com. Вони можуть бути створені через API орендарями з доступом до white labeling. White labeled tenants не можуть створювати інших white labeled tenants (дозволено тільки один рівень вкладеності).

Структура об'єкта Tenant виглядає так:

Структура Tenant
Copy Copy
1
2export enum SiteType {
3 Unknown = 0,
4 WordPress = 1
5}
6
7/** Це також можна обробити через DomainConfig API. **/
8export interface TenantDomainConfig {
9 domain: string
10 emailFromName?: string
11 emailFromEmail?: string
12 createdAt?: string,
13 siteType?: FastCommentsSiteType, // ймовірно, ви хочете Unknown
14 logoSrc?: string, // шлях до необробленого зображення
15 logoSrc100px?: string, // змінений розмір для ескізів
16 footerUnsubscribeURL?: string,
17 emailHeaders?: Record<string, string>,
18 disableUnsubscribeLinks?: boolean,
19 dkim?: {
20 domainName: string,
21 keySelector: string,
22 privateKey: string
23 }
24}
25
26export interface TenantBillingInfo {
27 name: string
28 address: string
29 city: string
30 state: string
31 zip: string
32 country: string
33}
34
35export enum TenantPaymentFrequency {
36 Monthly = 0,
37 Annually = 1
38}
39
40export interface Tenant {
41 id: string
42 name: string
43 email?: string
44 signUpDate: number; // number через "legacy" причини
45 packageId?: string | null
46 paymentFrequency?: TenantPaymentFrequency
47 billingInfoValid?: boolean
48 billingHandledExternally?: boolean
49 createdBy?: string
50 isSetup?: boolean
51 domainConfiguration: FastCommentsAPITenantDomainConfig[]
52 billingInfo?: FastCommentsAPITenantBillingInfo
53 stripeCustomerId?: string
54 stripeSubscriptionId?: string
55 stripePlanId?: string
56 enableProfanityFilter?: boolean
57 enableSpamFilter?: boolean
58 lastBillingIssueReminderDate?: string
59 removeUnverifiedComments?: boolean
60 unverifiedCommentsTTLms?: number
61 commentsRequireApproval?: boolean
62 autoApproveCommentOnVerification?: boolean
63 sendProfaneToSpam?: boolean
64 /** @readonly - Обчислюється на основі packageId. **/
65 hasFlexPricing?: boolean
66 /** @readonly **/
67 flexLastBilledAmount?: number
68 /** @readonly - Обчислюється на основі packageId. **/
69 hasAuditing?: boolean
70 /** Ви можете зберегти у tenant пару ключ-значення, яку можна використовувати для запитів. Ключі не можуть містити "." або "$", або бути довшими за 100 символів. Значення не можуть бути довшими за 2000 символів. **/
71 meta?: Record<string, string | null>
72}
73

Структура користувача Internal Link

User — це об'єкт, що представляє найбільш загальний знаменник усіх користувачів.

Майте на увазі, що в FastComments у нас є кілька різних сценаріїв використання для користувачів:

  • Безпечний SSO
  • Простий SSO
  • Користувачі орендаря (наприклад: Адміністратори)
  • Коментатори

Цей API призначений для Коментаторів та користувачів, створених через Простий SSO. Насправді будь-який користувач, створений через ваш сайт, може бути отриманий через цей API. Користувачів орендаря також можна отримати цим способом, але ви отримаєте більше інформації, взаємодіючи з /tenant-users/ API.

Для Secure SSO будь ласка використовуйте /sso-users/ API.

Ви не можете оновлювати ці типи користувачів. Вони створили свій акаунт через ваш сайт, тому ми надаємо базовий доступ лише для читання, але ви не можете вносити зміни. Якщо ви хочете мати такий тип потоку — вам потрібно налаштувати Secure SSO.

Структура об'єкта User наступна:

Структура об’єкта User
Copy Copy
1
2export interface User {
3 /** Це також id, який використовується як userId в об'єктах коментарів. **/
4 id: string
5 username: string
6 /** Наприклад, посилання на блог коментатора. **/
7 websiteUrl?: string
8 email: string
9 signUpDate: number
10 createdFromUrlId: string
11 createdFromTenantId: string
12 avatarSrc?: string
13 locale: FastCommentsLocale
14 displayLabel?: string
15 karma?: number
16}
17

Структура голосу Internal Link

Об'єкт Vote представляє голос, залишений користувачем.

Взаємозв'язок між коментарями та голосом визначається через commentId.

Структура об'єкта Vote виглядає так:

Структура Vote
Copy Copy
1
2interface Vote {
3 id: string
4 urlId: string
5 commentId: string
6 userId: string
7 direction: 1 | -1
8 createdAt: string
9}
10

Структура конфігурації питання Internal Link

FastComments надає спосіб створювати запитання та агрегувати їхні результати. Приклад запитання (надалі — QuestionConfig) може бути рейтингом у вигляді зірок, повзунком або питанням NPS (визначається через type).

Дані запитання можна агрегувати окремо, разом, з часом, загалом, за сторінкою тощо.

Фреймворк має всі можливості, необхідні для створення клієнтських віджетів (з вашим сервером перед цим API), панелей адміністратора та інструментів звітності.

Спочатку потрібно визначити QuestionConfig. Структура виглядає так:

Структура QuestionConfig
Copy Copy
1
2type QuestionConfigType = 'nps' | 'slider' | 'star' | 'thumbs';
3
4interface QuestionConfig {
5 id: string
6 tenantId: string
7 name: string
8 question: string
9 helpText?: string
10 createdAt: string
11 createdBy: string
12 /** ТІЛЬКИ ДЛЯ ЧИТАННЯ - збільшується для кожної нової відповіді. **/
13 usedCount: number
14 /** Рядок дати, коли конфігурація була востаннє використана (залишено результат). **/
15 lastUsed?: string
16 type: QuestionConfigType
17 numStars?: number
18 min?: number
19 max?: number
20 defaultValue?: number
21 labelNegative?: string
22 labelPositive?: string
23 subQuestionIds?: string[]
24 alwaysShowSubQuestions?: boolean
25 reportingOrder: number
26}
27

Структура результату питання Internal Link

Щоб зберегти результати для питань, ви створюєте QuestionResult. Потім ви можете агрегувати результати питань, а також зв'язувати їх із коментарями для цілей звітності.

Структура QuestionResult
Copy Copy
1
2interface QuestionResultMeta {
3 name: string
4 values: string[]
5}
6
7interface QuestionResult {
8 id: string
9 tenantId: string
10 urlId: string
11 anonUserId?: string
12 userId?: string
13 createdAt?: string
14 value: number
15 commentId?: string
16 questionId: string
17 meta?: QuestionResultMeta[]
18}
19

Структура значка користувача Internal Link

UserBadge — це об'єкт, який представляє бейдж, призначений користувачеві в системі FastComments.

Бейджі можуть призначатися користувачам автоматично на основі їхньої активності (наприклад, кількість коментарів, час відповіді, статус ветерана) або вручну адміністраторами сайту.

Структура об'єкта UserBadge така:

Структура UserBadge
Copy Copy
1
2export interface UserBadge {
3 /** Унікальний ідентифікатор цього призначення бейджа користувачу */
4 id: string
5 /** ID користувача, якому призначено цей бейдж */
6 userId: string
7 /** ID визначення бейджа з каталогу бейджів тенанта */
8 badgeId: string
9 /** ID тенанта, який створив/призначив цей бейдж */
10 fromTenantId: string
11 /** Коли цей бейдж було створено (мілісекунди від початку епохи) */
12 createdAt?: number
13 /** Коли цей бейдж було отримано користувачем (мілісекунди від початку епохи) */
14 receivedAt?: number
15 /**
16 * Тип бейджа:
17 * 0=CommentCount, 1=CommentUpVotes, 2=CommentReplies, 3=CommentsPinned,
18 * 4=Veteran, 5=NightOwl, 6=FastReplyTime, 7=ModeratorCommentsDeleted,
19 * 8=ModeratorCommentsApproved, 9=ModeratorCommentsUnapproved, 10=ModeratorCommentsReviewed,
20 * 11=ModeratorCommentsMarkedSpam, 12=ModeratorCommentsMarkedNotSpam, 13=RepliedToSpecificPage,
21 * 14=Manual
22 */
23 type: number
24 /** Для бейджів, що залежать від порогу, значення порога */
25 threshold?: number
26 /** Назва/мітка бейджа */
27 name?: string
28 /** Детальний опис бейджа */
29 description?: string
30 /** Текст, відображений на бейджі */
31 displayLabel?: string
32 /** URL до зображення, що відображається на бейджі */
33 displaySrc?: string
34 /** Колір фону бейджа (шістнадцятковий код) */
35 backgroundColor?: string
36 /** Колір рамки бейджа (шістнадцятковий код) */
37 borderColor?: string
38 /** Колір тексту на бейджі (шістнадцятковий код) */
39 textColor?: string
40 /** Додатковий CSS-клас для стилізації */
41 cssClass?: string
42 /** Для бейджів ветерана — часовий поріг у мілісекундах */
43 veteranUserThresholdMillis?: number
44 /** Чи відображається цей бейдж у коментарях користувача */
45 displayedOnComments: boolean
46 /** Порядок відображення бейджа */
47 order?: number
48 /** Якщо встановлено, цей бейдж відображається лише на сторінці з відповідним urlId. Null для глобальних бейджів. */
49 urlId?: string | null
50}
51

Структура прогресу значка користувача Internal Link


UserBadgeProgress — це об'єкт, який представляє прогрес користувача щодо здобуття різних значків у системі FastComments.

Це відстеження допомагає визначити, коли користувачі повинні отримувати автоматичні значки на основі їхньої активності та участі у вашій спільноті.

Структура об'єкта UserBadgeProgress виглядає так:

Структура UserBadgeProgress
Copy Copy
1
2export interface UserBadgeProgress {
3 /** Унікальний ідентифікатор цього запису прогресу */
4 id: string
5 /** ID орендаря (tenant), якому належить цей запис прогресу */
6 tenantId: string
7 /** ID користувача, за яким відстежується цей запис прогресу */
8 userId: string
9 /** ID першого коментаря користувача в системі */
10 firstCommentId?: string
11 /** Дата першого коментаря користувача (мілісекунди від початку епохи) */
12 firstCommentDate?: number
13 /** Автоматично обчислений коефіцієнт довіри на основі активності користувача */
14 autoTrustFactor?: number
15 /** Коефіцієнт довіри, встановлений вручну адміністраторами */
16 manualTrustFactor?: number
17 /** Детальний об'єкт прогресу з різними метриками, ключі відповідають enum BadgeType */
18 progress: {
19 /** 0: CommentCount - Кількість коментарів, які залишив користувач */
20 '0'?: number
21 /** 1: CommentUpVotes - Кількість upvotes, які отримав користувач */
22 '1'?: number
23 /** 2: CommentReplies - Кількість відповідей, які надав користувач */
24 '2'?: number
25 /** 3: CommentsPinned - Кількість закріплених коментарів, які має користувач */
26 '3'?: number
27 /** 4: Veteran - Вік облікового запису користувача */
28 '4'?: number
29 /** 5: NightOwl - Кількість разів, коли користувач публікував у нічний час */
30 '5'?: number
31 /** 6: FastReplyTime - Середній час відповіді в мілісекундах */
32 '6'?: number
33 /** 7: ModeratorCommentsDeleted - Для значків модератора, кількість видалених коментарів */
34 '7'?: number
35 /** 8: ModeratorCommentsApproved - Для значків модератора, кількість схвалених коментарів */
36 '8'?: number
37 /** 9: ModeratorCommentsUnapproved - Для значків модератора, кількість несхвалених коментарів */
38 '9'?: number
39 /** 10: ModeratorCommentsReviewed - Для значків модератора, кількість переглянутих коментарів */
40 '10'?: number
41 /** 11: ModeratorCommentsMarkedSpam - Для значків модератора, кількість коментарів, позначених як спам */
42 '11'?: number
43 /** 12: ModeratorCommentsMarkedNotSpam - Для значків модератора, кількість коментарів, позначених як не спам */
44 '12'?: number
45 /** 13: RepliedToSpecificPage - Для кожної сторінки, кількість відповідей */
46 '13'?: Record<string, number>
47 }
48}
49
---

На завершення

Ми сподіваємося, що наша документація API була для вас вичерпною та зрозумілою. Якщо ви знайдете будь-які прогалини, повідомте нам нижче.