The FastComments API

FastComments provides an API for interacting with many resources. Build integrations with our platform, or even build your own clients!

In this documentation, you will find all supported resources by the API documented with their request and response types.

For Enterprise customers, all API access is captured in the Audit Log.


The API is authenticated by passing your api key as either an X-API-KEY header or API_KEY query parameter. You will also need your tenantId for making API calls. This can be retrieved from the same page as your api key.

Authentication Option One - Headers

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

Authentication Option Two - Query Parameters

  • Query Param: API_KEY
  • Query Param: tenantId

AuditLog Structure 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 Structure
Copy Copy
2interface AuditLog {
3 id: string;
4 userId?: string;
5 username?: string;
6 resourceName: string;
7 crudType: 'c' | 'r' | 'u' | 'd' | 'login';
8 from: string;
9 url?: string;
10 ip?: string;
11 when: string;
12 description?: string;
13 serverStartDate: string;
14 objectDetails?: object;

The audit log is immutable. It also cannot be written to manually. may only decide when to write to the audit log. However, you may read from it via this API.

Events in the audit log expire after two years.

Comment Structure Internal Link

A Comment object represents a comment left by a user.

The relationship between parent and child comments is defined via parentId.

The structure for the Comment object is as follows:

Comment Structure
Copy Copy
2interface Comment {
3 /** READONLY: Set to true if the spam engine determined the comment was spam. **/
4 aiDeterminedSpam?: boolean
5 /** Whether the comment is approved to show. Set to true when saving the comment, else it will be hidden. **/
6 approved?: boolean
7 /** The user's avatar. **/
8 avatarSrc?: string
9 /** The commenter's raw comment. **/
10 comment: string
11 /** READONLY: The commenter's comment parsed into HTML. **/
12 commentHTML?: string
13 /** The commenter's email. Required if anonymous commenting is off. **/
14 commenterEmail?: string
15 /** The commenter's link (for example, their blog). **/
16 commenterLink?: string
17 /** The commenter's name. Always required. If not available, set to something like "Anonymous". **/
18 commenterName: string
19 /** The date the comment was left, in UTC epoch. **/
20 date: number
21 /** The "display label" for the comment - for example "Admin", "Moderator", or something like "VIP User". **/
22 displayLabel?: string
23 /** The domain the comment was posted on. **/
24 domain?: string
25 /** READONLY: The number of times the comment was flagged. **/
26 flagCount?: number
27 /** READONLY: The #hashtags written in the comment that were successfully parsed. **/
28 hashTags?: CommentHashTag[]
29 /** READONLY: Does the comment contain images? **/
30 hasImages?: boolean
31 /** READONLY: Does the comment contain links? **/
32 hasLinks?: boolean
33 /** READONLY: The unique comment id. **/
34 id: string
35 /** READONLY: Did the current user block the user that wrote this comment? **/
36 isBlocked?: boolean
37 /** READONLY: Is the comment by an admin? Automatically set based on userId. **/
38 isByAdmin?: boolean
39 /** READONLY: Is the comment by a moderator? Automatically set based on userId. **/
40 isByModerator?: boolean
41 /** READONLY: Is the flagged by the currently logged-in user (contextUserId)? **/
42 isFlagged?: boolean
43 /** Is the comment pinned? **/
44 isPinned?: boolean
45 /** Is the comment spam? **/
46 isSpam?: boolean
47 /** READONLY: Is the comment voted down for the current user (contextUserId)? **/
48 isVotedDown?: boolean
49 /** READONLY: Is the comment voted up for the current user (contextUserId)? **/
50 isVotedUp?: boolean
51 /** The locale the comment is in. If not provided, will be derived from the language accept HTTP header. **/
52 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'
53 /** READONLY: The @mentions written in the comment that were successfully parsed. **/
54 mentions?: CommentUserMention[]
55 /** Optional metadata associated with the comment. **/
56 meta?: Record<string, string | number | boolean>
57 /** The optional list of moderation group ids associated with this comment. **/
58 moderationGroupIds?: string[]|null
59 /** READONLY: The id of the vote object that corresponds to the vote from the current user (contextUserId) on this comment. **/
60 myVoteId?: string
61 /** Whether notifications were sent for this comment for commenters. To prevent notifications being sent on imports, set this to true. **/
62 notificationSentForParent?: boolean
63 /** Whether notifications were sent for this comment for tenant users. To prevent notifications being sent on imports, set this to true. **/
64 notificationSentForParentTenant?: boolean
65 /** The title of the page this comment was on. **/
66 pageTitle?: string
67 /** If we're replying to a comment, this is the ID that we are replying to. **/
68 parentId?: string|null
69 /** Whether the comment is marked reviewed. **/
70 reviewed: boolean
71 /** The tenant id where the comment belongs. **/
72 tenantId: string
73 /** The user that wrote the comment. Created automatically when saving a comment with a name/email. **/
74 userId?: string|null
75 /** The URL to the location that this comment is visible, like a blog post. **/
76 url: string
77 /** A "cleaned" version of the urlId you passed us. When saving, you specify this field, but when you fetch the comment back this will be "cleaned" and your original value moved to "urlIdRaw". **/
78 urlId: string
79 /** READONLY: The original urlId you passed us. **/
80 urlIdRaw?: string
81 /** Is the user and this comment verified? **/
82 verified: boolean
83 /** Number of votes up. **/
84 votesUp?: number
85 /** Number of votes down. **/
86 votesDown?: number
87 /** The "karma" of the comment (= votes up - votes down). **/
88 votes?: number

Some of these fields are marked READONLY - these are returned by the API but cannot be set.

Comment Text Structure

Comments are written in a FastComments flavor of markdown, which is just markdown plus traditional bbcode style tags for images, like [img]path[/img].

Text is stored in two fields. The text the user entered is stored unmodified in the comment field. This is rendered and stored in the commentHTML field.

The allowed HTML tags are b, u, i, strike, pre, span, code, img, a, strong, ul, ol, li, and br.

It's recommended to render the HTML, since it is a very small subset of HTML, building a renderer is pretty straightforward. There are multiple libraries for React Native and Flutter, for instance, to help with this

You may choose to render the un-normalized value of the comment field. An example parser is here..

The example parser could also be adjusted to work with HTML, and transform the HTML tags into expected elements to render for your platform.


When users are tagged in a comment, the information is stored in a list called mentions. Each object in that list has the following structure.

The Comment Mentions Object
Copy CopyRun External Link
2interface CommentUserMention {
3 /** The user id. For SSO users, this will have your tenant id prefixed. **/
4 id: string
5 /** The final @mention tag text, including the @ symbol. **/
6 tag: string
7 /** The original @mention tag text, including the @ symbol. **/
8 rawTag: string
9 /** What type of user was tagged. user = account. sso = SSOUser. **/
10 type: 'user'|'sso'
11 /** If the user opts out of notifications, this will still be set to true. **/
12 sent: boolean


When hashtags are used and successfully parsed, the information is stored in a list called hashTags. Each object in that list has the following structure.

The Comment HashTag Object
Copy CopyRun External Link
2interface CommentHashTag {
3 /** The hashtag id. **/
4 id: string
5 /** The final #hashtag tag text, including the # symbol. **/
6 tag: string
7 /** If the hashtag is associated with a custom URL, this will be defined. **/
8 url?: string

HashTag Structure Internal Link

A HashTag object represents a tag that can be left by a user. HashTags can be used to link to an external piece of content or to tie related comments together.

The structure for the HashTag object is as follows:

HashTag Structure
Copy Copy
2interface HashTag {
3 /** Should start with the "#" or desired character. **/
4 tag: string
5 /** An optional URL that the hashtag can point to. Instead of filtering comments by hashtag, the UI will redirect to this upon click. **/
6 url?: string
7 /** READONLY **/
8 createdAt: string


  • 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.

Page Structure Internal Link

A Page object represents the page that many comments may belong to. This relationship is defined by urlId.

A Page stores information such as the page title, comment count, and urlId.

The structure for the Page object is as follows:

Page Structure
Copy Copy
2interface Page {
3 id: string
4 urlId: string
5 url: string
6 title?: string
7 createdAt: string
8 commentCount: number
9 rootCommentCount: number
10 /** Setting this to null means all SSO users can see the page. An empty list means it is closed to all users. **/
11 accessibleByGroupIds?: string[] | null

SSOUser Structure Internal Link

FastComments provides an easy to use SSO solution. Updating a user's information with the HMAC-based integration is as simple as having the user load the page with an updated payload.

However, it may be desirable to manage a user outside that flow, to improve consistency of your application.

The SSO User API provides a way to CRUD objects that we call SSOUsers. These objects are different from regular Users and kept separate for type safety.

The structure for the SSOUser object is as follows:

SSOUser Structure
Copy Copy
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 displayLabel?: string
13 displayName?: string
14 isAccountOwner?: boolean
15 isAdminAdmin?: boolean
16 isCommentModeratorAdmin?: boolean
17 /** If null, Access Control will not be applied to the user. If an empty list, this user will not be able to see any pages or @mention other users. **/
18 groupIds?: string[] | null
19 createdFromSimpleSSO?: boolean
20 /** Don't let other users see this user's activity, including comments, on their profile. Default is true to provide secure profiles by default. **/
21 isProfileActivityPrivate?: boolean

Access Control

Users can be broken into groups. This is what the groupIds field is for, and is optional.


By default @mentions will use username to search for other sso users when the @ character is typed. If displayName is used, then results matching username will be ignored when there is a match for displayName, and the @mention search results will use displayName.

TenantDailyUsage Structure Internal Link

A TenantDailyUsage object represents the usage for a tenant on a given day. If there was no activity for a given tenant on a given day, that day will not have a TenantDailyUsage object.

The TenantDailyUsage object is not real time and may be minutes behind actual usage.

The structure for the TenantDailyUsage object is as follows:

TenantDailyUsage Structure
Copy Copy
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 /** Ignored for billing. **/
19 ignored: boolean

Tenant Structure Internal Link

The Tenant defines a customer. They can be created via the API by tenants with white labeling access. White labeled tenants cannot create other white labeled tenants (only one level of nesting is allowed).

The structure for the Tenant object is as follows:

Tenant Structure
Copy Copy
2export enum SiteType {
3 Unknown = 0,
4 WordPress = 1
7/** This can also be handled via the DomainConfig API. **/
8export interface TenantDomainConfig {
9 domain: string
10 emailFromName?: string
11 emailFromEmail?: string
12 createdAt?: string,
13 siteType?: FastCommentsSiteType, // you probably want Unknown
14 logoSrc?: string, // raw image path
15 logoSrc100px?: string, // resized for thumbnails
16 footerUnsubscribeURL?: string,
17 emailHeaders?: Record<string, string>,
18 disableUnsubscribeLinks?: boolean,
19 dkim?: {
20 domainName: string,
21 keySelector: string,
22 privateKey: string
23 }
26export interface TenantBillingInfo {
27 name: string
28 address: string
29 city: string
30 state: string
31 zip: string
32 country: string
35export enum TenantPaymentFrequency {
36 Monthly = 0,
37 Annually = 1
40export interface Tenant {
41 id: string
42 name: string
43 email: string
44 signUpDate: number; // number due to "legacy" reasons
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 - Is calculated based on packageId. **/
65 hasFlexPricing?: boolean
66 /** @readonly **/
67 flexLastBilledAmount?: number
68 /** @readonly - Is calculated based on packageId. **/
69 hasAuditing?: boolean

Vote Structure Internal Link

A Vote object represents a vote left by a user.

The relationship between comments and vote is defined via commentId.

The structure for the Vote object is as follows:

Vote Structure
Copy Copy
2interface Vote {
3 id: string
4 urlId: string
5 commentId: string
6 userId: string
7 direction: 1 | -1
8 createdAt: string

In Conclusion

We hope you've found our API documentation thorough and easy to understand. If you find any gaps, let us know below.