Console API allows you to do administrative tasks of a blog. This is the same API we use internally in the Console. You can use it to automate some tasks or even build a completely new mini-console by yourself.
https://blogs.hyvor.com/api/console/v0/blog/{subdomain}X-API-KEY header.GET - to get data, usually an array of resourcesPOST - to create a resourcePATCH - to partially or completely update a resourceDELETE - to delete a resourceThe Console API has many endpoints and is categorized by what “resource” you want to access or manage. Most categories have CRUD operations but some may have more endpoints for specific tasks. These objects are defined within the Category. Also, note that Console API objects are different from Data API objects.
Jump to each category:
Endpoints:
GET /blog - Get blog dataPATCH /blog - Update blog dataPOST /blog/variant - Create a blog variantPATCH /blog/variant - Update a blog variantObjects:
GET /blog
type Request = {};
type Response = Blog;PATCH /blog
type Request = Partial<Blog>; // except id and variants
type Response = Blog;POST /blog/variant
type Request = {
language_id: number;
};
type Response = BlogVariant;PATCH /blog/variant
type Request = {
language_id: number;
name?: string;
description?: string;
};
type Response = BlogVariant;Endpoints:
GET /posts - Get postsGET /pages - Get pagesPOST /post - Create a post/pageGET /post/{id} - Get a post/pagePATCH /post/{id} - Update a post/pageDELETE /post/{id} - Delete a post/pagePOST /post/{id}/variant - Create a post variantPATCH /post/{id}/variant - Update a post variantPOST /post/{id}/variant/publish - Publish a post variantPOST /post/{id}/variant/unpublish - Unpublish a post variantDELETE /post/{id}/variant - Delete a post variantPATCH /post/{id}/tags - Update post tagsPATCH /post/{id}/authors - Update post authorsObjects:
Get posts with filtering. The filter parameters are similar to the ones in the Console. Returns a lightweight PostListItem per post, rather than the full Post object - fetch GET /post/{id} for the full post.
GET /posts
type Request = {
status?: 'featured' | 'published' | 'draft' | 'scheduled';
author_id?: number;
tag_id?: number;
start_timestamp?: number; // unix timestamp
end_timestamp?: number; // unix timestamp
search?: string;
language_id?: number; // defaults to the blog's primary language
limit?: number; // default 50, max 100
offset?: number;
};
type Response = PostListItem[];Same lightweight PostListItem shape as GET /posts.
GET /pages
type Request = {};
type Response = PostListItem[];Create an empty draft post. A post variant will be created from the primary language of the blog.
POST /post
type Request = {
is_page?: boolean; // default to false
};
type Response = Post;GET /post/{id}
type Request = {};
type Response = Post;PATCH /post/{id}
type Request = {
is_featured?: boolean;
featured_image_url?: string | null;
canonical_url?: string | null;
code_head?: string | null;
code_foot?: string | null;
published_at?: number | null; // unix timestamp
};
type Response = Post;DELETE /post/{id}
type Request = {};
type Response = {};POST /post/{id}/variant
type Request = {
language_id: number;
};
type Response = PostVariant;PATCH /post/{id}/variant
type Request = {
language_id: number;
slug?: string; // max 255 chars
content?: string | null;
content_unsaved?: string | null;
title?: string | null; // max 255 chars
description?: string | null; // max 255 chars
};
type Response = PostVariant;content and content_unsaved should be in ProseMirror JSON format. See Get ProseMirror JSON endpoint to convert HTML to ProseMirror JSON.
POST /post/{id}/variant/publish
type Request = {
language_id: number;
};
type Response = PostVariant;Publishes a post variant. If the variant does not have a slug, one is automatically generated from the title. If the post does not have a published_at time, it is set to now. Requires posts.publish.own scope.
POST /post/{id}/variant/unpublish
type Request = {
language_id: number;
};
type Response = PostVariant;Sets the variant status back to draft. Works on both published and scheduled variants. Requires posts.publish.own scope.
DELETE /post/{id}/variant
type Request = {
language_id: number;
};
type Response = {};PATCH /post/{id}/tags
type Request = {
ids: number[]; // tag IDs
};
type Response = {};PATCH /post/{id}/authors
type Request = {
ids: number[]; // author (user) IDs
};
type Response = {};Endpoints:
GET /tags - Get or search tagsPOST /tag - Create a tagPATCH /tag/{id} - Update a tagDELETE /tag/{id} - Delete a tagPOST /tag/{id}/variant - Create a tag variantPATCH /tag/{id}/variant - Update a tag variantDELETE /tag/{id}/variant - Delete a tag variantObjects:
Lists tags, optionally searching by name (primary language).
GET /tags
type Request = {
limit?: number; // default 50, max 100
offset?: number;
search?: string; // filters tags by name (primary language)
};
type Response = Tag[];POST /tag
type Request = {
name: string; // name for the primary language variant
is_private: boolean; // default false
};
type Response = Tag;PATCH /tag/{id}
type Request = {
is_private?: boolean;
slug?: string;
code_head?: string | null;
code_foot?: string | null;
};
type Response = Tag;DELETE /tag/{id}
type Request = {};
type Response = {};POST /tag/{id}/variant
type Request = {
language_id: number;
};PATCH /tag/{id}/variant
type Request = {
language_id: number;
name?: string;
description?: string | null;
};DELETE /tag/{id}/variant
type Request = {
language_id: number;
};Endpoints:
GET /users - Get usersGET /users/search - Search usersPOST /user - Create a userPOST /user/guest - Create a guest userPATCH /user/{id} - Update a userDELETE /user/{id} - Delete a userPOST /user/{id}/variant - Create a user variantPATCH /user/{id}/variant - Update a user variantDELETE /user/{id}/variant - Delete a user variantObjects:
GET /users
type Request = {
offset?: number;
};
type Response = User[];Searches for users by name.
GET /users/search
type Request = {
search: string;
};
type Response = User[];POST /user
type Request = {
username_or_email: string;
role: 'owner' | 'admin' | 'editor' | 'writer' | 'contributor';
};
type Response = User;POST /user/guest
type Request = {
name: string;
};
type Response = User;PATCH /user/{id}
type Request = {
hyvor_user_id?: number;
role?: 'owner' | 'admin' | 'editor' | 'writer' | 'contributor';
status: 'active' | 'blocked';
slug: string;
email?: string;
website_url?: string;
picture_url?: string;
social_facebook?: string;
social_twitter?: string;
social_linkedin?: string;
social_youtube?: string;
social_tiktok?: string;
social_instagram?: string;
social_github?: string;
};
type Response = User;DELETE /user/{id}
type Request = {};
type Response = {};POST /user/{id}/variant
type Request = {};
type Response = UserVariant;PATCH /user/{id}/variant
type Request = {
name?: string;
bio?: string;
location?: string;
};
type Response = UserVariant;DELETE /user/{id}/variant
type Request = {};
type Response = {};Endpoints:
GET /media - Get mediaPOST /media - Create a mediaPOST /media/from-url - Create a media from URLDELETE /media/{id} - Delete a navigationGET /media/unsplash/search - Get media from unsplashPATCH /media - Patch mediaObjects:
GET /media
type Request = {
limit: number;
offset: number;
search?: string;
extensions?: string[];
type?: string;
};
type Response = Media[];POST /media
type Request = {
file: File;
post_id: number;
};
type Response = Media;POST /media/from-url
type Request = {
url: string;
post_id?: number;
};
type Response = Media;DELETE /media/{id}
type Request = {};
type Response = {};PATCH /media/{id}
type Request = Partial<Media>;
type Response = Media;Endpoints:
GET /navigations - Get navigationsPATCH /navigations/sort - Update sort navigationsPOST /navigation - Create a navigationPATCH /navigation/{id} - Update a navigationDELETE /navigation/{id} - Delete a navigationPOST /navigation/{id}/variant - Create a navigation variantPATCH /navigation/{id}/variant - Update a navigation variantDELETE /navigation/{id}/variant - Delete a navigation variantObjects:
GET /navigations
type Request = {};
type Response = Navigation[];PATCH /navigations/sort
type Request = {
ids?: number[];
};
type Response = {};POST /navigation
type Request = {
url: string;
name: string;
type: 'header' | 'footer';
};
type Response = Navigation;PATCH /navigation/{id}
type Request = {
url: string;
type: 'header' | 'footer';
};
type Response = Navigation;DELETE /navigation/{id}
type Request = {};
type Response = {};POST /navigation/{id}/variant
type Request = {
language_id: number;
name?: string;
};
type Response = NavigationVariant;PATCH /navigation/{id}/variant
type Request = {
language_id: number;
name: string;
};
type Response = NavigationVariant;DELETE /navigation/{id}/variant
type Request = {
language_id: number;
};
type Response = {};Endpoints:
GET /languages - Get languagesPOST /language - Create a languagePATCH /language/{id} - Update a languageDELETE /language/{id} - Delete a languageObjects:
GET /languages
type Request = {};
type Response = Languages[];POST /language
type Request = {
code: string; // max 12 chars
name: string; // max 255 chars
direction: 'ltr' | 'rtl';
};
type Response = Language;PATCH /language/{id}
type Request = {
code: string; // max 12 chars
name: string; // max 255 chars
direction: 'ltr' | 'rtl';
};
type Response = Language;DELETE /language/{id}
type Request = {};
type Response = {};Endpoints:
GET /redirects - Get redirectsPOST /redirect - Create a redirectPATCH /redirect/{id} - Update a redirectDELETE /redirect/{id} - Delete a redirectObjects:
GET /redirects
type Request = {
search?: string;
limit?: number;
offset?: number;
};
type Response = Redirect[];POST /redirect
type Request = {
dynamic: boolean;
path: string;
to: string;
type: 'temporary' | 'permanent';
};
type Response = Redirect;PATCH /redirect/{id}
type Request = {
path?: string;
to?: string;
type?: 'temporary' | 'permanent';
};
type Response = Redirect;DELETE /redirect/{id}
type Request = {};
type Response = {};Endpoints:
GET /webhooks - Get webhooksPOST /webhook - Create a webhookPATCH /webhook/{id} - Update a webhookDELETE /webhook/{id} - Delete a webhookObjects:
GET /webhooks
type Request = {};
type Response = Webhook[];POST /webhook
type Request = {
url: string;
events: 'cache.single' | 'cache.templates' | 'cache.all'[];
};
type Response = Webhook;PATCH /webhook/{id}
type Request = {
url?: string;
events?: 'cache.single' | 'cache.templates' | 'cache.all'[];
};
type Response = Webhook;DELETE /webhook/{id}
type Request = {};
type Response = {};Endpoints:
GET /theme/files - Get theme filesPOST /theme/file - Create a theme filePATCH /theme/file/{id} - Update a theme fileDELETE /theme/file/{id} - Delete a theme fileObjects:
GET /theme/files
type Request = {};
type Response = FileObject[];POST /theme/file
type Request = {
folder: 'templates' | 'assets' | 'styles' | 'lang';
name: string;
content?: string;
file: File;
};
type Response = FileObject;PATCH /theme/file/{id}
type Request = {
name?: string;
content?: string;
};
type Response = FileObject;DELETE /theme/file/{id}
type Request = {};
type Response = {};Endpoints:
GET /exports - Get exportsPOST /export - Create an exportObjects:
GET /exports
type Request = {};
type Response = ExportObject[];POST /export
type Request = {};
type Response = ExportObject;Endpoints:
POST /link-analysis/check-urls - Check post variant linkPATCH /link-analysis/ignore-link - Ignore a linkGET /link-analysis/stats - Get link statisticsGET /link-analysis/links - Get linksGET /link-analysis/checks - Get checksPOST /link-analysis/check - Create a checkObjects:
POST /link-analysis/check-urls
type Request = {
post_variant_id: number;
urls: string[];
force?: boolean;
};
type Response = LinkObject[];PATCH /link-analysis/ignore-link
type Request = {
post_variant_id: number;
urls: string[];
status: boolean;
};
type Response = LinkObject;GET /link-analysis/stats
type Request = {};
type Response = {
counts: number;
};GET /link-analysis/links
type Request = {
type?: 'ok' | 'broken' | 'ignored' | 'redirected';
limit?: number;
offset?: number;
};
type Response = LinkObject[];GET /link-analysis/checks
type Request = {
limit?: number;
offset?: number;
};
type Response = CheckObject[];POST /link-analysis/check
type Request = {};
type Response = CheckObject;Endpoints:
GET /routes - Get routesPOST /route - Create a routePATCH /route/{id} - Update a routeDELETE /route/{id} - Delete a routeObjects:
GET /routes
type Request = {};
type Response = Route[];POST /route
type Request = {
name: string;
match: string;
template: string;
post_filter?: string;
content_type?: string;
};
type Response = Route;PATCH /route/{id}
type Request = {
name: string;
match: string;
template: string;
post_filter?: string;
content_type?: string;
};
type Response = Route;DELETE /route/{id}
type Request = {};
type Response = {};Endpoints:
GET /misc/themes - Get all themesGET /misc/prosemirror/json - Get prosemirror jsonDELETE /blog/cache - Delete blog cacheDELETE /blog - Delete the blogGET /misc/themes
type Request = {};
type Response = Theme[];GET /misc/prosemirror/json
type Request = {
html: string;
};
type Response = {
json: string;
};DELETE /blog/cache
type Request = {
type: 'all' | 'template' | 'paths';
paths?: string[];
};
type Response = {};Soft-deletes the blog. The blog and its data are permanently deleted 30 days later. Requires the blog.delete scope.
DELETE /blog
type Request = {};
type Response = {};interface Blog {
id: number;
created_at: number;
is_blocked: boolean;
subdomain: string;
type: 'default' | 'dev';
hosting_at: 'subdomain' | 'domain' | 'self';
hosting_domain: string | null;
hosting_url: string | null;
embeddable: boolean;
embedding_domains: string | null;
logo_url: string | null;
cover_url: string | null;
social_facebook: string | null;
social_twitter: string | null;
social_linkedin: string | null;
social_youtube: string | null;
social_tiktok: string | null;
social_instagram: string | null;
social_github: string | null;
code_head: string | null;
code_foot: string | null;
seo_indexing: boolean;
seo_robots_txt: string | null;
seo_external_links_follow: 'follow' | 'nofollow';
comments_code: string | null;
newsletter_code: string | null;
color_modes: 'light' | 'dark' | 'both';
color_mode_default: 'light' | 'dark' | 'os';
syntax_on: boolean;
syntax_line_numbers: boolean;
syntax_theme: string | null;
flashload: boolean;
variants: BlogVariant[];
}interface BlogVariant {
language_id: number;
name: string | null;
description: string | null;
}interface Post {
id: number;
preview_id: string;
created_at: number;
updated_at: number;
published_at: number | null;
is_featured: boolean;
is_page: boolean;
featured_image_url: string | null;
canonical_url: string | null;
code_head: string | null;
code_foot: string | null;
variant_statuses: {
id: number;
language_id: number;
status: 'draft' | 'published' | 'scheduled';
}[];
tags: Tag[];
authors: User[];
}variant_statuses only tells you which languages a post has and their status. Fetch GET /post/{id}?variant_language_code=... to get the full PostVariant object (content, title, SEO fields, etc.) for a single language.
interface PostVariant {
language_id: number;
slug: string | null;
status: 'draft' | 'published' | 'scheduled';
url: string;
content: string | null;
content_unsaved: string | null;
title: string | null;
description: string | null;
}Returned by GET /posts and GET /pages. A lightweight per-post summary: slug, url, title, and link_analysis reflect the variant of the requested (or blog’s primary) language, and tags/authors are just their primary-language names. Fetch GET /post/{id} for the full Post object, including tags and authors.
interface PostListItem {
id: number;
created_at: number;
updated_at: number;
published_at: number | null;
is_featured: boolean;
is_page: boolean;
slug: string | null;
url: string | null;
title: string | null;
link_analysis: Record<string, number>;
variant_statuses: {
language_id: number;
status: 'draft' | 'published' | 'scheduled';
}[];
tags: string[]; // tag names, primary language
authors: string[]; // author names, primary language
}interface Tag {
id: number;
created_at: number;
updated_at: number;
is_private: boolean;
slug: string;
posts_count: number;
code_head: string | null;
code_foot: string | null;
variants: TagVariant[];
}interface TagVariant {
language_id: number;
url: string | null;
name: string | null;
description: string | null;
}interface User {
id: number;
created_at: number;
updated_at: number;
hyvor_user_id: number | null;
status: 'invited' | 'active' | 'blocked';
role: 'owner' | 'admin' | 'editor' | 'writer' | 'contributor';
slug: string;
posts_count: number;
email: string;
picture_url: string | null;
website_url: string | null;
social_facebook: string | null;
social_twitter: string | null;
social_linkedin: string | null;
social_youtube: string | null;
social_tiktok: string | null;
social_instagram: string | null;
social_github: string | null;
variants: UserVariant[];
}interface UserVariant {
language_id: number;
url: string;
name: string | null;
bio: string | null;
location: string | null;
}interface Media {
id: number;
uploaded_at: number;
name: string;
url: string;
original_name: string;
extension: string;
}interface Navigation {
id: number;
created_at: number;
url: string;
type: NavigationType;
sort: number;
variants: NavigationVariant[];
}interface NavigationVariant {
language_id: number;
name: string | null;
}interface Language {
id: number;
code: string;
name: string;
is_primary: boolean;
}interface Redirect {
id: number;
created_at: number;
path: string;
to: string;
type: 'temporary' | 'permanent';
}interface Webhook {
id: number;
url: string;
events: string[];
secret: string;
}interface Route {
id: number;
created_at: number;
name: string;
match: string;
template: string;
posts_filter: string | null;
content_type: string | null;
is_enabled: boolean;
}interface FileObject {
id: number;
name: string;
content: string | null;
folder: 'templates' | 'assets' | 'styles' | 'lang';
}interface Export {
id: number;
createdf_at: number;
format: 'hyvor_blogs' | 'wordpress';
status: 'pending' | 'completed' | 'failed';
url: string | null;
error?: string;
}interface Theme {
id: number;
type: 'original' | 'ported';
name: string;
}interface LinkObject {
id: number;
url: string;
full_url: string;
status_code: number;
status_type: 'ok' | 'broken' | 'redirect' | 'ignored';
ignored: boolean;
post_id: number;
post_variant_id: number;
post_variant_language_id: number;
post_variant_title: string;
}interface CheckObject {
id: number;
created_at: number;
status: 'pending' | 'completed' | 'failed';
error: string | null;
post_count: number;
post_variants_count: number;
page_count: number;
page_variants_count: number;
links_total_count: number;
links_ok_count: number;
links_broken_count: number;
links_redirect_count: number;
links_ignored_count: number;
}