Skip to main content
StormyCMS

API Reference

Complete reference for all GraphQL operations, types, and inputs available in the StormyCMS Public API.

Base URL

https://api.stormycms.com/graphql

Authentication

All requests must include authentication headers:

HeaderValueRequired
x-site-api-keysk_site_...Yes
x-client-idYour site's client IDYes
Content-Typeapplication/jsonYes

Alternative authentication using Bearer token:

HeaderValueRequired
AuthorizationBearer sk_site_...Yes
x-client-idYour site's client IDYes
Content-Typeapplication/jsonYes

Rate Limits

  • Site API Keys: 10,000 requests per hour per key
  • Rate limit headers are included in responses:
    • X-RateLimit-Limit: Maximum requests per hour
    • X-RateLimit-Remaining: Remaining requests
    • X-RateLimit-Reset: Unix timestamp when limit resets

Queries

Page Queries

page(id: ID!)

Retrieve a specific page by its ID.

Parameters:

  • id (ID!) - Unique identifier of the page

Returns: Page

Example:

query {
page(id: "page_123") {
id
meta {
title
description
keywords
}
layout_id
components {
id
name
text
}
}
}

pages(limit: Int, offset: Int)

Get a paginated list of pages.

Parameters:

  • limit (Int, optional) - Maximum pages to return (default: 20, max: 100)
  • offset (Int, optional) - Pages to skip for pagination (default: 0)

Returns: [Page!]!

Example:

query {
pages(limit: 10, offset: 20) {
id
meta {
title
}
created_at
}
}

all_layouts()

Retrieve all available layouts in the system.

Returns: [Layout!]!

Layout Queries

layout(id: ID!)

Retrieve a specific layout by its ID.

Parameters:

  • id (ID!) - Unique identifier of the layout

Returns: Layout

layouts()

Get all layouts.

Returns: [Layout!]!

Site Queries

getSite(id: ID!)

Get site information. Only accessible with the site's own API key.

Parameters:

  • id (ID!) - Unique identifier of the site

Returns: Site

Mutations

Page Mutations

create_page(meta: MetadataInput!, components: [ComponentInput!]!, layout_id: ID!, component_ids: [ID!]!)

Create a new page. Requires site admin permissions.

Parameters:

  • meta (MetadataInput!) - Page metadata
  • components ([ComponentInput!]!) - Array of components
  • layout_id (ID!) - Layout to associate with the page
  • component_ids ([ID!]!) - Array of existing component IDs

Returns: Page

update_page(id: ID!, meta: MetadataInput!, components: [ComponentInput!]!, layout_id: ID!, component_ids: [ID!]!)

Update an existing page. Requires site editor permissions.

Parameters:

  • id (ID!) - ID of the page to update
  • meta (MetadataInput!) - Updated metadata
  • components ([ComponentInput!]!) - Updated components
  • layout_id (ID!) - Updated layout ID
  • component_ids ([ID!]!) - Updated component IDs

Returns: Page

delete_page(id: ID!)

Delete a page.

Parameters:

  • id (ID!) - ID of the page to delete

Returns: Page

Layout Mutations

create_layout(name: String!, components: [ComponentInput!]!, component_ids: [ID!]!)

Create a new layout.

Parameters:

  • name (String!) - Name of the layout
  • components ([ComponentInput!]!) - Array of components
  • component_ids ([ID!]!) - Array of component IDs

Returns: Layout

update_layout(id: ID!, name: String!, components: [ComponentInput!]!, component_ids: [ID!]!)

Update an existing layout.

Parameters:

  • id (ID!) - ID of the layout to update
  • name (String!) - Updated name
  • components ([ComponentInput!]!) - Updated components
  • component_ids ([ID!]!) - Updated component IDs

Returns: Layout

delete_layout(id: ID!)

Delete a layout.

Parameters:

  • id (ID!) - ID of the layout to delete

Returns: Layout

Types

Page

