# Deikora Template Reference for AI

## What is Deikora

Deikora is a link-in-bio / public-profile page builder. A user claims a username (slug) and builds a public page at `https://deikora.com/<slug>`. The page can contain links, social icons, contact forms, menus, maps, opening hours, portfolios, and many other content items. Everything is customizable through a theme (colors, fonts, layout, wallpaper, item shapes).

A **Deikora template** is a portable JSON document. Templates can be downloaded, shared, and imported into a Deikora account. The current template version is `1.0`.

Templates come in two flavors:

- **Full template** (`"type": "full"`) — captures a complete page: profile info, social links, items, and theme.
- **Style preset** (`"type": "style"`) — captures only the visual theme (`theme_config`). It is meant to be merged onto a page.

## Full template (`type: "full"`)

Use this when you want to create a complete page from scratch or overwrite an existing page.

### Full template JSON structure

```json
{
  "version": "1.0",
  "type": "full",
  "metadata": {
    "id": "ovnaweb",
    "category": "business"
  },
  "page": {
    "name": "Ovnaweb",
    "category": "Web Development Agency",
    "bio": "Premium websites and webapps for service businesses and growing brands.",
    "avatar_url": "https://example.com/avatar.png",
    "banner_url": "https://example.com/banner.png",
    "og_image_url": "https://example.com/og.png",
    "contact_badges": {
      "phone": [],
      "signal": [],
      "display": "both",
      "telegram": [],
      "whatsapp": [
        {
          "id": "b6f86237-82d2-4326-9f1d-47a3b5646cc7",
          "show": true,
          "value": "+18495048500",
          "message": "Hi found you on deikora!"
        }
      ],
      "messenger": []
    },
    "theme_id": null,
    "theme_config": {
      "text": {
        "font": "inter",
        "primaryTextColor": "rgb(10, 10, 10)",
        "secondaryTextColor": "rgb(136, 136, 136)"
      },
      "items": {
        "solid": {
          "color": "rgb(17, 17, 17)",
          "width": 1,
          "opacity": 1,
          "showBorder": false
        },
        "style": "outline",
        "border": {
          "color": "rgb(17, 17, 17)",
          "width": 1,
          "opacity": 1,
          "showBorder": true
        },
        "outline": {
          "color": "rgb(17, 17, 17)",
          "width": 1,
          "opacity": 1,
          "showBorder": true
        },
        "itemColor": "rgb(255, 255, 255)",
        "roundness": "md",
        "textColor": "rgb(245, 245, 250)",
        "itemShadow": "sm"
      },
      "footer": {
        "hideDeikora": false
      },
      "header": {
        "align": "center",
        "layout": "logo-banner",
        "showBio": true,
        "bioColor": "rgb(136, 136, 136)",
        "badgeSize": "md",
        "badgeLayout": "inline",
        "heroBgColor": "rgb(17, 17, 17)",
        "showSocials": true,
        "showUsername": true,
        "usernameFont": "orbitron",
        "socialsPreset": "brand-no-color",
        "usernameColor": "rgb(10, 10, 10)",
        "socialsShowText": true,
        "profileImageSize": "big",
        "showProfileImage": true,
        "profileImageShape": "circle",
        "showCategoryBadge": false,
        "showContactBadges": true,
        "socialsTextSource": "platform",
        "showProfileImageBg": false,
        "contactBadgesPreset": "brand-color",
        "profileImageBgColor": "rgb(255, 255, 255)",
        "showProfileImageBorder": true,
        "profileImageBorderColor": "rgb(60, 60, 75)"
      },
      "wallpaper": {
        "style": "fill",
        "dotColor": "rgba(255, 255, 255, 0.08)",
        "blurColor": "rgba(17, 17, 17, 0.4)",
        "fillColor": "rgba(255, 255, 255, 1)",
        "blurAmount": 8,
        "gradientColor": "rgb(220, 90, 100)",
        "gradientDirection": "down"
      }
    },
    "is_public": true,
    "custom_domain": null,
    "page_type": "business"
  },
  "socials": [
    {
      "id": "176c898a-e198-4a77-8afc-fa8192641085",
      "platform": "facebook",
      "url": "https://www.facebook.com/ovnaweb",
      "position": 0
    },
    {
      "id": "caed2d1b-d2bf-4555-8c1d-444e9a9eb233",
      "platform": "instagram",
      "url": "https://www.instagram.com/ovnaweb/",
      "position": 1
    }
  ],
  "items": [
    {
      "id": "f598b53a-bc8b-4106-a122-7fada9944d1b",
      "type": "link",
      "settings": {
        "url": "https://www.ovnaweb.com/",
        "icon": null,
        "title": "website",
        "preset": "body",
        "imageUrl": "https://example.com/link-image.png",
        "arrowIcon": "arrow-right",
        "colorRole": "primary",
        "showArrow": true,
        "description": "Visit our website!",
        "elementStyles": {
          "title": {
            "align": "left"
          }
        },
        "itemStyleOverrides": {
          "style": "solid",
          "shadow": "4px 4px 0px 0px rgba(0, 0, 0, 1), 0px 3px 8px -2px rgba(0, 0, 0, 0.56)",
          "roundness": "md"
        }
      },
      "sort_order": 0
    },
    {
      "id": "3a1c75b8-e997-46f8-a091-477d7824194a",
      "type": "calendly",
      "settings": {
        "url": "https://calendly.com/ovnaweb/15min",
        "preset": "body",
        "colorRole": "primary",
        "buttonText": "Book a meeting",
        "itemStyleOverrides": {
          "style": "solid",
          "shadow": "4px 4px 0px 0px rgba(0, 0, 0, 1), 0px 3px 8px -2px rgba(0, 0, 0, 0.56)",
          "roundness": "md"
        }
      },
      "sort_order": 1
    },
    {
      "id": "d412ea52-ea0d-494f-9412-fedd58af57e9",
      "type": "contact_form",
      "settings": {
        "layout": "inline",
        "buttonText": "Get a quote",
        "itemStyleOverrides": {
          "horizontalPadding": "none"
        }
      },
      "sort_order": 2
    }
  ]
}
```

