@cloudcannon/sdk
v0.0.4
Published
REST API client for the CloudCannon CMS.
Downloads
758
Readme
@cloudcannon/sdk
A TypeScript SDK for interacting with the CloudCannon REST API.
Table of contents
- Installation
- Creating and configuring the client
- Client functions
- Root client
- Organizations (
client.org(uuid)) - Sites (
client.site(uuid)) - Inboxes (
client.inbox(uuid)) - Site Inboxes (
client.siteInbox(uuid)) - Editing Sessions (
client.editingSession(uuid)) - Editing Session Files (
client.editingSessionFile(uuid)) - Builds (
client.build(uuid)) - Backups (
client.backup(uuid)) - Syncs (
client.sync(uuid))
- Pagination, sorting, and filtering
- Error handling
- Advanced: using the raw
client.fetch
Installation
npm install @cloudcannon/sdkCreating and configuring the client
Import CloudCannonClient and instantiate it with your API key:
import CloudCannonClient from '@cloudcannon/sdk';
const client = new CloudCannonClient({
key: 'your-api-key-here',
});Optional configuration
| Option | Type | Description |
|--------|------|-------------|
| key | string | Required. Your CloudCannon API key. |
| apiOrigin | string | The API host. Defaults to app.cloudcannon.com. |
| getCustomAuthHeaders | () => Record<string, string> | Provide custom authentication headers instead of the default X-API-KEY. |
const client = new CloudCannonClient({
key: 'your-api-key-here',
apiOrigin: 'app.cloudcannon.com',
});Client functions
The SDK exposes a hierarchy of sub-clients that map to CloudCannon's REST API resources. Each sub-client is accessed by calling a method on the root client with a UUID, or by calling top-level list methods directly on the root client.
Root client
client.orgs(options?)
List all organizations you have access to. Supports pagination, sorting, and filtering.
const { items, total_items } = await client.orgs({
// Pagination, sorting, and filtering options
page: 1, // Page number to fetch (1-indexed)
items: 10, // Number of items per page
sort_attribute: 'name', // Attribute to sort the results by (e.g. 'id', 'uuid', 'name', 'partner_points', 'updated_at')
sort_direction: 'ASC', // Sort direction: 'ASC' or 'DESC'
filters: {
// Optional filters
search: 'acme', // Search term
plan: 'pro', // Filter by plan name
country: 'US', // Filter by country
billing_status: 'active', // Filter by billing status
expired: false, // Filter by expired status
locked: false, // Filter by locked status
trial: false, // Filter by trial status
hosting_limit_exceeded: false, // Filter by hosting limit
build_time_limit_exceeded: false, // Filter by build time limit
user_limit_exceeded: false, // Filter by user limit
domain_limit_exceeded: false, // Filter by domain limit
in_partner_program: false, // Filter by partner program membership
user_uuid: 'user-uuid', // Filter by user UUID
uuid: 'org-uuid', // Filter by organization UUID
id: 123, // Filter by organization ID
// Date range filters (ISO 8601 strings)
created_at_lt: '2024-01-01T00:00:00Z',
created_at_gt: '2023-01-01T00:00:00Z',
created_at_lte: '2024-01-01T00:00:00Z',
created_at_gte: '2023-01-01T00:00:00Z',
updated_at_lt: '2024-01-01T00:00:00Z',
updated_at_gt: '2023-01-01T00:00:00Z',
updated_at_lte: '2024-01-01T00:00:00Z',
updated_at_gte: '2023-01-01T00:00:00Z',
},
});
// { // PaginatedResponse<Org>
// items: [
// { // Org
// uuid: "STRING_VALUE",
// id: 123,
// name: "STRING_VALUE",
// plan: "STRING_VALUE",
// billing_status: "STRING_VALUE",
// country: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }
// ],
// current_page: 1,
// total_items: 10,
// total_pages: 1,
// }client.getUploadData()
Fetch temporary S3 upload credentials used when uploading files through editing sessions.
const uploadData = await client.getUploadData();
// { // UploadData
// url: "STRING_VALUE",
// prefix: "STRING_VALUE",
// fields: {
// "<key>": "STRING_VALUE",
// },
// }Organizations (client.org(uuid))
const org = client.org('org-uuid');org.get()
Get details for a single organization.
const orgDetails = await org.get();
// { // Org
// uuid: "STRING_VALUE",
// id: 123,
// name: "STRING_VALUE",
// plan: "STRING_VALUE",
// billing_status: "STRING_VALUE",
// country: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }org.sites(options?)
List all sites within the organization. Supports pagination, sorting, and filtering.
const { items } = await org.sites({
// Pagination, sorting, and filtering options
page: 1, // Page number to fetch (1-indexed)
items: 20, // Number of items per page
sort_attribute: 'site_name', // Attribute to sort by (e.g. 'id', 'uuid', 'site_name', 'domain_name', 'created_at', 'updated_at', 'last_synced', 'last_compiled', 'storage_provider', 'stable_domain', 'subpath', 'sync_error')
sort_direction: 'DESC', // Sort direction: 'ASC' or 'DESC'
filters: {
// Optional filters
search: 'marketing', // Search term
site_name: 'My Site', // Filter by site name
domain_name: 'example.com', // Filter by domain name
stable_domain: 'my-site', // Filter by stable domain
ssg: 'hugo', // Filter by static site generator
storage_provider: 'github', // Filter by source provider
output_storage_provider: 'github', // Filter by output provider
hosting_choice: 'cloudcannon', // Filter by hosting choice
authentication: 'password', // Filter by authentication type
force_ssl: true, // Filter by SSL enforcement
editing_locked: false, // Filter by editing lock status
uploads_locked: false, // Filter by uploads lock status
browsing_locked: false, // Filter by browsing lock status
building_locked: false, // Filter by building lock status
uses_i18n: false, // Filter by i18n usage
sync_error: 'none', // Filter by sync error status
compile_error: 'none', // Filter by compile error status
project_uuid: 'project-uuid', // Filter by project UUID
base_domain_uuid: 'domain-uuid', // Filter by base domain UUID
dam_uuid: 'dam-uuid', // Filter by DAM UUID
inbox_uuid: 'inbox-uuid', // Filter by inbox UUID
uuid: 'site-uuid', // Filter by site UUID
id: 123, // Filter by site ID
// Date range filters
created_at_lt: '2024-01-01T00:00:00Z',
created_at_gt: '2023-01-01T00:00:00Z',
created_at_lte: '2024-01-01T00:00:00Z',
created_at_gte: '2023-01-01T00:00:00Z',
updated_at_lt: '2024-01-01T00:00:00Z',
updated_at_gt: '2023-01-01T00:00:00Z',
updated_at_lte: '2024-01-01T00:00:00Z',
updated_at_gte: '2023-01-01T00:00:00Z',
last_synced: '2024-01-01T00:00:00Z',
last_compiled: '2024-01-01T00:00:00Z',
},
});
// { // PaginatedResponse<Site>
// items: [
// { // Site
// uuid: "STRING_VALUE",
// id: 123,
// site_name: "STRING_VALUE",
// stable_domain: "STRING_VALUE",
// domain_name: "STRING_VALUE",
// ssg: "STRING_VALUE",
// storage_provider: "STRING_VALUE",
// hosting_choice: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }
// ],
// current_page: 1,
// total_items: 10,
// total_pages: 1,
// }org.createSite(name)
Create a new site in the organization.
const site = await org.createSite('My New Site');
// { // Site
// uuid: "STRING_VALUE",
// id: 123,
// site_name: "My New Site",
// stable_domain: "my-site",
// domain_name: "STRING_VALUE",
// ssg: "STRING_VALUE",
// storage_provider: "STRING_VALUE",
// hosting_choice: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }org.connectSite(name, providerDetails)
Create a new site connected to a Git provider.
const site = await org.connectSite(
'My Site',
{
provider: 'github', // Git provider (e.g. 'github', 'gitlab', 'bitbucket')
repository: 'owner/repo', // Repository identifier (owner/name)
branch: 'main', // Branch to connect
folder: 'src', // Optional subfolder within the repository
},
);
// { // Site
// uuid: "STRING_VALUE",
// id: 123,
// site_name: "My Site",
// stable_domain: "my-site",
// storage_provider: "github",
// domain_name: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }org.getInboxes(options?)
List inboxes belonging to the organization. Supports pagination, sorting, and filtering.
const { items } = await org.getInboxes({
page: 1,
items: 20,
sort_attribute: 'name', // Sort by 'created_at', 'updated_at', 'id', 'key', 'name', or 'uuid'
sort_direction: 'ASC',
filters: {
search: 'contact',
name: 'Contact Form',
captcha_type: 'recaptcha',
uuid: 'inbox-uuid',
id: 123,
// Date range filters
created_at_lt: '2024-01-01T00:00:00Z',
created_at_gt: '2023-01-01T00:00:00Z',
created_at_lte: '2024-01-01T00:00:00Z',
created_at_gte: '2023-01-01T00:00:00Z',
updated_at_lt: '2024-01-01T00:00:00Z',
updated_at_gt: '2023-01-01T00:00:00Z',
updated_at_lte: '2024-01-01T00:00:00Z',
updated_at_gte: '2023-01-01T00:00:00Z',
},
});
// { // PaginatedResponse<Inbox>
// items: [
// { // Inbox
// uuid: "STRING_VALUE",
// id: 123,
// name: "STRING_VALUE",
// key: "STRING_VALUE",
// monthly_quota: 1000,
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }
// ],
// current_page: 1,
// total_items: 10,
// total_pages: 1,
// }org.createInbox(body)
Create a new inbox.
const inbox = await org.createInbox({
name: 'Contact Form', // Display name for the inbox
key: 'contact-form', // Unique key/slug for the inbox
monthly_quota: 1000, // Optional monthly submission quota
keep_form_hook_days: 30, // Optional number of days to retain submissions
captcha_key: 'site-key', // Optional reCAPTCHA site key
captcha_secret: 'secret', // Optional reCAPTCHA secret key
captcha_type: 'recaptcha', // Optional captcha type
});
// { // Inbox
// uuid: "STRING_VALUE",
// id: 123,
// name: "Contact Form",
// key: "contact-form",
// monthly_quota: 1000,
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }org.getDams(options?)
List DAMs (Digital Asset Managers) connected to the organization. Supports pagination, sorting, and filtering.
const { items } = await org.getDams({
page: 1,
items: 20,
sort_attribute: 'name', // Sort by 'id', 'uuid', 'name', 'type', or 'base_url'
sort_direction: 'ASC',
filters: {
search: 'assets',
name: 'My DAM',
dam_type: 's3', // Filter by DAM type (e.g. 's3', 'cloudinary', 'azure')
uuid: 'dam-uuid',
id: 123,
unlinked_site_uuid: 'site-uuid', // Filter DAMs not linked to a specific site
site_uuid: 'site-uuid', // Filter DAMs linked to a specific site
// Date range filters
created_at_lt: '2024-01-01T00:00:00Z',
created_at_gt: '2023-01-01T00:00:00Z',
created_at_lte: '2024-01-01T00:00:00Z',
created_at_gte: '2023-01-01T00:00:00Z',
updated_at_lt: '2024-01-01T00:00:00Z',
updated_at_gt: '2023-01-01T00:00:00Z',
updated_at_lte: '2024-01-01T00:00:00Z',
updated_at_gte: '2023-01-01T00:00:00Z',
},
});
// { // PaginatedResponse<Dam>
// items: [
// { // Dam
// uuid: "STRING_VALUE",
// id: 123,
// name: "STRING_VALUE",
// dam_type: "s3",
// base_url: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }
// ],
// current_page: 1,
// total_items: 10,
// total_pages: 1,
// }org.createDam(body)
Create a new DAM connection.
const dam = await org.createDam({
dam_type: 's3', // DAM type: 's3', 'tenovos', 'cloudinary', 'azure', 'google', 'cloudflare', or 'digitalocean'
name: 'My Asset Library', // Display name for the DAM
config: JSON.stringify({ // DAM-specific configuration as a JSON string
bucket: 'my-bucket',
region: 'us-east-1',
}),
base_url: 'https://cdn.example.com', // Base URL for assets
access_key: 'access-key', // Optional access key
access_secret: 'secret', // Optional access secret
max_upload_size: 10485760, // Optional maximum upload size in bytes
});
// { // Dam
// uuid: "STRING_VALUE",
// id: 123,
// name: "My Asset Library",
// dam_type: "s3",
// base_url: "https://cdn.example.com",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }org.getRepositories(provider)
List repositories available from a given provider (e.g. github, gitlab, bitbucket).
const repos = await org.getRepositories('github');
// [ // RepositorySchema[]
// {
// full_name: "owner/repo",
// name: "repo",
// language: "typescript",
// private: true,
// avatar_url: "STRING_VALUE",
// size: 123,
// permissions: {
// admin: true,
// push: true,
// pull: true,
// },
// }
// ]Sites (client.site(uuid))
const site = client.site('site-uuid');site.get()
Get site details.
const siteDetails = await site.get();
// { // Site
// uuid: "STRING_VALUE",
// id: 123,
// site_name: "STRING_VALUE",
// stable_domain: "STRING_VALUE",
// domain_name: "STRING_VALUE",
// ssg: "STRING_VALUE",
// storage_provider: "STRING_VALUE",
// hosting_choice: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }site.update(body)
Update site settings.
const updatedSite = await site.update({
site_name: 'Updated Site Name', // New display name for the site
editing_locked: false, // Whether editing is locked
active_quest: 'onboarding', // Optional active quest/flow identifier
cloudcannon_config_path: '/cloudcannon.config.yml', // Optional path to CloudCannon config file
flags: { // Optional site flags/settings object
custom_flag: true,
},
});
// { // Site
// uuid: "STRING_VALUE",
// id: 123,
// site_name: "Updated Site Name",
// stable_domain: "STRING_VALUE",
// domain_name: "STRING_VALUE",
// ssg: "STRING_VALUE",
// storage_provider: "STRING_VALUE",
// hosting_choice: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }site.delete()
Delete the site.
await site.delete();
// Returns: voidsite.copy(body)
Copy the site to a new site.
const newSite = await site.copy({
site_name: 'Copy of My Site', // Name for the new copied site
editing_locked: false, // Whether the new site should have editing locked
active_quest: null, // Optional active quest for the new site
cloudcannon_config_path: null, // Optional config path for the new site
flags: {}, // Optional flags for the new site
publish_mode: null, // Optional publish mode
destroy_on_publish: false, // Whether to destroy the site on publish
});
// { // Site
// uuid: "STRING_VALUE",
// id: 123,
// site_name: "Copy of My Site",
// stable_domain: "copy-of-my-site",
// domain_name: "STRING_VALUE",
// ssg: "STRING_VALUE",
// storage_provider: "STRING_VALUE",
// hosting_choice: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }site.updateBuildConfig(options)
Update the build configuration for the site.
await site.updateBuildConfig({
default_locale: 'en', // Optional default locale for i18n
uses_i18n: true, // Whether the site uses internationalization
building_locked: false, // Whether building is locked
ssg: 'hugo', // Optional static site generator identifier
compile: {
install_command: 'npm install', // Command to run before building
build_command: 'hugo', // Build command
output_path: 'public', // Output directory for built files
environment_variables: [ // Optional environment variables
{ key: 'HUGO_VERSION', value: '0.120.0' },
],
hugoVersion: '0.120.0', // Optional Hugo version
denoVersion: '1.38.0', // Optional Deno version
rubyVersion: '3.2.0', // Optional Ruby version
nodeVersion: '20.0.0', // Optional Node.js version
preserved_paths: 'node_modules,dist/images', // Paths to preserve between builds (comma separated string)
preserveOutput: true, // Whether to preserve previous output
includeGit: false, // Whether to include Git history in build
manually_configure_urls: false, // Whether to manually configure URLs
},
});
// { // Site
// uuid: "STRING_VALUE",
// id: 123,
// site_name: "STRING_VALUE",
// stable_domain: "STRING_VALUE",
// ssg: "hugo",
// storage_provider: "STRING_VALUE",
// hosting_choice: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }site.getBuilds(options?)
List all builds for the site. Supports pagination, sorting, and filtering.
const { items } = await site.getBuilds({
page: 1,
items: 20,
sort_attribute: 'created_at', // Sort by 'id', 'uuid', or 'created_at'
sort_direction: 'DESC',
filters: {
search: 'build-123',
name: 'Production Build',
successful: true, // Filter by build success status
pinnable: true, // Filter by pinnable builds
site_uuid: 'site-uuid',
uuid: 'build-uuid',
id: 123,
completed_at: '2024-01-01T00:00:00Z',
// Date range filters
created_at_lt: '2024-01-01T00:00:00Z',
created_at_gt: '2023-01-01T00:00:00Z',
created_at_lte: '2024-01-01T00:00:00Z',
created_at_gte: '2023-01-01T00:00:00Z',
updated_at_lt: '2024-01-01T00:00:00Z',
updated_at_gt: '2023-01-01T00:00:00Z',
updated_at_lte: '2024-01-01T00:00:00Z',
updated_at_gte: '2023-01-01T00:00:00Z',
},
});
// { // PaginatedResponse<Build>
// items: [
// { // Build
// uuid: "STRING_VALUE",
// id: 123,
// name: "STRING_VALUE",
// site_id: 123,
// successful: true,
// completed_at: "TIMESTAMP",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }
// ],
// current_page: 1,
// total_items: 10,
// total_pages: 1,
// }site.rebuild()
Trigger a new build.
await site.rebuild();
// Returns: voidsite.listBackups(options?)
List backups/archives for the site. Supports pagination, sorting, and filtering.
const { items } = await site.listBackups({
page: 1,
items: 20,
sort_attribute: 'created_at', // Sort by 'id', 'uuid', or 'created_at'
sort_direction: 'DESC',
filters: {
search: 'backup-123',
uuid: 'backup-uuid',
id: 123,
size_gte: 1024, // Minimum backup size in bytes
size_lt: 104857600, // Maximum backup size (less than)
size_gt: 1024, // Minimum backup size (greater than)
size_lte: 104857600, // Maximum backup size (less than or equal)
// Date range filters
created_at_lt: '2024-01-01T00:00:00Z',
created_at_gt: '2023-01-01T00:00:00Z',
created_at_lte: '2024-01-01T00:00:00Z',
created_at_gte: '2023-01-01T00:00:00Z',
updated_at_lt: '2024-01-01T00:00:00Z',
updated_at_gt: '2023-01-01T00:00:00Z',
updated_at_lte: '2024-01-01T00:00:00Z',
updated_at_gte: '2023-01-01T00:00:00Z',
},
});
// { // PaginatedResponse<Backup>
// items: [
// { // SiteArchive
// uuid: "STRING_VALUE",
// id: 123,
// path: "STRING_VALUE",
// size: 123,
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }
// ],
// current_page: 1,
// total_items: 10,
// total_pages: 1,
// }site.createBackup(body?)
Create a new backup. Returns an optional socket_message_id for real-time progress updates.
const result = await site.createBackup({
exclude_git: false, // Whether to exclude Git history from the backup
});
// { // { socket_message_id?: string }
// socket_message_id: "STRING_VALUE",
// }site.listFiles()
List files in the site's repository.
const files = await site.listFiles();
// [ // FileListing[]
// {
// md5: "STRING_VALUE",
// s3Path: "STRING_VALUE",
// sitePath: "STRING_VALUE",
// }
// ]site.getFile(path)
Fetch a raw file from the site's repository. Returns a Response object.
const resp = await site.getFile('README.md');
const text = await resp.text();
// Returns: Response — raw fetch Response for the requested filesite.getSyncs(options?)
List syncs for the site. Supports pagination, sorting, and filtering.
const { items } = await site.getSyncs({
page: 1,
items: 20,
sort_attribute: 'created_at', // Sort by 'id', 'uuid', or 'created_at'
sort_direction: 'DESC',
filters: {
search: 'sync-123',
name: 'Main Sync',
successful: true, // Filter by sync success status
provider: 'github', // Filter by provider
identifier: 'main-branch', // Filter by sync identifier
after_identifier: 'prev-id', // Filter by after identifier
diff_id: 'diff-123', // Filter by diff ID
site_uuid: 'site-uuid',
uuid: 'sync-uuid',
id: 123,
completed_at: '2024-01-01T00:00:00Z',
// Date range filters
created_at_lt: '2024-01-01T00:00:00Z',
created_at_gt: '2023-01-01T00:00:00Z',
created_at_lte: '2024-01-01T00:00:00Z',
created_at_gte: '2023-01-01T00:00:00Z',
updated_at_lt: '2024-01-01T00:00:00Z',
updated_at_gt: '2023-01-01T00:00:00Z',
updated_at_lte: '2024-01-01T00:00:00Z',
updated_at_gte: '2023-01-01T00:00:00Z',
},
});
// { // PaginatedResponse<Sync>
// items: [
// { // Sync
// uuid: "STRING_VALUE",
// id: 123,
// name: "STRING_VALUE",
// successful: true,
// provider: "github",
// identifier: "main-branch",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }
// ],
// current_page: 1,
// total_items: 10,
// total_pages: 1,
// }site.getScan()
Get the latest site scan results.
const scan = await site.getScan();
// { // SiteScanner
// uuid: "STRING_VALUE",
// id: 123,
// files: 123,
// html_files: 123,
// css_files: 123,
// image_files: 123,
// js_files: 123,
// blog_posts: 123,
// data_files: 123,
// layouts: 123,
// total_size: 123,
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }site.getScreenshotHashes()
Get MD5 hashes for site screenshots.
const hashes = await site.getScreenshotHashes();
// { // Record<string, string>
// "desktop": "d41d8cd98f00b204e9800998ecf8427e",
// "mobile": "d41d8cd98f00b204e9800998ecf8427e",
// }site.getScreenshot(device, path)
Fetch a screenshot for a specific path and device (desktop or mobile). Returns a Response object.
const screenshot = await site.getScreenshot('desktop', '/about');
// Returns: Response — raw image fetch Responsesite.connectSourceProvider(options)
Connect a Git repository as the source provider.
await site.connectSourceProvider({
provider: 'github', // Git provider (e.g. 'github', 'gitlab', 'bitbucket')
repository: 'owner/repo', // Repository identifier (owner/name)
branch: 'main', // Branch to connect
});
// { // Site
// uuid: "STRING_VALUE",
// id: 123,
// site_name: "STRING_VALUE",
// stable_domain: "STRING_VALUE",
// storage_provider: "github",
// domain_name: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }site.updateSourceProvider(options)
Update the connected source provider's branch or repository.
await site.updateSourceProvider({
repository: 'owner/new-repo', // Updated repository identifier
branch: 'develop', // Updated branch name
});
// { // Site
// uuid: "STRING_VALUE",
// id: 123,
// site_name: "STRING_VALUE",
// stable_domain: "STRING_VALUE",
// storage_provider: "github",
// domain_name: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }site.disconnectSourceProvider()
Remove the source provider connection.
const updatedSite = await site.disconnectSourceProvider();
// { // Site
// uuid: "STRING_VALUE",
// id: 123,
// site_name: "STRING_VALUE",
// stable_domain: "STRING_VALUE",
// storage_provider: null,
// domain_name: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }site.connectOutputProvider(options)
Connect a Git repository as the output (built site) provider.
await site.connectOutputProvider({
provider: 'github', // Git provider
repository: 'owner/output', // Output repository identifier
branch: 'gh-pages', // Output branch
});
// { // Site
// uuid: "STRING_VALUE",
// id: 123,
// site_name: "STRING_VALUE",
// stable_domain: "STRING_VALUE",
// output_storage_provider: "github",
// domain_name: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }site.disconnectOutputProvider()
Remove the output provider connection.
const updatedSite = await site.disconnectOutputProvider();
// { // Site
// uuid: "STRING_VALUE",
// id: 123,
// site_name: "STRING_VALUE",
// stable_domain: "STRING_VALUE",
// output_storage_provider: null,
// domain_name: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }site.getInboxConnections()
Get inboxes connected to this site.
const inboxes = await site.getInboxConnections();
// [ // SiteInbox
// {
// uuid: "STRING_VALUE",
// id: 123,
// inbox_uuid: "STRING_VALUE",
// default_inbox: true,
// visible: true,
// require_captcha: true,
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }
// ]site.connectInbox(body)
Connect an inbox to this site.
const siteInbox = await site.connectInbox({
inbox_uuid: 'inbox-uuid', // UUID of the inbox to connect
default_inbox: true, // Whether this is the default inbox for the site
visible: true, // Whether the inbox is visible
require_captcha: true, // Whether to require captcha for submissions
});
// { // SiteInbox
// uuid: "STRING_VALUE",
// id: 123,
// inbox_uuid: "inbox-uuid",
// default_inbox: true,
// visible: true,
// require_captcha: true,
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }site.getDamConnections()
Get DAMs connected to this site.
const dams = await site.getDamConnections();
// [ // SiteDam
// {
// uuid: "STRING_VALUE",
// id: 123,
// dam_uuid: "STRING_VALUE",
// uploads_locked: false,
// reference_key: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }
// ]site.connectDam(body)
Connect a DAM to this site.
const siteDam = await site.connectDam({
dam_uuid: 'dam-uuid', // UUID of the DAM to connect
uploads_locked: false, // Whether uploads to the DAM are locked
config: { // Optional DAM-specific configuration
folder: 'site-assets',
},
reference_key: 'main-assets', // Optional reference key
});
// { // SiteDam
// uuid: "STRING_VALUE",
// id: 123,
// dam_uuid: "dam-uuid",
// uploads_locked: false,
// reference_key: "main-assets",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }site.getEditingSessions()
List editing sessions for the site.
const sessions = await site.getEditingSessions();
// [ // EditingSession
// {
// uuid: "STRING_VALUE",
// id: 123,
// site_id: 123,
// state: "STRING_VALUE",
// base_commit_hash: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }
// ]site.createEditingSession()
Create a new editing session.
const session = await site.createEditingSession();
// { // EditingSession
// uuid: "STRING_VALUE",
// id: 123,
// site_id: 123,
// state: "STRING_VALUE",
// base_commit_hash: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }site.getLatestEditingSession()
Get the most recent editing session.
const latestSession = await site.getLatestEditingSession();
// { // EditingSession
// uuid: "STRING_VALUE",
// id: 123,
// site_id: 123,
// state: "STRING_VALUE",
// base_commit_hash: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }site.uploadFile(path, content, options?)
Upload a file to the site through an editing session. Content is uploaded to S3 and committed through the editing session workflow.
await site.uploadFile(
'content/posts/hello.md', // Path in the site's repository
'# Hello World', // File content (string, Blob, ArrayBuffer, etc.)
{
type: 'text/markdown', // Optional MIME type (defaults to 'text/plain')
overwriteExistingFile: true, // Whether to overwrite if the file already exists
}
);
// Returns: voidsite.triggerPull()
Manually trigger a pull from the source provider.
await site.triggerPull();
// Returns: voidInboxes (client.inbox(uuid))
const inbox = client.inbox('inbox-uuid');inbox.getSubmissions(options?)
List form submissions for the inbox. Supports pagination, sorting, and filtering.
const { items } = await inbox.getSubmissions({
page: 1,
items: 20,
sort_attribute: 'last_sent_at', // Sort by 'last_sent_at', 'created_at', 'id', or 'uuid'
sort_direction: 'DESC',
filters: {
category: 'pending', // Filter by status: 'spam', 'sent', 'errored', or 'pending'
search: '[email protected]',
sent: true, // Filter by sent status
spam_checked: true, // Filter by spam checked status
automatically_marked_spam: false, // Filter by auto-marked spam
explicitly_marked_status: 0, // Filter by explicit status
has_error: false, // Filter by error presence
has_spam_check_error: false, // Filter by spam check error
ip: '192.168.1.1', // Filter by IP address
host: 'example.com', // Filter by host
inbox_uuid: 'inbox-uuid',
site_uuid: 'site-uuid',
uuid: 'submission-uuid',
id: 123,
// Date range filters for cleared_at
cleared_at_lt: '2024-01-01T00:00:00Z',
cleared_at_gt: '2023-01-01T00:00:00Z',
cleared_at_lte: '2024-01-01T00:00:00Z',
cleared_at_gte: '2023-01-01T00:00:00Z',
// Date range filters for last_sent_at
last_sent_at_lt: '2024-01-01T00:00:00Z',
last_sent_at_gt: '2023-01-01T00:00:00Z',
last_sent_at_lte: '2024-01-01T00:00:00Z',
last_sent_at_gte: '2023-01-01T00:00:00Z',
// Count filters
sent_count_lt: 5,
sent_count_gt: 0,
sent_count_lte: 10,
sent_count_gte: 1,
// Standard date range filters
created_at_lt: '2024-01-01T00:00:00Z',
created_at_gt: '2023-01-01T00:00:00Z',
created_at_lte: '2024-01-01T00:00:00Z',
created_at_gte: '2023-01-01T00:00:00Z',
updated_at_lt: '2024-01-01T00:00:00Z',
updated_at_gt: '2023-01-01T00:00:00Z',
updated_at_lte: '2024-01-01T00:00:00Z',
updated_at_gte: '2023-01-01T00:00:00Z',
},
});
// { // PaginatedResponse<FormSubmission>
// items: [
// { // FormHook
// uuid: "STRING_VALUE",
// id: 123,
// sent: true,
// ip: "STRING_VALUE",
// host: "STRING_VALUE",
// data: {},
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }
// ],
// current_page: 1,
// total_items: 10,
// total_pages: 1,
// }Site Inboxes (client.siteInbox(uuid))
const siteInbox = client.siteInbox('site-inbox-uuid');siteInbox.update(body)
Update a site-inbox connection.
const updated = await siteInbox.update({
inbox_uuid: 'inbox-uuid', // UUID of the inbox to link
default_inbox: true, // Whether this is the default inbox for the site
visible: true, // Whether the inbox is visible on the site
require_captcha: true, // Whether to require captcha for form submissions
});
// { // SiteInbox
// uuid: "STRING_VALUE",
// id: 123,
// inbox_uuid: "inbox-uuid",
// default_inbox: true,
// visible: true,
// require_captcha: true,
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }Editing Sessions (client.editingSession(uuid))
const session = client.editingSession('session-uuid');session.get()
Get editing session details.
const sessionDetails = await session.get();
// { // EditingSession
// uuid: "STRING_VALUE",
// id: 123,
// site_id: 123,
// state: "STRING_VALUE",
// base_commit_hash: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }session.getFiles()
List files in the editing session.
const files = await session.getFiles();
// [ // EditingSessionFile
// {
// uuid: "STRING_VALUE",
// id: 123,
// editing_session_uuid: "STRING_VALUE",
// path: "STRING_VALUE",
// source_path: "STRING_VALUE",
// edit_type: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }
// ]session.createFile(body)
Create a new file in the editing session.
const file = await session.createFile({
edit_type: 'update', // Type of edit: 'update', 'delete'.
path: 'content/new-post.md', // Target path for the file
source_path: 'content/draft.md', // Optional source path (for move/copy operations)
discard_unsaved: false, // Whether to discard any unsaved changes
previous_content_hash: 'abc123', // Optional hash of the previous content
metadata: { // Optional metadata object
title: 'New Post',
},
});
// { // EditingSessionFile
// uuid: "STRING_VALUE",
// id: 123,
// editing_session_uuid: "STRING_VALUE",
// path: "content/new-post.md",
// edit_type: "create",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }session.commit()
Commit the editing session, pushing changes to the connected repository.
const result = await session.commit();
// { // CommitEditingSessionResponse
// socket_message_id: "STRING_VALUE",
// }Editing Session Files (client.editingSessionFile(uuid))
const file = client.editingSessionFile('file-uuid');file.get()
Get details for an editing session file.
const fileDetails = await file.get();
// { // EditingSessionFile
// uuid: "STRING_VALUE",
// id: 123,
// editing_session_uuid: "STRING_VALUE",
// path: "STRING_VALUE",
// source_path: "STRING_VALUE",
// edit_type: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }file.getContributions()
List contributions (versions) for the file.
const contributions = await file.getContributions();
// [ // EditingSessionFileContribution
// {
// uuid: "STRING_VALUE",
// id: 123,
// editing_session_file_uuid: "STRING_VALUE",
// session_uuid: "STRING_VALUE",
// state: "STRING_VALUE",
// file_contents: "STRING_VALUE",
// content_hash: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }
// ]file.createContribution(body)
Create a new contribution for the file.
const contribution = await file.createContribution({
s3_key: 'uploads/12345/content.md', // S3 key where the file content is stored
content_hash: 'd41d8cd98f00b204e9800998ecf8427e', // MD5 hash of the new content
previous_content_hash: 'abc123def456', // Optional hash of the previous content for conflict detection
});
// { // EditingSessionFileContribution
// uuid: "STRING_VALUE",
// id: 123,
// editing_session_file_uuid: "STRING_VALUE",
// session_uuid: "STRING_VALUE",
// state: "STRING_VALUE",
// file_contents: "STRING_VALUE",
// content_hash: "d41d8cd98f00b204e9800998ecf8427e",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }file.unlock(body)
Unlock the file so other users can edit it.
const contribution = await file.unlock({
previous_content_hash: 'd41d8cd98f00b204e9800998ecf8427e', // Expected current content hash
});
// { // EditingSessionFileContribution
// uuid: "STRING_VALUE",
// id: 123,
// editing_session_file_uuid: "STRING_VALUE",
// session_uuid: "STRING_VALUE",
// state: "STRING_VALUE",
// file_contents: "STRING_VALUE",
// content_hash: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }Builds (client.build(uuid))
const build = client.build('build-uuid');build.get()
Get build details. Returns a Response object.
const resp = await build.get();
const buildData = await resp.json();
// { // Build
// uuid: "STRING_VALUE",
// id: 123,
// name: "STRING_VALUE",
// site_id: 123,
// successful: true,
// completed_at: "TIMESTAMP",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }Backups (client.backup(uuid))
const backup = client.backup('backup-uuid');backup.download()
Download a backup archive. Returns a Response object.
const resp = await backup.download();
// Returns: Response — raw binary fetch Response (consume the body stream)Syncs (client.sync(uuid))
const sync = client.sync('sync-uuid');sync.get()
Get sync details. Returns a Response object.
const resp = await sync.get();
const syncData = await resp.json();
// { // Sync
// uuid: "STRING_VALUE",
// id: 123,
// name: "STRING_VALUE",
// successful: true,
// provider: "github",
// identifier: "STRING_VALUE",
// created_at: "TIMESTAMP",
// updated_at: "TIMESTAMP",
// }Pagination, sorting, and filtering
Many list methods support pagination, sorting, and filtering through a common options shape. The examples above show the available options for each endpoint. In general:
pageanditemscontrol pagination.sort_attributeandsort_directioncontrol ordering.filtersis an object of endpoint-specific query parameters.
Responses from paginated endpoints return:
{
items: T[]; // Array of results for the current page
current_page?: number; // Current page number
total_items?: number; // Total number of items across all pages
total_pages?: number; // Total number of pages available
}Error handling
The SDK throws standard Error objects for permission and not-found failures. For validation errors (HTTP 422), it throws an ApiError which includes the full validation messages, the request URL, and the original status code.
import { ApiError } from '@cloudcannon/sdk';
try {
await site.update({ site_name: '' });
} catch (err) {
if (err instanceof ApiError) {
console.error(err.status); // 422
console.error(err.errors); // Detailed validation errors from the API
console.error(err.url); // The endpoint that failed
}
}Advanced: using the raw client.fetch
The root client exposes a strongly-typed fetch method that you can use to call any CloudCannon API endpoint directly. The URL and request body are typed against the OpenAPI schema, so TypeScript will autocomplete valid paths and validate request shapes.
// GET request to an arbitrary endpoint
const resp = await client.fetch('/orgs/my-org', {
method: 'GET',
});
const org = await resp.json();// POST with a typed request body
const resp = await client.fetch('/orgs/my-org/sites', {
method: 'POST',
body: {
site_name: 'My New Site',
},
});
const site = await resp.json();fetch automatically injects your authentication headers and sets Content-Type: application/json. It returns a typed response object keyed by HTTP status codes, so you can handle success and error cases with full type safety.
const resp = await client.fetch('/sites/site-uuid');
if (resp.status === 200) {
const site = await resp.json();
} else if (resp.status === 404) {
// Handle not found
}This is useful when you need to access endpoints that are not yet covered by the high-level sub-clients, or when you need full control over headers and fetch options.