type Page {
id: ID! # Unique identifier
meta: Metadata! # Page metadata
layouts: [Layout!]! # Associated layouts
layout_id: ID! # Primary layout
components: [Component!]! # Page components
component_ids: [ID!]! # Component IDs
site_id: ID! # Site ID
}

Layout

type Layout {
id: ID! # Unique identifier
name: String! # Layout name
props: [[String!]!]! # Translated properties
components: [Component!]! # Layout components
component_ids: [ID!]! # Component IDs
outlet_id: ID! # Content outlet ID
child_layout_id: ID # Child layout ID (optional)
}

Site

type Site {
id: ID! # Unique identifier
name: String! # Site name
owner_id: ID! # Owner user ID
admin_ids: [UserIdWithDate!]! # Admin users
contributor_ids: [UserIdWithDate!]! # Contributors
client_id: String! # OAuth client ID
redirect_urls: [String!]! # OAuth redirect URLs
created_at: String! # Creation timestamp
}

Metadata

type Metadata {
title: String! # Page title
description: String! # SEO description
keywords: [String!]! # SEO keywords
}

Component

type Component {
id: ID! # Unique identifier
name: String! # Component type/name
props: [[String!]!]! # Translated properties
text: String! # Text content
child_ids: [ID!]! # Child component IDs
}

UserIdWithDate

type UserIdWithDate {
user_id: ID! # User ID
add_date: String! # When user was added
}

Input Types

MetadataInput

input MetadataInput {
title: String # Optional title
description: String # Optional description
keywords: [String] # Optional keywords
}

ComponentInput

input ComponentInput {
id: ID # Optional ID
name: String # Optional component name
props: [PropInput] # Optional properties
text: [TranslationInput] # Optional text content
child_ids: [ID] # Optional child IDs
}

PropInput

input PropInput {
key: String! # Property key
translations: [TranslationInput]! # Property translations
}

TranslationInput

input TranslationInput {
locale: String! # Language code (e.g., "en", "es")
value: String! # Translated value
}

Error Responses

HTTP Status Codes

CodeMeaning
200Success
400Bad Request - Invalid query or variables
401Unauthorized - Invalid or missing API key
403Forbidden - Insufficient permissions
429Too Many Requests - Rate limit exceeded
500Internal Server Error

GraphQL Errors

GraphQL errors are returned in the response body:

{
"errors": [
{
"message": "Page not found",
"locations": [{ "line": 2, "column": 3 }],
"path": ["page"],
"extensions": { "code": "NOT_FOUND" }
}
],
"data": null
}

Common error codes:

  • NOT_FOUND - Resource doesn't exist
  • UNAUTHORIZED - Authentication required
  • FORBIDDEN - Insufficient permissions
  • VALIDATION_ERROR - Invalid input data
  • RATE_LIMITED - Too many requests

SDK Examples

JavaScript/TypeScript

class StormyCMS {
private apiKey: string;
private clientId: string;
private baseUrl: string;
constructor(apiKey: string, clientId: string) {
this.apiKey = apiKey;
this.clientId = clientId;
this.baseUrl = 'https://api.stormycms.com/graphql';
}
async query(query: string, variables?: any) {
const response = await fetch(this.baseUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-site-api-key': this.apiKey,
'x-client-id': this.clientId,
},
body: JSON.stringify({ query, variables }),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
if (result.errors) {
throw new Error(result.errors[0].message);
}
return result.data;
}
async getPage(id: string) {
return this.query(`
query GetPage($id: ID!) {
page(id: $id) {
id
meta { title description }
components { id name text }
}
}
`, { id });
}
}

cURL

Terminal window
curl -X POST https://api.stormycms.com/graphql \
-H "Content-Type: application/json" \
-H "x-site-api-key: sk_site_abc123def456" \
-H "x-client-id: YOUR_CLIENT_ID" \
-d '{
"query": "query { pages(limit: 5) { id meta { title } } }"
}'

Next Steps

Last updated: 2/27/26, 3:48 AM

StormyCMSPowerful Headless CMS with GraphQL API
Community
githubdiscordStormyCMS