PagibleAI adds authenticated GraphQL mutations for generating text, refining structured page content, describing stored files, transcribing audio and translating text. The available operations depend on the configured AI providers and the current user’s CMS permissions.
GraphQL AI Text Mutations
See PagibleAI GraphQL API for authentication and JSON scalar handling, GraphQL Pages for conflict-safe drafts, and GraphQL Files for stored file references and multipart uploads.
Generate text with write
write generates plain text from a prompt. You can add context and up to ten stored file UUIDs as reference material.
mutation WriteText(
$prompt: String!
$context: String
$files: [String!]
) {
write(prompt: $prompt, context: $context, files: $files)
}
{
"prompt": "Write a concise product description for wireless headphones.",
"context": "Audience: commuters. Tone: direct and practical.",
"files": ["018f2567-8508-7a62-9309-41708fbfe5fa"]
}
write arguments
The mutation returns String and requires the text:write permission. Referenced files also require file:view permission.
Refine structured content
refine rewrites existing CMS content and validates the result against the selected content schema. Encode the original content as a JSON string for the MLL JSON scalar, describe the desired changes, and use pagetype when the page type has a specialized schema. The caller needs the page:refine permission.
mutation RefineContent(
$prompt: String!
$content: JSON!
$type: String
$context: String
$lang: String
$pagetype: String
) {
refine(
prompt: $prompt
content: $content
type: $type
context: $context
lang: $lang
pagetype: $pagetype
)
}
{
"prompt": "Make the introduction clearer and add a specific call to action.",
"content": "[{\"id\":\"intro\",\"type\":\"text\",\"group\":\"main\",\"data\":{\"text\":\"Take a look at our services.\"}}]",
"type": "content",
"context": "B2B consulting landing page",
"lang": "en",
"pagetype": "page"
}
refine arguments
The mutation returns validated JSON as an encoded string. Parse it before review, then pass the encoded result to savePage when you want to create a draft. refine does not save or publish the page itself.
While refining, the AI model can use CMS tools to read pages, shared elements and files, and to add, save, trash or restore shared elements and files. These tools run with the caller's permissions and only create draft versions; nothing is published. If the provider supports it, the model can also search and fetch web content.
{
"data": {
"refine": "[{\"id\":\"intro\",\"type\":\"text\",\"group\":\"main\",\"data\":{\"text\":\"Choose the service that fits your next project, then book a consultation.\"}}]"
}
}
Save refined content as a page draft
mutation SaveRefinedPage(
$page: ID!
$latestId: ID!
$content: JSON!
) {
savePage(
id: $page
latestId: $latestId
input: {content: $content}
) {
id
changed
latest { id published }
}
}
const refined = JSON.parse(refineResult.data.refine);
// Validate and render a preview before saving.
const saveVariables = {
page: page.id,
latestId: page.latest.id,
content: JSON.stringify(refined),
};
const saveResult = await runGraphql(SAVE_REFINED_PAGE, saveVariables);
if (saveResult.data.savePage.changed) {
// Re-read the page and review the conflict before continuing.
}
// savePage created a draft. It did not publish the page.
Treat generated content as untrusted editorial input: validate it against the active theme schema, preview it, inspect links and factual claims, and only then save the draft. Publishing remains a separate operation.
Describe a stored file
mutation DescribeFile($file: String!, $lang: String) {
describe(file: $file, lang: $lang)
}
{
"file": "018f2567-8508-7a62-9309-41708fbfe5fa",
"lang": "en"
}
{
"data": {
"describe": "A side view of a compact electric bicycle beside a city café."
}
}
file is a stored file UUID of at most 36 characters; lang is at most 5 characters. The mutation returns a text description and requires both file:describe and file:view.
Transcribe uploaded audio
transcribe accepts an Upload! using the GraphQL multipart request specification. It returns the transcription through the JSON scalar as a JSON-encoded list of segments. Each segment contains start and end times formatted as HH:MM:SS.mmm and the spoken text.
mutation TranscribeAudio($file: Upload!) {
transcribe(file: $file)
}
{
"data": {
"transcribe": "[{\"start\":\"00:00:00.000\",\"end\":\"00:00:02.480\",\"text\":\"Welcome to the product briefing.\"}]"
}
}
The upload must comply with the configured file-size and MIME policies. The caller needs audio:transcribe permission.
Translate text
mutation TranslateText(
$texts: [String!]!
$to: String!
$from: String
$context: String
) {
translate(texts: $texts, to: $to, from: $from, context: $context)
}
{
"texts": [
"Welcome to our website.",
"Compare our service plans."
],
"to": "de",
"from": "en",
"context": "Formal business website"
}
{
"data": {
"translate": [
"Willkommen auf unserer Website.",
"Vergleichen Sie unsere Servicepakete."
]
}
}
translate arguments
The result is [String!]! in the same order as the input. The caller needs text:translate permission.
Errors and provider configuration
AI calls can fail because of validation, permissions, provider configuration, rate limits or upstream service errors. Check the GraphQL errors array and keep provider credentials in server-side configuration. These mutations return generated data; they do not publish CMS content automatically.
All AI mutations share the cms-ai rate limiter, which allows 10 requests per minute per user (or per IP address for guests). Further requests are rejected until the window resets.
Stored files that point to remote URLs are fetched for write and describe. URLs resolving to private or reserved IP addresses are rejected unless CMS_ALLOW_INTERNAL=true is set.
When the AI provider rejects a request, errors[].message contains the provider's own error message, for example an invalid API key, an exhausted quota or an unsupported model. The full error is also written to the Laravel log.
{
"errors": [
{
"message": "Incorrect API key provided.",
"path": ["write"]
}
],
"data": {
"write": null
}
}