[{"data":1,"prerenderedAt":550},["ShallowReactive",2],{"bootstrap":3,"blog-commercify-anything-even-pokemon-and-poke-mart-express":277},{"navigation":4,"globalConfig":196,"forms":218},{"headerSections":5,"headerFooterLinks":67,"footer":76,"legalLinks":153,"socialLinks":176},[6,39,44,50,57,62],{"hasSubMenu":7,"title":8,"links":9,"columns":38},true,"Product",[10,20,26,32],{"showTag":11,"_modelApiKey":12,"text":13,"subtitle":14,"icon":15,"isExternal":11,"link":16,"openForm":11},false,"navigation_link","Universal checkout","Sell anywhere","globe-simple",{"_modelApiKey":17,"slug":18,"title":19},"page","universal-checkout","Universal Checkout",{"showTag":11,"_modelApiKey":12,"text":21,"subtitle":22,"icon":23,"isExternal":11,"link":24,"openForm":11},"Distributed OMS","Manage orders","package",{"_modelApiKey":17,"slug":25,"title":21},"distributed-oms",{"showTag":11,"_modelApiKey":12,"text":27,"subtitle":28,"icon":29,"isExternal":11,"link":30,"openForm":11},"Promotion engine","Automated discounts","seal-percent",{"_modelApiKey":17,"slug":31,"title":27},"promotion-engine",{"showTag":11,"_modelApiKey":12,"text":33,"subtitle":34,"icon":35,"isExternal":11,"link":36,"openForm":11},"POS system","Operate stores","devices",{"_modelApiKey":17,"slug":37,"title":33},"pos-system",2,{"hasSubMenu":11,"showTag":11,"_modelApiKey":12,"text":40,"isExternal":11,"link":41,"openForm":11,"title":40},"Pricing",{"_modelApiKey":42,"slug":43},"pricing_page","pricing",{"hasSubMenu":11,"showTag":11,"_modelApiKey":12,"text":45,"isExternal":11,"link":46,"openForm":11,"title":45},"Customers",{"_modelApiKey":47,"slug":48,"title":49},"customer_landing_page","customers","Customers page",{"hasSubMenu":11,"showTag":11,"_modelApiKey":12,"text":51,"isExternal":11,"link":52,"openForm":11,"form":54,"title":51},"Partners",{"_modelApiKey":17,"slug":53,"title":51},"partners",{"_modelApiKey":55,"slug":53,"name":56},"form","PartnersForm",{"hasSubMenu":11,"showTag":11,"_modelApiKey":12,"text":58,"label":59,"isExternal":7,"url":60,"openForm":11,"title":61},"Docs Hub","Learn more","https:\u002F\u002Fdocs.commercelayer.io\u002F","Docs",{"hasSubMenu":11,"showTag":11,"_modelApiKey":12,"text":63,"isExternal":11,"link":64,"openForm":11,"title":63},"Blog",{"_modelApiKey":65,"slug":66},"blog_landing_page","blog",[68,72],{"text":69,"link":70},"Sign in",{"_modelApiKey":12,"text":69,"isExternal":7,"url":71,"openForm":11},"https:\u002F\u002Fdashboard.commercelayer.io\u002Fsign_in",{"text":73,"link":74},"Sign up for free",{"_modelApiKey":12,"text":73,"isExternal":7,"url":75,"openForm":11},"https:\u002F\u002Fdashboard.commercelayer.io\u002Fsign_up",[77,89,109,132],{"hasSubMenu":7,"title":8,"links":78},[79,81,83,85,87],{"showTag":11,"_modelApiKey":12,"text":13,"subtitle":14,"icon":15,"isExternal":11,"link":80,"openForm":11},{"_modelApiKey":17,"slug":18,"title":19},{"showTag":11,"_modelApiKey":12,"text":21,"subtitle":22,"icon":23,"isExternal":11,"link":82,"openForm":11},{"_modelApiKey":17,"slug":25,"title":21},{"showTag":11,"_modelApiKey":12,"text":27,"subtitle":28,"icon":29,"isExternal":11,"link":84,"openForm":11},{"_modelApiKey":17,"slug":31,"title":27},{"showTag":11,"_modelApiKey":12,"text":33,"subtitle":34,"icon":35,"isExternal":11,"link":86,"openForm":11},{"_modelApiKey":17,"slug":37,"title":33},{"showTag":11,"_modelApiKey":12,"text":40,"isExternal":11,"link":88,"openForm":11},{"_modelApiKey":42,"slug":43},{"hasSubMenu":7,"title":90,"links":91},"Resources",[92,94,99,104,107],{"showTag":11,"_modelApiKey":12,"text":93,"isExternal":7,"url":60,"openForm":11},"Documentation",{"showTag":11,"_modelApiKey":12,"text":95,"label":95,"isExternal":11,"link":96,"openForm":11},"Agentic Commerce",{"_modelApiKey":17,"slug":97,"title":98},"agentic-commerce-whitepaper","Agentic Commerce Whitepaper",{"showTag":11,"_modelApiKey":12,"text":100,"isExternal":11,"link":101,"openForm":11},"Core concepts",{"_modelApiKey":17,"slug":102,"title":103},"headless-commerce","Headless commerce",{"showTag":11,"_modelApiKey":12,"text":105,"isExternal":7,"url":106,"openForm":11},"Changelog","https:\u002F\u002Fdocs.commercelayer.io\u002Fchangelog\u002F",{"showTag":11,"_modelApiKey":12,"text":63,"isExternal":11,"link":108,"openForm":11},{"_modelApiKey":65,"slug":66},{"hasSubMenu":7,"title":110,"links":111},"Company",[112,116,118,121,126],{"showTag":11,"_modelApiKey":12,"text":113,"isExternal":11,"link":114,"openForm":11},"Vision",{"_modelApiKey":17,"slug":115,"title":113},"vision",{"showTag":11,"_modelApiKey":12,"text":45,"isExternal":11,"link":117,"openForm":11},{"_modelApiKey":47,"slug":48,"title":49},{"showTag":11,"_modelApiKey":12,"text":51,"isExternal":11,"link":119,"openForm":11,"form":120},{"_modelApiKey":17,"slug":53,"title":51},{"_modelApiKey":55,"slug":53,"name":56},{"showTag":11,"_modelApiKey":12,"text":122,"isExternal":11,"link":123,"openForm":11},"Security",{"_modelApiKey":17,"slug":124,"title":125},"security","Security at Commerce Layer",{"showTag":11,"_modelApiKey":12,"text":127,"label":128,"isExternal":11,"openForm":7,"form":129},"Giveback","Giveback program",{"_modelApiKey":55,"slug":130,"name":131},"giveback","GivebackForm",{"hasSubMenu":7,"title":133,"links":134},"Get in touch",[135,140,145,149],{"showTag":11,"_modelApiKey":12,"text":136,"isExternal":11,"openForm":7,"form":137},"Contact",{"_modelApiKey":55,"slug":138,"name":139},"contact","ContactUsForm",{"showTag":11,"_modelApiKey":12,"text":141,"isExternal":11,"openForm":7,"form":142},"Book a demo",{"_modelApiKey":55,"slug":143,"name":144},"demo","RequestDemoForm",{"showTag":11,"_modelApiKey":12,"text":146,"label":147,"isExternal":7,"url":148,"openForm":11},"Support","Email support","mailto:support@commercelayer.io",{"showTag":11,"_modelApiKey":12,"text":150,"label":151,"isExternal":7,"url":152,"openForm":11},"Community","Discord community","https:\u002F\u002Fdiscord.gg\u002Fcommercelayer",{"hasSubMenu":7,"title":154,"links":155},"Legal",[156,161,165,169,173],{"showTag":11,"_modelApiKey":12,"text":157,"label":158,"isExternal":7,"url":159,"openForm":11,"htmlClassNames":160},"Terms","Terms and conditions","\u002Flegal-embed\u002Fterms-of-service","iubenda-nostyle no-brand iubenda-noiframe iubenda-embed",{"showTag":11,"_modelApiKey":12,"text":162,"label":163,"isExternal":7,"url":164,"openForm":11,"htmlClassNames":160},"Privacy","Privacy policy","\u002Flegal-embed\u002Fprivacy-policy",{"showTag":11,"_modelApiKey":12,"text":166,"label":167,"isExternal":7,"url":168,"openForm":11,"htmlClassNames":160},"Cookies","Cookie policy","\u002Flegal-embed\u002Fcookie-policy",{"showTag":11,"_modelApiKey":12,"text":170,"isExternal":7,"url":171,"openForm":11,"htmlClassNames":172},"Notice at collection","#","iubenda-cs-uspr-link",{"showTag":11,"_modelApiKey":12,"text":174,"isExternal":7,"url":171,"openForm":11,"htmlClassNames":175},"Privacy preferences","iubenda-cs-preferences-link",[177,180,184,188,192],{"title":178,"type":179,"url":152,"isExternal":7},"Discord","discord-logo",{"title":181,"type":182,"url":183,"isExternal":7},"Github","github","https:\u002F\u002Fgithub.com\u002Fcommercelayer",{"title":185,"type":186,"url":187,"isExternal":7},"Bluesky","bluesky-logo","https:\u002F\u002Fbsky.app\u002Fprofile\u002Fcommercelayer.io",{"title":189,"type":190,"url":191,"isExternal":7},"X","x-logo","https:\u002F\u002Fx.com\u002Fcommercelayer",{"title":193,"type":194,"url":195,"isExternal":7},"LinkedIn","linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fcommerce-layer",{"pagesWithoutCtaPanel":197,"ctaPanel":198,"notification":208,"showApiResponseTime":11,"newsletterSignup":216},[],{"title":199,"subtitle":200,"ctas":201},"Ready to get started?","Discover how we can help your business.",[202,205],{"_modelApiKey":203,"text":204,"isExternal":7,"url":75,"openForm":11},"link","Get started for free",{"_modelApiKey":203,"text":206,"isExternal":11,"openForm":7,"form":207},"Contact us",{"_modelApiKey":55,"slug":138,"name":139},{"showNotification":7,"link":209,"linkText":210,"text":215},{"_modelApiKey":203,"text":210,"isExternal":11,"link":211,"openForm":11},"Read article",{"_modelApiKey":212,"slug":213,"title":214},"blog_post","payment-api-redesigned","Introducing our new Payments API. For humans and agents.","\u003Cp>Introducing our new Payments API. For humans and agents.\u003C\u002Fp>\n",{"ctaText":217},"Subscribe",[219,225,229,236,240,246,249,253,261,262,267,272,274],{"_modelApiKey":55,"slug":220,"pardotFormEmbedCode":221,"formEmbedMinHeight":222,"successTitle":223,"successCopy":224},"agentic-commerce","https:\u002F\u002Fcommercelayer.fillout.com\u002Ft\u002F5w4Khwgxr6us?whitepaper=agentic",520,"Thank you for your request!","We’ll be in touch soon to arrange a date and time for your personalized demo.",{"_modelApiKey":55,"slug":226,"pardotFormEmbedCode":227,"formEmbedMinHeight":228,"successTitle":223,"successCopy":224},"shopify","https:\u002F\u002Fform.fillout.com\u002Ft\u002FgVnLSmKZwRus",850,{"_modelApiKey":55,"slug":130,"pardotFormEmbedCode":230,"formEmbedMinHeight":231,"displayTitle":232,"copy":233,"successTitle":234,"successCopy":235},"https:\u002F\u002Fform.fillout.com\u002Ft\u002FmVDF8aAiofus",500,"We give back.","\u003Cp>Part of Commerce Layer&#39;s company ethos is to empathize and support one another: co-workers, customers, and community. We want to do our part to help nonprofit organizations and small businesses who may feel adversely affected by the current global economic climate, and as a result, need in-kind support to reach their customers.\u003C\u002Fp>\n\n\u003Cp>If this general description matches your organization’s needs, please tell us your story by completing the following form so we can consider helping your cause.\u003C\u002Fp>\n","Thank you!","We will contact you soon to learn more about your story.",{"_modelApiKey":55,"slug":237,"pardotFormEmbedCode":227,"formEmbedMinHeight":228,"displayTitle":238,"copy":239},"book-an-onboarding-session","Book an onboarding session","\u003Cp>Schedule some time and our devs will help you set up a Commerce Layer + Sanity store.\u003C\u002Fp>\n",{"_modelApiKey":55,"slug":241,"pardotFormEmbedCode":242,"formEmbedMinHeight":243,"displayTitle":244,"successTitle":234,"successCopy":245},"download-our-whitepaper","https:\u002F\u002Fform.fillout.com\u002Ft\u002F5YPWmy8oT7us?whitepaper=ComposableCommerce",450,"Download our whitepaper.","Check your inbox. You should receive a download link soon.",{"_modelApiKey":55,"slug":247,"pardotFormEmbedCode":248,"formEmbedMinHeight":243,"displayTitle":244,"successTitle":234,"successCopy":245},"download-the-content-and-commerce-whitepaper","https:\u002F\u002Fform.fillout.com\u002Ft\u002F5YPWmy8oT7us?whitepaper=ContentAndCommerce",{"_modelApiKey":55,"slug":250,"pardotFormEmbedCode":251,"formEmbedMinHeight":243,"displayTitle":244,"copy":252,"successTitle":234,"successCopy":245},"whitepaper","https:\u002F\u002Fform.fillout.com\u002Ft\u002F5YPWmy8oT7us?whitepaper=Jamstack","\u003Cp>Commerce Layer is the perfect platform for building commerce on the Jamstack. Convert any design into pixel perfect HTML pages. Connect a best-of-breed headless CMS. Go serverless and forget the hassle of managing complex infrastructures.\u003C\u002Fp>\n",{"_modelApiKey":55,"slug":254,"pardotFormEmbedCode":255,"formEmbedMinHeight":256,"displayTitle":257,"copy":258,"successTitle":259,"successCopy":260},"contact-links","https:\u002F\u002Fform.fillout.com\u002Ft\u002FeWPyhHGHT7us",750,"Contact us.","\u003Cp>Tell us about your project. Our team will reach out to you for a personalized offer.\u003C\u002Fp>\n","Thanks for your message!","We’ll be in touch soon to discuss your project details.",{"_modelApiKey":55,"slug":138,"pardotFormEmbedCode":255,"formEmbedMinHeight":256,"displayTitle":257,"copy":258,"successTitle":259,"successCopy":260},{"_modelApiKey":55,"slug":263,"pardotFormEmbedCode":227,"formEmbedMinHeight":228,"displayTitle":264,"successTitle":265,"successCopy":266},"demo-embed","Want to see it in action? Request a demo.","Thanks for your request!","We’ll be in touch soon to arrange a date and time for your free live demo.",{"_modelApiKey":55,"slug":53,"pardotFormEmbedCode":268,"formEmbedMinHeight":228,"displayTitle":269,"copy":270,"successTitle":234,"successCopy":271},"https:\u002F\u002Fform.fillout.com\u002Ft\u002F9MTkDWMUSqus","Become our partner.","\u003Cp>Join us and get our guidance in helping your clients succeed. Our partners are our ambassadors. We are committed to your success as much as you are.\u003C\u002Fp>\n","We will contact you soon to discuss the details of our partnership.",{"_modelApiKey":55,"slug":273,"pardotFormEmbedCode":268,"formEmbedMinHeight":228,"displayTitle":269,"copy":270,"successTitle":234,"successCopy":271},"partners-embed",{"_modelApiKey":55,"slug":143,"pardotFormEmbedCode":227,"formEmbedMinHeight":228,"displayTitle":275,"copy":276,"successTitle":265,"successCopy":266},"Get a free live demo.","\u003Cp>Get a personalized demo and learn more about what Commerce Layer can do for your company.\u003C\u002Fp>\n",{"_modelApiKey":212,"link":278,"subtitle":283,"date":283,"author":284,"additionalAuthors":294,"icon":295,"abstract":296,"tag":297,"displayTitle":279,"cardRatio":300,"featured":11,"seoMetaTags":301,"layout":365,"blogPostCarousel":303,"_seoMetaTags":511,"authors":545},{"text":279,"isExternal":11,"url":280,"link":281},"Commercify anything: The PokéMart Express!","",{"_modelApiKey":212,"slug":282},"commercify-anything-even-pokemon-and-poke-mart-express","October 21, 2024",{"name":285,"picture":286},"Alex Canessa",{"url":287,"alt":288,"title":288,"width":289,"height":289,"format":290,"focalPoint":291,"customData":293},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1754320167-alessandro-can.jpg","Commerce Layer avatar",1280,"jpg",{"x":292,"y":292},0.5,{},[],"bug-droid","Get innovative with your checkout. This tutorial brings a fun Pokemon example right into the shopping cart.",{"color":298,"name":299},"gray","Tutorials","portrait",[302,306,310,313,317,320,323,327,331,335,338,342,346,350,354,357,361],{"attributes":303,"tag":304,"content":305},null,"title","Commerceify anything and innovate with cart and checkout.",{"attributes":307,"tag":309,"content":303},{"property":308,"content":305},"og:title","meta",{"attributes":311,"tag":309,"content":303},{"name":312,"content":305},"twitter:title",{"attributes":314,"tag":309,"content":303},{"name":315,"content":316},"description","Use a Pokémon public API and learn how to innovate within cart and checkout from Commerce Layer's head of developer relations, Alex Canessa.",{"attributes":318,"tag":309,"content":303},{"property":319,"content":316},"og:description",{"attributes":321,"tag":309,"content":303},{"name":322,"content":316},"twitter:description",{"attributes":324,"tag":309,"content":303},{"property":325,"content":326},"og:image","https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1729512575-cl_pokemon-checkout-02.jpg?auto=format&fit=max&w=1200",{"attributes":328,"tag":309,"content":303},{"property":329,"content":330},"og:image:width","1200",{"attributes":332,"tag":309,"content":303},{"property":333,"content":334},"og:image:height","630",{"attributes":336,"tag":309,"content":303},{"name":337,"content":326},"twitter:image",{"attributes":339,"tag":309,"content":303},{"property":340,"content":341},"og:locale","en",{"attributes":343,"tag":309,"content":303},{"property":344,"content":345},"og:type","article",{"attributes":347,"tag":309,"content":303},{"property":348,"content":349},"og:site_name","Commerce Layer",{"attributes":351,"tag":309,"content":303},{"property":352,"content":353},"article:modified_time","2025-10-08T16:20:11Z",{"attributes":355,"tag":309,"content":303},{"property":356,"content":280},"article:publisher",{"attributes":358,"tag":309,"content":303},{"name":359,"content":360},"twitter:card","summary_large_image",{"attributes":362,"tag":309,"content":303},{"name":363,"content":364},"twitter:site","@commercelayer",[366,372,377,380,382,385,388,391,393,396,409,417,421,431,434,436,439,441,444,446,449,451,454,456,459,461,464,472,480,483,485,488,490,493,495,498,508],{"_modelApiKey":367,"copy":368,"listStyle":369,"darkTheme":11,"buttons":370,"color":371,"indent":7},"wysiwyg","\u003Cp>It’s 5:00 p.m. and I am in a pub in Helsinki after a great workshop with one of our solution partners. That kind of workshop that starts triggering ideas. I heard someone saying that a basic architecture is simply Commerce Layer and a CMS. That’s it, the minimum setup.\u003C\u002Fp>\n\n\u003Cp>Well, I don’t think that’s necessarily true.\u003C\u002Fp>\n\n\u003Cp>Commerce Layer helps brands and retailers to sell \u003Cstrong>any product\u003C\u002Fstrong> across \u003Cstrong>any channels\u003C\u002Fstrong>, in \u003Cstrong>any location\u003C\u002Fstrong>.\u003C\u002Fp>\n\n\u003Cp>In other words, I can make anything I want \u003Cstrong>shoppable\u003C\u002Fstrong>. \u003C\u002Fp>\n\n\u003Cp>What if I had some data exposed by an API, maybe legacy, something I might intend to migrate? Even with this, I can still start selling immediately and create a fully-functional ecommerce website with just that legacy stuff and Commerce Layer. \u003Cem>Side-note: You might not even need a website with \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fcore\u002Fapi-reference\u002Flinks\">Commerce Layer’s Links\u003C\u002Fa>, but that’s a story for a different time.\u003C\u002Fem>\u003C\u002Fp>\n\n\u003Cp>Since I first learned of Commerce Layer, I have always wanted to create a foundational website that uses Commerce Layer at its core. I wanted to build something for iteration and experimental stuff. I wanted a site where I could publish different use cases. That time has come...\u003C\u002Fp>\n\n\u003Ch3>Goal\u003C\u002Fh3>\n\n\u003Cp>We will build a website selling Pokémons using a public API to feed our content and Commerce Layer to sell them. \u003C\u002Fp>\n\n\u003Ch4>Components\u003C\u002Fh4>\n\n\u003Cp>To build this demo, we will use the following services:\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>\u003Cstrong>Commerce Layer\u003C\u002Fstrong>: A headless commerce platform and the backbone of your ecommerce, handling all commerce functionalities like product management, cart, and orders.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Next.js\u003C\u002Fstrong>: A React framework for building static and dynamic websites and web applications, offering server-side rendering and generating static websites for projects like our Pokémon store.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Vercel\u003C\u002Fstrong>: A platform for hosting and deploying your Next.js projects. It provides seamless integration with Next.js, ensuring easy deployments and automatic scaling.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>PokéAPI\u003C\u002Fstrong>: An open API for Pokémon data. We will use this to pull Pokémon information into the store.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Cp>Too see the final outcome of what we are about to build, follow this \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fpokemart-express.vercel.app\">link\u003C\u002Fa>.\u003C\u002Fp>\n\n\u003Ch4>Commerce Layer\u003C\u002Fh4>\n\n\u003Cp>First of all, create a Commerce Layer account.\u003C\u002Fp>\n\n\u003Cp>\u003Ca target=\"_blank\" href=\"https:\u002F\u002Fdashboard.commercelayer.io\u002Fsign_up\">Sign up for free\u003C\u002Fa> and you will be able to create your organization, I called mine “PokéMart Express” 🤓. At this point do not follow the rest of the tutorial seeding it with data, we’ll manually add what we need later.\u003C\u002Fp>\n\n\u003Ch4>Next.js\u003C\u002Fh4>\n\n\u003Cp>Let’s create our Next.js website. Following \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fgetting-started\">the Next.js documentation\u003C\u002Fa>, we&#39;ll set up our project environment. I’m all in for TypeScript and Tailwind for styling.\u003C\u002Fp>\n","checkbox",[],"red",{"_modelApiKey":373,"code":374,"showLineNumbers":11,"highlightLines":280,"language":375,"size":376},"code_block","npx create-next-app@latest --typescript","shell","Standard",{"_modelApiKey":367,"copy":378,"listStyle":369,"darkTheme":11,"buttons":379,"color":371,"indent":11},"\u003Cp>\u003Cem>And hey, I&#39;m a fan of \u003Ca target=\"_blank\" hrefs=\"https:\u002F\u002Fpnpm.io\u002F\">pnpm\u003C\u002Fa>, but feel free to use npm or yarn, whatever floats your boat.\u003C\u002Fem>\u003C\u002Fp>\n\n\u003Ch4>Vercel\u003C\u002Fh4>\n\n\u003Cp>After you&#39;ve got your Next.js website up and running and pushed the repo to your favorite git provider, it&#39;s time to make it live. Head over to Vercel and \u003Ca target=\"_blank\" hrefs=\"https:\u002F\u002Fvercel.com\u002Fsignup\">sign up or log in\u003C\u002Fa>. Then connect your repository.\u003C\u002Fp>\n\n\u003Ch4>Data\u003C\u002Fh4>\n\n\u003Cp>As I said, I’ll use PokeAPI for this. The point here is that it could be any API. Specifically, I will use a \u003Ca target=\"_blank\" hrefs=\"https:\u002F\u002Fgithub.com\u002FGabb-c\u002Fpokenode-ts\">TS wrapper for it\u003C\u002Fa>.\u003C\u002Fp>\n\n\u003Cp>Let’s start by getting a PDP (Pokemon Detail Page) up and running:\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>Create the \u003Ccode>pages\u002Fpokemon\u002F[slug].tsx\u003C\u002Fcode> file.\u003C\u002Fli>\n\u003Cli>Install \u003Ccode>pokenode-ts\u003C\u002Fcode>\u003C\u002Fli>\n\u003C\u002Ful>\n",[],{"_modelApiKey":373,"code":381,"showLineNumbers":11,"highlightLines":280,"language":375,"size":376},"pnpm install axios axios-cache-interceptor pokenode-ts",{"_modelApiKey":367,"copy":383,"listStyle":369,"darkTheme":11,"buttons":384,"color":371,"indent":11},"\u003Cul>\n\u003Cli>Use the PokemonClient to get Pokemon information using the slug:\u003C\u002Fli>\n\u003C\u002Ful>\n",[],{"_modelApiKey":373,"code":386,"showLineNumbers":11,"highlightLines":280,"language":387,"size":376},"import { cache } from \"react\";\nimport { PokemonClient, Pokemon } from \"pokenode-ts\";\n\nexport const getData = cache(\n  async (paramSlug?: string | string[]): Promise\u003CPokemon | null> => {\n    if (!paramSlug) {\n      return null;\n    }\n\n    const slug = Array.isArray(paramSlug) ? paramSlug[0] : paramSlug;\n    const api = new PokemonClient();\n\n    try {\n      const pokemonData = await api.getPokemonByName(slug);\n      console.log(pokemonData.name);\n\n      return pokemonData;\n    } catch (error) {\n      console.error(error);\n\n      return null;\n    }\n  }\n);","typescript",{"_modelApiKey":367,"copy":389,"listStyle":369,"darkTheme":11,"buttons":390,"color":371,"indent":11},"\u003Cul>\n\u003Cli>And then let’s get it from the Page component:\u003C\u002Fli>\n\u003C\u002Ful>\n",[],{"_modelApiKey":373,"code":392,"showLineNumbers":11,"highlightLines":280,"language":387,"size":376},"const Page: NextPage\u003CPageProps> = async ({ params }) => {\n  const pokemon = await getData(params?.slug);\n\n  return \u003Cp>Pokemon: {pokemon?.name || \"Not found\"}\u003C\u002Fp>;\n};\n\t\napp\u002Fpokemons\u002F[slug]\u002Fpage.tsx",{"_modelApiKey":367,"copy":394,"listStyle":369,"darkTheme":11,"buttons":395,"color":371,"indent":11},"\u003Cp>If you go to \u003Ccode>\u002Fpokemons\u002Fraichu\u003C\u002Fcode> you should see the name from the PokeAPI 🎉.\u003C\u002Fp>\n\n\u003Ch3>Front-end\u003C\u002Fh3>\n\n\u003Cp>Now that we have everything set up, let’s plan on what to do next:\u003C\u002Fp>\n\n\u003Col>\n\u003Cli>Create a PLP (Pokemon Listing Page) and a PDP (Pokemon Detail Page).\u003C\u002Fli>\n\u003Cli>Style the whole website and make it look like the old games, it’d be great to recreate a pixel-style CSS.\u003C\u002Fli>\n\u003Cli>Create a series of Components that we can re-use while implementing.\u003C\u002Fli>\n\u003C\u002Fol>\n\n\u003Cp>I’ll use AI to give me a template to follow, and maybe even some tailwind class-set to re-create it, starting with a nice pixel-style banner. I will implement it and style it. It takes a while creating different components with different styles. For now I just want to focus on the experience, so I built a homepage and a PDP.\u003C\u002Fp>\n",[],{"_modelApiKey":397,"border":11,"caption":398,"image":399,"size":408,"darkTheme":11,"rounded":7,"color":371},"image_block","The PokéMart Express demo site.",{"url":400,"alt":401,"title":402,"width":403,"height":404,"format":405,"focalPoint":406,"customData":407},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1729510342-pokemart-express.png","The demo site is PokéMart Express and shows four different Pokémon characters available for purchase: Pikachu, Charmander, Squarely,and Blubasaur.","PokéMart Express",2436,1284,"png",{"x":292,"y":292},{},"standard",{"_modelApiKey":397,"border":11,"caption":410,"image":411,"size":408,"darkTheme":11,"rounded":7,"color":371},"A demo PDP: The Pickachu details page experience.",{"url":412,"alt":410,"title":413,"width":403,"height":414,"format":405,"focalPoint":415,"customData":416},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1729510454-pickachu.png","Pikachu details page",1654,{"x":292,"y":292},{},{"_modelApiKey":367,"copy":418,"listStyle":419,"darkTheme":11,"buttons":420,"color":371,"indent":11},"\u003Cp>As soon as I finished building the PDP, I felt like it wasn’t aligned enough to the Pokémon experience. Remember that one of the benefits of using Commerce Layer is that I can create an user experience that isn’t rigid and bounded by what the commerce engine provides.\u003C\u002Fp>\n\n\u003Cp>I was thinking that I might create a &quot;launch the pokéball&quot; to add the Pokémon to the cart. And while this might be a bit of an ambitious plan, let’s try it.\u003C\u002Fp>\n\n\u003Cp>\u003Cstrong>And it’s starting to look a lot like the game.\u003C\u002Fstrong> I do want to add moves and evolutions below the catching screen, but that’s for another time. For now, I’ll stick with the Pokéball animation. Then I’ll move onto Commerce Layer integration.\u003C\u002Fp>\n","directional",[],{"_modelApiKey":397,"border":11,"caption":422,"image":423,"size":408,"darkTheme":11,"rounded":7,"color":371},"Add to cart? Nah, launch the Pokéball!",{"url":424,"alt":425,"title":422,"width":426,"height":427,"format":428,"focalPoint":429,"customData":430},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1729510938-catching-20pokemon.gif","The add to cart experience has been transformed to a launch the Pokéball game where the user has to shoot a ball into the shopping cart, just like a game.",640,404,"gif",{"x":292,"y":292},{},{"_modelApiKey":367,"copy":432,"listStyle":369,"darkTheme":11,"buttons":433,"color":371,"indent":11},"\u003Cp>💡 \u003Cstrong>If you want to start the project now, you can checkout at the \u003Ccode>step-1\u003C\u002Fcode> tag!\u003C\u002Fstrong>\u003C\u002Fp>\n\n\u003Ch3>Commerce Layer\u003C\u002Fh3>\n\n\u003Cp>Now that I have a PDP, it’s time for me to connect to Commerce Layer. First of all, I need to set some data in CL.\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>Create a Merchant.\u003C\u002Fli>\n\u003Cli>Add a US Market.\u003C\u002Fli>\n\u003Cli>Add \u003Cem>some\u003C\u002Fem> pokemon SKUs.\u003C\u002Fli>\n\u003Cli>Add prices for those SKUs in the US Market.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Cp>I won’t need a stock location or an inventory model as it’s all virtual. (However, I will add those later to test some logic.) \u003C\u002Fp>\n\n\u003Cp>Next up, I will expose this API by creating a sales channel, which I then need to connect to my store.\u003C\u002Fp>\n\n\u003Ch4>\u003Cstrong>Connect the Next.js app\u003C\u002Fstrong>\u003C\u002Fh4>\n\n\u003Cp>I want to create a \u003Ccode>CommerceLayerAuth\u003C\u002Fcode> provider that will be responsible of getting and refreshing the token to pass to the \u003Ccode>CommerceLayer\u003C\u002Fcode> component.\u003C\u002Fp>\n\n\u003Cp>To do so, I first need to install a couple npm packages:\u003C\u002Fp>\n",[],{"_modelApiKey":373,"code":435,"showLineNumbers":11,"highlightLines":280,"language":375,"size":376},"pnpm install @commercelayer\u002Freact-components @commercelayer\u002Fjs-auth",{"_modelApiKey":367,"copy":437,"listStyle":369,"darkTheme":11,"buttons":438,"color":371,"indent":11},"\u003Cp>Let’s start this component from its props:\u003C\u002Fp>\n",[],{"_modelApiKey":373,"code":440,"showLineNumbers":11,"highlightLines":280,"language":387,"size":376},"export type CommerceLayerAuthProps = {\n\tchildren: React.ReactNode; \u002F\u002F This will be the wrapped application.\n\tclientId: string; \u002F\u002F Ultimately will be coming from env variables (apply to the next two as well).\n\tmarket: number;\n\tslug: string;\n}",{"_modelApiKey":367,"copy":442,"listStyle":369,"darkTheme":11,"buttons":443,"color":371,"indent":11},"\u003Cp>Let’s then write the logic around getting the authorization (and store it in a state).\u003C\u002Fp>\n",[],{"_modelApiKey":373,"code":445,"showLineNumbers":11,"highlightLines":280,"language":387,"size":376},"const CommerceLayerAuth = ({\n  children,\n  clientId,\n  market,\n}: CommerceLayerAuthProps) => {\n  const [authorization, setAuthorization] =\n    useState\u003CAuthenticateReturn\u003C\"client_credentials\"> | null>(null);\n\n  useEffect(() => {\n    \u002F\u002F @todo: get authorization from local storage if it exists.\n\n    const fetchAuthorization = async () => {\n      const auth = await authenticate(\"client_credentials\", {\n        clientId,\n        scope: `market:code:${market}`,\n      });\n\n      setAuthorization(auth);\n    };\n\n    fetchAuthorization();\n  }, [clientId, market]);\n\n  return (\n    \u003Cdiv>\n      \u003Ccode>{JSON.stringify(authorization)}\u003C\u002Fcode>\n      \u003Cp>{children}\u003C\u002Fp>\n    \u003C\u002Fdiv>\n  );\n};",{"_modelApiKey":367,"copy":447,"listStyle":369,"darkTheme":11,"buttons":448,"color":371,"indent":11},"\u003Cp>And then I can save (and check) using the local storage for the authorization token.\u003C\u002Fp>\n",[],{"_modelApiKey":373,"code":450,"showLineNumbers":11,"highlightLines":280,"language":387,"size":376},"\u002F\u002F @note: I've created these three helpers.\n\ntype Authorization = AuthenticateReturn\u003C\"client_credentials\">;\n\nconst getStoredAuthorization = (market: number): Authorization | null => {\n  const authAsString = localStorage.getItem(`authorization-${market}`);\n\n  if (authAsString != null) {\n    const localAuth = JSON.parse(authAsString);\n    return {\n      ...localAuth,\n      expires: new Date(localAuth.expires),\n    };\n  }\n\n  return null;\n};\n\nconst hasExpired = (time?: Date): boolean => {\n  if (!time) {\n    return true;\n  }\n\n  return time \u003C new Date(Date.now());\n};\n\nconst isValid = (auth: Authorization | null): auth is Authorization => {\n  if (!auth) {\n    return false;\n  }\n\n  return !hasExpired(auth.expires);\n};\n\n\u002F\u002F @note: And inside the useEffect:\n\nuseEffect(() => {\n  const storedAuthorization = getStoredAuthorization(market);\n\n  if (isValid(storedAuthorization)) {\n    setAuthorization(storedAuthorization);\n    return;\n  }\n  \n  \u002F\u002F authenticate and then save in the local storage using the market:\n  localStorage.setItem(`authorization-${market}`, JSON.stringify(auth));",{"_modelApiKey":367,"copy":452,"listStyle":369,"darkTheme":11,"buttons":453,"color":371,"indent":11},"\u003Cp>Now, I simply need to pass everything to the CommerceLayer provider, add a OrderStorage, and wrap the whole app with that.\u003C\u002Fp>\n",[],{"_modelApiKey":373,"code":455,"showLineNumbers":11,"highlightLines":280,"language":387,"size":376},"return (\n  \u003CCommerceLayer\n    accessToken={authorization.accessToken}\n    endpoint={`https:\u002F\u002F${slug}.commercelayer.io`}\n  >\n    \u003COrderStorage persistKey={`order-${market}`}>\n      {\u002F* @ts-expect-error: OrderContainer children do not align to ReactNode type. *\u002F}\n      \u003COrderContainer>{children}\u003C\u002FOrderContainer>\n    \u003C\u002FOrderStorage>\n  \u003C\u002FCommerceLayer>\n);",{"_modelApiKey":367,"copy":457,"listStyle":369,"darkTheme":11,"buttons":458,"color":371,"indent":11},"\u003Ch4>\u003Cstrong>Load data from Commerce Layer\u003C\u002Fstrong>\u003C\u002Fh4>\n\n\u003Cp>The first thing I want to try is to get the computed price from my Auth → Market → Price List → SKU. To do so, I will simply use the \u003Ccode>Price\u003C\u002Fcode> component from the \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fcommercelayer.github.io\u002Fcommercelayer-react-components\u002F\">CL React Component library\u003C\u002Fa>). \u003C\u002Fp>\n\n\u003Cp>I pass the \u003Ccode>sku\u003C\u002Fcode> to the \u003Ccode>PokemonCard\u003C\u002Fcode>, which has now:\u003C\u002Fp>\n",[],{"_modelApiKey":373,"code":460,"showLineNumbers":11,"highlightLines":280,"language":387,"size":376},"\u003CPricesContainer>\n  \u003CPrice skuCode={sku} \u002F>\n\u003C\u002FPricesContainer>",{"_modelApiKey":367,"copy":462,"listStyle":369,"darkTheme":11,"buttons":463,"color":371,"indent":11},"\u003Cp>And when I refresh my homepage and PDP with the Grid, I get all the prices:\u003C\u002Fp>\n",[],{"_modelApiKey":397,"border":11,"caption":465,"image":466,"size":408,"darkTheme":11,"rounded":7,"color":371},"Commerce Layer's Price List App",{"url":467,"alt":465,"title":465,"width":468,"height":469,"format":405,"focalPoint":470,"customData":471},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1729511596-image.png",2146,1894,{"x":292,"y":292},{},{"_modelApiKey":397,"border":11,"caption":473,"image":474,"size":408,"darkTheme":11,"rounded":7,"color":371},"The PokéMart Express PDP with updated prices from Commerce Layer.",{"url":475,"alt":473,"title":473,"width":476,"height":477,"format":405,"focalPoint":478,"customData":479},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1729511650-untitled.png",2054,946,{"x":292,"y":292},{},{"_modelApiKey":367,"copy":481,"listStyle":369,"darkTheme":11,"buttons":482,"color":371,"indent":11},"\u003Ch4>Add to Cart\u003C\u002Fh4>\n\n\u003Cp>Now that I can check the price coming from Commerce Layer, I want to connect the “CATCH IT” with adding to the cart. To do that, I’ll need to use the SDK via the \u003Ccode>useOrderContainer\u003C\u002Fcode> \u003Ca href=\"https:\u002F\u002Fcommercelayer.github.io\u002Fcommercelayer-react-components\u002F?path=\u002Fdocs\u002Fhooks-useordercontainer--docs\">hook\u003C\u002Fa> as the react component won’t work in this case.\u003C\u002Fp>\n\n\u003Cp>It’s quite simple:\u003C\u002Fp>\n",[],{"_modelApiKey":373,"code":484,"showLineNumbers":11,"highlightLines":280,"language":387,"size":376},"\u002F\u002F import from the react-components library.\nimport { useOrderContainer } from \"@commercelayer\u002Freact-components\";\n\n\u002F\u002F get the `addToCart` function from the hook.\nconst { addToCart } = useOrderContainer();\n\n\u002F\u002F use it when the catchingStatus is \"catching\"\nuseEffect(() => {\n  if (catchingStatus === \"catching\") {\n    addToCart({\n      skuCode: pokemon.name,\n      quantity: 1,\n    }).then(() => {\n      setCatchingStatus(\"cought\");\n    });\n  }\n}, [addToCart, catchingStatus, pokemon]);",{"_modelApiKey":367,"copy":486,"listStyle":369,"darkTheme":11,"buttons":487,"color":371,"indent":11},"\u003Ch4>Cart quantity\u003C\u002Fh4>\n\n\u003Cp>Before I test the add to cart, I want to integrate the \u003Ccode>Basket\u003C\u002Fcode> component, so that I can see if it works. I want the trolley to have a pokéball in when something is added to the order. I don’t really care about the number at this point.\u003C\u002Fp>\n\n\u003Cp>Since my \u003Ccode>Basket\u003C\u002Fcode> components accepts an \u003Ccode>items: number\u003C\u002Fcode> property, I will add the logic to the \u003Ccode>Header\u003C\u002Fcode>.\u003C\u002Fp>\n\n\u003Cp>I will use the hook again to get information about the order.\u003C\u002Fp>\n",[],{"_modelApiKey":373,"code":489,"showLineNumbers":11,"highlightLines":280,"language":387,"size":376},"const { order } = useOrderContainer();\n\n\u003CBasket items={order?.skus_count} \u002F>",{"_modelApiKey":367,"copy":491,"listStyle":369,"darkTheme":11,"buttons":492,"color":371,"indent":11},"\u003Cp>Inside the Basket component, I will use the CartLink component from Commerce Layer.\u003C\u002Fp>\n",[],{"_modelApiKey":373,"code":494,"showLineNumbers":11,"highlightLines":280,"language":387,"size":376},"import { CartLink } from \"@commercelayer\u002Freact-components\";\nimport { useMemo } from \"react\";\n\nexport type BasketProps = {\n  items?: number;\n};\n\nconst Basket = ({ items = 0 }: BasketProps) => {\n  const imageSource = useMemo(() => {\n    return items === 0 ? \"\u002Fimages\u002Fbasket-empty.png\" : \"\u002Fimages\u002Fbasket-full.png\";\n  }, [items]);\n\n  return (\n    \u003CCartLink\n      className=\"w-7 inline-block\"\n      label={\u003Cimg src={imageSource} className=\"w-full\" alt=\"Basket\" \u002F>}\n    \u002F>\n  );\n};\n\nexport default Basket;",{"_modelApiKey":367,"copy":496,"listStyle":419,"darkTheme":11,"buttons":497,"color":371,"indent":11},"\u003Cp>Let’s test if our “Catch to Cart” works.\u003C\u002Fp>\n",[],{"_modelApiKey":397,"border":11,"caption":499,"image":500,"size":408,"darkTheme":11,"rounded":7,"color":371},"Innovating in the checkout: PokéMart Express catch to cart! ",{"url":501,"alt":502,"title":503,"width":504,"height":505,"format":428,"focalPoint":506,"customData":507},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1729511893-catch_to_cart.gif","The gif shows the mini-game created to make checkout more engaging. In this case, add to cart has been transformed into a game.","Innovating in the checkout: PokéMart Express catch to cart!",596,454,{"x":292,"y":292},{},{"_modelApiKey":367,"copy":509,"listStyle":369,"darkTheme":11,"buttons":510,"color":371,"indent":11},"\u003Cp>YAY 🎉!\u003C\u002Fp>\n\n\u003Ch4>Push the code and deploy\u003C\u002Fh4>\n\n\u003Cp>Now I’m ready to push and deploy to Vercel. \u003Cstrong>Don’t forget to add your env variables!\u003C\u002Fstrong>\u003C\u002Fp>\n\n\u003Cp>The repository can be find \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fcommercelayer\u002Fpokemart-express\">here\u003C\u002Fa>.\u003C\u002Fp>\n\n\u003Ch3>Conclusion\u003C\u002Fh3>\n\n\u003Cp>To recap, we&#39;ve seamlessly integrated product data from an external API with Commerce Layer&#39;s robust commerce capabilities, creating a unique shopping experience. We&#39;ve shown not only how to integrate an external API, but also that you can bring innovative ideas to some of the most sterile experiences like cart and checkout. \u003C\u002Fp>\n\n\u003Cp>The highel-level key takeaway? \u003C\u002Fp>\n\n\u003Cp>Commerce Layer empowers you to sell \u003Cstrong>anything\u003C\u002Fstrong>, \u003Cstrong>anywhere\u003C\u002Fstrong>, without limitations. Whether you&#39;re dealing with virtual goods or physical products, Commerce Layer provides the flexibility and tools to bring your innovative commerce ideas to life quickly and efficiently. From rapid prototyping to scaling complex operations, Commerce Layer adapts to your needs, making it the ideal choice for businesses looking to push the boundaries of commerce.\u003C\u002Fp>\n",[],[512,513,515,517,519,521,523,525,527,529,531,533,535,537,539,541,543],{"attributes":303,"tag":304,"content":305},{"attributes":514,"tag":309,"content":303},{"property":308,"content":305},{"attributes":516,"tag":309,"content":303},{"name":312,"content":305},{"attributes":518,"tag":309,"content":303},{"name":315,"content":316},{"attributes":520,"tag":309,"content":303},{"property":319,"content":316},{"attributes":522,"tag":309,"content":303},{"name":322,"content":316},{"attributes":524,"tag":309,"content":303},{"property":325,"content":326},{"attributes":526,"tag":309,"content":303},{"property":329,"content":330},{"attributes":528,"tag":309,"content":303},{"property":333,"content":334},{"attributes":530,"tag":309,"content":303},{"name":337,"content":326},{"attributes":532,"tag":309,"content":303},{"property":340,"content":341},{"attributes":534,"tag":309,"content":303},{"property":344,"content":345},{"attributes":536,"tag":309,"content":303},{"property":348,"content":349},{"attributes":538,"tag":309,"content":303},{"property":352,"content":353},{"attributes":540,"tag":309,"content":303},{"property":356,"content":280},{"attributes":542,"tag":309,"content":303},{"name":359,"content":360},{"attributes":544,"tag":309,"content":303},{"name":363,"content":364},[546],{"name":285,"picture":547},{"url":287,"alt":288,"title":288,"width":289,"height":289,"format":290,"focalPoint":548,"customData":549},{"x":292,"y":292},{},1790330006023]