Documentation Index
Fetch the complete documentation index at: https://mintlify.com/buttondown/cli/llms.txt
Use this file to discover all available pages before exploring further.
The newsletter module handles synchronization of newsletter settings between the Buttondown API and a local JSON file.
Overview
The newsletter configuration represents the top-level settings for your Buttondown newsletter. Unlike other resources that handle collections, this module manages a single newsletter object.
Types
Newsletter
Based on the Buttondown API Newsletter schema from OpenAPI specification.
type Newsletter = components["schemas"]["Newsletter"]
Typically includes:
id - Unique newsletter identifier
username - Newsletter username/slug
name - Newsletter display name
description - Newsletter description
settings - Various configuration options
creation_date - When the newsletter was created
And many other configuration fields for branding, behavior, and integrations.
Resource Objects
REMOTE_NEWSLETTER_RESOURCE
Handles newsletter operations with the Buttondown API.
const REMOTE_NEWSLETTER_RESOURCE: Resource<Newsletter, Newsletter>
Methods
get(configuration)
Fetches the newsletter configuration from the API.
async get(configuration: Configuration): Promise<Newsletter | null>
Configuration with API credentials and username
Newsletter object matching the configured username, or null if not found
Behavior
- Fetches all newsletters from the API (GET
/newsletters)
- Filters results to find newsletter matching
configuration.username
- Returns
null if no matching newsletter is found
Example
import { REMOTE_NEWSLETTER_RESOURCE } from "./sync/newsletter.js";
const config = {
baseUrl: "https://api.buttondown.email/v1",
apiKey: "your-api-key",
username: "my-newsletter",
directory: "./buttondown-data"
};
const newsletter = await REMOTE_NEWSLETTER_RESOURCE.get(config);
if (newsletter) {
console.log(`Found newsletter: ${newsletter.name}`);
console.log(`Username: ${newsletter.username}`);
} else {
console.error("Newsletter not found");
}
set(value, configuration)
Updates the newsletter configuration via the API.
async set(
value: Newsletter,
configuration: Configuration
): Promise<OperationResult>
Newsletter object with updated values (must include id)
Configuration with API credentials
Operation result indicating successful update
Behavior
- Sends PATCH request to
/newsletters/{id}
- Updates newsletter with provided fields
- Always returns:
{
updated: 1,
created: 0,
deleted: 0,
failed: 0
}
Example
const newsletter = await REMOTE_NEWSLETTER_RESOURCE.get(config);
if (newsletter) {
// Update settings
newsletter.name = "My Updated Newsletter";
newsletter.description = "New description";
const result = await REMOTE_NEWSLETTER_RESOURCE.set(
newsletter,
config
);
console.log(`Updated: ${result.updated}`);
}
LOCAL_NEWSLETTER_RESOURCE
Handles newsletter operations with local JSON file.
const LOCAL_NEWSLETTER_RESOURCE: Resource<Newsletter, Newsletter>
Methods
get(configuration)
Reads newsletter configuration from local newsletter.json file.
async get(configuration: Configuration): Promise<Newsletter>
Configuration with directory path
Newsletter object parsed from JSON file
Behavior
- Reads from
{directory}/newsletter.json
- Parses JSON content
- Returns newsletter object
- Throws error if file doesn’t exist or JSON is invalid
Example
import { LOCAL_NEWSLETTER_RESOURCE } from "./sync/newsletter.js";
const config = {
directory: "./buttondown-data",
baseUrl: "https://api.buttondown.email/v1",
apiKey: "your-api-key"
};
try {
const newsletter = await LOCAL_NEWSLETTER_RESOURCE.get(config);
console.log(`Local newsletter: ${newsletter.name}`);
} catch (error) {
console.error("Failed to read newsletter.json");
}
set(value, configuration)
Writes newsletter configuration to local newsletter.json file.
async set(
value: Newsletter,
configuration: Configuration
): Promise<OperationResult>
Newsletter object to write
Configuration with directory path
Operation result indicating successful write
Behavior
- Writes to
{directory}/newsletter.json
- Formats JSON with 2-space indentation
- Creates file if it doesn’t exist
- Overwrites existing file
- Always returns:
{
updated: 1,
created: 0,
deleted: 0,
failed: 0
}
Example
const newsletter = {
id: "news_123",
username: "my-newsletter",
name: "My Newsletter",
description: "A great newsletter",
// ... other fields
};
await LOCAL_NEWSLETTER_RESOURCE.set(newsletter, config);
console.log("Newsletter saved to newsletter.json");
NEWSLETTER_RESOURCE
Combined resource group for newsletter synchronization.
const NEWSLETTER_RESOURCE: ResourceGroup<
Newsletter,
Newsletter,
Newsletter
>
Properties
Resource identifier: "newsletter"
remote
Resource<Newsletter, Newsletter>
Remote API resource handler
local
Resource<Newsletter, Newsletter>
Local filesystem resource handler
Usage Patterns
Pull Newsletter from Remote
import { NEWSLETTER_RESOURCE } from "./sync/newsletter.js";
const config = {
baseUrl: "https://api.buttondown.email/v1",
apiKey: "your-api-key",
username: "my-newsletter",
directory: "./buttondown-data"
};
// Fetch from API
const newsletter = await NEWSLETTER_RESOURCE.remote.get(config);
if (newsletter) {
// Save to local file
await NEWSLETTER_RESOURCE.local.set(newsletter, config);
console.log("Newsletter synced to newsletter.json");
} else {
console.error("Newsletter not found on remote");
}
Push Local Changes to Remote
// Read from local file
const localNewsletter = await NEWSLETTER_RESOURCE.local.get(config);
// Update API
const result = await NEWSLETTER_RESOURCE.remote.set(
localNewsletter,
config
);
console.log(`Newsletter updated: ${result.updated}`);
Edit Newsletter Settings
import { readFile, writeFile } from "fs/promises";
import path from "path";
const config = {
directory: "./buttondown-data",
baseUrl: "https://api.buttondown.email/v1",
apiKey: "your-api-key"
};
// Read current settings
const filePath = path.join(config.directory, "newsletter.json");
const newsletter = JSON.parse(
await readFile(filePath, "utf8")
);
// Update settings
newsletter.name = "My New Newsletter Name";
newsletter.description = "Updated description";
// Write back
await writeFile(
filePath,
JSON.stringify(newsletter, null, 2)
);
console.log("Newsletter settings updated locally");
Sync Workflow
// 1. Pull latest from remote
const remote = await NEWSLETTER_RESOURCE.remote.get(config);
if (!remote) {
throw new Error("Newsletter not found");
}
// 2. Save backup locally
await NEWSLETTER_RESOURCE.local.set(remote, config);
// 3. Make local changes
const local = await NEWSLETTER_RESOURCE.local.get(config);
local.description = "Updated locally";
await NEWSLETTER_RESOURCE.local.set(local, config);
// 4. Push changes back to remote
await NEWSLETTER_RESOURCE.remote.set(local, config);
console.log("Sync complete");
Notes
Serialization
Unlike emails, automations, and snippets, the newsletter resource doesn’t require custom serialization/deserialization:
serialize: (r) => r, // Identity function
deserialize: (s) => s // Identity function
The newsletter object is stored as-is in JSON format without transformation.
Single Resource
The newsletter module differs from other sync operations:
- Handles a single object instead of a collection
- Returns
Newsletter | null instead of Newsletter[]
- No pagination needed
- No slug/identifier generation required
Username Matching
When fetching from remote, the module filters newsletters by configuration.username. Make sure your configuration includes the correct username:
const config = {
username: "my-newsletter", // Must match your Buttondown username
// ... other config
};