Full templates live here:

- https://deikora.com/templates/hvac.json
- https://deikora.com/templates/restaurant.json
- https://deikora.com/templates/creator.json
- https://deikora.com/templates/personal.json
- https://deikora.com/templates/business.json
- https://deikora.com/templates/portfolio.json

## Style preset (`type: "style"`)

Use this when you want to give a page a specific look without changing its content.

A style preset has the same outer shape as a full template, but `type` is `"style"` and `socials` and `items` are empty arrays. Only `metadata` and `page.theme_config` matter.

### Style preset JSON structure

```json
{
  "version": "1.0",
  "type": "style",
  "metadata": {
    "id": "daylight",
    "kind": "static",
    "isPro": true,
    "nameKey": "design.presetNames.daylight",
    "preview": "linear-gradient(135deg, rgb(255, 255, 255) 0%, rgb(245, 245, 247) 100%)",
    "category": "classic"
  },
  "page": {
    "theme_id": null,
    "theme_config": {
      "text": {
        "font": "inter",
        "primaryTextColor": "rgb(10, 10, 10)",
        "secondaryTextColor": "rgb(175, 175, 175)"
      },
      "items": {
        "solid": {
          "color": "rgb(17, 17, 17)",
          "width": 1,
          "opacity": 1,
          "showBorder": false
        },
        "style": "outline",
        "border": {
          "color": "rgb(17, 17, 17)",
          "width": 1,
          "opacity": 1,
          "showBorder": true
        },
        "outline": {
          "color": "rgb(17, 17, 17)",
          "width": 1,
          "opacity": 1,
          "showBorder": true
        },
        "itemColor": "rgb(175, 175, 175)",
        "roundness": "md",
        "textColor": "rgb(10, 10, 10)",
        "itemShadow": "sm"
      },
      "footer": {
        "hideDeikora": false
      },
      "header": {
        "layout": "logo",
        "showBio": true,
        "bioColor": "rgb(175, 175, 175)",
        "badgeSize": "md",
        "badgeLayout": "inline",
        "heroBgColor": "rgb(17, 17, 17)",
        "showSocials": true,
        "showUsername": true,
        "usernameFont": "inter",
        "socialsPreset": "brand-color",
        "usernameColor": "rgb(10, 10, 10)",
        "socialsShowText": false,
        "profileImageSize": "medium",
        "showProfileImage": true,
        "profileImageShape": "circle",
        "showCategoryBadge": false,
        "showContactBadges": true,
        "socialsTextSource": "platform",
        "showProfileImageBg": false,
        "contactBadgesPreset": "brand-color",
        "profileImageBgColor": "rgb(255, 255, 255)",
        "showProfileImageBorder": true,
        "profileImageBorderColor": "rgb(10, 10, 10)"
      },
      "wallpaper": {
        "style": "fill",
        "blurColor": "rgba(17, 17, 17, 0.4)",
        "fillColor": "rgb(255, 255, 255)",
        "blurAmount": 8,
        "gradientColor": "rgb(30, 30, 30)",
        "gradientDirection": "down"
      },
      "itemTypeStyles": {
        "faq": {
          "hideFrame": true
        },
        "link": {
          "shadow": "4px 4px 0px 0px rgba(0, 0, 0, 1), 0px 3px 8px -2px rgba(0, 0, 0, 0.56)",
          "hideFrame": true
        },
        "text": {
          "hideFrame": true
        },
        "hiring": {
          "padding": "none",
          "hideFrame": true,
          "horizontalPadding": "none"
        },
        "qr_code": {
          "hideFrame": true,
          "horizontalPadding": "none"
        },
        "services": {
          "hideFrame": true,
          "horizontalPadding": "none"
        },
        "portfolio": {
          "hideFrame": true,
          "horizontalPadding": "none"
        },
        "contact_card": {
          "hideFrame": true,
          "horizontalPadding": "none"
        },
        "contact_form": {
          "layout": "inline",
          "padding": "none",
          "hideFrame": true,
          "horizontalPadding": "none"
        }
      }
    }
  },
  "socials": [],
  "items": []
}
```

