This is the complete reference document for AI agents. Point your AI assistant to this page when working with Visimade.
AI agents can read this page directly
# VISIMADE.md - AI Agent Instructions
This document contains everything you need to work with the Visimade platform.
Visimade is a platform for creating interactive web pages with built-in data storage.
## Authentication
All API requests require a Bearer token in the Authorization header:
```
Authorization: Bearer vm_your_token_here
```
## Base URL
All API endpoints use: `https://visimade.com/api/`
For staging: `https://staging.visimade.com/api/`
---
## Creating a New Page
**Endpoint:** `POST /api/pages`
**Required Scope:** `pages:write`
### Request Body
```json
{
"name": "Page Title",
"html_content": "<!DOCTYPE html>...",
"description": "Optional description (max 500 chars)",
"storage_mode": "page" | "solo_app" | "team_app" | "social_app",
"is_published": true
}
```
### Storage Modes
- `page`: No data storage (static pages)
- `solo_app`: Private data per user (personal apps)
- `team_app`: Shared data for invited team members
- `social_app`: Public data with ownership (anyone can read, users edit own records)
### HTML Requirements
1. Must be a complete HTML document with DOCTYPE
2. Include `data-page-id="{{PAGE_ID}}"` in the body tag (required for data APIs)
3. The `{{PAGE_ID}}` placeholder is replaced with the actual ID when served
### Example
```bash
curl -X POST https://visimade.com/api/pages \
-H "Authorization: Bearer vm_token" \
-H "Content-Type: application/json" \
-d '{
"name": "My App",
"html_content": "<!DOCTYPE html><html><head><title>My App</title></head><body data-page-id=\"{{PAGE_ID}}\"><h1>Hello</h1></body></html>",
"storage_mode": "solo_app"
}'
```
### Response
```json
{
"page": {
"id": 123,
"name": "My App",
"slug": "my-app",
"url": "https://visimade.com/p/my-app"
}
}
```
---
## Looking Up a Page by Slug
**Endpoint:** `GET /api/pages/lookup?slug=page-slug`
**Required Scope:** `pages:read`
Use this when you have a page URL like `/p/my-page-slug` and need the page ID.
### Response
```json
{
"id": 123,
"name": "My Page",
"slug": "my-page-slug",
"isPublished": true
}
```
---
## Reading a Page
**Endpoint:** `GET /api/pages/:id`
**Required Scope:** `pages:read`
### Response
```json
{
"page": {
"id": 123,
"name": "My Page",
"slug": "my-page",
"html_content": "<!DOCTYPE html>...",
"is_published": true,
"description": "...",
"views": 1250
},
"storageMode": "team_app"
}
```
---
## Updating a Page
**Endpoint:** `PATCH /api/pages/:id`
**Required Scope:** `pages:write`
Updates automatically create a version backup.
### Request Body (all fields optional)
```json
{
"html_content": "<!DOCTYPE html>...",
"name": "New Title",
"description": "New description"
}
```
### IMPORTANT: How to Read Page HTML Before Editing
When editing a page, you MUST fetch the raw HTML content using the API:
```
GET /api/pages/:id → response.page.html_content
```
**NEVER fetch page HTML from the public URL** (`/p/[slug]`). The public URL returns the page with runtime-injected scripts (analytics, tracking, badges, engagement trackers, data APIs, etc.) that are NOT part of the page content. If you save this rendered output back via PATCH, you will corrupt the page with duplicate scripts that compound on every subsequent save.
---
## Working with Data
### List Collections
**Endpoint:** `GET /api/pages/:id/team-data` (or solo-data, social-data)
Returns all collections and record counts.
### List Records
**Endpoint:** `GET /api/pages/:id/team-data/:collection`
Query parameters:
- `where`: JSON filter, e.g., `{"status":"active"}`
- `orderBy`: `created_at` or `updated_at`
- `order`: `asc` or `desc`
- `limit`: Max records (default 50, max 100)
- `offset`: Skip records for pagination
- `mine`: Only records by current user
### Create Record
**Endpoint:** `POST /api/pages/:id/team-data/:collection`
```json
{
"data": {
"title": "New Item",
"status": "pending"
}
}
```
### Update Record
**Endpoint:** `PATCH /api/pages/:id/team-data/:collection/:recordId`
```json
{
"data": {
"status": "completed"
}
}
```
### Delete Record
**Endpoint:** `DELETE /api/pages/:id/team-data/:collection/:recordId`
---
## Client-Side JavaScript APIs
When creating pages, these APIs are automatically available based on storage mode:
### SoloData (solo_app mode)
```javascript
await SoloData.ready; // Always await before using
await SoloData.create('todos', { text: 'Buy milk' });
const { records } = await SoloData.find('todos');
await SoloData.update('todos', recordId, { completed: true });
await SoloData.delete('todos', recordId);
SoloData.getCurrentUser(); // { id, username } or null
SoloData.promptLogin(); // Open login modal
```
### TeamData (team_app mode)
```javascript
await TeamData.ready;
await TeamData.create('tasks', { title: 'New task' });
const { records } = await TeamData.find('tasks', { where: { status: 'active' } });
await TeamData.findMine('tasks'); // Only user's records
await TeamData.update('tasks', recordId, { status: 'done' });
await TeamData.delete('tasks', recordId);
TeamData.isMember(); // Is team member
TeamData.getRole(); // 'owner' | 'admin' | 'member' | 'viewer'
TeamData.canEdit(record); // Check permission
```
### SocialData (social_app mode)
```javascript
await SocialData.ready;
await SocialData.create('posts', { content: 'Hello!' });
const { records } = await SocialData.find('posts'); // All public records
await SocialData.findMine('posts'); // Only user's records
await SocialData.update('posts', recordId, { content: 'Updated' }); // Owner only
await SocialData.delete('posts', recordId); // Owner only
SocialData.getCurrentUser();
SocialData.isAuthenticated();
```
### CmsData (page_api_cms capability)
Creator-managed content. Only the page owner can write; all visitors can read.
Paid content can be gated behind membership plans.
```javascript
await CmsData.ready;
// Reading (everyone)
const { records } = await CmsData.find('posts', {
where: { category: 'news' },
orderBy: 'created_at',
order: 'desc',
limit: 10
});
const post = await CmsData.findById('posts', recordId);
// Writing (creator only)
await CmsData.create('posts', { title: 'Hello', content: '<p>World</p>' });
await CmsData.create('posts', { title: 'Premium' }, { planId: 42 }); // Paid content
await CmsData.update('posts', recordId, { title: 'Updated' });
await CmsData.delete('posts', recordId);
// Identity
CmsData.isCreator(); // true if page owner
CmsData.isAuthenticated(); // true if logged in
CmsData.getCurrentUser(); // { id, username } or null
CmsData.promptLogin(); // open login modal
```
---
## HTML Template
Use this as a starting point for new pages:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Page Title</title>
<meta name="description" content="Page description">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
line-height: 1.6;
color: #1e293b;
background: #f8fafc;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 40px 20px;
}
</style>
</head>
<body data-page-id="{{PAGE_ID}}">
<div class="container">
<h1>Hello World</h1>
</div>
<script>
// Your JavaScript here
// For data storage, use SoloData, TeamData, or SocialData based on storage_mode
</script>
</body>
</html>
```
---
## Common Patterns
### Wait for SDK and Check Auth
```javascript
async function init() {
await SocialData.ready; // MUST await before checking auth
const user = SocialData.getCurrentUser();
if (user) {
console.log('Logged in as', user.username);
loadUserData();
} else {
showLoginPrompt();
}
}
init();
```
### CRUD with Loading States
```javascript
async function loadItems() {
showLoading();
try {
const { records } = await TeamData.find('items', {
orderBy: 'created_at',
order: 'desc'
});
renderItems(records);
} catch (error) {
showError('Failed to load items');
} finally {
hideLoading();
}
}
```
### Check Ownership for Edit/Delete
```javascript
function renderItem(record) {
const user = SocialData.getCurrentUser();
const canModify = user && user.id === record.createdBy.id;
return `
<div class="item">
<span>${record.data.title}</span>
${canModify ? '<button onclick="editItem()">Edit</button>' : ''}
</div>
`;
}
```
---
## Error Handling
| Status | Meaning |
|--------|---------|
| 200 | Success |
| 201 | Created |
| 400 | Bad request - check parameters |
| 401 | Unauthorized - invalid token |
| 403 | Forbidden - insufficient permissions |
| 404 | Not found |
| 429 | Rate limited - wait and retry |
---
## Full API Reference
For complete endpoint documentation, parameter details, and advanced features, see:
https://visimade.com/developers/api
Start your conversation with Claude Code like this:
My Visimade API token is: vm_your_token_here See the Visimade documentation at: https://visimade.com/ai-agents/visimade-md [Your request here - create a page, edit a page, work with data, etc.]
Claude will fetch this page and understand how to work with the Visimade API.
My Visimade API token is: vm_abc123... See the Visimade documentation at: https://visimade.com/ai-agents/visimade-md Create a habit tracker app with: - Daily checklist of habits - Streak counter for each habit - Weekly overview chart - Use Solo App mode for private user data
My Visimade API token is: vm_abc123... See the Visimade documentation at: https://visimade.com/ai-agents/visimade-md I want to improve this page: /p/my-dashboard Add dark mode support with a toggle button in the header.
My Visimade API token is: vm_abc123... See the Visimade documentation at: https://visimade.com/ai-agents/visimade-md Look at the tasks in /p/project-board Find all tasks marked as "blocked" and create a summary of what's blocking them and suggested next steps.