Post Mutations
Mutation operations for managing posts in your Loopwise school
The post mutations allow you to create, update, and delete posts within your Loopwise school. These operations enable you to programmatically manage your blog content and article publishing.
Available mutations:
createPost— Creates a new postupdatePost— Updates an existing postdeletePost— Deletes a post (soft delete)
All post mutations return an errors field in the response that will contain any validation or processing errors that occurred during the operation.
Post Access Types
Posts support different access types:
login_required— Users must be logged in to accesspaid— Users must have purchased accesspublic_access— Available to all users
Body Content Format
The body field is an HTML string. Posts are also editable in the school dashboard with a rich text editor, which supports standard article markup: headings (h1–h6), paragraphs, lists, blockquotes, links, images, tables, and code blocks.
Compatibility note: if you write HTML through the API that the dashboard editor does not recognize (custom tags, inline scripts, unusual attributes), it may be normalized or removed the next time someone edits the post in the dashboard. Stick to standard article markup for content that will be co-edited in the dashboard.
To embed images inside the body, upload them first with the uploadImage mutation and use the returned URL in an <img> tag.
Cover Photos
Set a cover photo by passing coverPhotoUrl in the input of createPost or updatePost:
- Upload the image with the
uploadImagemutation. - Pass the returned image URL as
coverPhotoUrl.
Only URLs served from the Loopwise CDN (as returned by uploadImage) are accepted; other hosts are rejected with UPLOAD-008.
Create a Post
The createPost mutation allows you to create a new post in your Loopwise school with the specified properties.
Input Parameters
| Field | Type | Description |
|---|---|---|
input | AdminPostInput! | Input object containing post creation details |
AdminPostInput Fields
| Field | Type | Required | Description |
|---|---|---|---|
title | String | Yes | Post title |
subtitle | String | No | Post subtitle |
body | String | Yes | Post body content as HTML (see Body Content Format) |
excerpt | String | No | Post excerpt |
slug | String | Yes | URL slug for the post. Must contain only lowercase letters, numbers, and hyphens |
accessType | String | Yes | Access type for the post (login_required, paid, public_access) |
published | Boolean | No | Whether the post is published (default: false) |
publishedAt | Int | No | Unix timestamp when the post should be published |
categoryId | String | No | ID of a post category (list them with the postCategories query) |
tagList | [String!] | No | Tags to associate with this post |
noindex | Boolean | No | Exclude this post from search engine indexing |
userId | String | No | ID of the user (author) for this post (default: school owner) |
coverPhotoUrl | String | No | Cover photo URL returned by uploadImage (see Cover Photos) |
title,body,slug, andaccessTypeare declared as nullable in the schema (the same input type is shared withupdatePost), but they are required when creating a post. Missing fields are rejected with error codePOST-006.
Return Type
type AdminPostCreatePayload {
# Array of error messages, if any occurred during the operation
errors: [String!]
# The created post object, null if operation failed
post: AdminPost
}Example
mutation CreatePost {
createPost(input: {
title: "Getting Started with GraphQL"
subtitle: "A comprehensive guide for beginners"
body: "GraphQL is a query language for APIs..."
excerpt: "Learn the basics of GraphQL"
slug: "getting-started-with-graphql"
accessType: "public_access"
published: true
tagList: ["graphql", "tutorial", "api"]
}) {
post {
id
title
subtitle
slug
accessType
published
tags
}
errors
}
}Sample Response
{
"data": {
"createPost": {
"post": {
"id": "post_12345",
"title": "Getting Started with GraphQL",
"subtitle": "A comprehensive guide for beginners",
"slug": "getting-started-with-graphql",
"accessType": "public_access",
"published": true,
"tags": ["graphql", "tutorial", "api"]
},
"errors": []
}
}
}Common Errors
| Error | Description |
|---|---|
POST-006 Missing required field(s) | title, body, slug, or accessType was not provided |
Title cannot be empty | The post title is required |
Body cannot be empty | The post body content is required |
Slug already exists | The provided slug is already in use |
Invalid access type | The accessType must be one of: login_required, paid, public_access |
Category not found | The specified category ID does not exist |
User not found | The specified user ID does not exist |
Update a Post
The updatePost mutation updates an existing post in your Loopwise school. It has partial-update (PATCH) semantics: only the fields you include in the input are changed, and omitted fields keep their current values. You can update a single field — for example the title — without resending the body.
Input Parameters
| Field | Type | Description |
|---|---|---|
id | String! | ID of the post to update |
input | AdminPostInput! | Fields to change; omitted fields are left untouched |
AdminPostInput Fields
All fields are optional on update.
| Field | Type | Description |
|---|---|---|
title | String | Post title (cannot be set to null) |
subtitle | String | Post subtitle. Pass null to clear it |
body | String | Post body content as HTML (cannot be set to null; see Body Content Format) |
excerpt | String | Post excerpt. Pass null to clear it |
slug | String | URL slug. Must contain only lowercase letters, numbers, and hyphens |
accessType | String | Access type (login_required, paid, public_access) |
published | Boolean | Whether the post is published |
publishedAt | Int | Unix timestamp of the publish time (see note below) |
categoryId | String | ID of a post category. Pass null to detach the category |
tagList | [String!] | Replaces the post's tags. Pass [] to clear all tags |
noindex | Boolean | Exclude this post from search engine indexing |
userId | String | ID of the user (author) for this post |
coverPhotoUrl | String | Cover photo URL returned by uploadImage (see Cover Photos) |
publishedAtfollowspublished: unpublishing a post clears itspublishedAt, and publishing a post without a timestamp setspublishedAtto the current time. It cannot be cleared independently while the post is published.
Return Type
type AdminPostUpdatePayload {
# Array of error messages, if any occurred during the operation
errors: [String!]
# The updated post object, null if operation failed
post: AdminPost
}Example
Update only the title and tags — every other field, including the body, is left untouched:
mutation UpdatePost {
updatePost(
id: "post_12345"
input: {
title: "Advanced GraphQL Techniques"
tagList: ["graphql", "advanced", "optimization"]
}
) {
post {
id
title
subtitle
slug
accessType
published
publishedAt
tags
updatedAt
}
errors
}
}Sample Response
{
"data": {
"updatePost": {
"post": {
"id": "post_12345",
"title": "Advanced GraphQL Techniques",
"subtitle": "A comprehensive guide for beginners",
"slug": "getting-started-with-graphql",
"accessType": "public_access",
"published": true,
"publishedAt": 1687436400,
"tags": ["graphql", "advanced", "optimization"],
"updatedAt": 1687436500
},
"errors": []
}
}
}Common Errors
| Error | Description |
|---|---|
Post not found | The specified post ID does not exist |
Title cannot be empty | The post title is required |
Body cannot be empty | The post body content is required |
Slug already exists | The provided slug is already in use by another post |
Invalid access type | The accessType must be one of: login_required, paid, public_access |
Category not found | The specified category ID does not exist |
User not found | The specified user ID does not exist |
Delete a Post
The deletePost mutation allows you to delete a post from your Loopwise school. This is a soft delete operation, meaning the post data is retained but marked as deleted.
Input Parameters
| Field | Type | Description |
|---|---|---|
id | String! | ID of the post to delete |
Return Type
type AdminPostDeletePayload {
# Array of error messages, if any occurred during the operation
errors: [String!]
# Boolean indicating whether the deletion was successful
success: Boolean
}Example
mutation DeletePost {
deletePost(id: "post_12345") {
success
errors
}
}Sample Response
{
"data": {
"deletePost": {
"success": true,
"errors": []
}
}
}Error Response
If the deletion fails, you might receive a response like this:
{
"data": {
"deletePost": {
"success": false,
"errors": ["Post not found"]
}
}
}Common Errors
| Error | Description |
|---|---|
Post not found | The specified post ID does not exist |
Post already deleted | The post has already been deleted |
Insufficient permissions | You don't have permission to delete this post |
Important Notes
- This is a soft delete operation — the post data is retained in the system but marked as deleted
- Deleted posts will not appear in regular queries
- The post can potentially be restored by system administrators if needed
- All associated data (comments, ratings, etc.) will also be hidden when the post is deleted