Style presets live here:

- https://deikora.com/themes/midnight
- https://deikora.com/themes/daylight
- https://deikora.com/themes/sakura
- https://deikora.com/themes/ocean
- https://deikora.com/themes/forest
- https://deikora.com/themes/nebula-midnight
- https://deikora.com/themes/prism-crystal

Browse the full gallery at https://deikora.com/en/themes.

## How to combine a style preset with a full template

Style presets are **color-only**. When applying one to a full template, replace the full template's `page.theme_config` with the style preset's `page.theme_config`. Keep the full template's `page` fields (`name`, `bio`, `avatar_url`, etc.), `socials`, and `items` unchanged.

Do **not** copy `socials` or `items` from a style preset — they are always empty.

## AI instructions

To build a Deikora page for a user:

1. Read this reference.
2. Pick the closest full template from the examples above.
3. If the user wants a specific look, pick a style preset and merge its `theme_config` into the full template.
4. Customize the page name, bio, items, and socials for the user.
5. Use valid `iconify:<set>:<icon>` icon references everywhere an icon is needed.
6. Return the full JSON document with `"version": "1.0"` and `"type": "full"`.
7. Validate the output against the checklist at the bottom of this document.

## Icons

Icons must be valid **Iconify** references in the exact format:

```
iconify:<set>:<icon-name>
```

Examples:

- `"icon": "iconify:lucide:phone"`
- `"icon": "iconify:lucide:utensils-crossed"`
- `"icon": "iconify:lucide:map-pin"`
- `"icon": "iconify:fluent:wrench-16-regular"`

If an item does not need an icon, use `null` (not an empty string). Do **not** use formats like `"lucide:phone"`, `"phone"`, or emoji strings unless they are intentional plain-text labels.

