openapi: 3.1.0 info: title: Ghost Admin Authors Posts API description: The Ghost Admin API provides full read and write access to all content and configuration within a Ghost publication. It enables developers to create, update, and delete posts, pages, tags, members, tiers, newsletters, and offers programmatically. Authentication is handled via JSON Web Tokens generated from an Admin API key, integration tokens, or staff access tokens. The Admin API supports everything the Ghost Admin interface can do and more, making it suitable for building custom publishing workflows, content automation, member management systems, and advanced integrations. version: '5.0' contact: name: Ghost Foundation url: https://ghost.org/docs/admin-api/ termsOfService: https://ghost.org/terms/ servers: - url: https://{site}.ghost.io/ghost/api/admin description: Ghost Pro Hosted Site variables: site: default: your-site description: Your Ghost site subdomain - url: '{protocol}://{domain}/ghost/api/admin' description: Self-Hosted Ghost Instance variables: protocol: default: https enum: - https - http domain: default: localhost:2368 description: Your Ghost instance domain and port security: - adminApiToken: [] tags: - name: Posts description: Create, read, update, and delete posts. Posts are the primary content resource in Ghost and support rich content via the Lexical editor format. paths: /posts/: get: operationId: adminBrowsePosts summary: Browse posts description: Retrieve a paginated list of posts with all statuses including draft, scheduled, and published. Supports filtering, ordering, and including related resources. tags: - Posts parameters: - $ref: '#/components/parameters/includePostRelations' - $ref: '#/components/parameters/fields' - $ref: '#/components/parameters/filter' - $ref: '#/components/parameters/limit' - $ref: '#/components/parameters/page' - $ref: '#/components/parameters/order' - $ref: '#/components/parameters/formats' responses: '200': description: A list of posts content: application/json: schema: type: object properties: posts: type: array items: $ref: '#/components/schemas/Post' meta: $ref: '#/components/schemas/PaginationMeta' '401': $ref: '#/components/responses/Unauthorized' post: operationId: adminCreatePost summary: Create a post description: Create a new post. The title field is required, all other fields are optional and will have defaults applied. Content can be provided in Lexical or HTML format. Tags can be specified by name or as full tag objects. If a tag does not exist, it will be created automatically. tags: - Posts requestBody: required: true content: application/json: schema: type: object required: - posts properties: posts: type: array items: $ref: '#/components/schemas/PostInput' minItems: 1 maxItems: 1 responses: '201': description: Post created successfully content: application/json: schema: type: object properties: posts: type: array items: $ref: '#/components/schemas/Post' '401': $ref: '#/components/responses/Unauthorized' '422': $ref: '#/components/responses/ValidationError' /posts/{id}/: get: operationId: adminReadPost summary: Read a post by ID description: Retrieve a single post by its unique identifier, including draft and scheduled posts. tags: - Posts parameters: - $ref: '#/components/parameters/resourceId' - $ref: '#/components/parameters/includePostRelations' - $ref: '#/components/parameters/fields' - $ref: '#/components/parameters/formats' responses: '200': description: A single post content: application/json: schema: type: object properties: posts: type: array items: $ref: '#/components/schemas/Post' minItems: 1 maxItems: 1 '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' put: operationId: adminUpdatePost summary: Update a post description: Update an existing post. The updated_at field must be sent with the current value to prevent update collisions. Only the fields being changed need to be included in the request body, along with updated_at. tags: - Posts parameters: - $ref: '#/components/parameters/resourceId' requestBody: required: true content: application/json: schema: type: object required: - posts properties: posts: type: array items: $ref: '#/components/schemas/PostInput' minItems: 1 maxItems: 1 responses: '200': description: Post updated successfully content: application/json: schema: type: object properties: posts: type: array items: $ref: '#/components/schemas/Post' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '409': description: Update collision due to stale updated_at value content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '422': $ref: '#/components/responses/ValidationError' delete: operationId: adminDeletePost summary: Delete a post description: Permanently delete a post by its unique identifier. tags: - Posts parameters: - $ref: '#/components/parameters/resourceId' responses: '204': description: Post deleted successfully '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /posts/slug/{slug}/: get: operationId: readPostBySlug summary: Read a post by slug description: Retrieve a single published post by its URL slug. This is useful when you know the post's URL but not its ID. tags: - Posts parameters: - $ref: '#/components/parameters/resourceSlug' - $ref: '#/components/parameters/includePostRelations_2' - $ref: '#/components/parameters/fields_2' - $ref: '#/components/parameters/formats_2' responses: '200': description: A single post content: application/json: schema: type: object properties: posts: type: array items: $ref: '#/components/schemas/Post_2' minItems: 1 maxItems: 1 '401': $ref: '#/components/responses/Unauthorized_2' '404': $ref: '#/components/responses/NotFound' components: schemas: Post_2: type: object description: A post represents a piece of published content in a Ghost publication. properties: id: type: string format: uuid description: Unique identifier for the post uuid: type: string format: uuid description: Universally unique identifier for the post title: type: string description: Title of the post slug: type: string description: URL-safe slug derived from the title html: type: string description: HTML content of the post plaintext: type: string description: Plain text content of the post, available when requested via formats comment_id: type: string description: Identifier used for the commenting system feature_image: type: string format: uri description: URL of the featured image for the post nullable: true feature_image_alt: type: string description: Alt text for the featured image nullable: true feature_image_caption: type: string description: Caption for the featured image nullable: true featured: type: boolean description: Whether the post is marked as featured visibility: type: string description: Visibility level of the post enum: - public - members - paid - tiers created_at: type: string format: date-time description: Timestamp when the post was created updated_at: type: string format: date-time description: Timestamp when the post was last updated published_at: type: string format: date-time description: Timestamp when the post was published nullable: true custom_excerpt: type: string description: Custom excerpt for the post nullable: true codeinjection_head: type: string description: Code injected into the head of the post page nullable: true codeinjection_foot: type: string description: Code injected into the foot of the post page nullable: true custom_template: type: string description: Custom template assigned to the post nullable: true canonical_url: type: string format: uri description: Canonical URL for the post nullable: true url: type: string format: uri description: Full URL of the post on the Ghost site excerpt: type: string description: Auto-generated excerpt from the post content reading_time: type: integer description: Estimated reading time in minutes minimum: 0 access: type: boolean description: Whether the current request has access to the full post content og_image: type: string format: uri description: Open Graph image URL nullable: true og_title: type: string description: Open Graph title nullable: true og_description: type: string description: Open Graph description nullable: true twitter_image: type: string format: uri description: Twitter card image URL nullable: true twitter_title: type: string description: Twitter card title nullable: true twitter_description: type: string description: Twitter card description nullable: true meta_title: type: string description: SEO meta title nullable: true meta_description: type: string description: SEO meta description nullable: true email_subject: type: string description: Custom subject for email newsletters nullable: true frontmatter: type: string description: Custom frontmatter data nullable: true tags: type: array description: Tags associated with the post, included when requested items: $ref: '#/components/schemas/Tag_2' authors: type: array description: Authors of the post, included when requested items: $ref: '#/components/schemas/Author' primary_author: description: Primary author of the post, included when authors are requested $ref: '#/components/schemas/Author' primary_tag: description: Primary tag of the post, included when tags are requested $ref: '#/components/schemas/Tag_2' nullable: true Tag: type: object description: A tag for organizing and categorizing content. properties: id: type: string format: uuid description: Unique identifier name: type: string description: Tag name slug: type: string description: URL-safe slug description: type: string description: Tag description nullable: true feature_image: type: string format: uri description: Featured image URL nullable: true visibility: type: string description: Visibility setting enum: - public - internal og_image: type: string format: uri nullable: true description: Open Graph image URL og_title: type: string nullable: true description: Open Graph title og_description: type: string nullable: true description: Open Graph description twitter_image: type: string format: uri nullable: true description: Twitter card image URL twitter_title: type: string nullable: true description: Twitter card title twitter_description: type: string nullable: true description: Twitter card description meta_title: type: string nullable: true description: SEO meta title meta_description: type: string nullable: true description: SEO meta description codeinjection_head: type: string nullable: true description: Code injection in the head codeinjection_foot: type: string nullable: true description: Code injection in the foot canonical_url: type: string format: uri nullable: true description: Canonical URL accent_color: type: string nullable: true description: Accent color hex code pattern: ^#[0-9a-fA-F]{6}$ url: type: string format: uri description: Full URL of the tag page created_at: type: string format: date-time description: Creation timestamp updated_at: type: string format: date-time description: Last update timestamp ErrorResponse: type: object description: Standard Ghost API error response properties: errors: type: array items: type: object properties: message: type: string description: Human-readable error message type: type: string description: Error type identifier context: type: string description: Additional error context nullable: true Tag_2: type: object description: A tag is used to organize and categorize content in Ghost. Tags with slugs starting with hash are internal tags not visible to readers. properties: id: type: string format: uuid description: Unique identifier for the tag name: type: string description: Name of the tag slug: type: string description: URL-safe slug for the tag description: type: string description: Description of the tag nullable: true feature_image: type: string format: uri description: Featured image URL for the tag nullable: true visibility: type: string description: Visibility of the tag enum: - public - internal og_image: type: string format: uri description: Open Graph image for the tag page nullable: true og_title: type: string description: Open Graph title for the tag page nullable: true og_description: type: string description: Open Graph description for the tag page nullable: true twitter_image: type: string format: uri description: Twitter card image for the tag page nullable: true twitter_title: type: string description: Twitter card title for the tag page nullable: true twitter_description: type: string description: Twitter card description for the tag page nullable: true meta_title: type: string description: SEO meta title for the tag page nullable: true meta_description: type: string description: SEO meta description for the tag page nullable: true codeinjection_head: type: string description: Code injected into the head on tag pages nullable: true codeinjection_foot: type: string description: Code injected into the foot on tag pages nullable: true canonical_url: type: string format: uri description: Canonical URL for the tag page nullable: true accent_color: type: string description: Accent color for the tag nullable: true pattern: ^#[0-9a-fA-F]{6}$ url: type: string format: uri description: Full URL of the tag page count: type: object description: Count data, included when requested via include=count.posts properties: posts: type: integer description: Number of posts with this tag minimum: 0 Author: type: object description: An author represents a staff user who creates content in a Ghost publication. properties: id: type: string format: uuid description: Unique identifier for the author name: type: string description: Display name of the author slug: type: string description: URL-safe slug for the author profile_image: type: string format: uri description: Profile image URL nullable: true cover_image: type: string format: uri description: Cover image URL for the author page nullable: true bio: type: string description: Author biography nullable: true website: type: string format: uri description: Author personal website URL nullable: true location: type: string description: Author location nullable: true facebook: type: string description: Facebook username nullable: true twitter: type: string description: Twitter handle nullable: true meta_title: type: string description: SEO meta title for the author page nullable: true meta_description: type: string description: SEO meta description for the author page nullable: true url: type: string format: uri description: Full URL of the author page count: type: object description: Count data, included when requested via include=count.posts properties: posts: type: integer description: Number of posts by this author minimum: 0 User: type: object description: A staff user account in the Ghost publication. properties: id: type: string format: uuid description: Unique identifier name: type: string description: Display name slug: type: string description: URL-safe slug email: type: string format: email description: Email address profile_image: type: string format: uri description: Profile image URL nullable: true cover_image: type: string format: uri description: Cover image URL nullable: true bio: type: string description: Biography nullable: true website: type: string format: uri description: Personal website URL nullable: true location: type: string description: Location nullable: true facebook: type: string description: Facebook username nullable: true twitter: type: string description: Twitter handle nullable: true accessibility: type: string description: Accessibility settings JSON nullable: true status: type: string description: User account status enum: - active - inactive - locked meta_title: type: string nullable: true description: SEO meta title meta_description: type: string nullable: true description: SEO meta description tour: type: string description: Onboarding tour progress JSON nullable: true last_seen: type: string format: date-time description: Last login timestamp nullable: true url: type: string format: uri description: Full URL of the author page roles: type: array description: Assigned roles items: type: object properties: id: type: string format: uuid description: Role identifier name: type: string description: Role name description: type: string description: Role description created_at: type: string format: date-time description: Account creation timestamp updated_at: type: string format: date-time description: Last update timestamp PostInput: type: object description: Input fields for creating or updating a post or page. properties: title: type: string description: Title of the post slug: type: string description: Custom URL slug lexical: type: string description: Content in Lexical editor format (JSON string) html: type: string description: Content in HTML format, converted to Lexical on save status: type: string description: Publication status enum: - published - draft - scheduled visibility: type: string description: Access visibility level enum: - public - members - paid - tiers featured: type: boolean description: Whether the post is featured feature_image: type: string format: uri description: Featured image URL nullable: true feature_image_alt: type: string description: Alt text for the featured image nullable: true feature_image_caption: type: string description: Caption for the featured image nullable: true custom_excerpt: type: string description: Custom excerpt nullable: true codeinjection_head: type: string description: Code injection in the head nullable: true codeinjection_foot: type: string description: Code injection in the foot nullable: true custom_template: type: string description: Custom template name nullable: true canonical_url: type: string format: uri description: Canonical URL nullable: true published_at: type: string format: date-time description: Scheduled publication time nullable: true updated_at: type: string format: date-time description: Required for updates to prevent collisions tags: type: array description: Tags to associate, can be name strings or tag objects items: oneOf: - type: object properties: name: type: string slug: type: string - $ref: '#/components/schemas/Tag' authors: type: array description: Authors to associate items: type: object properties: id: type: string format: uuid slug: type: string email: type: string format: email email_subject: type: string description: Custom email newsletter subject nullable: true og_image: type: string format: uri nullable: true description: Open Graph image URL og_title: type: string nullable: true description: Open Graph title og_description: type: string nullable: true description: Open Graph description twitter_image: type: string format: uri nullable: true description: Twitter card image URL twitter_title: type: string nullable: true description: Twitter card title twitter_description: type: string nullable: true description: Twitter card description meta_title: type: string nullable: true description: SEO meta title meta_description: type: string nullable: true description: SEO meta description PaginationMeta: type: object description: Pagination metadata properties: pagination: type: object properties: page: type: integer description: Current page minimum: 1 limit: type: integer description: Items per page minimum: 1 pages: type: integer description: Total pages minimum: 1 total: type: integer description: Total items minimum: 0 next: type: integer description: Next page number nullable: true prev: type: integer description: Previous page number nullable: true Post: type: object description: A post or page resource with all content, metadata, and relationships. properties: id: type: string format: uuid description: Unique identifier uuid: type: string format: uuid description: Universally unique identifier title: type: string description: Title of the post slug: type: string description: URL-safe slug lexical: type: string description: Post content in Lexical editor format (JSON string) html: type: string description: Rendered HTML content plaintext: type: string description: Plain text content comment_id: type: string description: Commenting system identifier feature_image: type: string format: uri description: Featured image URL nullable: true feature_image_alt: type: string description: Alt text for the featured image nullable: true feature_image_caption: type: string description: Caption for the featured image nullable: true featured: type: boolean description: Whether the post is featured status: type: string description: Publication status enum: - published - draft - scheduled - sent visibility: type: string description: Access visibility level enum: - public - members - paid - tiers created_at: type: string format: date-time description: Creation timestamp updated_at: type: string format: date-time description: Last update timestamp published_at: type: string format: date-time description: Publication timestamp nullable: true custom_excerpt: type: string description: Custom excerpt nullable: true codeinjection_head: type: string description: Code injection in the page head nullable: true codeinjection_foot: type: string description: Code injection in the page foot nullable: true custom_template: type: string description: Custom Handlebars template name nullable: true canonical_url: type: string format: uri description: Canonical URL nullable: true url: type: string format: uri description: Full URL on the Ghost site excerpt: type: string description: Auto-generated excerpt reading_time: type: integer description: Estimated reading time in minutes minimum: 0 email_subject: type: string description: Custom email newsletter subject nullable: true frontmatter: type: string description: Custom frontmatter nullable: true og_image: type: string format: uri nullable: true description: Open Graph image URL og_title: type: string nullable: true description: Open Graph title og_description: type: string nullable: true description: Open Graph description twitter_image: type: string format: uri nullable: true description: Twitter card image URL twitter_title: type: string nullable: true description: Twitter card title twitter_description: type: string nullable: true description: Twitter card description meta_title: type: string nullable: true description: SEO meta title meta_description: type: string nullable: true description: SEO meta description tags: type: array description: Associated tags items: $ref: '#/components/schemas/Tag' authors: type: array description: Post authors items: $ref: '#/components/schemas/User' primary_author: $ref: '#/components/schemas/User' description: Primary author primary_tag: $ref: '#/components/schemas/Tag' nullable: true description: Primary tag email: type: object description: Email newsletter delivery details nullable: true properties: id: type: string format: uuid description: Email record identifier opened_count: type: integer description: Number of email opens minimum: 0 ErrorResponse_2: type: object description: Standard Ghost API error response properties: errors: type: array items: type: object properties: message: type: string description: Human-readable error message type: type: string description: Error type identifier context: type: string description: Additional context about the error nullable: true parameters: order: name: order in: query required: false description: Field and direction to order results by. schema: type: string page: name: page in: query required: false description: Page number for paginated results. Defaults to 1. schema: type: integer minimum: 1 default: 1 formats_2: name: formats in: query required: false description: Comma-separated list of content formats to include. By default only html is returned. Use formats=html,plaintext to also include plaintext. schema: type: string enum: - html - plaintext - html,plaintext includePostRelations_2: name: include in: query required: false description: Comma-separated list of related resources to include. Supported values are authors and tags. schema: type: string enum: - authors - tags - authors,tags formats: name: formats in: query required: false description: Comma-separated list of content formats to include in the response. schema: type: string includePostRelations: name: include in: query required: false description: Comma-separated list of related resources to include. Supported values are authors and tags. schema: type: string limit: name: limit in: query required: false description: Maximum number of resources to return per page. Defaults to 15. schema: oneOf: - type: integer minimum: 1 - type: string enum: - all default: 15 fields: name: fields in: query required: false description: Comma-separated list of fields to return in the response. schema: type: string fields_2: name: fields in: query required: false description: Comma-separated list of fields to return in the response. Use this to limit the size of the response by only requesting the fields you need. schema: type: string resourceSlug: name: slug in: path required: true description: The URL slug of the resource schema: type: string filter: name: filter in: query required: false description: Apply fine-grained filters using Ghost's NQL query language. schema: type: string resourceId: name: id in: path required: true description: The unique identifier of the resource schema: type: string format: uuid responses: Unauthorized: description: Authentication failed or token is missing or invalid content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' NotFound: description: The requested resource was not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' ValidationError: description: Request body validation failed content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' Unauthorized_2: description: Authentication failed or API key is missing content: application/json: schema: $ref: '#/components/schemas/ErrorResponse_2' securitySchemes: adminApiToken: type: http scheme: bearer bearerFormat: JWT description: JSON Web Token generated from an Admin API key. The key is split into an ID and secret at the colon separator. The ID is used as the kid header and the secret is used to sign the token with HS256. externalDocs: description: Ghost Admin API Documentation url: https://ghost.org/docs/admin-api/