---
name: okzest-image-generation
description: >-
  When the user wants to generate, personalise, or embed a dynamic image using OKZest.
  Use when the user mentions "OKZest", "dynamic image", "personalised image", "image with a name",
  "image with custom text", "embed an image in email", "image URL for email marketing",
  "generate an image with user data", "customise an image layer", or "image merge tag".
  This skill covers the full workflow: discovering designs via MCP, customising with URL parameters
  or direct layer edits, and generating image outputs — as well as the REST API for programmatic/binary use cases.
metadata:
  version: 1.0.0
  source: local
  confidence: high
tools:
  - name: list_designs
    description: Returns all designs in the account with IDs, names, render URLs, and available URL parameters.
    when: When the user doesn't know which design to use, or wants to see what's available.
  - name: get_design
    description: Returns full metadata for one design, including all URL parameter names for dynamic layers.
    when: Before calling generate_image_url — always check what parameters are available.
  - name: generate_image_url
    description: Builds a live runtime image URL with optional URL parameter overrides. No files are written.
    when: When the user wants an embeddable image URL for email, web, or social use.
  - name: get_design_fields
    description: Returns the editable layers for a design plus the exact properties supported by each layer.
    when: Before editing real layer properties such as text, colour, size, position, opacity, or image_url.
  - name: modify_design_layers
    description: Applies layer edits, renders the image once server-side, and returns a temporary image URL.
    when: When the user needs true layer editing rather than simple merge-tag or query-string substitution.
---

# OKZest Image Generation

OKZest supports two image-generation patterns:

1. **Runtime image URLs** from pre-built designs using URL parameters
2. **One-off rendered images** when you need to edit actual layer properties

Use runtime URLs when you want a permanent embeddable link. Use layer editing when you need deeper control over text, colours, positioning, or image layers.

## When To Use This Skill

- User wants to embed a personalised image in an email or landing page
- User wants to generate an image URL with custom text (names, titles, stats)
- User is using Zapier, Make, or another automation tool to send personalised images
- User wants to discover what designs are available in their account
- User wants to understand how to customise an image's text or image layers
- User wants to edit a design's real layer properties beyond simple merge tags

## The Three-Step Workflow

Always follow this order when you want a permanent runtime URL:

### Step 1 — Discover designs
```
list_designs()
```
Returns: design ID, name, base render URL, available URL parameters, and open counts.
Pick the design that matches the use case.

### Step 2 — Inspect available parameters
```
get_design(id: "<design-id>")
```
Returns the full `optional_url_params` list — these are the layer names you can override via URL query strings.
Never guess parameter names. Always call this before `generate_image_url`.

### Step 3 — Generate the image URL
```
generate_image_url(
  designId: "<design-id>",
  urlParams: '{"first_name": "Jane", "job_title": "CEO", "company": "Acme"}'
)
```
Returns a live URL like:
```
https://img.okzest.com/img?c=<companyId>&i=<designId>&first_name=Jane&job_title=CEO&company=Acme
```
This URL renders the image in real time — no storage writes. Paste directly into `<img>` tags, email templates, or markdown.

## Editing Design Layers

Use this flow when the user wants to change real layer properties such as `text`, `color`, `font_size`, `x`, `y`, `width`, `height`, `opacity`, or `image_url`.

### Step 1 — Discover designs
```
list_designs()
```
Pick the design that matches the use case.

### Step 2 — Inspect editable layers
```
get_design_fields(designId: "<design-id>")
```
Returns the editable layers plus the exact properties supported by each one.
Never guess editable property names. Always inspect them first.

### Step 3 — Render the edited image
```
modify_design_layers(
  designId: "<design-id>",
  layersJson: '[{"layer_id":"heading","text":"Hello Jane","color":"#ff0000"}]'
)
```
Returns:
```
{
  "imageUrl": "https://...",
  "mimeType": "image/png",
  "expiresInSeconds": 30
}
```

**Warning:** The URL from `modify_design_layers` is temporary and expires after 30 seconds. Consume it immediately. Do **not** treat it like the permanent runtime URL returned by `generate_image_url`.

## REST API (Programmatic / Binary Use Cases)

Use the REST API (`https://api.okzest.com`) with `X-API-KEY` header when you need binary output or design metadata outside of the MCP context.

| Endpoint | Use case |
|---|---|
| `GET /v1/images` | List all designs (same as `list_designs`) |
| `GET /v1/images/{id}` | Get one design's metadata (same as `get_design`) |
| `GET /v1/images/{id}/fields` | Inspect editable layers and supported properties (same as `get_design_fields`) |
| `POST /v1/images` | Generate and download the image as binary JPEG/PNG/GIF/WebP |

**Use `POST /v1/images` only when you need the binary file** — for example, to upload to another service. For embedding in email or HTML, use the runtime GET URL instead.

```json
POST /v1/images
{
  "design_id": "abc123",
  "layers": [
	{ "layer_id": "heading", "text": "Jane Doe" },
	{ "layer_id": "profile_photo", "image_url": "https://example.com/jane.jpg" }
  ],
  "format": "jpg",
  "quality": 85
}
```

## URL Parameter Pattern

Parameters are appended as plain query strings to the base design URL:
```
https://img.okzest.com/img?c={companyId}&i={designId}&{param1}={value1}&{param2}={value2}
```

- Parameter names come from the design's `optional_url_params` list — always check with `get_design` first
- Values must be URL-encoded (the `generate_image_url` tool handles this automatically)
- Unrecognised parameters are ignored — they don't cause errors

## Common Patterns

**Email personalisation (most common):**
```
1. list_designs()                             → pick "welcome-email-header"
2. get_design("welcome-email-header")         → see param names: first_name, company
3. generate_image_url("welcome-email-header", '{"first_name": "{{subscriber.first_name}}", "company": "{{subscriber.company}}"}')
→ embed the returned URL in the email <img> tag
```

**Zapier / Make automation:**
- Use the runtime URL from `generate_image_url` (or the GET endpoint) — not `POST /v1/images`
- The URL is the deliverable; plug it directly into the email or webhook body

**A/B testing with different images:**
```
generate_image_url("design-a", '{"headline": "Version A"}')
generate_image_url("design-b", '{"headline": "Version B"}')
```
Each URL renders independently; no storage is consumed.

**Layer editing beyond merge tags:**
```
1. list_designs()                               → pick "webinar-banner"
2. get_design_fields("webinar-banner")          → inspect editable layers and properties
3. modify_design_layers(
     "webinar-banner",
     '[{"layer_id":"heading","text":"Hello Jane","color":"#ff0000"}]'
   )
→ use the returned imageUrl immediately before it expires
```

## Anti-Patterns

- **Don't use `POST /v1/images` when you only need an embeddable URL** — it returns binary bytes, not a reusable image URL.
- **Never guess layer parameter names** — always call `get_design` first to see `optional_url_params`.
- **Don't treat `modify_design_layers` output as permanent** — its `imageUrl` expires after 30 seconds and must be consumed immediately.
- **Don't confuse `design_id` with `name`** — the `layer_id` in `POST /v1/images` refers to the layer within the design JSON, not the design's name.

## Authentication

Both the MCP server and REST API use the same API key, passed as:
- **MCP:** `x-api-key` header configured in `mcp-config.json`
- **REST:** `X-API-KEY` request header

API keys are managed in the OKZest dashboard under Settings → API Keys.