Recommended default icon set is `lucide`. You can discover valid icon names with the Iconify search API:

```
https://api.iconify.design/search?query=phone&limit=20
```

Each result `icon` field is already in `<set>:<icon-name>` form. Prefix it with `iconify:` when writing the Deikora template.

Common icon choices by item type:

| Item type | Suggested icon |
| --- | --- |
| `link` | `iconify:lucide:globe` |
| `contact_form` | `iconify:lucide:mail` |
| `menu` | `iconify:lucide:utensils-crossed` |
| `services` | `iconify:lucide:briefcase` |
| `map` | `iconify:lucide:map-pin` |
| `opening_hours` | `iconify:lucide:clock` |
| `calendly` | `iconify:lucide:calendar` |
| `portfolio` | `iconify:lucide:images` |
| `faq` | `iconify:lucide:help-circle` |
| `hiring` | `iconify:lucide:user-plus` |
| `info_card` | `iconify:lucide:sparkles` |
| `amenities` | `iconify:lucide:check-circle` |
| `qr_code` | `iconify:lucide:qr-code` |
| `contact_card` | `iconify:lucide:id-card` |

## Item types

These are the supported `type` values for `items`. Each item has a `settings` object and a `sort_order` integer.

### `link`
A button-style link.

```json
{
  "id": "link-1",
  "type": "link",
  "settings": {
    "title": "Visit our website",
    "url": "https://example.com",
    "description": "Our main website",
    "icon": "iconify:lucide:globe",
    "imageUrl": null,
    "showArrow": true,
    "arrowIcon": "arrow-right",
    "preset": "body",
    "colorRole": "primary"
  },
  "sort_order": 0
}
```

### `text`
A heading or paragraph block.

```json
{
  "id": "text-1",
  "type": "text",
  "settings": {
    "content": "About us",
    "preset": "heading",
    "size": "4xl",
    "weight": "black",
    "align": "center",
    "fontFamily": "archivoBlack",
    "uppercase": true,
    "hideFrame": true
  },
  "sort_order": 1
}
```

### `contact_form`
A contact form.

```json
{
  "id": "contact-1",
  "type": "contact_form",
  "settings": {
    "layout": "inline",
    "buttonText": "Send message"
  },
  "sort_order": 2
}
```

### `calendly`
A Calendly booking button.

```json
{
  "id": "calendly-1",
  "type": "calendly",
  "settings": {
    "url": "https://calendly.com/example/15min",
    "buttonText": "Book a meeting"
  },
  "sort_order": 3
}
```

### `opening_hours`
Opening hours with live status.

```json
{
  "id": "hours-1",
  "type": "opening_hours",
  "settings": {
    "style": "expanded",
    "schedule": {
      "monday": { "open": "09:00", "close": "17:00", "closed": false },
      "tuesday": { "open": "09:00", "close": "17:00", "closed": false },
      "wednesday": { "open": "09:00", "close": "17:00", "closed": false },
      "thursday": { "open": "09:00", "close": "17:00", "closed": false },
      "friday": { "open": "09:00", "close": "17:00", "closed": false },
      "saturday": { "open": "09:00", "close": "17:00", "closed": true },
      "sunday": { "open": "09:00", "close": "17:00", "closed": true }
    }
  },
  "sort_order": 4
}
```

### `menu` / `store` / `services`
Catalog-style items with categories and priced entries. Use `menu` for food, `store` for products, `services` for bookable services.

```json
{
  "id": "services-1",
  "type": "services",
  "settings": {
    "layout": "cards",
    "currency": "$",
    "categories": [
      {
        "id": "cat-1",
        "name": "Services",
        "items": [
          {
            "id": "svc-1",
            "name": "Consultation",
            "description": "One-hour strategy session",
            "price": "150",
            "duration": "1 hour",
            "pricingModel": "fixed"
          }
        ]
      }
    ]
  },
  "sort_order": 5
}
```

### `portfolio`
An image gallery.

