Blocks System
Arky uses a unified block system to model all structured data — from CMS entries and product specifications to reservation forms and order metadata. Blocks provide type safety, multilingual support, nested structures, and AI generation capabilities.
Overview
Section titled “Overview”A block is a typed, key-value pair with metadata (properties) that defines how the data should be structured, validated, and displayed.
{ "id": "block_xyz", "key": "title", "type": "TEXT", "properties": { "label": { "en": "Title", "es": "Título" }, "maxLength": 255 }, "value": [ { "en": "Welcome to Arky", "es": "Bienvenido a Arky" } ]}Block Types
Section titled “Block Types”Arky supports these core block types:
| Type | Description | Use Cases |
|---|---|---|
TEXT | Multilingual text content | Titles, descriptions, HTML content |
TEXT_FILTER | Text for filtering/search | Search queries, filter values |
NUMBER | Numeric values | Prices, dates (timestamps), quantities |
NUMBER_FILTER | Numeric filters | Price ranges, date filters |
BOOLEAN | True/false flags | Feature toggles, checkboxes |
GEO_LOCATION | Geographic coordinates & addresses | Store locations, delivery addresses |
RELATIONSHIP_ENTRY | References to CMS entries | Related posts, categories |
RELATIONSHIP_MEDIA | References to media files | Images, videos, documents |
PHONE_NUMBER | Phone number values | Contact info with validation |
EMAIL | Email addresses | Contact emails |
BLOCK | Nested block containers | Repeatable sections, complex forms |
Block Structure
Section titled “Block Structure”Every block shares this common structure:
interface Block { id: string; // Unique identifier key: string; // Field name (e.g., "title", "price") type: BlockType; // TEXT | NUMBER | BOOLEAN | etc. properties: Props; // Type-specific metadata value: Value[]; // Array of values (supports multi-value fields)}Why Arrays for Values?
Section titled “Why Arrays for Values?”Even single-value fields use arrays (value: [...]) to support:
- Multi-value fields: Tags, galleries, multiple addresses
- Localization:
[{ "en": "Hello", "es": "Hola" }] - Relationship hydration:
[{ id, title, ... }]for entries or media
TEXT Blocks
Section titled “TEXT Blocks”TEXT blocks handle all text-based content with optional multilingual support.
Examples
Section titled “Examples”{ "id": "1", "key": "description", "type": "TEXT", "properties": { "label": { "en": "Description" }, "maxLength": 500 }, "value": [ { "en": "A powerful headless CMS" } ]}{ "id": "2", "key": "content", "type": "TEXT", "properties": { "label": { "en": "Content", "es": "Contenido" } }, "value": [ { "en": "<p>Welcome to <strong>Arky</strong></p>", "es": "<p>Bienvenido a <strong>Arky</strong></p>" } ]}{ "id": "3", "key": "tags", "type": "TEXT", "properties": { "maxValues": 10 }, "value": [ { "en": "cms" }, { "en": "headless" }, { "en": "api-first" } ]}Properties
Section titled “Properties”interface TextProperties { label?: Record<string, string>; // Localized field labels pattern?: string; // Regex validation minLength?: number; maxLength?: number; style?: Record<string, string>; // CSS styles for UI rendering url?: string; // External link metadata minValues?: number; maxValues?: number; // 1 = single, >1 = multi-value}NUMBER Blocks
Section titled “NUMBER Blocks”NUMBER blocks handle numeric values.
Examples
Section titled “Examples”{ "id": "4", "key": "price", "type": "NUMBER", "properties": { "label": { "en": "Price" } }, "value": [29.99]}{ "id": "5", "key": "publishedAt", "type": "NUMBER", "properties": { "label": { "en": "Published Date" } }, "value": [1704067200]}Properties
Section titled “Properties”interface NumberProperties { label?: Record<string, string>; minValues?: number; maxValues?: number; operation?: "plus" | "minus" | "equals" | "greater_than" | "less_than" | "greater_than_or_equal" | "less_than_or_equal" | "contains";}BOOLEAN Blocks
Section titled “BOOLEAN Blocks”BOOLEAN blocks represent true/false states.
Example
Section titled “Example”{ "id": "7", "key": "featured", "type": "BOOLEAN", "properties": { "label": { "en": "Featured Product" }, "maxValues": 1 }, "value": [true]}Properties
Section titled “Properties”interface BooleanProperties { label?: Record<string, string>; maxValues?: number;}GEO_LOCATION Blocks
Section titled “GEO_LOCATION Blocks”GEO_LOCATION blocks store geographic data for mapping and address fields.
Example
Section titled “Example”{ "id": "8", "key": "location", "type": "GEO_LOCATION", "properties": { "label": { "en": "Store Location" } }, "value": [ { "country": "United States", "countryCode": "US", "city": "New York", "address": "123 Broadway", "postalCode": "10001", "coordinates": { "lat": 40.7128, "lon": -74.0060 } } ]}Value Structure
Section titled “Value Structure”interface GeoLocationValue { country?: string; countryCode?: string; city?: string; address?: string; postalCode?: string; coordinates?: { lat: number; lon: number; };}Properties
Section titled “Properties”interface GeoProperties { label?: Record<string, string>;}RELATIONSHIP Blocks
Section titled “RELATIONSHIP Blocks”RELATIONSHIP blocks reference other entities (media files or CMS entries).
- RELATIONSHIP_MEDIA: References to uploaded files
- RELATIONSHIP_ENTRY: References to CMS entries
Reference Format
Section titled “Reference Format”References use prefixed IDs:
media:<id>— Media filesentry:<id>— CMS entries
Examples
Section titled “Examples”{ "id": "9", "key": "gallery", "type": "RELATIONSHIP_MEDIA", "properties": { "maxValues": 10 }, "value": [ "media:abc123", "media:def456" ]}{ "id": "9", "key": "gallery", "type": "RELATIONSHIP_MEDIA", "properties": { "maxValues": 10 }, "value": [ { "id": "abc123", "name": "product.jpg", "mimeType": "image/jpeg", "url": "business_123/media/abc123.jpg", "resolutions": { "thumbnail": { "url": "...", "width": 150, "height": 150 }, "original": { "url": "...", "width": 1920, "height": 1080 } } } ]}{ "id": "10", "key": "relatedPosts", "type": "RELATIONSHIP_ENTRY", "properties": { "maxValues": 5 }, "value": [ "entry:post_123", "entry:post_456" ]}Hydration
Section titled “Hydration”By default, relationships return dehydrated references ("media:xyz"). Use query params to hydrate:
GET /v1/collections/posts/entries/123?hydrate=trueProperties
Section titled “Properties”interface RelationshipProperties { label?: Record<string, string>; minValues?: number; maxValues?: number; url?: string; // External source URL}PHONE_NUMBER Blocks
Section titled “PHONE_NUMBER Blocks”Dedicated phone number type with validation.
Example
Section titled “Example”{ "id": "11", "key": "contactPhone", "type": "PHONE_NUMBER", "properties": { "label": { "en": "Contact Phone" }, "pattern": "^\\+?[0-9\\s-()]+$", "isRequired": true, "placeholder": "+1 (555) 123-4567" }, "value": ["+15551234567"]}Properties
Section titled “Properties”interface PhoneNumberProperties { label?: Record<string, string>; pattern?: string; isRequired?: boolean; placeholder?: string;}EMAIL Blocks
Section titled “EMAIL Blocks”Email address type.
Example
Section titled “Example”{ "id": "12", "key": "contactEmail", "type": "EMAIL", "properties": { "label": { "en": "Email" } }, "value": ["user@example.com"]}Properties
Section titled “Properties”interface TextProperties { label?: Record<string, string>; pattern?: string; minLength?: number; maxLength?: number; minValues?: number; maxValues?: number;}BLOCK Blocks (Nested Structures)
Section titled “BLOCK Blocks (Nested Structures)”BLOCK blocks contain nested arrays of other blocks, enabling repeatable sections and complex forms.
Example: Contact Info Repeater
Section titled “Example: Contact Info Repeater”{ "id": "11", "key": "contacts", "type": "BLOCK", "properties": { "label": { "en": "Contact Information" }, "maxValues": 5 }, "value": [ { "id": "contact_1", "key": "contact", "type": "BLOCK", "properties": {}, "value": [ { "id": "c1_name", "key": "name", "type": "TEXT", "properties": {}, "value": [{ "en": "John Doe" }] }, { "id": "c1_phone", "key": "phone", "type": "PHONE_NUMBER", "properties": {}, "value": ["+1234567890"] } ] } ]}Use Cases
Section titled “Use Cases”- Repeatable sections: FAQ items, team members, testimonials
- Complex forms: Multi-step checkout, reservation details
- Structured content: Recipe ingredients, event schedules
- Order/Reservation metadata: Custom fields for bookings
Properties
Section titled “Properties”interface BlockProperties { label?: Record<string, string>; each?: string; // Iteration hint for rendering style?: Record<string, string>; url?: string; minValues?: number; maxValues?: number;}Filter Blocks
Section titled “Filter Blocks”Special block types for filtering and search:
TEXT_FILTER
Section titled “TEXT_FILTER”Used for text-based filtering (search queries).
{ "id": "f1", "key": "searchQuery", "type": "TEXT_FILTER", "properties": {}, "value": ["smartphone"]}NUMBER_FILTER
Section titled “NUMBER_FILTER”Used for numeric filtering (price ranges, date ranges).
{ "id": "f2", "key": "priceFilter", "type": "NUMBER_FILTER", "properties": { "operation": "less_than_or_equal" }, "value": [">=100", "<=500"]}Working with Blocks (SDK)
Section titled “Working with Blocks (SDK)”Extracting Values
Section titled “Extracting Values”import { getBlockValue, getBlockTextValue, extractBlockValues } from 'arky-sdk/utils/blocks';
const entry = await sdk.cms.getCollectionEntry({ id: 'entry_123' });
// Single valueconst title = getBlockValue(entry, 'title');
// Localized textconst description = getBlockTextValue( entry.blocks.find(b => b.key === 'description'), 'en');
// Extract all values as objectconst values = extractBlockValues(entry.blocks);// { title: "...", price: 29.99, featured: true }Handling Media
Section titled “Handling Media”import { getImageUrl } from 'arky-sdk/utils/blocks';
const product = await sdk.eshop.getProduct({ id: 'prod_123' });const galleryBlock = product.blocks.find(b => b.key === 'gallery');
// Extract first image URLconst imageUrl = getImageUrl(galleryBlock, true, 'https://storage.arky.io');// "https://storage.arky.io/business_123/media/abc123.jpg"Best Practices
Section titled “Best Practices”Use Appropriate Types
Section titled “Use Appropriate Types”- Use
PHONE_NUMBERinstead ofTEXTfor phone numbers - Use
EMAILinstead ofTEXTfor emails - Use
GEO_LOCATIONinstead of separate text fields for addresses
Localization
Section titled “Localization”Always provide multilingual labels and content:
{ "properties": { "label": { "en": "Title", "es": "Título", "fr": "Titre" } }, "value": [ { "en": "Hello", "es": "Hola", "fr": "Bonjour" } ]}Semantic Keys
Section titled “Semantic Keys”Use descriptive, consistent keys:
- ✅
productName,price,publishedAt - ❌
field1,data,text
Dehydrate by Default
Section titled “Dehydrate by Default”Fetch relationships dehydrated (media:xyz) unless you need full objects. This reduces payload size and improves performance.
Nested Blocks for Flexibility
Section titled “Nested Blocks for Flexibility”Use BLOCK type for repeatable, structured sections rather than hardcoding multiple top-level fields.
Related APIs
Section titled “Related APIs”- CMS API — Collections and entries with block-based content
- E-shop API — Products with block-based specifications
- Reservations API — Services and bookings with custom block fields