> ## Documentation Index
> Fetch the complete documentation index at: https://developer.jtl-software.com/llms.txt
> Use this file to discover all available pages before exploring further.

# JTL Developer Blog

> News, tutorials, and insights from the JTL developer team on building apps and integrations for JTL Cloud.

export const BlogIndex = ({posts}) => {
  const formatDate = iso => new Date(iso + 'T00:00:00Z').toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'long',
    day: 'numeric',
    timeZone: 'UTC'
  });
  const avatar = author => author.avatar ? <img className="blog-avatar" src={author.avatar} alt={author.name} /> : <span className="blog-avatar blog-avatar-initials">
				{author.name.split(' ').map(n => n[0]).slice(0, 2).join('')}
			</span>;
  const featuredPost = post => <a href={post.href} className="blog-featured">
			<div className="blog-featured-panel">
				<div>
					<div className="blog-featured-meta">
						{formatDate(post.date)}
						{post.readingTime ? ` · ${post.readingTime}` : ''}
					</div>
					<h3 className="blog-featured-title">{post.title}</h3>
				</div>
				<div className="blog-featured-author">
					{avatar(post.author)}
					<div>
						<div className="blog-featured-author-name">{post.author.name}</div>
						<div className="blog-featured-author-role">{post.author.role}</div>
					</div>
				</div>
			</div>
			{post.image ? <img className="blog-featured-image" src={post.image} alt={post.title} /> : <div className="blog-featured-image blog-image-placeholder" />}
		</a>;
  const postCard = post => <a key={post.href} href={post.href} className="blog-card">
			{post.image ? <img className="blog-card-image" src={post.image} alt={post.title} /> : <div className="blog-card-image blog-image-placeholder" />}
			<div className="blog-card-meta">
				<span>{formatDate(post.date)}</span>
			</div>
			<h3 className="blog-card-title">{post.title}</h3>
			<p className="blog-card-excerpt">{post.excerpt}</p>
		</a>;
  if (posts.length === 0) {
    return <p className="blog-empty">No posts yet. Check back soon.</p>;
  }
  const rest = posts.slice(1);
  return <>
			{featuredPost(posts[0])}

			{rest.length > 0 ? <>
					<div className="blog-tabs">
						<span className="blog-tab blog-tab-active">All articles</span>
					</div>
					<div className="blog-grid">{rest.map(post => postCard(post))}</div>
				</> : null}
		</>;
};

export const posts = [{
  href: '/blog/posts/what-are-jtl-cloud-apps',
  title: 'What are JTL Cloud Apps?',
  excerpt: 'Cloud Apps are web apps you host that run alongside ERPs and use JTL APIs and webhooks. Learn what you can build and how they differ from extensions.',
  date: '2026-10-02',
  readingTime: '9 min read',
  author: {
    name: 'Demola Malomo',
    role: 'Technical Writer',
    avatar: '/images/blog/authors/demola_malomo.jpeg'
  },
  image: '/images/blog/what_are_jtl_cloud_apps.png'
}, {
  href: '/blog/posts/turn-your-wawi-integration-into-a-cloud-app',
  title: 'Turn your ERP Integration into a Cloud App',
  excerpt: 'Stop rebuilding the same ERP integration for every client. Package it as one Cloud App, start with a private app and grow to the App Store.',
  date: '2026-10-02',
  readingTime: '9 min read',
  author: {
    name: 'Demola Malomo',
    role: 'Technical Writer',
    avatar: '/images/blog/authors/demola_malomo.jpeg'
  },
  image: '/images/blog/turn_your_jtlwawi_integration_into_a_cloud_app.png'
}];

<div className="blog-page" />

<BlogIndex posts={posts} />