```json
{
  "id": "portfolio-1",
  "type": "portfolio",
  "settings": {
    "title": "Our work",
    "items": [
      {
        "id": "img-1",
        "type": "image",
        "url": "https://example.com/photo.jpg",
        "title": "Project One",
        "caption": "Description of the project",
        "aspectRatio": 1.5
      }
    ],
    "showDots": true,
    "showArrows": true,
    "aspectRatio": "auto"
  },
  "sort_order": 6
}
```

### `faq`
Expandable FAQ list.

```json
{
  "id": "faq-1",
  "type": "faq",
  "settings": {
    "text": "Frequently asked questions",
    "layout": "expanded",
    "entries": [
      {
        "id": "q-1",
        "question": "What is Deikora?",
        "answer": "Deikora is a link-in-bio and public-profile page builder."
      }
    ],
    "hideFrame": true
  },
  "sort_order": 7
}
```

### `separator`
A visual divider or spacer.

```json
{
  "id": "sep-1",
  "type": "separator",
  "settings": {
    "style": "solid",
    "spacing": "lg"
  },
  "sort_order": 8
}
```

## Styling individual items

### `itemStyleOverrides`
Use this to override the global item style for one item.

```json
{
  "itemStyleOverrides": {
    "style": "solid",
    "roundness": "md",
    "padding": "compact",
    "horizontalPadding": "none",
    "shadow": "md",
    "border": {
      "showBorder": true,
      "color": "rgb(17, 17, 17)",
      "width": 1,
      "opacity": 1
    }
  }
}
```

`style` can be `"solid"` or `"outline"`. `roundness` can be `"none"`, `"sm"`, `"md"`, or `"full"`. `padding` and `horizontalPadding` can be `"none"`, `"tight"`, or `"compact"`.

### `elementStyles`
Use this to style specific text or icon parts inside an item.

```json
{
  "elementStyles": {
    "title": {
      "align": "left",
      "color": "rgb(10, 10, 10)"
    },
    "icon": {
      "color": "rgb(120, 180, 210)"
    },
    "description": {
      "color": "rgb(100, 100, 100)"
    }
  }
}
```

## Wallpaper

The `wallpaper` object controls the page background.

- `"style": "fill"` — solid color. Set `fillColor`.
- `"style": "gradient"` — gradient. Set `fillColor` and `gradientColor`, and optionally `gradientDirection` (`"up"` or `"down"`).
- `"style": "three"` — animated Three.js shader. Set `threePresetId` to a valid preset ID (e.g. `"nebula-midnight"`, `"prism-crystal"`). Animated presets are Pro.
- `"style": "image"` — background image. Set `imageUrl`.
- `"style": "dots"` — dot pattern. Set `dotColor` and `fillColor`.
- `"style": "blur"` — blurred color backdrop. Set `blurColor` and `blurAmount`.

## Common mistakes

- **Wrong icon format.** Use `iconify:<set>:<icon>`, not `lucide:phone` or emoji.
- **Wrong template `type`.** Full pages use `"type": "full"`. Style-only presets use `"type": "style"`.
- **Copying `socials`/`items` from a style preset.** Style presets have empty arrays.
- **Forgetting `sort_order`.** Every item must have a unique integer `sort_order`.
- **Using invalid item `type` values.** Only the documented item types are supported.
- **Setting `style: "outline"` without a visible border.** Make sure `border.showBorder` is `true`.
- **Using `rgb()` strings for boolean-like fields.** Colors must be valid CSS `rgb()` / `rgba()` strings.

## Pre-return checklist

Before returning the final JSON, verify:

1. `"version"` is `"1.0"` and `"type"` is `"full"`.
2. `page.name`, `page.bio`, and `page.category` are set.
3. Every item has a unique `id` and a unique `sort_order`.
4. Every icon is either `null` or in `iconify:<set>:<icon>` format.
5. Social URLs start with `https://`.
6. `theme_config` uses valid `rgb()` / `rgba()` color strings.
7. If the user asked for a specific Deikora theme, its `theme_config` has been merged in.
8. No placeholder text like "example.com" remains unless the user explicitly wants it.
