### Setup Script Output Example Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/configuration.md Illustrates the expected output from the setup script when a collection is found and fields are set. ```bash Found existing collection [id: col-xyz] Set 5 fields Collection ready [existing items: 23] ✅ Setup complete! Collection is ready for webhook integration. ``` -------------------------------- ### JSON API Server Startup Command Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/EXAMPLE_SCRIPTS.md Command to start the JSON API server example using Hono and Node.js. Requires a Framer project URL environment variable. ```bash EXAMPLE_PROJECT_URL="https://framer.com/projects/" npm run dev ``` -------------------------------- ### Examples & Patterns Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/DOCUMENTATION_INDEX.txt Documentation for all 4 examples and associated patterns, providing practical usage guidance. ```APIDOC ## Examples & Patterns ### Description This section showcases all 4 working examples and associated patterns, offering practical code snippets and usage guidance for developers. ### Reference - See `EXAMPLE_SCRIPTS.md` for all documented examples. ``` -------------------------------- ### Environment File Usage Examples Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/configuration.md Shows how to use the `.env` file with Node.js, Bun, and Deno for script execution. ```bash # Node.js v20.6+ node --env-file=.env script.ts # Bun bun run script.ts # Deno denp run --env-file=.env script.ts ``` -------------------------------- ### Cron Job Examples for Scheduling Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/configuration.md Provides examples of crontab entries for scheduling a Node.js script to run at different intervals and times. ```bash # Every 4 hours 0 */4 * * * cd /path/to/examples/publish && node --env-file=../../.env publish.ts >> /var/log/framer-publish.log 2>&1 ``` ```bash # Every 2 hours (9 AM - 6 PM, weekdays) 0 9-18/2 * * 1-5 cd /path/to/examples/publish && node --env-file=../../.env publish.ts >> /var/log/framer-publish.log 2>&1 ``` ```bash # Daily at 9 AM 0 9 * * * cd /path/to/examples/publish && node --env-file=../../.env publish.ts >> /var/log/framer-publish.log 2>&1 ``` ```bash # Weekdays at 9 AM 0 9 * * 1-5 cd /path/to/examples/publish && node --env-file=../../.env publish.ts >> /var/log/framer-publish.log 2>&1 ``` -------------------------------- ### Example PageProperties Object Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/api-reference-notion-utils.md An example illustrating the structure of a PageProperties object, showing different types of Notion properties. ```json { "Title": { type: "title", title: [...] }, "Status": { type: "select", select: {...} }, "Created": { type: "created_time", created_time: "..." }, "Deleted": { type: "checkbox", checkbox: true } } ``` -------------------------------- ### Run Framer Server API Source: https://github.com/framer/server-api-examples/blob/main/examples/json-api/README.md Command to start the Framer Server API. Ensure you set the EXAMPLE_PROJECT_URL environment variable. ```bash EXAMPLE_PROJECT_URL="https://framer.com/projects/..." npm run dev ``` -------------------------------- ### Run Local Development Server Source: https://github.com/framer/server-api-examples/blob/main/examples/notion-automations-sync/README.md Command to start the local development server for the Cloudflare Worker. ```bash npm run dev ``` -------------------------------- ### Example cURL Request Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/endpoints.md Send a POST request to the server endpoint with webhook data. This example demonstrates the expected payload structure for processing Notion updates. ```bash curl -X POST http://localhost:8787/ \ -H "Authorization: secret-token" \ -H "Content-Type: application/json" \ -d '{ \ "source": { \ "type": "automation", \ "automation_id": "aut-123", \ "action_id": "act-456", \ "event_id": "evt-789", \ "attempt": 1 \ }, \ "data": { \ "id": "abc-def-ghi-jkl", \ "parent": { "type": "database_id", "database_id": "db-xyz" }, \ "archived": false, \ "in_trash": false, \ "properties": { \ "Title": { \ "type": "title", \ "title": [{"type": "text", "text": {"content": "Test"}}] \ }, \ "Deleted": { "type": "checkbox", "checkbox": false } \ } \ } \ }' ``` -------------------------------- ### Wrangler Configuration Example Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/configuration.md Shows a sample `wrangler.jsonc` file for configuring a Cloudflare Worker, including name, entry point, and production environment routes. ```json { "name": "notion-framer-sync", "main": "src/index.ts", "compatibility_date": "2024-12-19", "env": { "production": { "routes": [ { "pattern": "sync.example.com/*", "zone_name": "example.com" } ] } } } ``` -------------------------------- ### Common Cron Schedules Source: https://github.com/framer/server-api-examples/blob/main/examples/publish/README.md Examples of common cron schedule patterns for task automation. ```bash 0 */4 * * * # Every 4 hours ``` ```bash 0 9-18/2 * * 1-5 # Every 2 hours between 9:00 and 18:00, mon-fri ``` ```bash 0 9 * * * # Daily at 9:00 ``` ```bash 0 9 * * 1-5 # Weekdays at 9:00 ``` -------------------------------- ### CSV File Example Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/configuration.md Example CSV data format for the CSV Importer, including required 'slug' column and other fields like title, price, stock, and date. ```csv slug,title,price,in_stock,release_date laptop-pro,Laptop Pro 15",1299.99,true,2024-01-15 mouse-wireless,Wireless Mouse,49.99,false,2024-02-20 keyboard-mechanical,Mechanical Keyboard,149.99,true,2024-01-10 ``` -------------------------------- ### Environment File Format Example Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/configuration.md Demonstrates the standard `.env` file format for local development, including Framer API, CSV importer, and Notion sync variables. ```dotenv # Framer API EXAMPLE_PROJECT_URL=https://framer.com/projects/MyProject--abc123def456 FRAMER_API_KEY=sk_live_xxxxxxxxxxxx FRAMER_PROJECT_URL=https://framer.com/projects/MyProject--abc123def456 # CSV Importer CSV_PATH=./data/products.csv COLLECTION_NAME=Products # Notion Sync WEBHOOK_TOKEN=your-secret-webhook-token FRAMER_COLLECTION_NAME=Notion Sync NOTION_DATABASE_ID=abc123def456 ``` -------------------------------- ### systemd Timer Enable and Start Commands Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/EXAMPLE_SCRIPTS.md These bash commands enable and start the systemd timer for the Framer publish script, ensuring it runs automatically. ```bash sudo systemctl enable framer-publish.timer sudo systemctl start framer-publish.timer ``` -------------------------------- ### CSV Importer Output Example Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/EXAMPLE_SCRIPTS.md Shows the expected output message after successfully importing items using the CSV importer script. ```text Imported 3 items ``` -------------------------------- ### Create a Managed Collection Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/api-reference-framer-client.md This example shows how to create a managed collection and set its fields using IDs. This is useful for integrations like Notion Automations Sync. ```typescript using framer = await connect(projectUrl, apiKey); const collection = await framer.createManagedCollection("Articles"); console.log(`Created managed collection: ${collection.id}`); // Set fields with IDs await collection.setFields([ { id: "title", name: "Title", type: "string" }, { id: "published", name: "Published", type: "date" } ]); ``` -------------------------------- ### Sample CSV Data Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/EXAMPLE_SCRIPTS.md Provides an example CSV file content for product data, including slug, title, price, stock status, and release date. Shows inferred field types. ```csv slug,title,price,in_stock,release_date laptop-pro,Laptop Pro 15,1299.99,true,2024-01-15 mouse-wireless,Wireless Mouse,49.99,false,2024-02-20 keyboard-mech,Mechanical Keyboard,149.99,true,2024-01-10 ``` -------------------------------- ### JSON API Runtime Configuration Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/configuration.md Sets up the Framer project URL from environment variables for the JSON API example. Asserts that the variable is set. ```typescript const projectUrl = process.env["EXAMPLE_PROJECT_URL"]; assert(projectUrl, "EXAMPLE_PROJECT_URL environment variable is required"); const app = new Hono<{ Variables: Variables }>(); ``` -------------------------------- ### Setup Collection Fields from Configuration Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/api-reference-collections.md Dynamically sets fields for a managed collection based on a provided configuration mapping. Logs the number of fields successfully set. ```typescript async function setupFields(collection: ManagedCollection) { const fields = config.FIELD_MAPPING.map((mapping) => ({ type: mapping.type, name: mapping.framerName, id: mapping.framerId, })); await collection.setFields(fields); const setFields = await collection.getFields(); console.log(`Set ${setFields.length} fields`); } ``` -------------------------------- ### Execute CSV Importer Script Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/EXAMPLE_SCRIPTS.md Demonstrates how to run the CSV importer script using Node.js. Shows examples with default settings and custom CSV paths or collection names. ```bash # With default CSV and collection name node --env-file=../../.env src/csv-to-collection.ts # Custom CSV path CSV_PATH=/path/to/data.csv node --env-file=../../.env src/csv-to-collection.ts # Custom collection name COLLECTION_NAME="Custom Collection" node --env-file=../../.env src/csv-to-collection.ts # Both custom CSV_PATH=/path/to/data.csv COLLECTION_NAME="Custom" node --env-file=../../.env src/csv-to-collection.ts ``` -------------------------------- ### Schedule Project Publish with Cron Source: https://github.com/framer/server-api-examples/blob/main/examples/publish/README.md Configure a cron job to automatically publish your Framer project. This example publishes every 4 hours and logs output. ```bash # Edit crontab crontab -e # Add this line (adjust paths as needed) 0 */4 * * * cd /path/to/examples/publish && node --env-file=../../.env publish.ts >> /var/log/framer-publish.log 2>&1 ``` -------------------------------- ### Infer Field Type Examples Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/api-reference-csv-loader.md Demonstrates the `inferFieldType` function with various input arrays to show how it determines the data type. ```typescript import { inferFieldType } from "./load-csv.ts"; inferFieldType(["10", "20", "30"]); // "number" inferFieldType(["true", "false", "true"]); // "boolean" inferFieldType(["Alice", "Bob", "Charlie"]); // "string" inferFieldType(["10", "hello", "20"]); // "string" (mixed) inferFieldType(["", "", ""]); // "string" (all empty) inferFieldType(["true", "maybe", "false"]); // "string" (one non-boolean) ``` -------------------------------- ### Example Usage of FieldMapping in Webhook Handler Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/api-reference-notion-utils.md Demonstrates how `extractFieldData` uses `FIELD_MAPPING` to process Notion properties and prepare them for adding to a collection. ```typescript const fieldData = extractFieldData( payload.data.properties, config.FIELD_MAPPING ); // fieldData now has Framer field IDs as keys // { title: {...}, status: {...}, created: {...}, priority: {...} } await collection.addItems([{ id: pageId, slug, fieldData }]); ``` -------------------------------- ### CSV Import: Add Slug Column Example Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/ERRORS_AND_CONSTRAINTS.md Illustrates the required format for a CSV file when importing data, specifically highlighting the necessity of a 'slug' column. ```csv slug,title,price item-1,Product 1,99.99 item-2,Product 2,149.99 ``` -------------------------------- ### JSON API Endpoint for Collection Items Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/api-reference-collections.md Example of how to expose collection items via a JSON API endpoint. This demonstrates fetching items and returning a subset of their data. ```typescript // JSON API endpoint: GET /collections/:collectionId app.get("/collections/:collectionId", async (c) => { const collectionId = c.req.param("collectionId"); const allCollections = await c.var.framer.getCollections(); const collection = allCollections.find((col) => col.id === collectionId); if (!collection) { return c.json({ error: "Collection not found" }, 404); } const allItems = await collection.getItems(); const items = allItems.map((item) => ({ id: item.id, slug: item.slug, })); return c.json({ items }); }); ``` -------------------------------- ### Inspect Framer API Collections and Items Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/ERRORS_AND_CONSTRAINTS.md These examples demonstrate how to fetch collections and items from the Framer API and log their structure to the console. This is useful for understanding the data format and available fields. ```typescript const collections = await framer.getCollections(); console.log(JSON.stringify(collections, null, 2)); // Shows all fields, IDs, and structure const items = await collection.getItems(); console.log("First item:", JSON.stringify(items[0], null, 2)); ``` -------------------------------- ### Setup Script for Framer Collection Initialization Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/EXAMPLE_SCRIPTS.md This TypeScript script initializes a Framer managed collection. It finds an existing collection by name or creates a new one, sets up fields based on a configuration mapping, and reports the collection's status. ```typescript async function findOrCreateCollection(name: string) { const existingCollections = await framer.getManagedCollections(); const existing = existingCollections.find((c) => c.name === name); if (existing) return existing; return framer.createManagedCollection(name); } // 2. Set fields from config async function setupFields(collection: ManagedCollection) { const fields = config.FIELD_MAPPING.map((mapping) => ({ type: mapping.type, name: mapping.framerName, id: mapping.framerId, })); await collection.setFields(fields); } // 3. Report status async function logCollectionStatus(collection: ManagedCollection) { const itemIds = await collection.getItemIds(); console.log(`Collection ready [existing items: ${itemIds.length}]`); } ``` -------------------------------- ### Example CSV Content and Parsed Structure Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/api-reference-csv-loader.md Illustrates a typical CSV file structure with a header and data rows, and shows how it's parsed into columns, rows, and inferred field types. ```csv slug,title,price,in_stock,description laptop-pro-15,Laptop Pro 15",1299.99,true,Powerful laptop for professionals wireless-mouse,Wireless Mouse,49.99,false,Ergonomic wireless mouse mechanical-keyboard,Mechanical Keyboard,149.99,true,Backlit mechanical keyboard with RGB ``` ```typescript { columns: ["slug", "title", "price", "in_stock", "description"], rows: [ { slug: "laptop-pro-15", title: "Laptop Pro 15\"", price: "1299.99", in_stock: "true", description: "Powerful laptop for professionals" }, // ... more rows ], fieldTypes: new Map([ ["slug", "string"], ["title", "string"], ["price", "number"], ["in_stock", "boolean"], ["description", "string"] ]) } ``` -------------------------------- ### Webhook Request with POST Method Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/ERRORS_AND_CONSTRAINTS.md Shows the correct usage of the POST HTTP method for sending data to a webhook endpoint, contrasting it with incorrect methods like GET. ```bash curl -X POST http://localhost:8787/ ... # Correct ``` -------------------------------- ### Implement Collection Item Fetch Endpoint Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/endpoints.md A Node.js (Hono) example demonstrating how to create an API endpoint to fetch a specific item from a Framer collection. It includes error handling for missing collections or items. ```typescript app.get("/collections/:collectionId/:itemId", async (c) => { const collectionId = c.req.param("collectionId"); const itemId = c.req.param("itemId"); const allCollections = await c.var.framer.getCollections(); const collection = allCollections.find((col) => col.id === collectionId); if (!collection) { return c.json({ error: "Collection not found" }, 404); } const allItems = await collection.getItems(); const item = allItems.find((i) => i.id === itemId); if (!item) { return c.json({ error: "Item not found" }, 404); } return c.json(item); }); ``` -------------------------------- ### CSV Importer Runtime Configuration Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/configuration.md Configures the CSV Importer example by reading project URL, CSV path, and collection name from environment variables. Provides default values for CSV path and collection name. ```typescript const projectUrl = process.env["EXAMPLE_PROJECT_URL"]; assert(projectUrl, "EXAMPLE_PROJECT_URL environment variable is required"); const csvPath = process.env["CSV_PATH"] ?? path.join(import.meta.dirname, "../data/sample-products.csv"); const collectionName = process.env["COLLECTION_NAME"] ?? "Products"; ``` -------------------------------- ### Deploying with Correct Deployment ID Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/ERRORS_AND_CONSTRAINTS.md This example shows the correct way to deploy changes using the Framer API. It emphasizes using the deployment ID obtained from a recent `publish()` call to ensure the correct version is deployed. ```typescript const { deployment } = await framer.publish(); const deployed = await framer.deploy(deployment.id); // Use this ID ``` -------------------------------- ### Hono Middleware for Framer Client Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/EXAMPLE_SCRIPTS.md Example of Hono middleware that establishes a Framer API client for each request and ensures its cleanup. Provides a fresh connection per request. ```typescript app.use(async (c, next) => { using framer = await connect(projectUrl); c.set("framer", framer); await next(); }); // Behavior: // - Creates fresh connection for each HTTP request // - Closes after response sent // - No connection pooling or state sharing // - Safe for stateless server deployments ``` -------------------------------- ### Webhook Recovery: Set Collection Name Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/ERRORS_AND_CONSTRAINTS.md Illustrates how to recover from a 'Collection Not Found' error in a webhook by either running a setup script or ensuring the correct collection name is set in the environment variables. ```bash # Run setup script to create collection npm run setup # Or check collection name FRAMER_COLLECTION_NAME="Products" npm run dev ``` -------------------------------- ### Get Item Endpoint Source: https://github.com/framer/server-api-examples/blob/main/examples/json-api/README.md HTTP GET request to retrieve a single item by collection ID and item ID, including its field data. ```http GET /collections/:collectionId/:itemId ``` -------------------------------- ### Run Publish Script Source: https://github.com/framer/server-api-examples/blob/main/examples/publish/README.md Execute the publish script using Node.js, Bun, or Deno. Ensure the .env file is accessible for environment variables. ```bash node --env-file=../../.env publish.ts ``` ```bash bun --env-file=../../.env run publish.ts ``` ```bash deno --env-file=../../.env run publish.ts ``` -------------------------------- ### Configuration Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/DOCUMENTATION_INDEX.txt Documentation for configuration settings, including all environment variables and options. ```APIDOC ## Configuration ### Description This section details the configuration options for the Framer Server API, including all environment variables and user-configurable settings. ### Reference - See `configuration.md` for comprehensive details on environment variables, options, and setup steps. ``` -------------------------------- ### Runtime Configuration with Environment Variables Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/configuration.md Reads the project URL from the EXAMPLE_PROJECT_URL environment variable. Asserts that the variable is set before proceeding. ```typescript const projectUrl = process.env["EXAMPLE_PROJECT_URL"]; assert(projectUrl, "EXAMPLE_PROJECT_URL environment variable is required"); using framer = await connect(projectUrl); ``` -------------------------------- ### List Collections Endpoint Source: https://github.com/framer/server-api-examples/blob/main/examples/json-api/README.md HTTP GET request to list all collections in a Framer project. ```http GET /collections ``` -------------------------------- ### JSON API Server Startup Output Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/EXAMPLE_SCRIPTS.md Indicates the local address where the JSON API server is running after a successful startup. ```text Server running at http://localhost:3000 ``` -------------------------------- ### Webhook Success Response Example Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/EXAMPLE_SCRIPTS.md This JSON payload indicates a successful processing of a webhook request by the server. ```json { "success": true, "action": "upserted", "id": "abcdefghijkl", "slug": "item-abcdefghijkl", "published": true } ``` -------------------------------- ### Get Collection Items Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/api-reference-collections.md Retrieves all items within a collection. Useful for iterating through and processing collection data. ```typescript using framer = await connect(projectUrl, apiKey); const collections = await framer.getCollections(); const products = collections.find(c => c.name === "Products"); const items = await products.getItems(); console.log(`Collection has ${items.length} items`); for (const item of items) { console.log(` ${item.slug}: ${JSON.stringify(item.fieldData)}`); } ``` -------------------------------- ### Get Collection Fields Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/api-reference-collections.md Retrieves all field definitions for a given collection. Useful for understanding the structure of your data. ```typescript using framer = await connect(projectUrl, apiKey); const collections = await framer.getCollections(); const products = collections.find(c => c.name === "Products"); const fields = await products.getFields(); console.log("Fields:"); for (const field of fields) { console.log(` ${field.id}: ${field.name} (${field.type})`); } ``` -------------------------------- ### List Items Endpoint Source: https://github.com/framer/server-api-examples/blob/main/examples/json-api/README.md HTTP GET request to list all items within a specific collection by its ID. ```http GET /collections/:collectionId ``` -------------------------------- ### Publishing Workflow Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/README.md Illustrates the three-step process for publishing changes: checking for changes, creating a deployment, and deploying to custom domains. ```typescript // 1. Check for changes const changes = await framer.getChangedPaths(); // 2. Publish to create deployment const { deployment } = await framer.publish(); // 3. Deploy to custom domains const deployed = await framer.deploy(deployment.id); ``` -------------------------------- ### Get a Specific Item using cURL Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/EXAMPLE_SCRIPTS.md Use this command to retrieve details for a specific item within a collection. ```bash curl http://localhost:3000/collections/col-abc/item-1 ``` -------------------------------- ### Publish and Deploy Project Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/api-reference-framer-client.md Connects to Framer, publishes a project, and then deploys it. It logs the deployed hostnames or indicates if only the default Framer domain is used. Returns an empty array if no custom domains are configured. ```typescript using framer = await connect(projectUrl, apiKey); const { deployment } = await framer.publish(); const deployed = await framer.deploy(deployment.id); if (deployed.length > 0) { console.log(`Deployed to:`); for (const hostname of deployed) { console.log(` https://${hostname.hostname}`); } } else { console.log("No custom domains; using default Framer domain"); } ``` -------------------------------- ### Get Specific Item API Source: https://github.com/framer/server-api-examples/blob/main/examples/json-api/README.md Retrieve a single item from a collection using both the collection ID and the item ID. ```APIDOC ## GET /collections/:collectionId/:itemId ### Description Returns a single item with its field data. ### Method GET ### Endpoint /collections/:collectionId/:itemId ### Parameters #### Path Parameters - **collectionId** (string) - Required - The ID of the collection containing the item. - **itemId** (string) - Required - The ID of the item to retrieve. ### Response #### Success Response (200) - **item** (object) - The requested item object with its field data. ``` -------------------------------- ### CSV Type Inference: All Empty Column Example Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/ERRORS_AND_CONSTRAINTS.md Shows that a CSV column with no non-empty values defaults to being inferred as 'string'. ```csv notes ``` -------------------------------- ### CSV Importer Algorithm Overview Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/EXAMPLE_SCRIPTS.md Outlines the step-by-step process for the CSV importer script, from loading and parsing the CSV to connecting to the Framer API, reconciling fields, and importing items. ```text 1. Load CSV from file └─ Parse headers and rows └─ Infer field types from data 2. Connect to Framer API └─ Authenticate with API key 3. Find or create collection └─ Query existing collections └─ Create new if not found 4. Reconcile fields ├─ Get existing fields from collection ├─ Determine which fields to create └─ Create new fields with inferred types 5. Build item list ├─ Map CSV columns to field IDs ├─ Get existing items ├─ Build field data for new items └─ Preserve existing IDs for updates 6. Import items └─ Call collection.addItems() └─ Upsert by slug (use existing ID if found) 7. Report └─ Log number of items imported ``` -------------------------------- ### Usage of isDeleted in Webhook Handler Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/api-reference-notion-utils.md Example of how the `isDeleted` function is used within a webhook handler to determine if a page should be removed. ```typescript if (isDeleted(payload.data.properties, config.TOMBSTONE_PROPERTY)) { await collection.removeItems([pageId]); await publishAndDeploy(framer); return json({ success: true, action: "deleted", id: pageId }); } ``` -------------------------------- ### GET /collections/:collectionId Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/endpoints.md Retrieves all items in a specific collection, identified by its collectionId. Returns an array of items, each with an ID and slug. ```APIDOC ## GET /collections/:collectionId ### Description Retrieves all items in a specific collection. ### Method GET ### Endpoint /collections/:collectionId ### Parameters #### Path Parameters - **collectionId** (string) - Required - The collection ID (from `/collections` endpoint) ### Request Example ```bash curl http://localhost:3000/collections/col-abc123 ``` ### Response #### Success Response (200) - **items** (Item[]) - Array of items in collection - **items[].id** (string) - Item ID - **items[].slug** (string) - Item slug (URL-safe identifier) #### Response Example ```json { "items": [ { "id": "item-1", "slug": "laptop-pro" } ] } ``` ### Error Cases - **404** - Collection ID doesn't exist - **500** - API connection error ``` -------------------------------- ### Script Execution with Deno Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/configuration.md Runs a script using Deno, loading environment variables from a specified file. ```bash # With Deno den o --env-file=../../.env run publish.ts ``` -------------------------------- ### CSV Importer Execution with Deno Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/configuration.md Command to execute the CSV Importer script using Deno. ```bash deno run src/csv-to-collection.ts ``` -------------------------------- ### Script Execution with Bun Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/configuration.md Executes a script using Bun, loading environment variables from a specified file. ```bash # With Bun bun --env-file=../../.env run publish.ts ``` -------------------------------- ### FieldDefinition Interface Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/types.md Extended field definition for managed collections, including the field ID. Used in setup for Notion Automations Sync. ```typescript interface FieldDefinition { id: string; name: string; type: "string" | "number" | "boolean" | "date"; } ``` -------------------------------- ### Publish Script Execution Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/EXAMPLE_SCRIPTS.md This command executes the publish script using Node.js, loading environment variables from a .env file. ```bash node --env-file=../../.env publish.ts ``` -------------------------------- ### Get Item by ID Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/endpoints.md Retrieves a specific item from a collection using its ID. This endpoint is useful for fetching individual item details. ```APIDOC ## GET /collections/:collectionId/:itemId ### Description Retrieves a specific item from a collection using its ID. This endpoint is useful for fetching individual item details. ### Method GET ### Endpoint /collections/:collectionId/:itemId ### Parameters #### Path Parameters - **collectionId** (string) - Required - The ID of the collection. - **itemId** (string) - Required - The ID of the item to retrieve. ### Response #### Success Response (200) - **id** (string) - The ID of the item. - **slug** (string) - The slug of the item. - **fieldData** (object) - An object containing the item's field data. - **fieldName** (object) - Represents a specific field. - **type** (string) - The data type of the field. - **value** (any) - The value of the field. #### Response Example ```json { "id": "item-1", "slug": "laptop-pro-15", "fieldData": { "field-title": { "type": "string", "value": "Laptop Pro 15\"" }, "field-price": { "type": "number", "value": 1299.99 } } } ``` ``` -------------------------------- ### Field Mapping Interface and Configuration Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/configuration.md Defines the structure for mapping Notion properties to Framer fields and provides an example configuration with five fields. ```typescript export interface FieldMapping { notionProperty: string; // Notion property name framerId: string; // Framer field ID framerName: string; // Framer field display name type: "string" | "number" | "boolean" | "date"; // Field type } export const config: Config = { FIELD_MAPPING: [ { notionProperty: "Title", framerId: "title", framerName: "Title", type: "string", }, { notionProperty: "Description", framerId: "description", framerName: "Description", type: "string", }, { notionProperty: "Status", framerId: "status", framerName: "Status", type: "string", }, { notionProperty: "Created", framerId: "created", framerName: "Created", type: "date", }, { notionProperty: "Priority", framerId: "priority", framerName: "Priority", type: "number", }, ], }; ``` -------------------------------- ### Field Type Inference Example Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/configuration.md Demonstrates how the CSV Importer infers data types (number, boolean, string) from CSV column values. ```csv price,in_stock,tags 99.99,true,"apple,samsung" 49.99,false,"laptop" 0,true,"computer" ``` -------------------------------- ### CSV Importer Execution with Bun Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/configuration.md Command to execute the CSV Importer script using Bun. ```bash bun run src/csv-to-collection.ts ``` -------------------------------- ### Get Changed Paths and Publish Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/api-reference-framer-client.md Retrieve paths of modified files and publish them. This snippet first checks for changes and then initiates a publish if any are found. ```typescript using framer = await connect(projectUrl, apiKey); const changedPaths = await framer.getChangedPaths(); let totalChanges = 0; for (const [type, paths] of Object.entries(changedPaths)) { console.log(`${type}: ${paths.length} file(s)`); totalChanges += paths.length; } if (totalChanges > 0) { const { deployment } = await framer.publish(); console.log(`Published: ${deployment.id}`); } ``` -------------------------------- ### Webhook Request Example Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/EXAMPLE_SCRIPTS.md This JSON payload represents a typical webhook request received from Framer, containing information about an automation event and associated data. ```json { "source": { "type": "automation", "automation_id": "aut-123", "action_id": "act-456", "event_id": "evt-789", "attempt": 1 }, "data": { "id": "abc-def-ghi-jkl", "parent": { "type": "database_id", "database_id": "db-xyz" }, "archived": false, "in_trash": false, "properties": { "Title": { "type": "title", "title": [{"type": "text", "text": {"content": "Test Page"}}] }, "Deleted": { "type": "checkbox", "checkbox": false } } } } ``` -------------------------------- ### Publishing/Deployment Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/DOCUMENTATION_INDEX.txt Documentation for publishing and deployment processes, including publish, deploy, and change detection. ```APIDOC ## Publishing/Deployment ### Description This section covers the processes involved in publishing and deploying changes within Framer, including methods for publishing, deploying, and detecting changes. ### Operations - Publish changes - Deploy changes - Change detection ### Reference - See `api-reference-framer-client.md#publish` for the publish method. - See `EXAMPLE_SCRIPTS.md#publish-script` for scheduling examples. ``` -------------------------------- ### Publish and Deploy Project Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/api-reference-framer-client.md Publish pending changes to create a deployment and then deploy it to custom domains. This is typically used after checking for changes with `getChangedPaths()`. ```typescript using framer = await connect(projectUrl, apiKey); const { deployment } = await framer.publish(); console.log(`Created deployment: ${deployment.id}`); // Deploy to custom domains const hostnames = await framer.deploy(deployment.id); console.log(`Deployed to ${hostnames.length} domain(s)`); ``` -------------------------------- ### Core Client API Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/DOCUMENTATION_INDEX.txt Documentation for the core client API, comprising 11 documented methods. ```APIDOC ## Core Client API ### Description This section covers the core client API, which includes 11 distinct methods for interacting with Framer functionalities. Full method signatures, parameter types, and return values are documented. ### Methods - **publish**: Method for publishing changes. See `api-reference-framer-client.md#publish` for details. - **Other 10 methods**: Comprehensive documentation available in `api-reference-framer-client.md`. ``` -------------------------------- ### HTTP Server with Per-Request Connections Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/README.md Sets up an HTTP server where each request establishes a new Framer connection. This is useful for stateless server environments. ```typescript app.use(async (c, next) => { using framer = await connect(projectUrl); c.set("framer", framer); await next(); }); app.get("/collections", async (c) => { const collections = await c.var.framer.getCollections(); return c.json({ collections }); }); ``` -------------------------------- ### Expose Local Server with Cloudflared Source: https://github.com/framer/server-api-examples/blob/main/examples/notion-automations-sync/README.md Command to expose your local development server to the internet using `cloudflared` for testing webhooks. ```bash cloudflared tunnel --url http://localhost:8787 ``` -------------------------------- ### Run CSV Importer Script Source: https://github.com/framer/server-api-examples/blob/main/examples/csv-importer/README.md Execute the CSV importer script using Node.js, Bun, or Deno. Ensure you have the necessary environment variables configured. ```bash node --env-file=../../.env src/csv-to-collection.ts ``` ```bash bun run src/csv-to-collection.ts ``` ```bash deno run src/csv-to-collection.ts ``` -------------------------------- ### CSV Importer: Get Collection Items for Updates Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/api-reference-collections.md Demonstrates how to retrieve existing items from a collection to map slugs to IDs for efficient updates during CSV import. ```typescript const existingItems = await collection.getItems(); const slugToExistingId = new Map(existingItems.map((item) => [item.slug, item.id])); // Use existing IDs for updates const items = rows.map((row) => ({ id: slugToExistingId.get(row.slug), slug: row.slug, fieldData: { /* ... */ } })); ``` -------------------------------- ### Webhook Request with Valid JSON Payload Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/ERRORS_AND_CONSTRAINTS.md Provides an example of a cURL request with a correctly formatted JSON payload, intended for webhook endpoints that expect JSON data. ```bash curl -X POST http://localhost:8787/ \ -H "Content-Type: application/json" \ -d '{"valid": "json"}' ``` -------------------------------- ### CSV Type Inference: Boolean Case Sensitivity Example Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/ERRORS_AND_CONSTRAINTS.md Highlights that boolean inference in CSVs is case-sensitive; only exact 'true' or 'false' are recognized, otherwise, it defaults to 'string'. ```csv flag True FALSE true ``` -------------------------------- ### connect() Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/api-reference-framer-client.md Establishes an authenticated connection to a Framer project. It can be used with an explicit API key or by relying on an environment variable. The connection can be managed manually or automatically using Node.js v24+ `using` keyword. ```APIDOC ## connect() ### Description Establishes an authenticated connection to a Framer project. ### Signature ```ts async function connect( projectUrl: string, apiKey?: string ): Promise; ``` ### Parameters #### Path Parameters * **projectUrl** (string) - Required - Framer project URL from browser (e.g., `https://framer.com/projects/Sites--aabbccddeeff`) * **apiKey** (string) - Optional - API key from project settings; uses environment variable if omitted. Defaults to `process.env.FRAMER_API_KEY`. ### Return Type `Promise` — Authenticated client instance with methods to query and modify project data. ### Throws - Throws if `projectUrl` is invalid or unreachable - Throws if `apiKey` is missing and `FRAMER_API_KEY` env var is not set - Throws if authentication fails (invalid key) ### Example ```ts // With explicit API key const framer = await connect( "https://framer.com/projects/MyProject--abc123def456", "sk_live_abc..." ); // Using environment variable const framer = await connect("https://framer.com/projects/MyProject--abc123def456"); // With automatic cleanup (Node.js v24+) using framer = await connect(projectUrl); // ... use framer ... // Connection closes automatically when scope exits // Manual cleanup const framer = await connect(projectUrl); try { const collections = await framer.getCollections(); } finally { await framer.disconnect(); } ``` ``` -------------------------------- ### Notion Automations Webhook Success Response (Deleted) Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/endpoints.md Example of a successful JSON response from a webhook endpoint when an item has been deleted in Framer based on a Notion automation event. ```json { "success": true, "action": "deleted", "id": "abcdefghijkl", "published": true } ``` -------------------------------- ### Load CSV and Process Columns Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/api-reference-csv-loader.md Example of using the `loadCsv` function to read a CSV file and process its columns to create new fields based on inferred types. ```typescript import { loadCsv } from "./load-csv.ts"; const csvPath = process.env["CSV_PATH"] ?? path.join(import.meta.dirname, "../data/sample-products.csv"); const { columns, rows, fieldTypes } = loadCsv(csvPath); // Verify required column assert(columns.includes("slug"), "CSV must contain a 'slug' column"); // Create fields using inferred types const fieldsToCreate = columns .filter((column) => column !== "slug" && !existingFieldNames.has(column.toLowerCase())) .map( (column): CreateField => ({ type: fieldTypes.get(column) ?? "string", name: column, }), ); // Convert values to typed field data function toFieldData(value: string, type: FieldType): FieldDataEntryInput { switch (type) { case "boolean": return { type: "boolean" as const, value: value.toLowerCase() === "true" }; case "number": return { type: "number" as const, value: parseFloat(value) || 0 }; case "string": return { type: "string" as const, value }; } } ``` -------------------------------- ### Deployment Commands Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/configuration.md Provides the bash commands for setting secrets and deploying the Cloudflare Worker. ```bash # Set secrets wrangler secret bulk .env # Deploy npm run deploy # Output shows worker URL # https://notion-framer-sync.{account}.workers.dev ``` -------------------------------- ### List All Collections Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/endpoints.md This endpoint retrieves a list of all collections in the Framer project. It returns an array of collection objects, each with an ID and name. Use this to get an overview of available collections. ```typescript app.get("/collections", async (c) => { const allCollections = await c.var.framer.getCollections(); const collections = allCollections.map((col) => ({ id: col.id, name: col.name, })); return c.json({ collections }); }); ``` ```bash curl http://localhost:3000/collections ``` -------------------------------- ### CSV Type Inference: Leading Zeros Example Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/ERRORS_AND_CONSTRAINTS.md Illustrates that CSV columns with leading zeros are treated as 'string' because `parseFloat` converts them to numbers without preserving the original formatting. ```csv code 001 002 ``` -------------------------------- ### Environment Variables for Local Development Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/configuration.md Defines environment variables required for local development of Notion Automations Sync, including Framer project URL, API key, collection name, and webhook token. ```bash # .env file FRAMER_PROJECT_URL=https://framer.com/projects/MyProject--abc123 FRAMER_API_KEY=sk_live_... FRAMER_COLLECTION_NAME=Sync Collection WEBHOOK_TOKEN=secret-webhook-token-xyz NOTION_DATABASE_ID=abc123def456 # Optional ``` -------------------------------- ### Notion Sync Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/DOCUMENTATION_INDEX.txt Documentation for Notion synchronization, including property extraction, mapping, and webhooks. ```APIDOC ## Notion Sync ### Description This section details the integration with Notion, covering property extraction from Notion, mapping of properties, and the use of webhooks for synchronization. ### Details - Property extraction - Property mapping - Webhooks ### Reference - See `api-reference-notion-utils.md` for detailed information. ``` -------------------------------- ### CSV Type Inference: Mixed Types Example Source: https://github.com/framer/server-api-examples/blob/main/_autodocs/ERRORS_AND_CONSTRAINTS.md Demonstrates how a CSV column with mixed text and numbers is inferred as 'string' because non-numeric values prevent full numeric parsing. ```csv value 100 200 special ```