API Reference
State Endpoints
Manage poster state: validate structure, encode to shareable URLs, and decode URLs back to state.
Validate State
POST
/api/v1/state/validateValidate a LayerShareState structure before encoding or rendering. Returns detailed error messages.
Request Body
| Parameter | Type | Description |
|---|---|---|
(body)required | LayerShareState | Request body is the LayerShareState to validate directly (no wrapper needed) |
request.json
{
"canvas": {
"aspectRatio": "9:16",
"backgroundColor": "#1a1a1a"
},
"layers": [
{
"id": "bg",
"name": "Background",
"type": "background",
"visible": true,
"locked": false,
"transform": {
"x": 0,
"y": 0,
"width": 1,
"height": 1,
"rotation": 0,
"opacity": 1
},
"contentType": "solid",
"fill": {
"type": "radial",
"center": { "x": 0.4, "y": 0.35 },
"radius": 0.95,
"stops": [
{ "color": "#f8fafc", "opacity": 1, "position": 0 },
{ "color": "#0f172a", "opacity": 1, "position": 1 }
]
},
"solidColor": "#f8fafc"
},
{
"id": "text-1",
"name": "Title",
"type": "text",
"visible": true,
"locked": false,
"transform": {
"x": 0,
"y": 0,
"width": 1,
"height": 1,
"rotation": 0,
"opacity": 1
},
"content": "Hello World",
"fontFamily": "DM Sans",
"fontSize": 48,
"fontWeight": "bold",
"color": "#ffffff",
"textAlign": "center",
"letterSpacing": 0,
"lineHeight": 1.2
}
],
"effect": {
"effectId": "ascii-standard",
"enabled": true,
"ascii": {
"style": "standard",
"cellSize": 8,
"invert": false,
"color": true
}
}
}Response (Valid)
response.json
{
"valid": true
}Response (Invalid)
error.json
{
"valid": false,
"errors": [
"canvas.aspectRatio: must be one of 4:3, 3:4, 16:9, 9:16, 1:1, full",
"layers[0].transform: transform is required and must be an object",
"effect.effectId: \"invalid-effect\" is not a valid effect ID"
]
}Required Layer Fields
Every layer must have these base fields:
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier for the layer |
name | string | Display name in layers panel |
type | string | Layer type (text, image, video, 3d, background, etc.) |
visible | boolean | Whether layer is visible |
locked | boolean | Whether layer is locked for editing |
transform | object | Position, size, rotation, opacity |
Encode State to URL
POST
/api/v1/state/encodeConvert a LayerShareState to a shareable URL. URLs are automatically compressed when over 2000 characters.
Request Body
| Parameter | Type | Description |
|---|---|---|
staterequired | LayerShareState | The poster state to encode |
baseUrl | string | Base URL for the shareable linkDefault: https://efecto.app |
request.json
{
"state": {
"canvas": {
"aspectRatio": "9:16",
"backgroundColor": "#1a1a1a"
},
"layers": [
{
"id": "bg",
"name": "Background",
"type": "background",
"visible": true,
"locked": false,
"transform": { "x": 0, "y": 0, "width": 1, "height": 1, "rotation": 0, "opacity": 1 },
"contentType": "image",
"fill": { "type": "solid", "color": "#1a1a1a", "opacity": 1 },
"solidColor": "#1a1a1a",
"inputMedia": {
"mediaUrl": "https://images.unsplash.com/photo-1234",
"mediaType": "image",
"brightness": 1,
"contrast": 1,
"saturation": 1,
"objectFit": "cover"
}
},
{
"id": "text-1",
"name": "Title",
"type": "text",
"visible": true,
"locked": false,
"transform": { "x": 0, "y": -0.3, "width": 0.8, "height": 0.2, "rotation": 0, "opacity": 1 },
"content": "EFECTO",
"fontFamily": "DM Sans",
"fontSize": 72,
"fontWeight": "bold",
"color": "#ffffff",
"textAlign": "center",
"letterSpacing": 0,
"lineHeight": 1.2
}
],
"effect": {
"effectId": "dither-floyd-steinberg",
"enabled": true,
"dither": {
"pattern": "floydSteinberg",
"pixelation": 3,
"colors": ["#000000", "#ffffff"],
"brightness": 1,
"contrast": 1.2
}
},
"postProcesses": [
{
"id": "pp-1",
"type": "scanlines",
"enabled": true,
"settings": { "intensity": 0.3, "count": 200 }
}
]
},
"baseUrl": "https://efecto.app"
}Response
response.json
{
"url": "https://efecto.app/canvas?lm=1&ca=16:9&cbg=%231a1a1a&...",
"params": "lm=1&ca=16:9&cbg=%231a1a1a&..."
}URL compression
Large states are automatically compressed. URLs over 2000 characters use pako compression, indicated by the
lz=1 parameter.Decode URL to State
POST
/api/v1/state/decodeConvert a shareable URL back to LayerShareState. Supports both layer-mode and legacy URLs.
Request Body
| Parameter | Type | Description |
|---|---|---|
urlrequired | string | The Efecto URL to decode |
request.json
{
"url": "https://efecto.app/canvas?lm=1&ca=16:9&cbg=%231a1a1a&..."
}Response
response.json
{
"mode": "layer",
"state": {
"canvas": {
"aspectRatio": "16:9",
"backgroundColor": "#1a1a1a"
},
"layers": [...]
}
}URL Modes
The mode field indicates the URL format:
- layer - Modern LayerAppState format (supports all layer types)
- legacy - Legacy AppState format (single model mode)
Get JSON Schema
GET
/api/v1/schemaGet the JSON Schema for LayerAppState and layer types.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
type | string | Filter by layer type (text, image, video, 3d, shape, background, group) |
Response
response.json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "LayerAppState",
"type": "object",
"required": ["canvas", "layers"],
"properties": {
"canvas": {
"type": "object",
"required": ["aspectRatio", "backgroundColor"],
"properties": {
"aspectRatio": {
"type": "string",
"enum": ["4:3", "3:4", "16:9", "9:16", "1:1", "full"]
},
"backgroundColor": { "type": "string", "pattern": "^#[0-9a-fA-F]{6}$" }
}
},
"layers": {
"type": "array",
"items": { "$ref": "#/$defs/Layer" }
}
}
}Available Types
/api/v1/schema- Full LayerAppState schema/api/v1/schema?type=text- TextLayer schema/api/v1/schema?type=image- ImageLayer schema/api/v1/schema?type=video- VideoLayer schema/api/v1/schema?type=3d- Layer3D schema/api/v1/schema?type=shape- ShapeLayer schema/api/v1/schema?type=background- BackgroundLayer schema/api/v1/schema?type=group- GroupLayer schema
Technical Notes
The API uses LayerShareState - the canonical format for sharing and API operations.
Required Fields
canvas.aspectRatio- one of: 4:3, 3:4, 16:9, 9:16, 1:1, fullcanvas.backgroundColor- hex color string (e.g., "#1a1a1a")- Each layer needs:
id,name,type,visible,locked,transform - Background layer should be at index 0
effect(optional):effectId,enabled, plus effect-specific settingspostProcesses(optional): array of post-process instances