[{"data":1,"prerenderedAt":795},["ShallowReactive",2],{"bootstrap":3,"blog-building-an-external-payment-gateway-with-twitter-api":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":690,"_seoMetaTags":756,"authors":790},{"text":279,"isExternal":11,"url":280,"link":281},"Building an external payment gateway with the Twitter API.","",{"_modelApiKey":212,"slug":282},"building-an-external-payment-gateway-with-twitter-api","August 17, 2022",{"name":285,"picture":286},"Bolaji Ayodeji",{"url":287,"alt":288,"title":288,"width":289,"height":289,"format":290,"focalPoint":291,"customData":293},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1643036479-bolaji.jpg","Bolaji Ayodeji — Developer Advocate at Commerce Layer",1280,"jpg",{"x":292,"y":292},0.5,{},[],"twitter-logo","We makes integrating with any local payment gateway like Twitter possible, allowing you to explore any option your customers demand. In this article, you will learn how to get started with our payment gateways, external payment gateways, and payment methods.",{"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","Building an External Payment Gateway with Twitter API",{"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","In this article, you will learn how to use Commerce Layer's external payment gateways to create a pay-with-tweet payment gateway using Twitter API.",{"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\u002F1660814238-pay-with-a-tweet.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:18:04Z",{"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,380,383,393,396,403,406,411,414,416,419,424,428,431,434,437,439,442,444,447,449,452,454,457,459,462,464,467,476,479,481,484,486,489,491,494,496,499,501,504,506,509,511,514,517,520,523,526,530,533,535,538,540,543,545,553,556,558,561,568,571,573,576,578,581,583,586,588,591,593,596,598,601,603,606,608,611,613,616,618,621,623,626,628,631,633,636,638,641,643,646,648,651,659,666,669,671,674,682,685,687],{"_modelApiKey":367,"copy":368,"listStyle":369,"darkTheme":11,"buttons":370,"color":371,"indent":7},"wysiwyg","\u003Cp>In the \u003Ca href=\"https:\u002F\u002Fcommercelayer.io\u002Fblog\u002Fadd-any-payment-gateway-anywhere\" target=\"_blank\" rel=\"noopener noreferrer\">previous article\u003C\u002Fa>, we explored payment gateways in detail and how businesses can increase sales by improving their checkout process and providing more creative and local payment methods that customers love and trust. Remember that 18% of people from the Baymard summary said they don’t trust websites with their credit card data. This is why we made integrating with any local payment gateway possible so you can explore any option that your customers demand. In this article, we will take a step further and show you how to get started with Commerce Layer payment gateways, external payment gateways, and payment methods. Ultimately, we will create a demo “Pay With Tweet” external payment gateway that will enable customers to pay for their order by just making a tweet without any cash transaction. Sounds weirdly cool, right? Well, let’s get into it, and you’ll learn more about it.\u003C\u002Fp>\n","directional",[],"red",{"_modelApiKey":373,"title":374,"preTitle":375,"linkText":376,"darkTheme":11,"link":377},"link_block","Add any payment gateway. Anywhere.","Previous article","Read",{"isExternal":11,"link":378},{"_modelApiKey":212,"slug":379},"add-any-payment-gateway-anywhere",{"_modelApiKey":367,"copy":381,"listStyle":369,"darkTheme":11,"buttons":382,"color":371,"indent":11},"\u003Chr>\n\n\u003Ch3>Prerequisites\u003C\u002Fh3>\n\n\u003Cul>\n\u003Cli>A general understanding of how APIs and the command-line work.\u003C\u002Fli>\n\u003Cli>Some prior knowledge of the JavaScript programming language.\u003C\u002Fli>\n\u003Cli>You have a \u003Ca href=\"https:\u002F\u002Fdashboard.commercelayer.io\u002Fsign_up\" target=\"_blank\" rel=\"noopener noreferrer\">Commerce Layer\u003C\u002Fa> account already.\u003C\u002Fli>\n\u003Cli>You have set up your organization and created the required commerce data resources for your market. You can follow the \u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fdevelopers\u002Fwelcome\u002Fonboarding-tutorial\" target=\"_blank\" rel=\"noopener noreferrer\">onboarding tutorial\u003C\u002Fa> or \u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fdevelopers\u002Fwelcome\u002Fmanual-configuration\" target=\"_blank\" rel=\"noopener noreferrer\">manual configuration guide\u003C\u002Fa> to achieve this.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Chr>\n\n\u003Ch3>The Pay with Tweet gateway\u003C\u002Fh3>\n\n\u003Cp>External payment gateways enable you to connect any payment gateway with Commerce Layer beyond those integrated natively. To make it clear that the payment gateway can be “any,” we decided to build a creative one: the “Pay with a Tweet” gateway. The idea is that when a customer purchases from your store, they’re prompted to make a tweet with a predefined text that includes their order number. The external payment gateway then reads the Twitter API for the tweet and authorizes the order if the tweet is found. All this happens with the customer not having to make a monetary payment. Ideas like this are useful when you’re building a store for, let’s say, free swag distribution at developer events or free items for customers that qualify for a certain promotion. Instead of just giving out the items “directly free,” asking the customer to make a tweet to publicize your business to their Twitter network seems like a fair deal 😎. This becomes an exchange of an item for peer-to-peer publicity\u002Fmarketing rather than the traditional item for money (imagine using this for sales in a conference or group event; cool right?!).\u003C\u002Fp>\n",[],{"_modelApiKey":384,"border":11,"caption":280,"image":385,"size":392,"darkTheme":11,"rounded":11,"color":371},"image_block",{"url":386,"alt":387,"title":387,"width":388,"height":389,"format":390,"focalPoint":303,"customData":391},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1660410417-pay-with-tweet.svg","Pay with tweet illustration",1200,800,"svg",{},"standard",{"_modelApiKey":367,"copy":394,"listStyle":369,"darkTheme":11,"buttons":395,"color":371,"indent":11},"\u003Cp>We will work with the Commerce Layer CLI, Twitter API, Lambda functions, and Commerce Layer external gateways. At the end of this article, you’d have learned how to use all the tools and services mentioned above.\u003C\u002Fp>\n\n\u003Ch3>The fundamentals of Commerce Layer payment gateways\u003C\u002Fh3>\n\n\u003Cp>As discussed in the \u003Ca href=\"https:\u002F\u002Fcommercelayer.io\u002Fblog\u002Fadd-any-payment-gateway-anywhere\" target=\"_blank\" rel=\"noopener noreferrer\">previous article\u003C\u002Fa>, Commerce Layer supports the ability to integrate with different available and popular payment options. By the time you are ready to add an external payment gateway, we assume you have created an organization, created a merchant, configured your markets, have some items ready for sale, and you are ready to start taking orders. The \u003Ca href=\"https:\u002F\u002Fcommercelayer.io\u002Fdocs\u002Fdata-model\u002Fpayment-gateways\" target=\"_blank\" rel=\"noopener noreferrer\">diagram below\u003C\u002Fa> illustrates the relationships between all the resources associated with payments.\u003C\u002Fp>\n",[],{"_modelApiKey":384,"border":11,"caption":280,"image":397,"size":392,"darkTheme":11,"rounded":11,"color":371},{"url":398,"alt":399,"title":399,"width":400,"height":401,"format":390,"focalPoint":303,"customData":402},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1642607462-payment-gateway.svg","Payment gateway resource and its relationships in payments management",1080,820,{},{"_modelApiKey":367,"copy":404,"listStyle":369,"darkTheme":11,"buttons":405,"color":371,"indent":11},"\u003Cp>Now, let’s talk about the payment gateway options Commerce Layer supports.\u003C\u002Fp>\n\n\u003Ch4>PSD2-ready payment gateways\u003C\u002Fh4>\n\n\u003Cp>Commerce Layer provides out-of-the-box integrations with the most popular payment gateways (Stripe, Klarna, PayPal, Adyen, Braintree, etc.). All these integrations comply with the PSD2 European regulation so that you can implement a payment flow that supports SCA and 3DS2. You can read our \u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fdevelopers\u002Fv\u002Fapi-reference\u002Fpayment_gateways\" target=\"_blank\" rel=\"noopener noreferrer\">payment gateways documentation\u003C\u002Fa> to learn how to create and use any of these gateways. Generally, you can achieve this using our dashboard, API, or CLI by creating the type of gateway you want and providing the required credentials.\u003C\u002Fp>\n\n\u003Cp>Here’s an example API request to create a Stripe payment gateway:\u003C\u002Fp>\n",[],{"_modelApiKey":407,"code":408,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"code_block","curl -g -X POST \\\n  'https:\u002F\u002Fyourdomain.commercelayer.io\u002Fapi\u002Fstripe_gateways' \\\n  -H 'Accept: application\u002Fvnd.api+json' \\\n  -H 'Authorization: Bearer your-access-token' \\\n  -H 'Content-Type: application\u002Fvnd.api+json' \\\n  -d '{\n  \"data\": {\n    \"type\": \"stripe_gateways\",\n    \"attributes\": {\n      \"name\": \"EUR payment gateway\",\n      \"login\": \"sk_live_xxxx-yyyy-zzzz\"\n    }\n  }\n}' ","shell","Standard",{"_modelApiKey":367,"copy":412,"listStyle":369,"darkTheme":11,"buttons":413,"color":371,"indent":11},"\u003Cp>Here’s an example CLI command to create an Adyen payment gateway:\u003C\u002Fp>\n",[],{"_modelApiKey":407,"code":415,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl create adyen_gateways -a \\\n\tname=\"US payment gateway\" \\\n\tmerchant_account=\"\u003Cyour merchant account>\" \\\n\tapi_key=\"\u003Cyour api key>\" \\\n\tlive_url_prefix=\"1797a841fbb37ca7-AdyenDemo\"",{"_modelApiKey":367,"copy":417,"listStyle":369,"darkTheme":11,"buttons":418,"color":371,"indent":11},"\u003Cp>The processes above are similar when creating other gateways. Don’t forget to explore our payment gateway \u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fdevelopers\u002Fv\u002Fapi-reference\u002Fpayment_gateways\" target=\"_blank\" rel=\"noopener noreferrer\">documentation\u003C\u002Fa> to get started.\u003C\u002Fp>\n\n\u003Ch4>Manual payment gateways\u003C\u002Fh4>\n\n\u003Cp>With Commerce Layer, you can process payments through wire transfer, cash, and other manual payment options. The process to achieve this is similar to the credit-card gateways. You will need to create the manual payment gateway, and when a customer creates an order, you will associate a manual payment source with the order. Kindly check out our documentation or how-to guide below to get started with manual payment gateways.\u003C\u002Fp>\n",[],{"_modelApiKey":373,"title":420,"preTitle":421,"linkText":59,"darkTheme":11,"link":422},"Manual gateways.","From the docs",{"_modelApiKey":203,"text":59,"label":280,"subtitle":280,"icon":280,"isExternal":7,"url":423,"link":303,"anchor":280,"openForm":11,"form":303,"htmlClassNames":280},"https:\u002F\u002Fdocs.commercelayer.io\u002Fdevelopers\u002Fv\u002Fapi-reference\u002Fmanual_gateways",{"_modelApiKey":373,"title":425,"preTitle":421,"linkText":59,"darkTheme":11,"link":426},"Manual payments.",{"_modelApiKey":203,"text":59,"label":280,"subtitle":280,"icon":280,"isExternal":7,"url":427,"link":303,"anchor":280,"openForm":11,"form":303,"htmlClassNames":280},"https:\u002F\u002Fdocs.commercelayer.io\u002Fdevelopers\u002Fv\u002Fhow-tos\u002Fpayments\u002Fmanual-payments",{"_modelApiKey":367,"copy":429,"listStyle":369,"darkTheme":11,"buttons":430,"color":371,"indent":11},"\u003Ch4>External payment gateways\u003C\u002Fh4>\n\n\u003Cp>For an \u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fdevelopers\u002Fv\u002Fapi-reference\u002Fexternal_gateways\" target=\"_blank\" rel=\"noopener noreferrer\">external payment gateway\u003C\u002Fa> to work, the payment source associated with the order must be an \u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fdevelopers\u002Fv\u002Fapi-reference\u002Fexternal_payments\" target=\"_blank\" rel=\"noopener noreferrer\">external payment\u003C\u002Fa>. When you create an external gateway, you will pass a set of resource arguments in the request body, including custom endpoint(s) responding to the following transaction types:\u003C\u002Fp>\n\n\u003Col>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fdevelopers\u002Fexternal-resources\u002Fexternal-payment-gateways#authorization\" target=\"_blank\" rel=\"noopener noreferrer\">Authorization\u003C\u002Fa>: this will authorize a payment source (verify that the required funds are available in the customer&#39;s payment source).\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fdevelopers\u002Fexternal-resources\u002Fexternal-payment-gateways#capture\" target=\"_blank\" rel=\"noopener noreferrer\">Capture\u003C\u002Fa>: this will capture an authorization (transfer the money from the customer payment source to the merchant).\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fdevelopers\u002Fexternal-resources\u002Fexternal-payment-gateways#void\" target=\"_blank\" rel=\"noopener noreferrer\">Void\u003C\u002Fa>: this will void an authorization (cancel the authorization on the customer&#39;s order).\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fdevelopers\u002Fexternal-resources\u002Fexternal-payment-gateways#refund\" target=\"_blank\" rel=\"noopener noreferrer\">Refund\u003C\u002Fa>: this will refund a capture, either totally or partially.\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fdevelopers\u002Fexternal-resources\u002Fexternal-payment-gateways#customer-token\" target=\"_blank\" rel=\"noopener noreferrer\">Customer token\u003C\u002Fa>: this will create a customer payment token.\u003C\u002Fli>\n\u003C\u002Fol>\n\n\u003Cp>The associated external endpoint(s) will be responsible for integrating with the payment gateway, including authorizing, capturing, voiding, and refunding an order. For example, let’s say you want to capture the authorization for an order. Assuming you have tokenized a credit card on the client side, you create an external payment with the token, you associate it to the order as the payment source, and when you place the order, Commerce Layer then triggers a \u003Ccode>POST\u003C\u002Fcode> request to the endpoint specified in the \u003Ccode>authorize_url\u003C\u002Fcode> field with some payload including the orders, markets, line items, skus, customers, shipments, etc. data. If the transaction is successful, a JSON response is sent back to Commerce Layer, returning a transaction token (provided by the payment gateway), the total amount that has been captured, and some metadata as seen below:\u003C\u002Fp>\n",[],{"_modelApiKey":407,"code":432,"showLineNumbers":11,"highlightLines":280,"language":433,"size":410},"{\n  \"success\": true,\n  \"data\": {\n    \"transaction_token\": \"your-external-transaction-token\",\n    \"amount_cents\": 20950,\n    \"metadata\": {\n       \"foo\": \"bar\"\n        }\n     }\n}","json",{"_modelApiKey":367,"copy":435,"listStyle":369,"darkTheme":11,"buttons":436,"color":371,"indent":11},"\u003Cp>If the transaction is unsuccessful, a similar response is sent back to Commerce Layer with an error message as seen below:\u003C\u002Fp>\n",[],{"_modelApiKey":407,"code":438,"showLineNumbers":11,"highlightLines":280,"language":433,"size":410},"{\n  \"success\": false,\n  \"data\": {\n    \"transaction_token\": \"your-external-transaction-token\",\n    \"amount_cents\": 20950,\n    \"error\": {\n      \"code\": \"YOUR-ERROR-CODE\",\n      \"message\": \"Your error message\"\n    }\n  }\n}",{"_modelApiKey":367,"copy":440,"listStyle":369,"darkTheme":11,"buttons":441,"color":371,"indent":11},"\u003Cp>The same responses are expected when you capture, void, or refund an order.\u003C\u002Fp>\n\n\u003Ch3>Building the Pay With Tweet gateway\u003C\u002Fh3>\n\n\u003Cp>Now the sweet part of this tutorial 😋. Here’s a breakdown of the entire flow of the system:\u003C\u002Fp>\n\n\u003Cp>\u003Cstrong>Customer purchase\u003C\u002Fstrong>\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>Visit the store (a market associated with an organization).\u003C\u002Fli>\n\u003Cli>Create a customer (associated with an email address).\u003C\u002Fli>\n\u003Cli>Create an order associated with the customer.\u003C\u002Fli>\n\u003Cli>Add some SKUs to the order.\u003C\u002Fli>\n\u003Cli>Add other required resources to the order.\u003C\u002Fli>\n\u003Cli>Make a tweet with predefined text (some text, hashtags, and a tag to a Twitter account representing the \u003Ccode>organization:market\u003C\u002Fcode> the customer is purchasing from).\u003C\u002Fli>\n\u003Cli>Place the order.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Cp>\u003Cstrong>Payment gateway\u003C\u002Fstrong>\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>Receive some payload from Commerce Layer when the external payment gateway is triggered.\u003C\u002Fli>\n\u003Cli>Fetch tweets from the defined Twitter account (that represents the Commerce Layer \u003Ccode>organisation:market\u003C\u002Fcode>) between when the order was last updated and 30 minutes after.\u003C\u002Fli>\n\u003Cli>Sort, filter, and read the tweets for one with the order number associated with the payload received.\u003C\u002Fli>\n\u003Cli>If found, authorize the transaction and place the order.\u003C\u002Fli>\n\u003Cli>If not found, return an error and fail the transaction.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Cp>\u003Cstrong>Extras\u003C\u002Fstrong>\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>Send an email to the customer with proof of purchased product.\u003C\u002Fli>\n\u003Cli>Send the customer information to fulfill the shipment.\u003C\u002Fli>\n\u003Cli>Et cetera.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Cp>The next sections will show you how to set up the Commerce Layer CLI, create an external payment gateway, build the actual integration, and place an order using the CLI. Ideally, this flow will work on your sales channel, where a customer will select some items from your product listing, add them to cart, and checkout the order. When they select a payment method, they will have the option to select the “Pay With Tweet” option, which will show them the predefined tweet (with a link to make the tweet automatically), and once the customer clicks something like “share tweet now,” your sales channel will trigger the external payment gateway and checkout the order if the transaction is successful. By the time you understand how it works with the CLI, you will be able to easily make the right API calls to add this integration into your already existing store running on your choice of technology and tools.\u003C\u002Fp>\n\n\u003Ch4>Getting started with Commerce Layer CLI\u003C\u002Fh4>\n\n\u003Cp>The \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fcommercelayer\u002Fcommercelayer-cli\" target=\"_blank\" rel=\"noopener noreferrer\">Commerce Layer CLI\u003C\u002Fa> helps you to manage your Commerce Layer applications and resources right from the terminal. Kindly install the CLI using your favorite package manager:\u003C\u002Fp>\n",[],{"_modelApiKey":407,"code":443,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"\u002F\u002Fnpm\nnpm install -g @commercelayer\u002Fcli\n\n\u002F\u002Fyarn\nyarn global add @commercelayer\u002Fcli",{"_modelApiKey":367,"copy":445,"listStyle":369,"darkTheme":11,"buttons":446,"color":371,"indent":11},"\u003Cp>Installing the CLI provides access to the \u003Ccode>commercelayer\u003C\u002Fcode> command that can also be accessed with the \u003Ccode>cl\u003C\u002Fcode> alias. Follow \u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fdevelopers\u002Fwelcome\u002Fmanual-configuration#create-an-application\" target=\"_blank\" rel=\"noopener noreferrer\">this guide\u003C\u002Fa> in the documentation to create an \u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fdevelopers\u002Froles-and-permissions#integration\" target=\"_blank\" rel=\"noopener noreferrer\">integration application\u003C\u002Fa> and save the provided \u003Cstrong>client ID\u003C\u002Fstrong>, \u003Cstrong>client secret\u003C\u002Fstrong>, and \u003Cstrong>base endpoint\u003C\u002Fstrong> credentials.\u003C\u002Fp>\n\n\u003Ch4>Setting up the external payment gateway\u003C\u002Fh4>\n\n\u003Cp>Kindly follow the steps below to create an external payment gateway using the CLI:\u003C\u002Fp>\n\n\u003Ch5>\u003Cstrong>1. Create a new payment gateway associated with a name and optional URLs that point to the endpoint that will process the transaction types.\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":448,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl create external_gateways -a \\\n\tname=\"Pay With Tweet\" \\\n\tauthorize_url=\"\" \\\n\tcapture_url=\"\" \\\n\tvoid_url=\"\" \\\n\trefund_url=\"\" \\\n\ttoken_url=\"\"",{"_modelApiKey":367,"copy":450,"listStyle":369,"darkTheme":11,"buttons":451,"color":371,"indent":11},"\u003Cp>Since we haven’t created our custom endpoint yet, you can leave the URLs empty or remove them entirely (you can always update the gateway after it’s created). When you have successfully created the external payment gateway, a resource object is returned:\u003C\u002Fp>\n",[],{"_modelApiKey":407,"code":453,"showLineNumbers":11,"highlightLines":280,"language":433,"size":410},"{\n  id: 'PkXRMsBBGv',\n  type: 'external_gateways',\n  name: 'Pay With Tweet',\n  created_at: '2022-07-09T06:26:38.122Z',\n  updated_at: '2022-07-09T06:26:38.122Z',\n  reference: null,\n  reference_origin: null,\n  metadata: {},\n  shared_secret: 'a51019c761a032ee50b10aa59802ded1',\n  authorize_url: 'null',\n  capture_url: null,\n  void_url: null,\n  refund_url: null,\n  token_url: null\n}",{"_modelApiKey":367,"copy":455,"listStyle":369,"darkTheme":11,"buttons":456,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>2. Create a new payment method associated with a market and payment gateway like so:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":458,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl create payment_methods -a \\\n\tpayment_source_type=\"ExternalPayment\" \\\n\tcurrency_code=\"USD\" \\\n\tprice_amount_cents=0 -r \\\n\tmarket=\"YlqxGhKrQg\" \\\n\tpayment_gateway=\"PkXRMsBBGv\"",{"_modelApiKey":367,"copy":460,"listStyle":369,"darkTheme":11,"buttons":461,"color":371,"indent":11},"\u003Cp>You can get your market ID via the dashboard or by running the command \u003Ccode>cl list markets\u003C\u002Fcode>. When you have successfully created the payment method, a resource object is returned:\u003C\u002Fp>\n",[],{"_modelApiKey":407,"code":463,"showLineNumbers":11,"highlightLines":280,"language":433,"size":410},"{\n  id: 'wmBvQsAzBm',\n  type: 'payment_methods',\n  payment_source_type: 'external_payments',\n  name: 'External Payment',\n  currency_code: 'USD',\n  moto: false,\n  disabled_at: null,\n  price_amount_cents: 0,\n  price_amount_float: 0,\n  formatted_price_amount: '$0.00',\n  created_at: '2022-07-09T06:47:05.841Z',\n  updated_at: '2022-07-09T06:47:05.841Z',\n  reference: null,\n  reference_origin: null,\n  metadata: {},\n  market: {\n    id: 'YlqxGhKrQg',\n    type: 'markets',\n    number: 9480,\n    name: 'USA',\n    facebook_pixel_id: null,\n    checkout_url: '',\n    external_prices_url: '',\n    private: false,\n    created_at: '2022-02-22T04:01:34.336Z',\n    updated_at: '2022-05-31T08:57:24.446Z',\n    reference: 'market_2',\n    reference_origin: 'CLI',\n    metadata: {}\n  },\n  payment_gateway: {\n    id: 'PkXRMsBBGv',\n    type: 'payment_gateways',\n    name: 'Pay With Tweet',\n    created_at: '2022-07-09T06:44:34.692Z',\n    updated_at: '2022-07-09T06:44:34.692Z',\n    reference: '',\n    reference_origin: '',\n    metadata: {}\n  }\n}",{"_modelApiKey":367,"copy":465,"listStyle":369,"darkTheme":11,"buttons":466,"color":371,"indent":11},"\u003Cp>The steps above comprise the essentials you will need to work with an external payment gateway. Your external endpoint will be responsible for the actual integration with the payment gateway. Now, let’s proceed to build that!\u003C\u002Fp>\n\n\u003Ch4>Getting Started with Twitter API\u003C\u002Fh4>\n\n\u003Cp>Twitter’s API allows you to interact with data on the Twitter platform. Working with the Twitter API is quite exciting; you can read their \u003Ca href=\"https:\u002F\u002Fdeveloper.twitter.com\u002Fen\u002Fdocs\u002Ftwitter-api\u002Fgetting-started\u002Fgetting-access-to-the-twitter-api\" target=\"_blank\" rel=\"noopener noreferrer\">documentation\u003C\u002Fa> or follow the quick steps below to get started:\u003C\u002Fp>\n\n\u003Col>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fdeveloper.twitter.com\u002Fen\u002Fportal\u002Fpetition\u002Fessential\u002Fbasic-info\" target=\"_blank\" rel=\"noopener noreferrer\">Sign up\u003C\u002Fa> for a Twitter developer account.\u003C\u002Fli>\n\u003Cli>Create a new project:\n\n\u003Cul>\n\u003Cli>Enter project name (e.g., CL Twitter Payment Gateway)\u003C\u002Fli>\n\u003Cli>Select a use case (e.g., Building tools for businesses)\u003C\u002Fli>\n\u003Cli>Enter a project description\u003C\u002Fli>\n\u003C\u002Ful>\u003C\u002Fli>\n\u003Cli>Create a new application:\n\n\u003Cul>\n\u003Cli>Select “development”\u003C\u002Fli>\n\u003Cli>Enter the development app name (e.g., Pay With Tweet)\u003C\u002Fli>\n\u003C\u002Ful>\u003C\u002Fli>\n\u003Cli>Copy your keys and access tokens:\n\n\u003Cul>\n\u003Cli>API Key and Secret\u003C\u002Fli>\n\u003Cli>Bearer Token\u003C\u002Fli>\n\u003Cli>Access Token and Secret\u003C\u002Fli>\n\u003C\u002Ful>\u003C\u002Fli>\n\u003Cli>You can use the app settings to update any detail you wish.\u003C\u002Fli>\n\u003C\u002Fol>\n",[],{"_modelApiKey":384,"border":7,"caption":280,"image":468,"size":392,"darkTheme":11,"rounded":7,"color":371},{"url":469,"alt":470,"title":470,"width":471,"height":472,"format":473,"focalPoint":474,"customData":475},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1660162526-twitter-dev-dashboard-edited.png","Twitter developer dashboard",1437,768,"png",{"x":292,"y":292},{},{"_modelApiKey":367,"copy":477,"listStyle":369,"darkTheme":11,"buttons":478,"color":371,"indent":11},"\u003Ch4>Building the gateway with Twitter SDK, Nodejs, Express, and Ngrok\u003C\u002Fh4>\n\n\u003Cp>We will build a custom \u003Ccode>\u002Fauthorize\u003C\u002Fcode> endpoint responsible for receiving the payload from Commerce Layer once an order is placed, processing the order, and authorizing the transaction. We’ll use TypeScript, Nodejs, and Express to build the server and then utilize Ngrok to tunnel our local server on the internet. Let’s get right into it!\u003C\u002Fp>\n\n\u003Ch5>\u003Cstrong>1. Install the Twitter API \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Ftwitterdev\u002Ftwitter-api-typescript-sdk\" target=\"_blank\" rel=\"noopener noreferrer\">Typescript SDK\u003C\u002Fa> with the command below:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":480,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"npm install twitter-api-sdk",{"_modelApiKey":367,"copy":482,"listStyle":369,"darkTheme":11,"buttons":483,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>2. Install \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FTypeScript\u002Fblob\u002Fmain\u002Fbin\u002Ftsc\" target=\"_blank\" rel=\"noopener noreferrer\">tsc\u003C\u002Fa> and \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fgilamran\u002Ftsc-watch\" target=\"_blank\" rel=\"noopener noreferrer\">tsc-watch\u003C\u002Fa> for compiling Typescript to JavaScript if you haven’t yet with the command below:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":485,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"npm install tsc\n\nnpm install tsc-watch",{"_modelApiKey":367,"copy":487,"listStyle":369,"darkTheme":11,"buttons":488,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>3. \u003Ca href=\"https:\u002F\u002Fdocs.npmjs.com\u002Fdownloading-and-installing-node-js-and-npm\" target=\"_blank\" rel=\"noopener noreferrer\">Install Node.js\u003C\u002Fa> if you don’t have it yet.\u003C\u002Fstrong>\u003C\u002Fh5>\n\n\u003Ch5>\u003Cstrong>4. Install Express if you don’t have it yet with the command below:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":490,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"\u002F\u002Fnpm\nnpm install express --save\n\n\u002F\u002Fyarn\nyarn add express",{"_modelApiKey":367,"copy":492,"listStyle":369,"darkTheme":11,"buttons":493,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>5. Install ngrok using the commands below or \u003Ca href=\"https:\u002F\u002Fngrok.com\u002Fdownload\" target=\"_blank\" rel=\"noopener noreferrer\">download it\u003C\u002Fa> for any operating system:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":495,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"\u002F\u002Fmac\nbrew install ngrok\n\n\u002F\u002Flinux\nsnap install ngrok\n\n\u002F\u002Fwindows\nchoco install ngrok",{"_modelApiKey":367,"copy":497,"listStyle":369,"darkTheme":11,"buttons":498,"color":371,"indent":11},"\u003Ch6>\u003Cstrong>6. \u003Ca href=\"https:\u002F\u002Fdashboard.ngrok.com\" target=\"_blank\" rel=\"noopener noreferrer\">Create a new ngrok account\u003C\u002Fa> if you don’t have one yet.\u003C\u002Fstrong>\u003C\u002Fh6>\n\n\u003Ch5>\u003Cstrong>7. Create a new API key and copy the generated token.\u003C\u002Fstrong>\u003C\u002Fh5>\n\n\u003Ch5>\u003Cstrong>8. Configure ngrok with the auth token using the command below:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":500,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"ngrok config add-authtoken 12wLGWJHEFWLTGUKPsYphK3g2FGKk4s_3gyhbDFJHs5JzJ",{"_modelApiKey":367,"copy":502,"listStyle":369,"darkTheme":11,"buttons":503,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>9. Install \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fbrix\u002Fcrypto-js\" target=\"_blank\" rel=\"noopener noreferrer\">CryptoJS\u003C\u002Fa> (we will use this to \u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fdevelopers\u002Fcallbacks-security\" target=\"_blank\" rel=\"noopener noreferrer\">verify the callback authenticity\u003C\u002Fa> from Commerce Layer):\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":505,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"npm install crypto-js",{"_modelApiKey":367,"copy":507,"listStyle":369,"darkTheme":11,"buttons":508,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>10. Create a tsconfig.json file and add the following code:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":510,"showLineNumbers":11,"highlightLines":280,"language":433,"size":410},"{\n  \"compilerOptions\": {\n    \"target\": \"ES2015\",\n    \"module\": \"commonjs\",\n    \"strict\": true,\n    \"moduleResolution\": \"node\",\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"outDir\": \"public\",\n    \"typeRoots\" : [\"typings\", \".\u002Fnode_modules\u002F@types\"]\n  },\n  \"include\": [\n    \"api\u002F*\",\n    \"typings\u002F*\"\n  ]\n}",{"_modelApiKey":367,"copy":512,"listStyle":369,"darkTheme":11,"buttons":513,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>11. Create a \u003Ccode>typings\u002Fexpress\u002Findex.d.ts\u003C\u002Fcode> file and add the following code:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":515,"showLineNumbers":11,"highlightLines":280,"language":516,"size":410},"declare module \"http\" {\n  interface IncomingMessage {\n      rawBody: any;\n  }\n}","typescript",{"_modelApiKey":367,"copy":518,"listStyle":369,"darkTheme":11,"buttons":519,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>12. Create a \u003Ccode>.env\u003C\u002Fcode> file and add the following credentials:\u003C\u002Fstrong>\u003C\u002Fh5>\n\n\u003Cul>\n\u003Cli>The shared secret generated when you created the external payment gateway earlier (you can find this on the Commerce Layer dashboard).\u003C\u002Fli>\n\u003Cli>The ID of the Twitter account you want to fetch tweets from (you can find the ID of your Twitter account using \u003Ca href=\"https:\u002F\u002Ftweeterid.com\" target=\"_blank\" rel=\"noopener noreferrer\">this platform\u003C\u002Fa>).\u003C\u002Fli>\n\u003Cli>The bearer token associated with the Twitter app you created earlier.\u003C\u002Fli>\n\u003C\u002Ful>\n",[],{"_modelApiKey":407,"code":521,"showLineNumbers":11,"highlightLines":280,"language":522,"size":410},"CL_SHARED_SECRET=\"\"\nCL_TWITTER_ID=\"\"\nTW_BEARER_TOKEN=\"\"","markup",{"_modelApiKey":367,"copy":524,"listStyle":369,"darkTheme":11,"buttons":525,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>13. Create an \u003Ccode>\u002Fapi\u003C\u002Fcode> directory, create a \u003Ccode>getTweets.ts\u003C\u002Fcode> file inside the directory, and add the following code to fetch 5 tweets (including the user’s data) that mentions the specified Twitter account within a defined time range:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":527,"showLineNumbers":7,"highlightLines":280,"language":528,"size":529},"require(\"dotenv\").config();\nimport { Client } from \"twitter-api-sdk\";\n\nconst client = new Client(process.env.TW_BEARER_TOKEN as string);\nconst clTwitterId = process.env.CL_TWITTER_ID as string;\n\n\u002F\u002F Get tweets and users that mentions the clTwitterId\nasync function getTweets(startTime: string, endTime: string) {\n  const mentions = await client.tweets.usersIdMentions(clTwitterId, {\n    start_time: startTime,\n    end_time: endTime,\n    max_results: 5,\n    \"tweet.fields\": [\"author_id\", \"id\", \"created_at\", \"text\"],\n    expansions: [\"author_id\"],\n    \"user.fields\": [\"id\", \"username\", \"name\"]\n  });\n\n  const tweets = mentions.data || [];\n  const users = mentions.includes?.users || [];\n  return {tweets, users};\n}\n\nexport default getTweets;","javascript","Wide",{"_modelApiKey":367,"copy":531,"listStyle":369,"darkTheme":11,"buttons":532,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>14. Create an \u003Ccode>app.ts\u003C\u002Fcode> file in the \u003Ccode>\u002Fapi\u003C\u002Fcode> directory, and add the following code to create an \u003Ccode>\u002Fauthorize\u003C\u002Fcode> endpoint that will process the transaction:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":534,"showLineNumbers":7,"highlightLines":280,"language":516,"size":529},"require(\"dotenv\").config();\nimport express, { Request, Response } from \"express\";\nimport getTweets from \".\u002FgetTweets\";\n\nconst CryptoJS = require(\"crypto-js\");\nconst hmacSHA256 = require(\"crypto-js\u002Fhmac-sha256\");\nconst app = require(\"express\")();\nconst port = process.env.PORT || 9000;\n\ninterface tweetUsers {\n  id: string | undefined;\n  username: string | undefined;\n  name: string | undefined;\n  email: string;\n  tweet: string;\n  created_at: string | undefined;\n}\n\n\u002F\u002F Use the JSON middleware and verify handler to attach a rawBody attribute to the req object.\napp.use(\n  express.json({\n    limit: \"5mb\",\n    verify: (req, res, buf) => {\n      req.rawBody = buf.toString();\n    }\n  })\n);\n\napp.post(\"\u002Fauthorize\", (req: Request, res: Response) => {\n  \u002F\u002F Verify the payload coming from Commerce Layer.\n  const signature = req.headers[\"x-commercelayer-signature\"];\n  const hash = hmacSHA256(req.rawBody, process.env.CL_SHARED_SECRET);\n  const encode = hash.toString(CryptoJS.enc.Base64);\n\n  if (req.method === \"POST\" && signature === encode) {\n    const payload = JSON.parse(req.rawBody);\n\n    \u002F\u002F Get the included orders data from the payload.\n    payload.included.slice(0, 1).map((order: any) => {\n      const startTime = order.attributes.updated_at;\n      const endTime = new Date(\n        new Date(startTime).getTime() + 1800000\n      ).toISOString();\n      const orderNumber = order.attributes.number;\n      const customerEmail = order.attributes.customer_email;\n      const amountCents = order.attributes.subtotal_taxable_amount_cents;\n      const transactionToken = order.attributes.token;\n\n      \u002F\u002F Fetch tweets created between startTime and endTime.\n      getTweets(startTime, endTime).then((data) => {\n        \u002F\u002F If tweet(s) found, process the transaction.\n        if (data.tweets.length !== 0) {\n          const tweets = data.tweets;\n          const users = data.users;\n          let customerData: tweetUsers;\n\n          tweets.map((tweet) => {\n            \u002F\u002F Find the tweet created by the customer.\n            if (tweet.text.includes(orderNumber)) {\n              customerData = {\n                id: tweet.author_id,\n                username: users.find((u) => u.id === tweet.author_id)?.username,\n                name: users.find((u) => u.id === tweet.author_id)?.name,\n                email: customerEmail,\n                tweet: tweet.text,\n                created_at: tweet.created_at\n              };\n              \u002F\u002F If successful, authorize the transaction.\n              res.status(200).json({\n                success: true,\n                data: {\n                  transaction_token: transactionToken,\n                  amount_cents: amountCents,\n                  metadata: {\n                    ...customerData\n                  }\n                }\n              });\n            } else {\n              \u002F\u002F If unsuccessful, return an error, and fail the transaction.\n              res.status(422).json({\n                success: false,\n                data: {\n                  transaction_token: transactionToken,\n                  amount_cents: amountCents,\n                  error: {\n                    code: \"404\",\n                    message: `Order number: ${orderNumber} not found in tweets`\n                  }\n                }\n              });\n            }\n          });\n        } else {\n          \u002F\u002F If tweet(s) not found, return an error, and fail the transaction.\n          res.status(422).json({\n            success: false,\n            data: {\n              transaction_token: transactionToken,\n              amount_cents: amountCents,\n              error: {\n                code: \"404\",\n                message: `Tweet with order number: ${orderNumber} not found.`\n              }\n            }\n          });\n        }\n      });\n    });\n  } else {\n    \u002F\u002F If signature does not match the shared secret, return an error.\n    res.status(401).json({\n      error: \"Unauthorized: Invalid signature\"\n    });\n  }\n});\n\napp.listen(port, () => {\n  console.log(`Listening at http:\u002F\u002Flocalhost:${port}`);\n});",{"_modelApiKey":367,"copy":536,"listStyle":369,"darkTheme":11,"buttons":537,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>15. Build and start the local Node.js server to begin listening on port 9000 like so:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":539,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"npx tsc && node public\u002Fapp.js",{"_modelApiKey":367,"copy":541,"listStyle":369,"darkTheme":11,"buttons":542,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>16. Start an HTTP tunnel listening for HTTP\u002FHTTPS traffic on port 9000:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":544,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"ngrok http 9000",{"_modelApiKey":384,"border":11,"caption":280,"image":546,"size":392,"darkTheme":11,"rounded":11,"color":371},{"url":547,"alt":548,"title":548,"width":549,"height":550,"format":473,"focalPoint":551,"customData":552},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1660309682-ngrok-terminal.png","Running ngrok tunnel",2000,1048,{"x":292,"y":292},{},{"_modelApiKey":367,"copy":554,"listStyle":369,"darkTheme":11,"buttons":555,"color":371,"indent":11},"\u003Cp>Now we can use \u003Ccode>https:\u002F\u002Fc54e-197-210-70-223.eu.ngrok.io\u002Fauthorize\u003C\u002Fcode> as our \u003Ccode>authorize_url\u003C\u002Fcode> to receive the payload from Commerce Layer and process the transaction (PS: that the URL will be different when you do this yourself, and it will change every time you restart the ngrok tunnel). You can consider deploying the Nodejs application online for a permanent URL. You should update the previously created external payment gateway with the \u003Ccode>authorize_url\u003C\u002Fcode>.\u003C\u002Fp>\n",[],{"_modelApiKey":407,"code":557,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl update external_gateways\u002FPkXRMsBBGv -a authorize_url=\"https:\u002F\u002Fc54e-197-210-70-223.eu.ngrok.io\u002Fauthorize\"",{"_modelApiKey":367,"copy":559,"listStyle":369,"darkTheme":11,"buttons":560,"color":371,"indent":11},"\u003Chr>\n",[],{"_modelApiKey":373,"title":562,"preTitle":563,"linkText":564,"darkTheme":11,"link":565},"Pay With Tweet","Code demo","View on GitHub",{"_modelApiKey":203,"text":566,"label":280,"subtitle":280,"icon":280,"isExternal":7,"url":567,"link":303,"anchor":280,"openForm":11,"form":303,"htmlClassNames":280},"Pay with tweet code demo","https:\u002F\u002Fgithub.com\u002FBolajiAyodeji\u002Fpay-with-tweet",{"_modelApiKey":367,"copy":569,"listStyle":369,"darkTheme":11,"buttons":570,"color":371,"indent":11},"\u003Chr>\n\n\u003Ch4>Testing the Pay With Tweet external payment gateway\u003C\u002Fh4>\n\n\u003Cp>Now let’s test the custom payment gateway by placing an order. This section will highlight the core fundamentals and lifecycle of orders in the Commerce Layer. Ideally, this flow will be used by your customer on a sales channel or any other choice of customer experience. For example, you might build your ecommerce web store and consider using our \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fcommercelayer\u002Fmfe-checkout\" target=\"_blank\" rel=\"noopener noreferrer\">hosted checkout\u003C\u002Fa> as a boilerplate to build a checkout experience for your external payment gateway. With Commerce Layer, you can do pretty much anything you want by composing multiple tools together. But for the sake of this tutorial, we will use the CLI to complete an order purchase. By doing this, you will learn all the requirements for placing orders and can use the same flow when working with our API directly.\u003C\u002Fp>\n\n\u003Ch5>\u003Cstrong>1. Log into your application via the CLI using the previously created integration application credentials like so:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":572,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl applications:login -o \u003CorganizationSlug> -i \u003CclientId> -s \u003CclientSecret> -a \u003CapplicationAlias>",{"_modelApiKey":367,"copy":574,"listStyle":369,"darkTheme":11,"buttons":575,"color":371,"indent":11},"\u003Cp>The application alias can be named anything. It will be associated with the application you want to log into on your terminal (this is useful when switching between multiple applications).\u003C\u002Fp>\n\n\u003Ch5>\u003Cstrong>2. List all SKUS and copy the ID of any one using the command below:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":577,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl get skus",{"_modelApiKey":367,"copy":579,"listStyle":369,"darkTheme":11,"buttons":580,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>3. List all markets and copy the ID of any one using the command below:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":582,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl get markets",{"_modelApiKey":367,"copy":584,"listStyle":369,"darkTheme":11,"buttons":585,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>4. Create an order associated with a market ID and save the returned order ID\u002Fnumber using the command below:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":587,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl create orders -r market=markets\u002FYlqxGhKrQg",{"_modelApiKey":367,"copy":589,"listStyle":369,"darkTheme":11,"buttons":590,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>5. Create a line item associated with an SKU ID and order ID using the command below:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":592,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl create line_items -a \\\n\tquantity=1 -r \\\n\torder=orders\u002FNZrQhxDVXX -r \\\n\titem=skus\u002FZwpOSrMAzP",{"_modelApiKey":367,"copy":594,"listStyle":369,"darkTheme":11,"buttons":595,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>6. Update the order with a customer using the command below:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":597,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl update orders\u002FNZrQhxDVXX -a customer_email=bolaji@commercelayer.io",{"_modelApiKey":367,"copy":599,"listStyle":369,"darkTheme":11,"buttons":600,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>7. Create an address using the command below:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":602,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl create addresses -a \\\n\tfirst_name=\"Bolaji\" \\\n\tlast_name=\"Ayodeji\" \\\n\tline_1=\"No 3, House B, Sample test street\" \\\n\tcity=\"San Francisco\" \\\n\tzip_code=94105 \\\n\tstate_code=\"CA\" \\\n\tcountry_code=\"US\" \\\n\tphone=1234567890",{"_modelApiKey":367,"copy":604,"listStyle":369,"darkTheme":11,"buttons":605,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>8. Update the order’s shipping and billing address with an address ID using the command below:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":607,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl update orders\u002FNZrQhxDVXX -r \\\n\tbilling_address=addresses\u002FBnNguAkzyX \\\n\tshipping_address=addresses\u002FBnNguAkzyX",{"_modelApiKey":367,"copy":609,"listStyle":369,"darkTheme":11,"buttons":610,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>9. Get the shipments (this is automatically created once an order is created) and available shipping methods (you should have created some for your market already) for the order using the command below:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":612,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl rget orders NZrQhxDVXX -i \\\n\tshipments,shipments.available_shipping_methods",{"_modelApiKey":367,"copy":614,"listStyle":369,"darkTheme":11,"buttons":615,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>10. Update the shipment with any shipping method of your choice using the command below:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":617,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl update shipments\u002FPVNXCkGlLx -r \\\n\tshipping_method=shipping_methods\u002FqVWbjFlAWN",{"_modelApiKey":367,"copy":619,"listStyle":369,"darkTheme":11,"buttons":620,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>11. Get available payment methods using the command below:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":622,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl get orders NZrQhxDVXX -i available_payment_methods",{"_modelApiKey":367,"copy":624,"listStyle":369,"darkTheme":11,"buttons":625,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>12. Update order with payment method using the command below:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":627,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl update orders\u002FNZrQhxDVXX -r \\\n\tpayment_method=payment_methods\u002FwmBvQsAzBm",{"_modelApiKey":367,"copy":629,"listStyle":369,"darkTheme":11,"buttons":630,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>13. Create an external payment source and add it to the order using the command below. For an external payment gateway to work, the payment source associated with the order must be an \u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fdevelopers\u002Fv\u002Fapi-reference\u002Fexternal_payments\" target=\"_blank\" rel=\"noopener noreferrer\">external payment\u003C\u002Fa>.\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":632,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl create external_payment \\\n\t-a payment_source_token=\"testToken12345\" \\\n\t-r order=orders\u002FNZrQhxDVXX",{"_modelApiKey":367,"copy":634,"listStyle":369,"darkTheme":11,"buttons":635,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>14. Make a tweet mentioning \u003Ca href=\"https:\u002F\u002Ftwitter.com\u002Fcommercelayer\" target=\"_blank\" rel=\"noopener noreferrer\">@commercelayer\u003C\u002Fa> and include the order number like so:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":637,"showLineNumbers":11,"highlightLines":280,"language":522,"size":410},"Thanks @commercelayer for the free BACKPACKFFFFFF000000XXXX swag (order number: 25114555).\n\n#commercelayer #composablecommerce",{"_modelApiKey":367,"copy":639,"listStyle":369,"darkTheme":11,"buttons":640,"color":371,"indent":11},"\u003Ch5>\u003Cstrong>15. Place the order using the command below:\u003C\u002Fstrong>\u003C\u002Fh5>\n",[],{"_modelApiKey":407,"code":642,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl update orders\u002FNZrQhxDVXX -a _place=true",{"_modelApiKey":367,"copy":644,"listStyle":369,"darkTheme":11,"buttons":645,"color":371,"indent":11},"\u003Cp>If no tweet is found between the timestamp the order was last updated and 30 minutes or no tweet found contains the order number, the CLI will return this error:\u003C\u002Fp>\n",[],{"_modelApiKey":407,"code":647,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410}," ›   Error: [\n ›     {\n ›       title: 'Unprocessable Entity',\n ›       detail: 'Unprocessable Entity',\n ›       code: 'VALIDATION_ERROR',\n ›       source: { pointer: '\u002Fdata' },\n ›       status: '422',\n ›       meta: { error: 'Unprocessable Entity' }\n ›     },\n ›     {\n ›       title: 'authorization failed',\n ›       detail: 'authorization failed',\n ›       code: 'VALIDATION_ERROR',\n ›       source: { pointer: '\u002Fdata' },\n ›       status: '422',\n ›       meta: { error: 'authorization_failed' }\n ›     },\n ›     {\n ›       title: 'transition is not permitted',\n ›       detail: 'status - transition is not permitted',\n ›       code: 'VALIDATION_ERROR',\n ›       source: { pointer: '\u002Fdata\u002Fattributes\u002Fstatus' },\n ›       status: '422',\n ›       meta: { error: 'not_permitted_transition' }\n ›     }\n ›   ]",{"_modelApiKey":367,"copy":649,"listStyle":369,"darkTheme":11,"buttons":650,"color":371,"indent":11},"\u003Cp>And the endpoint will return these errors to Commerce Layer with the associated data.\u003C\u002Fp>\n",[],{"_modelApiKey":384,"border":11,"caption":280,"image":652,"size":392,"darkTheme":11,"rounded":11,"color":371},{"url":653,"alt":654,"title":654,"width":655,"height":656,"format":473,"focalPoint":657,"customData":658},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1660312923-pay-with-tweet-error1-edited.png","Pay with tweet gateway error message",1240,769,{"x":292,"y":292},{},{"_modelApiKey":384,"border":11,"caption":280,"image":660,"size":392,"darkTheme":11,"rounded":11,"color":371},{"url":661,"alt":654,"title":654,"width":662,"height":663,"format":473,"focalPoint":664,"customData":665},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1660312958-pay-with-tweet-error2-edited.png",1202,751,{"x":292,"y":292},{},{"_modelApiKey":367,"copy":667,"listStyle":369,"darkTheme":11,"buttons":668,"color":371,"indent":11},"\u003Cp>If the tweet is found that includes the order number, the CLI will update the order’s status to \u003Ccode>placed\u003C\u002Fcode> and payment_status to \u003Ccode>authorized\u003C\u002Fcode>.\u003C\u002Fp>\n",[],{"_modelApiKey":407,"code":670,"showLineNumbers":11,"highlightLines":280,"language":433,"size":410},"{\n  id: 'NZrQhxDVXX',\n  type: 'orders',\n  number: 25114555,\n  autorefresh: true,\n  status: 'placed',\n  payment_status: 'authorized',\n  fulfillment_status: 'unfulfilled',\n  guest: true,\n  editable: false,\n  customer_email: 'bolaji@commercelayer.io',\n  language_code: 'en',\n  currency_code: 'USD',\n  token: '2bb69b735f125eeab22fd34900c75689',\n\t...\n}",{"_modelApiKey":367,"copy":672,"listStyle":369,"darkTheme":11,"buttons":673,"color":371,"indent":11},"\u003Cp>And the endpoint will return a \u003Ccode>success=”true”\u003C\u002Fcode> response to Commerce Layer with the associated metadata.\u003C\u002Fp>\n",[],{"_modelApiKey":384,"border":11,"caption":280,"image":675,"size":392,"darkTheme":11,"rounded":11,"color":371},{"url":676,"alt":677,"title":677,"width":678,"height":679,"format":473,"focalPoint":680,"customData":681},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1660312466-pay-with-tweet-success.png","Pay with tweet gateway success message",1220,1004,{"x":292,"y":292},{},{"_modelApiKey":367,"copy":683,"listStyle":369,"darkTheme":11,"buttons":684,"color":371,"indent":11},"\u003Cp>You can confirm the order’s status via the dashboard or with the CLI using the command below and proceed to approve and fulfill the order. You might also want to \u003Ca href=\"https:\u002F\u002Fcommercelayer.io\u002Fblog\u002Fa-comprehensive-guide-to-commerce-layer-webhooks\" target=\"_blank\" rel=\"noopener noreferrer\">use our webhooks\u003C\u002Fa> to send an email to the customer further once the order is placed or send the customer’s details to your external fulfillment service. Remember, with Commerce Layer; your options are limitless :).\u003C\u002Fp>\n",[],{"_modelApiKey":407,"code":686,"showLineNumbers":11,"highlightLines":280,"language":409,"size":410},"cl get orders\u002FNZrQhxDVXX",{"_modelApiKey":367,"copy":688,"listStyle":369,"darkTheme":11,"buttons":689,"color":371,"indent":11},"\u003Ch3>Conclusion\u003C\u002Fh3>\n\n\u003Cp>We believe you now understand how \u003Cstrong>to add any payment gateway anywhere\u003C\u002Fstrong> with Commerce Layer. Once an order is placed successfully, \u003Ca href=\"https:\u002F\u002Fdocs.commercelayer.io\u002Fdevelopers\u002Fv\u002Fhow-tos\u002Fcheckout\u002Fplacing-the-order#additional-notes\" target=\"_blank\" rel=\"noopener noreferrer\">the following actions\u003C\u002Fa> are performed asynchronously. In summary, this is how the payment process of an order works in Commerce Layer for both credit card and external payment gateways when a customer makes a purchase of some SKUs in a market:\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>Create an order\u003C\u002Fli>\n\u003Cli>Assign the order to the customer\u003C\u002Fli>\n\u003Cli>Assign the order to a shipping address\u003C\u002Fli>\n\u003Cli>Assign the order to a billing address\u003C\u002Fli>\n\u003Cli>Assign the order’s shipment with a shipping method\u003C\u002Fli>\n\u003Cli>Assign the order with a payment method\u003C\u002Fli>\n\u003Cli>Assign the order with a payment source\u003C\u002Fli>\n\u003Cli>Add a coupon if required\u003C\u002Fli>\n\u003Cli>Place the order\u003C\u002Fli>\n\u003Cli>Authorize the transaction\u003C\u002Fli>\n\u003Cli>Void the transaction if required (the end)\u003C\u002Fli>\n\u003Cli>Capture the transaction\u003C\u002Fli>\n\u003Cli>The end\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Cp>Now feel free to bring all the ideas and customer demands you have to life. Your goal is to satisfy your customers, retain them, and increase your revenue. The good news is that Commerce Layer is here to help you do just this and more; cheers!\u003C\u002Fp>\n",[],{"displayTitle":691,"cta":303,"ctaText":280,"cards":692},"Your next read",[693,709,727,741],{"_modelApiKey":212,"link":694,"subtitle":696,"date":696,"author":697,"additionalAuthors":704,"icon":705,"abstract":706,"tag":707,"displayTitle":374,"cardRatio":300,"featured":708},{"text":374,"isExternal":11,"url":280,"link":695},{"_modelApiKey":212,"slug":379},"July 5, 2022",{"name":698,"picture":699},"Seth Bindernagel",{"url":700,"alt":701,"title":701,"width":289,"height":289,"format":290,"focalPoint":702,"customData":703},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1656680208-seth.jpg","Seth Bindernagel avatar",{"x":292,"y":292},{},[],"credit-card","Local payment gateways are a necessity as you scale internationally. In this article you'll earn why, and how Commerce Layer enables you to add any payment gateway anywhere, making it easy to expand your business into new markets.",{"color":298,"name":100},0,{"_modelApiKey":212,"link":710,"subtitle":714,"date":714,"author":715,"additionalAuthors":722,"icon":723,"abstract":724,"tag":725,"displayTitle":711,"cardRatio":11,"featured":726},{"text":711,"isExternal":11,"url":280,"link":712},"Introducing Microstores.",{"_modelApiKey":212,"slug":713},"introducing-microstores","August 11, 2022",{"name":716,"picture":717},"Daniel Oh",{"url":718,"alt":719,"title":719,"width":289,"height":289,"format":290,"focalPoint":720,"customData":721},"https:\u002F\u002Fwww.datocms-assets.com\u002F35053\u002F1658849633-daniel.jpg","Daniel Oh avatar",{"x":292,"y":292},{},[],"storefront","Please welcome microstores, self-contained stores that are configured and spun up instantly, with no development required, that can then be accessed via URL or QR code and used to immediately drive transactions from the first contact with a customer.",{"color":298,"name":8},1,{"_modelApiKey":212,"link":728,"subtitle":732,"date":732,"author":733,"additionalAuthors":737,"icon":738,"abstract":739,"tag":740,"displayTitle":729,"cardRatio":11,"featured":38},{"text":729,"isExternal":11,"url":280,"link":730},"How to send emails with Commerce Layer webhooks, Zapier, and SendGrid.",{"_modelApiKey":212,"slug":731},"how-to-send-emails-with-commerce-layer-webhooks-zapier-and-sendgrid","August 4, 2022",{"name":285,"picture":734},{"url":287,"alt":288,"title":288,"width":289,"height":289,"format":290,"focalPoint":735,"customData":736},{"x":292,"y":292},{},[],"paper-plane-tilt","You can use our webhooks technology to send order confirmation emails to your customers when they make a new purchase. At the end of this tutorial, you will understand how to use Zapier and SendGrid to send plain order confirmation emails.",{"color":298,"name":299},{"_modelApiKey":212,"link":742,"subtitle":746,"date":746,"author":747,"additionalAuthors":751,"icon":752,"abstract":753,"tag":754,"displayTitle":743,"cardRatio":11,"featured":755},{"text":743,"isExternal":11,"url":280,"link":744},"A comprehensive guide to Commerce Layer webhooks.",{"_modelApiKey":212,"slug":745},"a-comprehensive-guide-to-commerce-layer-webhooks","June 9, 2022",{"name":285,"picture":748},{"url":287,"alt":288,"title":288,"width":289,"height":289,"format":290,"focalPoint":749,"customData":750},{"x":292,"y":292},{},[],"webhooks-logo","We provides a list of specific events you can monitor and transmit real-time data from using webhooks. In this article, we will introduce our webhooks mechanism and guide you through a couple of simple demo examples so that you can see it in action.",{"color":298,"name":299},3,[757,758,760,762,764,766,768,770,772,774,776,778,780,782,784,786,788],{"attributes":303,"tag":304,"content":305},{"attributes":759,"tag":309,"content":303},{"property":308,"content":305},{"attributes":761,"tag":309,"content":303},{"name":312,"content":305},{"attributes":763,"tag":309,"content":303},{"name":315,"content":316},{"attributes":765,"tag":309,"content":303},{"property":319,"content":316},{"attributes":767,"tag":309,"content":303},{"name":322,"content":316},{"attributes":769,"tag":309,"content":303},{"property":325,"content":326},{"attributes":771,"tag":309,"content":303},{"property":329,"content":330},{"attributes":773,"tag":309,"content":303},{"property":333,"content":334},{"attributes":775,"tag":309,"content":303},{"name":337,"content":326},{"attributes":777,"tag":309,"content":303},{"property":340,"content":341},{"attributes":779,"tag":309,"content":303},{"property":344,"content":345},{"attributes":781,"tag":309,"content":303},{"property":348,"content":349},{"attributes":783,"tag":309,"content":303},{"property":352,"content":353},{"attributes":785,"tag":309,"content":303},{"property":356,"content":280},{"attributes":787,"tag":309,"content":303},{"name":359,"content":360},{"attributes":789,"tag":309,"content":303},{"name":363,"content":364},[791],{"name":285,"picture":792},{"url":287,"alt":288,"title":288,"width":289,"height":289,"format":290,"focalPoint":793,"customData":794},{"x":292,"y":292},{},1790593731073]