For Agents
Create an API key in Settings as a project owner, scoped to the permissions and project it needs. Send Authorization: Bearer YOUR_KEY to /api/v1. Keys are shown once, hashed at rest, expire, and can be revoked.
One file. Any structure.
Download the JSON Schema. Every screen has a stable ID, native pixel dimensions, SHA-256 checksum, raw base64 image, a nested section path and a row/column position.
{
"schemaVersion": 1,
"export": {
"version": "v2",
"title": "Onboarding experiments"
},
"screens": [
{
"id": "consumer-a-welcome",
"title": "Welcome",
"section": [
"Onboarding",
"Consumer",
"Test A"
],
"column": 0,
"row": 0,
"width": 1206,
"height": 2622,
"sha256": "SHA256_OF_DECODED_IMAGE",
"image": "RAW_BASE64_IMAGE"
}
]
}Section names are your choice: product areas, audiences, experiments, platforms, or any other hierarchy (up to 32 levels). A parent includes its descendants. Each distinct path has its own layout: columns progress left to right, row 0 is the main flow, negative rows sit above and positive rows below. IDs are unique within an export; cells are unique within a section. Preserve screen IDs across versions to correlate feedback.
Import protocol
- Validate the single file locally and verify all checksums.
- POST its manifest with image fields removed.
- PUT each decoded screenshot to the returned export ID, up to three concurrently.
- POST complete. Only fully published exports appear to reviewers.
Rerunning an identical version resumes safely. Changing an existing version returns 409; use a new version. Limits: 200 screens, 3 MB per image, 20 megapixels per image, 100 MB total decoded data. API requests allow 600/minute/key. A large export may require waiting for the next rate-limit window; respect 429 and retry. Browser import and the CLI use this same protocol.
API reference
| Endpoint | Scope | Behavior |
|---|---|---|
PATCH /projects/:p/exports/:e/screens/:s | exports:write | Update frame tags: {tags: string[]}. Screenshot bytes and original manifest remain unchanged. |
GET /projects/:p/people?q= | comments:read | Find current project members for @mentions. Returns IDs, names and photos. |
DELETE /projects/:p/exports/:e/comments/:c | comments:write | Delete your own comment. Other people’s replies are preserved. |
GET /projects | projects:read | List projects owned by the key owner. |
POST /projects | projects:write | Create: {name, description?}. Unrestricted project key required. |
GET /projects/:p | projects:read | Read a project. |
PATCH /projects/:p | projects:write | Update: {name, description?}. Owner only. |
DELETE /projects/:p | projects:write | Archive project. Owner only. |
GET /projects/:p/exports | exports:read | List published export versions. |
POST /projects/:p/exports | exports:write | Create/resume a draft: import manifest without image fields. Returns {id,status}. |
GET /projects/:p/exports/:e | exports:read | Read manifest, nested section paths, upload status and private image URLs. |
PUT /projects/:p/exports/:e/screens/:s | exports:write | Upload raw PNG/JPEG/WebP bytes. SHA-256 and pixel dimensions must match manifest. |
POST /projects/:p/exports/:e/complete | exports:write | Publish atomically after all images have arrived. |
GET /projects/:p/exports/:e/screens/:s | exports:read | Stream a private screenshot with the same authentication. |
GET /projects/:p/exports/:e/comments | comments:read | List comments; optional status=open|resolved. Join screenId to the manifest for section context. |
POST /projects/:p/exports/:e/comments | comments:write | Create: {screenId,body,x,y,parentId?}. x/y normalized 0–1. parentId replies to a root. |
PATCH /projects/:p/exports/:e/comments/:c | comments:write | Update {resolved?: boolean, body?: string}. Body edits are author-only. Resolve root threads. |
Collections use cursor pagination: {items, nextCursor}, with 100 items per page. Pass ?cursor=nextCursor until null. Export and comment collections are ordered by ID; sort by createdAt when presenting a timeline. API errors use {error, issues?}; statuses 401 unauthenticated, 403 forbidden, 404 unavailable, 409 conflict, 413 too large, 422 invalid input, 429 rate limited.
Framehuddle CLI
The CLI is open source, with versioned releases and automatic Homebrew updates. Source and documentation · Releases
brew install b-nnett/framehuddle/framehuddle # Set FRAMEHUDDLE_API_KEY securely in your environment. framehuddle projects list --json framehuddle init --project PROJECT_ID --export EXPORT_ID framehuddle exports import ./export.visual-feedback.json framehuddle feedback --status open --json framehuddle screens get SCREEN_ID --output ./screen.png framehuddle --help # Upgrade: brew update && brew upgrade framehuddle # Existing Acquire exports (from the app repository): npm run convert:acquire -- board.figma.json export.visual-feedback.json v1
Project sharing and API key management are available only to a signed-in human in the app. Agents cannot mint more keys or grant other accounts access. Screenshots require authentication; there are no public blob URLs.