Console API
The same API we use in our Console is available via HTTP with API Key authentication. You may use this API to automate some of your tasks or build a mini-console of your own. This API allows you to access data and perform actions on a specific website. Account-level endpoints, such as creating a new website, managing subscription/billing are not available.
Getting Started
- Create a Console API key at Console β Settings β API.
- In each request, set the
X-API-KEYheader to the API key you created. - The Base URL is
https://talk.hyvor.com/api/console/v1/{website_id} - All endpoints require
website_idin the URL. You can find your website ID in the Console. - All endpoints return JSON data. The response will be an object or an array of objects.
- HTTP methods are as follows:
GET- Read a resource or a list of resourcesPOST- Create a resource, or perform an actionPATCH- Update a resourceDELETE- Delete a resource
- Request params can be set as JSON (recommended) or as
application/x-www-form-urlencoded.
User Authentication
By default, the Console API is authenticated as the owner of the website, giving access to all the endpoints. Also, when performing an action, it will be tracked as performed by the owner. For example, if you moderate a comment via the API, you will see it was moderated by the owner of the website in comment history. However, you can change the authenticating user.
To authenticate as a different moderator, set one of the following headers:
X-AUTH-USER-EMAIL- Email of the user's HYVOR account to authenticate as.X-AUTH-USER-SSO-ID- If your moderators are connected to an SSO account, you may use the SSO user ID (in your system) to authenticate as that user.
Note that the user must be a moderator of the website to authenticate as them.
Categories
Jump to each category
- Website
- Comments
- Reactions
- Ratings
- Pages
- Users
- Analytics
- Moderators
- Memberships
- Email Domain
- Rules
- Email Logs
- IP
- Domains
- Badges
- Single Sign-on
- Jobs
- Webhooks
- Integrations
- Media
In this documentation, we use TypeScript syntax to describe the request and response objects.
For example, type Response = { id: number } means that the response will be an
object with an id property of type number.
Website
Endpoints:
GET /website- Get website dataPATCH /website- Update website data
Objects:
Get website data
type Request = {}
type Response = WebsiteUpdate website data
type Request = Website // except id
type Response = WebsiteComments
Endpoints:
GET /comments- Get commentsGET /comments/unread-counts- Get unread comment countsPOST /comments/read- Mark comments as readPOST /comment- Post a commentGET /comment/{id}- Get a commentPATCH /comment/{id}- Update a commentDELETE /comment/{id}- Delete a commentPOST /comment/{id}/reply- Reply to a commentPOST /comment/{id}/vote- Vote on a commentGET /comment/{id}/voters- Get voters of a commentDELETE /comment/{id}/vote- Delete a vote on a commentGET /comment/{id}/flags- Get flags of a commentPOST /comment/{id}/flag- Create a flag on a commentDELETE /comment/{id}/flag- Delete a flag on a commentPOST /comments/bulk-moderate- Moderate multiple comments
Objects:
- Comment Object
- Comment History Object
- User Object
- Page Object
- Flag Object
- Vote Object
- Rating Object
- Reaction Object
Get comments
GET /comments type Request = {
type: null | 'published' | 'pending' | 'deleted' | 'spam' | 'flagged',
// filter by page
page_id: number | null,
page_identifier: string | null, // page-id set in the embed
// filter by user
user_htid: string | null, // ID with type: hyvor_100 | sso_100,
user_sso_id: string | null, // SSO user ID
// filter by IP
ip_address: string | null,
// filter by user's badge
badge_id: number | null,
// filter by other properties of the comment
filter: null | 'unread' | 'unreplied' | 'guest' | 'has_questions' | 'has_links' | 'has_media',
// search by comment text
search: string | null,
limit: number | null, // default: 50, max: 100
offset: number | null, // default: 0
before_id: number | null // for pagination (instead of offset)
}
type Response = Comment[]Note: If you set the search param, badge_id, and type=flagged will be ignored.
Get unread comment counts
Number of comments unread by moderators (has_mod_seen = 0) for each status. The total
is the sum of all statuses.
GET /comments/unread-counts type Request = {};
type Response = {
published: number,
pending: number,
spam: number,
deleted: number
}Mark comments as read
Mark comments as read by moderators (has_mod_seen = 1). If status is set, only
comments of that status will be marked as read. Otherwise, all comments will be marked as read.
This process is asynchronous.
POST /comments/read type Request = {
status: null | 'published' | 'pending' | 'deleted' | 'spam'
}
type Response = {}Post a Comment
Post a comment as a SSO or a guest user. It is not possible to post as a HYVOR user.
POST /comment type Request = {
page_id: number | null,
page_identifier: string | null, // page-id set in the embed
body: string | null, // in ProseMirror JSON format
body_html: string | null, // in HTML format
user_sso_id: string | null,
guest_name: string | null,
guest_email: string | null,
parent_id: number | null,
created_at: number | null, // unix timestamp
ip: string | null,
check_premoderation: boolean, // default: true
spam_detection: boolean, // default: true
rules: boolean // default: true
}
type Response = Comment- Either
page_idorpage_identifieris required. - Either
bodyorbody_htmlis required. - Either
user_sso_idorguest_nameis required.user_sso_idis the ID on your system. check_premoderation = falsewill bypass premoderation.spam_detection = falsewill bypass spam detection.rules = falsewill bypass rules.
Find more information about ProseMirror JSON format.
Get a comment
GET /comment/{id} type Request = {}
type Response = CommentUpdate a comment
PATCH /comment/{id} type Request = {
status: null | 'published' | 'pending' | 'deleted' | 'spam',
is_featured: boolean | null,
is_loved: boolean | null,
has_mod_seen: boolean | null,
body: string | null, // in ProseMirror JSON format
body_html: string | null, // in HTML format
created_at: number | null, // unix timestamp,
guest_name: string | null,
guest_email: string | null,
// Only considered if body or body_html is set
is_author: boolean, // default: false
check_premoderation: boolean, // default: true
spam_detection: boolean, // default: true
rules: boolean // default: true
}
type Response = Comment- Either
bodyorbody_htmlis required. is_author = truewill mark the update as made by the author of the comment. Otherwise it will be marked as made by the authenticated API user (a moderator).check_premoderation = falsewill bypass premoderation.spam_detection = falsewill bypass spam detection.rules = falsewill bypass rules.
Find more information about ProseMirror JSON format.
Delete a comment
DELETE /comment/{id} type Request = {}
type Response = {}Reply to a comment
By default, the website owner's account will be used to reply. See User Authentication to customize it.
POST /comment/{id}/reply type Request = {
body: string // in ProseMirror format
}
type Response = Comment;Vote on a comment
By default, the website owner's account will be used to vote. See User Authentication to customize it. If user_sso_id is set, respective user account will be used.
POST /comment/{id}/vote type Request = {
type: 'up' | 'down' | null // null to remove a vote
user_sso_id: string | null
}
type Response = Comment;Get voters of a comment
GET /comment/{id}/voters type Request = {
type: 'up' | 'down',
limit: number | null, // default: 25, max: 100
offset: number|null // default: 0
};
type Response = LoggedInUser[]Delete a vote on a comment
DELETE /comment/{id}/vote type Request = {
user_htid: string // ID of the user who voted, required. Ex: hyvor_100 | sso_100
}
type Response = {}Get flags of a comment
GET /comment/{id}/flags type Request = {
limit: number | null, // default: 25, max: 100
offset: number | null // default: 0
};
type Response = Flag[]Create a flag on a comment
POST /comment/{id}/flags type Request = {
reason: string | null
user_sso_id: string | null
};
type Response = CommentSet user_sso_id to flag as a specific SSO user. Otherwise, the user of the current Console API user will be used.
Delete a flag on a comment
DELETE /comment/{id}/flag type Request = {
flag_id: number // ID of the flag to delete
}
type Response = {}Moderate multiple comments
POST /comments/bulk-moderate type Request = {
// only one of user_htid/user_sso_id, ip_address or comment_ids should be set
user_htid: string | null, // ID with type: hyvor_100 | sso_100
user_sso_id: string | null, // SSO user ID
ip_address: string | null,
comment_ids: number[] | null,
status: 'published' | 'pending' | 'deleted' | 'spam'
}
type Response = {}Reactions
Endpoints:
GET /reactions- Get reactionsDELETE /reaction/{id}- Delete a reaction
Objects:
Get reactions
GET /reactions type Request = {
page_id: number | null,
user_htid: string | null, // ID with type: hyvor_100 | sso_100
user_sso_id: string | null, // SSO user ID
type: null | 'superb' | 'love' | 'wow' | 'sad' | 'laugh' | 'angry',
limit: number | null, // default: 50, max: 100
offset: number | null // default: 0
}
type Response = Reaction[]Delete a reaction
DELETE /reaction/{id} type Request = {}
type Response = {}Ratings
Endpoints:
GET /ratings- Get ratingsDELETE /rating/{id}- Delete a rating
Objects:
Get ratings
GET /ratings type Request = {
page_id: number | null,
user_htid: string | null, // ID with type: hyvor_100 | sso_100
user_sso_id: string | null, // SSO user ID
rating: number | null, // min: 1, max: 5
limit: number | null, // default: 50, max: 100
offset: number | null // default: 0
}
type Response = Rating[]Delete a rating
DELETE /rating/{id} type Request = {}
type Response = {}Pages
Endpoints:
GET /pages- Get pagesPOST /page- Create a pagePATCH /page/{id}- Update a pagePOST /page/{id}/reset- Reset page dataPOST /page/{id}/move- Move page data to another pageDELETE /page/{id}- Delete a page
{id} in the URL
By default {id} is the ID of the page set by Hyvor Talk (internal). You can find
this in the Page Object. However, for most cases, you may want to use
the page-id attribute you set in the embed. To use this, set the HTTP
header X-ID-Type to page_id.
Objects:
Get pages
GET /pages type Request = {
search: string | null, // search by title or identifier
filter: null | 'open' | 'closed' | 'premoderation_on',
sort: null | 'newest' | 'oldest' | 'recently_commented' | 'most_commented' | 'most_reactions' | 'most_ratings', // default: newest
limit: number | null, // default: 25, max: 100
offset: number | null // default: 0
}
type Response = Page[];Create a Page
Creates a new page with the given identifier. If a page with the same identifier already exists, it will be updated with the given data instead.
POST /page type Request = {
identifier: string, // unique page identifier (page-id)
url: string, // URL of the page
title: string | null,
author_email: string | null,
created_at: number | null // unix timestamp
}
type Response = Page;Update a Page
PATCH /page/{id} type Request = {
is_closed: boolean | null,
is_premoderation_on: boolean | null
author_email: string | null
}
type Response = Page;Reset page data
This endpoint will reset the data of the page (comments/reactions/ratings) you request. Use with caution. There is no undo.
POST /page/{id}/reset
type Request = {
is_closed: boolean | null,
is_premoderation_on: boolean | null
}
type Response = Page;Move page data
Use this endpoint to move all data from one page to another. This is useful when you change the page-id attribute of the embed.
POST /page/{id}/move type Request = {
to_page_id: number,
}
type Response = {};Delete a page
This endpoint will delete all data of the page (comments, reactions, ratings) and will delete the page too. Use with caution. There is no undo.
DELETE /page/{id}
type Request = {}
type Response = {}Users
Endpoints:
GET /users- Get usersGET /user/{id}- Get a user, with statsPATCH /user/{id}- Update a userGET /user/{id}/counts- Get comments and flags count of a userDELETE /user/{id}- Delete a userGET /user/{id}/email-notification- Get email notification subscription status of a userPOST /user/{id}/email-notification- Update email notification subscription status of a user
{id} in the URL
By default, {id} is the htid property in the User object. If you use Single Sign-on, it
makes sense to use the ID of the user in your system. To do this, set the HTTP header X-ID-Type to sso_user_id.
Objects:
Get users
GET /users type Request = {
search: string | null,
badge_id: number | null,
plan_id: number | null,
last_ip_address: string | null,
state: null | 'default' | 'banned' | 'shadowed' | 'trusted', // default: null
sort: null | 'recently_commented' | 'most_commented' | 'recently_seen' | 'recently_joined', // default: recently_commented
limit: number | null, // default: 25, max: 100
offset: number | null // default: 0
}
type Response = LoggedInUser[]search can be used to filter users:
- by name
- by exact HYVOR username (HYVOR users only)
- by exact email (SSO users only)
- by exact SSO ID
Get a user
GET /user/{id} type Request = {}
type Response = LoggedInUserUpdate a user
PATCH /user/{id} type Request = {
state: null | 'default' | 'banned' | 'shadowed' | 'trusted',
state_ends_at: number | null, // unix timestamp when the banned users are automatically unbanned
note: string | null,
badge_ids: number[] | null,
badge_ids_strategy: null | 'overwrite' | 'merge' | 'remove' // default: 'overwrite'
}
type Response = LoggedInUserGet comments and flags count of a user
GET /user/{id}/counts type Request = {}
type Response = {
comments: {
total: number,
published: number,
pending: number,
spam: number,
deleted: number
},
flags: {
received: number,
given: number
}
}Delete a user
DELETE /user/{id} type Request = {
data: boolean // set true to delete the user with all its data
}
type Response = {}Get email notification subscription status of a user
GET /user/{id}/email-notification type Request = {}
type Response = {
reply: boolean,
mention: boolean
}Update email notification subscription status of a user
POST /user/{id}/email-notification type Request = {
reply: boolean | null,
mention: boolean | null
}
type Response = {}Analytics
Endpoints:
GET /analytics/stats- Get website statisticsGET /analytics/credits- Get credit analyticsGET /analytics/comments- Get comment analytics
Get website statistics
GET /analytics/stats type Request = {}
type Response = {
comments: {
total: number,
last_30d: number
},
users: {
total: number,
last_30d: number
},
members: {
total: number,
last_30d: number
}
}Get credit analytics
GET /analytics/credits type Request = {
event: null | 'embed_comments' | 'embed_gated_content' | 'embed_comment_counts' | 'email_notifications' |
'spam_detection_akismet' | 'spam_detection_fortguard' | 'api_data',
start_timestamp: number | null,
end_timestamp: number | null,
group_by: 'day' | 'week' | 'month' | 'year'
}
type Response = {
timeseries: [
{
date: string, // YYYY-MM-DD 00:00:00,
credits: number,
events: number
},
...
]
}Get comment analytics
GET /analytics/comments type Request = {
start_timestamp: number | null,
end_timestamp: number | null,
group_by: 'day' | 'week' | 'month' | 'year'
}
type Response = {
timeseries: [
{
date: string, // YYYY-MM-DD 00:00:00,
count: number,
published: number,
pending: number,
spam: number,
deleted: number
},
...
]
}Moderators
Moderators can access the Console to moderate comments/users and change settings of your website.
Endpoints:
GET /mods- Get moderatorsPATCH /mod/{id}- Update a moderatorDELETE /mod/{id}- Delete a moderatorPOST /mod/{id}/make-owner- Make a moderator the ownerGET /mod-invites- Get moderator invitesPOST /mod-invite- Invite a moderatorPOST /mod-invite/{id}/resend- Resend a moderator inviteDELETE /mod-invite/{id}- Delete a mod invite
Objects:
Get moderators
GET /mods type Request = {}
type Response = Mod[]Update a moderator
PATCH /mod/{id} type Request = {
role: null | 'mod' | 'admin',
sso_user_htid: string | null, // ID with type: hyvor_100 | sso_100
is_alias_used: boolean | null
}
type Response = Modrole: You can change the role of a mod to admin or vice versa. The role of the owner
cannot be changed. See make-owner endpoint to transfer ownership of the website.
sso_user_htid: If your website uses SSO, you can set sso_user_htid to connect the moderator to a SSO user. This will allow the moderator to
moderate comments in the embed. Also, when replying from the Console, their SSO account will be used
instead of HYVOR account.
is_alias_used: If you have set up an alias for your website, comments of this
moderator will be posted with the alias. This is useful if you want to post comments as your
website.
Delete a moderator
DELETE /mod/{id} type Request = {}
type Response = {}Make a moderator the owner
This endpoint makes the given moderator the owner of the website. The current owner will be demoted to an admin. Only the current owner can access this endpoint.
POST /mod/{id}/make-owner type Request = {}
type Response = {}Get moderator invites
GET /mod-invites type Request = {}
type Response = ModInvite[]Invite a moderator
All moderators require a HYVOR account. username or email is the moderator's
HYVOR account username/email. An invitation email will be sent to the user and the user will be promoted
to a moderator/admin once the invitation is accepted.
POST /mod-invite type Request = {
// either username or email is required
username: string | null,
email: string | null,
role: 'mod' | 'admin',
}
type Response = ModInviteResend a moderator invite
POST /mod-invite/{id}/resend type Request = {}
type Response = {}Delete a moderator invite
DELETE /mod-invite/{id} type Request = {}
type Response = {}Memberships
Endpoints:
GET /memberships/stripe/connect- Get Stripe StatusPOST /memberships/stripe/connect/- Get Stripe onboarding URLGET /membership-plans- Get membership plansPOST /membership-plan- Create a membership planPATCH /membership-plan/{id}- Update a membership planDELETE /membership-plan/{id}- Delete a membership planGET /memberships/gated-content- Get gated contentPOST /memberships/gated-content- Create gated contentPATCH /memberships/gated-content/{id}- Update gated contentDELETE /memberships/gated-content/{id}- Delete gated content
Objects:
Get Stripe Status
GET /memberships/stripe/connect type Request = {}
type Response = {
is_connected: boolean,
data: StripeConnect | null
}Get Stripe onboarding URL
POST /memberships/stripe/connect/ type Request = {}
type Response = {
url: string // redirect here for Stripe onboarding
}Get membership plans
GET /membership-plans type Request = {}
type Response = Plan[]Create a membership plan
A website can have a maximum of 3 membership plans.
POST /membership-plan
type Request = {
name: string,
description: string | null,
features: string | null, // max length: 1024
monthly_price: number, // min: 1, max: 9999 Ex: 4.99
badge_id: number | null
}
type Response = PlanUpdate a membership plan
PATCH /membership-plan/{id} type Request = {
name: string | null,
description: string | null,
features: string | null, // max length: 1024
monthly_price: number | null, // min: 1, max: 9999 Ex: 4.99
badge_id: number | null
}
type Response = PlanDelete a membership plan
DELETE /membership-plan/{id} type Request = {}
type Response = {}Get gated content
GET /memberships/gated-content type Request = {
limit: number | null, // default: 10, max: 100
offset: number | null // default: 0
}
type Response = GatedContent[]Create gated content
POST /memberships/gated-content type Request = {
key: string, // key must be unique
content: string, // max length: 60,000
gate: string | null, // max length: 60,000
minimum_plan_id: number | null
}
type Response = GatedContentUpdate gated content
PATCH /memberships/gated-content/{id} type Request = {
key: string | null, // key must be unique
content: string | null, // max length: 60,000
gate: string | null, // max length: 60,000
minimum_plan_id: number | null
}
type Response = GatedContentDelete gated content
DELETE /memberships/gated-content/{id} type Request = {}
type Response = {}Email Domain
Endpoints:
POST /email/domain- Create an email domainPOST /email/domain/verify- Verify an email domainDELETE /email/domain- Delete an email domain
Objects:
Create an email domain
POST /email/domain type Request = {
domain: string // Ex: example.com
}
type Response = EmailDomainVerify an email domain
POST /email/domain/verify type Request = {}
type Response = {
data: {
verified: string,
debug: string | null
},
domain: EmailDomain
}Delete an email domain
DELETE /email/domain type Request = {}
type Response = {}Rules
Rules are used to automate moderation.
Endpoints:
GET /rules- Get rulesPOST /rule- Create a rulePATCH /rule/{id}- Update a ruleDELETE /rule/{id}- Delete a rule
Objects:
Get rules
GET /rules type Request = {}
type Response = Rule[]Create a rule
POST /rule type Request = Rule // except id
type Response = RuleUpdate a rule
PATCH /rule/{id} type Request = Rule // except id
type Response = RuleDelete a rule
DELETE /rule/{id} type Request = {}
type Response = {}Email Logs
Endpoints:
GET /email-logs- Get email logs
Objects:
Get email logs
GET /email-logs type Request = {
type: null | 'reply' | 'mention' | 'mod' | 'author',
user_htid: string | null, // ID with type: hyvor_100 | sso_100
user_sso_id: string | null,
limit: number | null, // default: 50, max: 100
offset: number | null // default: 0
}
type Response = EmailLog[]IP
Moderators can block users at the IP-level.
Endpoints:
GET /ips- Get IPsGET /ip/{ip}- Get IPPATCH /ip/{ip}- Change state of an IP
Objects:
Get IPs
This endpoint only returns IPs that have been banned, shadow-banned, trusted, or added a note about.
GET /ips
type Request = {
limit: number | null, // default: 25, max: 100
offset: number | null // default: 0
};
type Response = IP[]Get IP
GET /ip/{ip} type Request = {}
type Response = IPChange state of an IP
PATCH /ip/{ip} type Request = {
state: null | 'default' | 'banned' | 'shadowed' | 'trusted',
note: string | null,
state_ends_at: number | null
}
type Response = IPDomains
Endpoints:
GET /domains- Get domainsPOST /domain- Create a domainPATCH /domain/{id}- Update a domainDELETE /domain/{id}- Delete a domain
Objects:
Get domains
GET /domains type Request = {}
type Response = Domain[]Create a domain
POST /domain type Request = {
domain: string
}
type Response = DomainUpdate a domain
PATCH /domain/{id} type Request = {
domain: string
}
type Response = DomainDelete a domain
DELETE /domain/{id} type Request = {}
type Response = {}Badges
Endpoints:
GET /badges- Get badgesPOST /badge- Create a badgePATCH /badge/{id}- Update a badgeDELETE /badge/{id}- Delete a badge
Objects:
Get badges
GET /badges type Request = {}
type Response = Badge[]Create a badge
POST /badge type Request = {
text: string, // max length: 50
color: string, // hex color code Ex: #ff0000
background_color: string, // hex color code Ex: #0000ff
icon_url: string | null
}
type Response = BadgeUpdate a badge
PATCH /badge/{id} type Request = {
text: string | null, // max length: 50
color: string | null, // hex color code Ex: #ff0000
background_color: string, | null // hex color code Ex: #0000ff
icon_url: string | null
}
type Response = BadgeDelete a badge
DELETE /badge/{id} type Request = {}
type Response = {}Single Sign-on
Endpoints:
GET /sso/users- Get SSO usersPOST /sso/user- Create or update SSO userDELETE /sso/user- Delete a SSO user
Objects:
Get SSO users
GET /sso/users type Request = {
limit: number | null, // default: 50, max: 100
offset: number | null, // default: 0
search: string | null // search by name, email, or given ID
}
type Response = LoggedInUser[]Create or update SSO users
POST /sso/user type Request = {
id: string,
name: string,
email: string,
picture_url: string | null,
title: string | null,
website_url: string | null,
bio: string | null,
location: string | null,
}
type Response = LoggedInUserDelete a SSO user
DELETE /sso/user type Request = {
id: string,
data: boolean | null // default: false
}
type Response = {}id is the user ID in your system. By default, only user's profile data is deleted.
All comments made by the user will be shown with the name "Anonymous user". Set {data: true}, if you want to delete user's comments as well.
Jobs
Endpoints:
GET /jobs- Get jobsPOST /data/import/comments- Import commentsPOST /data/export- Export data
Objects:
Get jobs
GET /jobs type Request = {
type: null | 'import_comments' | 'import_newsletter_subscribers' | 'export' | 'bulk_moderate_comments'
}
type Response = Job[]Import comments
See importing docs for more details. Importing is asynchronous. We will notify the website owner via email when it's done.
POST /data/import/comments type Request = {
file: File,
format: 'wordpress' | 'disqus' | 'hyvor',
identifier_type: null | 'post_id' | 'relative_path' | 'absolute_url'
}
type Response = JobExport data
See exporting docs. Exporting is asynchronous. We will email to the given email (owner's email if empty) a link to download the file when it's ready.
POST /data/export type Request = {
format: 'hyvor_talk_json' | 'wordpress_xml' | 'newsletter_subscribers_csv',
from: number | null, // unix timestamp, filter comments by date (lower bound)
to: number | null, // unix timestamp, filter comments by date (upper bound)
email: string | null // if empty, owner's email will be used
}
type Response = JobWebhooks
Endpoints:
GET /webhooks- Get webhook configurationsPOST /webhook- Create a webhook configurationPATCH /webhook/{id}- Update a webhook configurationDELETE /webhook/{id}- Delete a webhook configurationGET /webhook/deliveries- Get webhook deliveries
Objects:
Get webhook configurations
GET /webhooks type Request = {}
type Response = WebhookConfiguration[]Create a webhook configuration
POST /webhook type Request = {
url: string,
event: [
'comment.create' | 'comment.update' | 'comment.delete' |
'reaction.created' | 'reaction.updated' | 'reaction.deleted' |
'rating.created' | 'rating.updated' | 'rating.deleted' |
'comment.vote.created' | 'comment.vote.updated' | 'comment.vote.deleted' |
'comment.flag.created' | 'comment.flag.deleted' |
'user.created' | 'user.updated' | 'media.created' | 'media.deleted' |
'memberships.subscription.created' |
'memberships.subscription.updated' | 'memberships.subscription.deleted'
] // one or more events can be present in the array
}
type Response = WebhookConfigurationUpdate a webhook configuration
PATCH /webhook/{id} type Request = {
url: string | null,
event: null | [
'comment.create' | 'comment.update' | 'comment.delete' |
'reaction.created' | 'reaction.updated' | 'reaction.deleted' |
'rating.created' | 'rating.updated' | 'rating.deleted' |
'comment.vote.created' | 'comment.vote.updated' | 'comment.vote.deleted' |
'comment.flag.created' | 'comment.flag.deleted' |
'user.created' | 'user.updated' | 'media.created' | 'media.deleted' | 'memberships.subscription.created' |
'memberships.subscription.updated' | 'memberships.subscription.deleted'
] // one or more events can be present in the array
}
type Response = WebhookConfigurationDelete a webhook configuration
DELETE /webhook/{id} type Request = {}
type Response = {}Get webhook deliveries
GET /webhook/deliveries type Request = {
limit: number | null, // default: 25, max: 100
offset: number | null // default: 0
}
type Response = WebhookDelivery[]Integrations
Endpoints:
GET /integrations/slack- Get Slack integration statusPOST /integrations/slack- Initialize Slack integrationPOST /integrations/slack/channel- Set a Slack ChannelDELETE /integrations/slack- Disconnect Slack integration
Objects:
Get Slack integration status
GET /integrations/slack type Request = {}
type Response = {
connection: SlackConnection
}Initialize Slack integration
POST /integrations/slack type Request = {}
type Response = {
url: string // redirect here for OAuth confirmation
}Set a Slack Channel
POST /integrations/slack/channel type Request = {
channel: string
}
type Response = {}Disconnect Slack integration
DELETE /integrations/slack type Request = {}
type Response = {}Media
Endpoints:
GET /media- Get mediaPOST /media/image- Upload an imageDELETE /media/{id}- Delete media
Objects:
Get media
GET /media type Request = {
limit: number | null, // default: 50, max: 100
offset: number | null // default: 0
}
type Response = Media[]Upload an image
POST /media/image type Request = {
image: File // max size: 5 MB,
// supported formats: jpg, jpeg, png, gif, svg, webp, apng, avif
}
type Response = MediaDelete media
DELETE /media/{id} type Request = {}
type Response = {}Objects
Website Object
interface Website = {
id: number,
name: string,
auth_type: 'hyvor' | 'sso',
auth_sso_type: null | 'stateless' | 'openid',
sso_stateless_private_key: string | null,
sso_stateless_login_url: string | null,
sso_stateless_is_keyless: boolean,
sso_openid_issuer_url: string | null,
sso_openid_client_id: string | null,
sso_openid_client_secret: string | null,
premoderation_status: 'off' | 'guest' | 'guest_and_new_commenters' | 'all', // default: 'off'
is_realtime_on: boolean,
realtime_typing: 'off' | 'on_without_typer' | 'on_with_typer',
is_realtime_online_count_on: boolean,
is_realtime_users_on: boolean, // default: true
is_user_profile_on: boolean,
is_keyboard_navigation_on: boolean,
is_ip_collection_on: boolean,
is_guest_commenting_on: boolean,
guest_commenting_email: 'no' | 'optional' | 'required',
guest_commenting_delay: number, // default: 1
default_avatar: string | null,
text_comment_box: string | null, // default: 'Write your comment...'
text_no_comments: string | null, // default: 'Be the first to comment...'
text_comment_button: string | null,
text_reply_box: string | null, // default: 'Reply to this comment...'
text_reply_button: string | null,
text_reactions: string | null, // default: 'What is your reaction?'
text_ratings: string | null, // default: 'What is your rating?'
text_comment_count_0: string | null,
text_comment_count_1: string | null,
text_comment_count_multi: string | null,
top_widget: 'none' | 'reactions' | 'ratings', // default: 'reactions'
ui_box_shadow: number, // default: 1
ui_box_roundness: number, // default: 4
ui_box_border_size: number, // default: 0
ui_box_width: number | null,
ui_button_roundness: number, // default: 4
ui_box_border_color: string, // default: 'aaaaaa'
ui_custom_css: string | null,
is_ch_new_on: boolean,
ch_new_color: string | null,
ch_upvote_1_threshold: number | null,
ch_upvote_2_threshold: number | null,
ch_upvote_1_color: string | null,
ch_upvote_2_color: string | null,
is_profile_pictures_on: boolean,
display_name_type: 'name' | 'username', // default: name
comments_per_request: number, // default: 50
replies_per_request: number, // default: 25
nested_levels: number, // default: 3
display_replied_to_type: 'none' | 'deep' | 'all', // default: 'deep'
comments_char_limit: number, // default: 50000
comments_min_char_limit: number, // default: 0
comments_editing_enabled: boolean,
comments_editing_timeout: number, // default: 0 (no timeout) in minutes
comments_force_guest_commenting: boolean,
is_emoji_enabled: boolean,
is_images_enabled: boolean,
is_embed_enabled: boolean,
is_math_enabled: boolean,
is_spam_detection_on: boolean,
spam_detection_provider: 'none' | 'akismet' | 'fortguard',
spam_detection_fortguard_content_score: number | null,
spam_detection_fortguard_languages: string[],
spam_detection_fortguard_languages_exclude: boolean,
spam_detection_fortguard_countries: string[],
spam_detection_fortguard_countries_exclude: boolean,
spam_detection_fortguard_sentiments: string[],
vote_type: 'both' | 'upvotes' | 'none', // default: 'both'
is_vote_viewing_on: boolean,
is_guest_voting_on: boolean,
sort: 'top' | 'newest' | 'oldest', // default: 'top'
language: string, // default: 'en-us'
note: string | null,
close_after_days: number,
color_text: string | null,
color_background_text: string | null, // default: '111111'
color_accent: string | null, // default: '000000'
color_accent_text: string | null, // default: 'ffffff'
color_box: string | null, // default: 'ffffff'
color_box_text: string | null, // default: '111111'
color_box_text_light: string | null, // default: '767676'
color_input: string | null,
color_dark_text: string | null,
color_dark_background_text: string | null, // default: 'ffffff'
color_dark_accent: string | null, // default: 'ffffff'
color_dark_accent_text: string | null, // default: '000000'
color_dark_box: string | null, // default: '232121'
color_dark_box_text: string | null, // default: 'ffffff'
color_dark_box_text_light: string | null, // default: 'aaaaaa'
color_dark_input: string | null,
color_theme: 'light' | 'dark' | 'os',
ratings_color: string | null, // default: 'ffcc48'
reaction_1: string | null,
reaction_2: string | null,
reaction_3: string | null,
reaction_4: string | null,
reaction_5: string | null,
reaction_6: string | null,
is_reaction_1_on: boolean,
is_reaction_2_on: boolean,
is_reaction_3_on: boolean,
is_reaction_4_on: boolean,
is_reaction_5_on: boolean,
is_reaction_6_on: boolean,
reaction_1_text: string | null,
reaction_2_text: string | null,
reaction_3_text: string | null,
reaction_4_text: string | null,
reaction_5_text: string | null,
reaction_6_text: string | null,
reaction_display_type: 'text' | 'image' | 'both', // default: 'both'
email_send_to_users: boolean,
notif_channel: 'email' | 'slack' | 'off', // default: 'email'
email_report_frequency: string,
email_company_name: string | null,
email_company_logo_url: string | null,
email_company_address: string | null,
email_alternate_address: string | null,
email_website_url: string | null,
email_notification_sending_address: string | null,
encryption_key: string | null,
data_api_key: string | null,
is_data_api_public: boolean,
console_api_key: string | null,
webhook_url: string | null,
webhook_on_create: boolean,
webhook_on_edit: boolean,
webhook_on_delete: boolean,
webhook_secret: string | null,
mod_badge_id: number | null,
mod_alias_name: string | null,
mod_alias_picture_url: string | null,
memberships_enabled: boolean,
memberships_currency: 'usd' | 'eur' | 'gbp', // default: 'usd'
memberships_yearly_discount: number | null,
memberships_text_button: string | null,
memberships_text_modal_title: string | null,
memberships_text_modal_title_members: string | null,
memberships_text_login_to_subscribe: string | null,
memberships_text_subscribe_as: string | null,
memberships_text_manage_subscription: string | null,
memberships_text_payment_success: string | null,
memberships_payment_success_url: string | null,
memberships_gated_allow_google: boolean,
email_report_daily: boolean,
email_report_weekly: boolean,
email_report_monthly: boolean,
highlight_new: boolean,
highlight_new_color: string | null, // default: '29ab3f',
highlight_upvote_threshold_1: number | null,
highlight_upvote_threshold_1_color: string | null, // default: 'f96436',
highlight_upvote_threshold_2: number | null,
highlight_upvote_threshold_2_color: string | null, // default: '223696',
}Comment Object
interface Comment = {
id: number,
created_at: number,
user: User,
page: Page,
body: string,
body_html: string,
status: 'published' | 'pending' | 'spam' | 'deleted',
parent: Comment | null,
ip_address: string | null,
has_mod_seen: boolean,
has_mod_replied: boolean,
is_featured: boolean,
is_loved: boolean,
is_edited: boolean,
has_questions: boolean,
has_links: boolean,
has_media: boolean,
is_automatic_spam: boolean,
flags_count: number,
last_flag_at: number | null,
upvotes: number,
downvotes: number,
user_vote: null, 'up' | 'down',
history: CommentHistory[]
}Comment History Object
interface CommentHistory = {
id: number,
created_at: number,
type: 'rule' | 'spam_detection' | 'moderation' | 'edit',
new_status: null | 'published' | 'pending' | 'spam' | 'deleted',
rule: Rule | null,
mod: Mod | null,
via: 'email' | 'slack' | null,
additional_info: string | null
}Page Object
interface Page = {
id: number,
created_at: number,
last_commented_at: number | null,
title: string,
identifier: string,
url: string,
is_closed: boolean,
is_premoderation_on: boolean,
author_email: string | null,
comments_count: number,
ratings: Rating
reactions: Reaction
}Flag Object
interface Flag = {
id: number,
user: User | null,
comment_id: number,
reason: string,
has_mod_seen: boolean
}Vote Object
interface Vote = {
id: number,
created_at: number | null,
comment_id: number,
user: User | null,
ip_hash: string | null,
type: 'up' | 'down'
}Rating Object
interface Rating = {
id: number,
created_at: number | null,
page: Page | null,
user: User | null,
rating: number
}Reaction Object
interface Reaction = {
id: number,
created_at: number | null,
page: Page | null,
user: User | null,
type: 'superb' | 'love' | 'wow' | 'sad' | 'laugh' | 'angry'
}User Object
There are multiple user object variants. LoggedInUser is used for logged-in users
(HYVOR and SSO). GuestUser is used with comments when guest commenting is used. CommentingUser is a union of these two.
interface LoggedInUser = {
type: 'hyvor' | 'sso',
id: number,
htid: string,
sso_id: string,
name: string,
title: string | null,
username: string | null,
email: string | null,
picture_url: string | null,
bio: string | null,
location: string | null,
website_url: string | null,
created_at: number | null,
last_commented_at: number | null,
comments_count: number,
state: 'default' | 'banned' | 'shadowed' | 'trusted',
state_ends_at: number | null,
note: string | null,
ban_reason: string | null,
badge_ids: number[],
register_ip: string | null,
last_ip: string | null,
days_visited: number,
last_seen_at: number | null,
emails_sent: number,
last_emailed_at: number | null,
membership_plan_id: number | null,
membership_stripe_customer_id: string | null,
membership_started_at: number | null,
membership_ends_at: number | null,
role: null | 'owner' | 'mod' | 'admin'
}
interface GuestUser = {
type: null,
name: string | 'Anonymous',
email: string | null,
picture_url: string | null
}
type CommentingUser = LoggedInUser | GuestUseremail is null for HYVOR users as we do not share HYVOR user's email addresses with the
website moderators.
UserMini Object
interface UserMini = {
id: number,
type: null | 'hyvor' | 'sso',
htid: string,
name: string,
username: string | null,
picture_url: string | null
}Mod Object
interface Mod = {
id: number,
created_at: number,
role: 'owner' | 'mod' | 'admin
user: UserMini,
sso_user: UserMini | null,
is_alias_used: boolean
}Mod Invite Object
interface ModInvite = {
id: number,
created_at: number,
role: 'owner' | 'mod' | 'admin
user: UserMini,
expires_at: number
}Stripe Connect Object
interface StripeConnect = {
id: number,
stripe_account_id: string,
is_active: boolean
}Plan Object
interface Plan = {
id: number,
created_at: number,
name: string,
description: string | null,
features: string | null,
monthly_price: number,
badge_id: number | null,
stripe_product_id: string | null,
stripe_monthly_price_id: string | null,
stripe_yearly_price_id: string | null,
members_count: number
}Gated Content Object
interface GatedContent = {
id: number,
created_at: number,
key: string,
content: string,
gate: string | null,
minimum_plan_id: number | null
}Membership Subscription Object
interface MembershipSubscription = {
id: number,
created_at: number | null,
user: User | null,
plan: Plan | null,
is_yearly: boolean,
stripe_id: string,
status: 'pending' | 'active' | 'past_due' | 'canceled',
cancel_at: number | null
}Segment Object
interface Segment = {
id: number,
created_at: number,
name: string,
description: string | null,
subscribers: number
}Issue Object
interface Issue = {
id: number,
uuid: string,
created_at: number,
subject: string,
from_name: string,
from_email: string,
reply_to_email: string,
content: string,
status: 'draft' | 'scheduled' | 'sending' | 'failed' | 'sent',
segments: number[],
scheduled_at: number | null,
sending_at: number | null,
sent_at: number | null
}Email Domain Object
interface EmailDomain = {
id: number,
domain: string,
dkim_public_key: string,
dkim_txt_name: string,
dkim_txt_value: string,
verified: boolean,
verified_in_ses: boolean,
requested_by_current_website: boolean
}Rule Object
interface Rule = {
id: number,
type: 'word_matches' | 'link_domain_matches' | 'user_name_matches' | 'link_count_exceeds' | 'flags_exceeds' | 'downvotes_exceeds' | 'upvotes_exceeds' | 'user_reputation_exceeds',
value: string,
to_status: 'published' | 'pending' | 'spam' | 'deleted',
priority: number
}Email Log Object
interface EmailLog = {
id: number,
created_at: number,
comment_id: number,
type: 'reply' | 'mention' | 'mod' | 'author',
comment_url: string,
user: LoggedInUser | null,
guest_email: string | null
}IP Object
interface IP = {
ip: string,
note: string | null,
state: 'default' | 'banned' | 'shadowed' | 'trusted',
state_ends_at: number | null
}Domain Object
interface Domain = {
id: number,
domain: string
}Badge Object
interface Badge = {
id: number,
text: string,
background_color: string,
color: string
}Job Object
interface Job = {
id: number,
created_at: number,
started_at: number | null,
completed_at: number | null,
failed_at: number | null,
data: { string : any },
result: { string : any } | null,
type: 'import_comments' | 'import_newsletter_subscribers' | 'export' | 'bulk_moderate_comments',
status: 'pending' | 'running' | 'completed' | 'failed',
error: string | null
}Webhook Configuration Object
interface WebhookConfiguration = {
id: number,
website_id: number,
url: string,
events: [
'comment.create' | 'comment.update' | 'comment.delete' |
'reaction.created' | 'reaction.updated' | 'reaction.deleted' |
'rating.created' | 'rating.updated' | 'rating.deleted' |
'comment.vote.created' | 'comment.vote.updated' | 'comment.vote.deleted' |
'comment.flag.created' | 'comment.flag.deleted' |
'user.created' | 'user.updated' | 'media.created' | 'media.deleted' |
'memberships.subscription.created' |
'memberships.subscription.updated' | 'memberships.subscription.deleted'
], // one or more events can be present in the array
secret: string
}Webhook Delivery Object
interface WebhookDelivery = {
id: number,
created_at: number | null,
website_id: number,
webhook_configuration_id: number,
url: string,
event: 'comment.create' | 'comment.update' | 'comment.delete' |
'reaction.created' | 'reaction.updated' | 'reaction.deleted' |
'rating.created' | 'rating.updated' | 'rating.deleted' |
'comment.vote.created' | 'comment.vote.updated' | 'comment.vote.deleted' |
'comment.flag.created' | 'comment.flag.deleted' |
'user.created' | 'user.updated' | 'media.created' | 'media.deleted' |
'memberships.subscription.created' |
'memberships.subscription.updated' | 'memberships.subscription.deleted',
status: 'pending' | 'completed' | 'retrying' | 'failed',
request_body: string | null,
num_attempts: number | null,
last_attempt_at: number | null,
response_body: string | null,
response_code: number | null
}Slack Connection Object
interface SlackConnection = {
has_token: boolean,
channel_name: string | null
}Media Object
interface Media = {
id: number,
created_at: number,
comment_id: number | null,
name: string,
size: number,
url: string
}