https://www.endpointdev.com/blog/tags/saas/2023-12-27T00:00:00+00:00End Point DevClient Profile: J.G. Title Companyhttps://www.endpointdev.com/blog/2023/12/client-profile-j-g-title-company/2023-12-27T00:00:00+00:00Juan Pablo Ventoso
<p><img src="/blog/2023/12/client-profile-j-g-title-company/j-g-title-company.webp" alt="The J.G. Title Company logo sits in the center of an image on a blue background with futuristic designs reminiscent of circuit boards. Text on either side of the logo reads “Nationwide titling”, with text under reading “info@jgtitleco.com” and “https://jgtitleco.com”"></p>
<p><a href="https://jgtitleco.com/">J.G. Title</a> is a prominent service company specializing in automotive dealership titling and registration processes across the country. They simplify operations for their dealers, businesses, and individuals by giving tax/fee quotes, document validation, and checklists for all jurisdictions.</p>
<p>Jordan Kivett, the owner of J.G. Title, envisioned an innovative web application to simplify dealership operations. He contacted us to request a quote for developing this solution and making his vision a reality. This project became a great opportunity for our <a href="/team/">.NET team</a> to build a robust system with state-of-the-art technologies functioning seamlessly together.</p>
<h3 id="the-solution">The solution</h3>
<p>J.G. Title submitted a detailed document containing a description of the requirements for the J.G. Title Suite app along with workflow diagrams explaining their current business processes. After analyzing all the documents and having some initial meetings, we decided to divide the project into different stages, and estimate each phase of work separately. We ended up with three phases:</p>
<ul>
<li>Phase I: Create a product that allows users to enter deals into the system and retrieve the quote estimation, including taxes, fees, and charges for services across 50 states.</li>
<li>Phase II: Implement several UI improvements such as a detailed dealership dashboard, financial management, and integration with <a href="https://quickbooks.intuit.com/">QuickBooks</a>.</li>
<li>Phase III: Add an ambitious PDF document management section featuring document recognition, analysis, and manipulation, to perform automatic validations on the document’s contents and automatically generate PDF outputs from the deal’s details.</li>
</ul>
<h3 id="tech-stack">Tech stack</h3>
<ul>
<li><a href="https://dotnet.microsoft.com/en-us/learn/dotnet/what-is-dotnet">.NET</a> 6 with <a href="https://learn.microsoft.com/en-us/dotnet/csharp/tour-of-csharp/">C#</a></li>
<li><a href="https://www.postgresql.org/">PostgreSQL</a> 14</li>
<li><a href="https://rockylinux.org/">Rocky Linux</a> 9 with <a href="https://www.nginx.com/">Nginx</a></li>
</ul>
<p>We had already worked with this combination of technologies for several clients, and we are confident in the combined power in a robust database such as Postgres along with .NET 6 running in a Linux environment. It has proven to be a stable, fast, and reliable setup for our web solutions.</p>
<p>We also used <a href="https://trello.com/">Trello</a> for tracking the project’s progress and tasks, <a href="https://github.com/">GitHub</a> for version control, and <a href="https://visualstudio.microsoft.com/vs/">Visual Studio 2022</a> or <a href="https://code.visualstudio.com/">VS Code</a> with <a href="https://learn.microsoft.com/en-us/dotnet/core/tools/">.NET CLI</a> as a coding environment. Some of us also used <a href="https://code.visualstudio.com/docs/devcontainers/tutorial">VS Code dev containers</a>. <a href="https://www.pgadmin.org/">pgAdmin</a> is our usual tool to manage the local Postgres database, as well as <a href="https://www.postman.com/">Postman</a> to test our API endpoints.</p>
<h3 id="the-team">The team</h3>
<p>Most of our .NET team is involved on this project. We also receive valuable help from our hosting team and our Postgres developers.</p>
<ul>
<li><a href="/team/bimal-gharti-magar/">Bimal Gharti Magar</a></li>
<li><a href="/team/dan-briones/">Dan Briones</a></li>
<li><a href="/team/dylan-wooters/">Dylan Wooters</a></li>
<li><a href="/team/juan-pablo-ventoso/">Juan Pablo Ventoso</a></li>
<li><a href="/team/kevin-campusano/">Kevin Campusano</a></li>
<li><a href="/team/mike-delange/">Mike DeLange</a></li>
</ul>
<p>The client is also highly involved in all aspects of the development process, from requirements gathering to documenting, testing, and providing feedback. We have bi-weekly standup calls, and the entire team (End Point + J.G. Title) interacts actively through Trello, working together and updating each task as the work progresses.</p>
<h3 id="results">Results</h3>
<p>We began working on the project on October 25, 2022, and completed Phase I within the expected timeline, on June 7, 2023. The next phases were launched iteratively, with new deployments usually scheduled twice a week.</p>
<p>The application is now widely used by dealerships and the J.G. Title team. They have over 200 users registered in the system, with more than 8,000 deals quoted, and new deals being added at an increasing rate.</p>
<p><img src="/blog/2023/12/client-profile-j-g-title-company/j-g-title-suite-featured.webp" alt="On the right side is an image of a laptop and phone, each running the J.G. Title Suite application. Text on the left reads “From chaos to clarity. Simplify, streamline, succeed: Embrace clarity in your dealership’s tax and title operations. Our dedicated team of specialists conducted extensive research and established partnerships with local DMVs and state Treasurers to become the trusted partner for automotive dealerships and businesses nationwide, offering efficient and reliable title and registration services. We continue transforming automotive title management on a national scale and welcome you to experience the future of automotive titling.""><br>
The J.G. Title Suite application, featured on the company’s website.</p>
<p>We are continuing work on several tasks related to Phase III of the project. As the application keeps growing and users send feedback, new phases of work will surely be added to the project in the future.</p>
<p>This partnership is a testament to our shared vision for efficiency and innovation, and we’re excited to continue reshaping the industry with J.G. Title Company!</p>
Integrating Contentful with NuxtJShttps://www.endpointdev.com/blog/2022/10/integrating-contentful-with-nuxt/2022-10-07T00:00:00+00:00Juan Pablo Ventoso
<p><img src="/blog/2022/10/integrating-contentful-with-nuxt/fishing-rio-de-la-plata-sunset.webp" alt="An orange sunset reflecting off of the sea at Rio de la Plata. A city skyline is silhouetted by the sunset."></p>
<!-- Photo by Juan Pablo Ventoso -->
<p>Some time ago, I had the opportunity to collaborate on a cool <a href="https://nuxtjs.org/">NuxtJS</a> project. I’m still somewhat new to <a href="https://vuejs.org/">Vue.js</a> and its related frameworks, meaning I’m discovering exciting new tools and third-party services that can be integrated with them every time a new requirement appears. And there is a particular concept that I heard of, but never worked with until this project: using a <a href="https://en.wikipedia.org/wiki/Headless_content_management_system">Headless CMS</a> to deliver content.</p>
<p>Essentially, a headless CMS permits creating a custom content model, making it accessible through one (or several) APIs that we can query, allowing us to choose whatever presentation layer we prefer to handle the display. This approach decouples the content management part (the “body”) of a project from the design, templates, and frontend logic (the “head”), becoming particularly useful when we have several application types that will interact with the same data, such as a website, a mobile app, or an IoT device.</p>
<p>With that in mind, let’s have a quick look at <a href="https://www.contentful.com/">Contentful</a>: It’s a headless CMS that is offered under the concept of content-as-a-service (<a href="https://www.contentful.com/r/knowledgebase/content-as-a-service/">CaaS</a>), meaning the content is delivered on demand from a cloud platform to the consumer by implementing an API or web service.</p>
<h3 id="pricing">Pricing</h3>
<p>For individual or small websites, the free option should be sufficient. It has a limit of 5 users and a size limit of 50MB for assets, and the technical support area is disabled. The next option (Medium, $489/month) also includes an additional role (author), additional locales, and the possibility to create up to ten different user accounts. The asset size is also extended up to 1000MB.</p>
<p><img src="/blog/2022/10/integrating-contentful-with-nuxt/contentful-pricing.webp" alt="Contentful pricing: Community tier is free, Team tier is $489/month, Enterprise is custom pricing."></p>
<p>You can review the full pricing details <a href="https://www.contentful.com/pricing/">on Contentful’s website</a>.</p>
<h3 id="creating-content">Creating content</h3>
<p>In order to start creating content, there are two essential steps:</p>
<ul>
<li>
<p>We will need to <a href="https://www.contentful.com/help/contentful-101/#step-2-create-a-space">set up a new space</a>. A space is an area where the content will be grouped into a single project.</p>
</li>
<li>
<p>We need to define the <a href="https://www.contentful.com/help/contentful-101/#step-3-create-the-content-model">model for our content</a>. The model is the type and structure that our content will have. For the integration below, we will need a new “Page” model, that will contain two fields to save the information that we need for a static page: <code>title</code> and <code>content</code>. We can also include a <code>publishDate</code> field, just to know when each page was created.</p>
</li>
</ul>
<p><img src="/blog/2022/10/integrating-contentful-with-nuxt/page-content-model.webp" alt="Page content model. A GUI shows 3 fields: Title, a short text field; Content, a rich text field; and Publish date, a Date & time field."></p>
<h3 id="integration">Integration</h3>
<p>With our space created and our content model ready, it’s time to add Contentful to our NuxtJS app. The integration process is quite simple, thanks to the <a href="https://www.npmjs.com/package/contentful">JavaScript client library</a> provided by Contentful. The library is based on the <a href="https://github.com/axios/axios">axios</a> client, allowing it to run on the client as well as on the server, for <a href="https://nuxtjs.org/docs/concepts/server-side-rendering/">SSR</a>. If we have <a href="https://www.npmjs.com/">npm</a> set up, we can add it to our project by running:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">npm install --save contentful
</code></pre></div><p>The most efficient way to use it across our app and have it ready for client and server-side rendering is to declare a new plugin. All we need to do is create a new file named <code>contentful.js</code> under our project’s <code>plugins</code> folder:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js"><span style="color:#080;font-weight:bold">const</span> contentful = require(<span style="color:#d20;background-color:#fff0f0">'contentful'</span>)
<span style="color:#080;font-weight:bold">const</span> config = {
space: process.env.CONTENTFUL_SPACE_ID,
accessToken: process.env.CONTENTFUL_API_ACCESS_TOKEN,
}
module.exports = {
createClient() {
<span style="color:#080;font-weight:bold">return</span> contentful.createClient(config)
},
}
</code></pre></div><p>Next, we need to add the new environment variables to our project’s <code>.env</code> file. The values that we need to provide are our <a href="https://www.contentful.com/help/find-space-id/">space ID</a> and the <a href="https://www.contentful.com/developers/docs/references/authentication/">access token</a> for querying the API:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-plain" data-lang="plain">CONTENTFUL_SPACE_ID={our_space_id}
CONTENTFUL_API_ACCESS_TOKEN={our_access_token}
</code></pre></div><p>We’re all set! Now, we have our plugin ready to use. One neat extra step that we did for this particular project is creating a <code>ContentfulPage</code> component that will automatically pull the contents from Contentful based on the given entry ID. By doing that, we can simply use the component in all the static pages that we have on our website.</p>
<p>First, let’s create the component, containing a simple wrapper for the template section, and an <code>entryId</code> property that we will use to query the API. We can save it under <code>~/components/ContentfulPage.vue</code>:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html"><<span style="color:#b06;font-weight:bold">template</span>>
<<span style="color:#b06;font-weight:bold">div</span> <span style="color:#369">:id</span>=<span style="color:#d20;background-color:#fff0f0">"entryId"</span>>
<<span style="color:#b06;font-weight:bold">p</span> <span style="color:#369">v-if</span>=<span style="color:#d20;background-color:#fff0f0">"$fetchState.pending"</span>>Loading...</<span style="color:#b06;font-weight:bold">p</span>>
<<span style="color:#b06;font-weight:bold">div</span> <span style="color:#369">v-else</span>>
<<span style="color:#b06;font-weight:bold">h1</span>>
{{ page.fields.title }}
</<span style="color:#b06;font-weight:bold">h1</span>>
<<span style="color:#b06;font-weight:bold">div</span> <span style="color:#369">class</span>=<span style="color:#d20;background-color:#fff0f0">"page-content"</span> <span style="color:#369">v-html</span>=<span style="color:#d20;background-color:#fff0f0">"$md.render(page.fields.content)"</span> />
</<span style="color:#b06;font-weight:bold">div</span>>
</<span style="color:#b06;font-weight:bold">div</span>>
</<span style="color:#b06;font-weight:bold">template</span>>
<<span style="color:#b06;font-weight:bold">script</span>>
<span style="color:#080;font-weight:bold">import</span> { createClient } from <span style="color:#d20;background-color:#fff0f0">'~/plugins/contentful'</span>
<span style="color:#080;font-weight:bold">const</span> contentful = createClient()
<span style="color:#080;font-weight:bold">export</span> <span style="color:#080;font-weight:bold">default</span> {
name: <span style="color:#d20;background-color:#fff0f0">'ContentfulPage'</span>,
props: {
entryId: {
type: <span style="color:#038">String</span>,
required: <span style="color:#080;font-weight:bold">true</span>,
},
},
data() {
<span style="color:#080;font-weight:bold">return</span> {
page: {},
}
},
<span style="color:#080;font-weight:bold">async</span> fetch() {
<span style="color:#080;font-weight:bold">this</span>.page = <span style="color:#080;font-weight:bold">await</span> contentful.getEntry(<span style="color:#080;font-weight:bold">this</span>.entryId)
},
}
</<span style="color:#b06;font-weight:bold">script</span>>
</code></pre></div><p>This component will asynchronously fetch the entry from Contentful, and display a “loading” legend while it does so. Once the query is complete, the content will be shown inside the <code>div</code> element with the <code>page-content</code> class. The component expects the returned page to have at least two attributes: <code>title</code> and <code>content</code>.</p>
<p>With the new component added to our project, we are ready to create a page (for example, <code>index.vue</code>) that uses it to render our content like this:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html"><<span style="color:#b06;font-weight:bold">template</span>>
<<span style="color:#b06;font-weight:bold">div</span>>
<<span style="color:#b06;font-weight:bold">contentful-page</span> <span style="color:#369">entry-id</span>=<span style="color:#d20;background-color:#fff0f0">"{index_entry_id}"</span> />
</<span style="color:#b06;font-weight:bold">div</span>>
</<span style="color:#b06;font-weight:bold">template</span>>
<<span style="color:#b06;font-weight:bold">script</span>>
<span style="color:#080;font-weight:bold">import</span> ContentfulPage from <span style="color:#d20;background-color:#fff0f0">'~/components/ContentfulPage'</span>
<span style="color:#080;font-weight:bold">export</span> <span style="color:#080;font-weight:bold">default</span> {
components: {
ContentfulPage,
},
}
</<span style="color:#b06;font-weight:bold">script</span>>
</code></pre></div><p>All we need to do is get the entry ID from the content we created in Contentful, pass it to the <code>entry-id</code> parameter of the component, and that’s it! Our content will be fetched from the API and displayed to the user. It will also work when rendering on the client, as well as for SSR.</p>
<h3 id="other-content-types">Other content types</h3>
<p>Of course, we’re not restricted to using this service to deliver static pages: We can store and deliver blog posts, listings, events, geolocation information, documents, and more. We have several field types that could be used for our content model, including location, media (images, videos), links, or JSON, among others. See the <a href="https://www.contentful.com/developers/docs/concepts/data-model/">data model section</a> of their official documentation for reference.</p>
<p><img src="/blog/2022/10/integrating-contentful-with-nuxt/add-new-field-types.webp" alt="A GUI selection screen reading “Add new field” shows 9 field types: Rich text, Text, Number, Date and Time, Location, Media, Boolean, JSON object, and Reference."></p>
<h3 id="alternatives">Alternatives</h3>
<p>There are several alternatives to Contentful out there: <a href="https://prismic.io/">Prismic CMS</a> or <a href="https://graphcms.com/">GraphCMS</a> — which is based entirely in GraphQL — are the most popular. There are also downloadable products, like <a href="https://www.silverstripe.org/">SilverStrap CMS</a>. Their pricing plans are varied, but all of them offer a free community plan for starters or small websites.</p>
<p>Have you used any other headless CMS not listed here? We would love to hear your comments!</p>
Backing up your SaaS data with Google Takeouthttps://www.endpointdev.com/blog/2022/05/backing-up-your-saas-data-with-google-takeout/2022-05-31T00:00:00+00:00Seth Jensen
<p><img src="/blog/2022/05/backing-up-your-saas-data-with-google-takeout/banner.webp" alt="A concrete building with rectangular windows at sunset"></p>
<!-- Photo by Seth Jensen -->
<p>Keeping backups is extremely important.</p>
<p>Losing important files can feel like a far-off problem, but the chance of misplacing a drive, theft, drive failure, accidental deletion, house fire, flood, etc., is much greater than we may think. The benefits outweigh the cost of backups, for files that matter at all. So everyone should make regular backups of data that they care about and that can’t be replaced.</p>
<p>Even among people who regularly make backups, there is one area many of us neglect: all of that data on various online services, also called software as a service or SaaS: Google Drive, Apple iCloud, Microsoft OneDrive, Dropbox, Box, etc.</p>
<p>It’s true, the most volatile files are the ones sitting in a single location on your laptop or thumb drive, not those on Google, WordPress, or iCloud servers. The danger of losing files is not nearly as present with SaaS. You can’t drop Google on the floor and lose a couple terabytes of data, like you can a hard drive, but you can be locked out of your account, accidentally delete files, and lose data by missing a notice about a service shutting down. Not to mention the possibility that your SaaS provider is hacked and loses your data.</p>
<p>I recently realized I had about five years of photos, nine years of Google Drive “stuff,” and who knows what else, not backed up from my Google account. I decided to download it all with Google Takeout, the service Google provides for making account backups.</p>
<h3 id="google-takeout">Google Takeout</h3>
<p>Google introduced Takeout in 2011 as a service to export and download your data stored in Google products. It seems like the perfect option to easily back up all your files from Google’s servers. But how is the process, and how useful is the actual downloaded data?</p>
<p><a href="https://support.google.com/accounts/answer/3024190?hl=en">Downloading from Takeout</a> is quite painless. You select the services you want to back up, the formats you want them in (when there are multiple options), and start an export. When it’s ready, you get an email linking to a compressed file containing your data. You can export either to a <code>.zip</code> archive or a <code>.tgz</code> (<code>.tar.gz</code>) archive. Zip is more universally accessible, so if you don’t have or want extra software (such as 7-Zip), it is probably the better option.</p>
<p>One of the hardest things about keeping SaaS backups, even when they are easy to manage, is just remembering to do it. Backups become less useful if they’re six months or even years out of date.</p>
<p>Fortunately, Google Takeout has an option to automatically create a new full export 6 times over the course of a year and email you a download link. I’m not great at remembering to renew backups, so I’m letting them email me every two months with a new export. This is a more important feature than I originally thought, as researching for this post dragged on over nearly two months, despite feeling like I had very recently backed my files up.</p>
<p>One concern I’ve had with downloading SaaS data is whether it could be used in other apps, or imported again. I would prefer that my backups aren’t buried among thousands of lines of cruft. So I’d like to dive into the data and get a feel for how useful it would be if I actually needed it.</p>
<h3 id="how-useful-is-the-exported-data">How useful is the exported data?</h3>
<p>Most of Google Takeout’s data is reasonably well organized and usable — YouTube videos in MP4, calendars in ICS, photos in JPEG sorted by year as well as albums you’ve created. But there is plenty of inefficiency, and a few gotchas you need to watch for.</p>
<p>For some services, like Google Drive, you can select between a common usable format (DOCX for Docs, XLSX for sheets, etc) and a PDF render. There’s not a ton of variety in choices, but the formats are generally common enough that you could easily open them in your program of choice.</p>
<p>My download came in three <code>.tgz</code> files, two around 50GB and one around 5GB. That’s not awful, despite some odd choices on Google’s part for space management. For example, Google Keep exports in a nice, usable JSON format, but also in HTML with a huge <code>style</code> tag. My JSON takes 500KB, while the HTML takes 1500KB. Luckily they don’t seem to do this with YouTube, Google Photos, or Drive, or else I would be more concerned about bloat.</p>
<p>Some exports are somewhere in the middle, like YouTube playlists, which only include the ID of the YouTube video. Helpful in the case of losing your account, but not so much if any of those videos are deleted from YouTube.</p>
<h3 id="what-does-takeout-exclude">What does Takeout exclude?</h3>
<p>Takeout includes most of the data you would care about: Gmail (in MBOX format, including attachments), Google Photos, Blogger, saved Maps places, your uploaded YouTube videos, etc. You can see a full list of services and formats in <a href="https://takeout.google.com/settings/takeout">Takeout itself</a>.</p>
<p>A major flaw with Takeout is that it only backs up data you are the owner of. That means that, for example, if a co-worker creates a document with nothing but a title and invites you to help work on it, you may have added dozens of pages of painfully earned writing, but Takeout doesn’t consider it yours, so it won’t get exported. You have to manually save your own copy, separately, for every shared file.</p>
<p>Sharing is one of the most useful things about Google’s SaaS options, so not having shared files backed up could largely defeat the purpose of the backup. You can download shared files separately, but any added effort to make a complete backup quickly becomes a hassle, and defeats part of the purpose of using Takeout.</p>
<p>Be on the lookout for shared files that might not be backed up. For me, that’s mostly Drive, Photos, and Calendar, but pay attention to other shared files you may want backed up.</p>
<p>While the data exports aren’t perfect, the potential loss is so great that finding some way to back up SaaS data is a no-brainer.</p>
<p>Signing off with an image I found in my Blogger backup: my initials, created using the GIMP, circa 2009.</p>
<p><img src="/blog/2022/05/backing-up-your-saas-data-with-google-takeout/srj.jpg" alt="S. R. J. initials with artificial sun background"></p>
Optimizing media delivery with Cloudinaryhttps://www.endpointdev.com/blog/2022/03/optimizing-image-delivery-with-cloudinary/2022-03-01T00:00:00+00:00Juan Pablo Ventoso
<p><img src="/blog/2022/03/optimizing-image-delivery-with-cloudinary/la-cumbrecita-202201.webp" alt="Beautiful cloudy mountain scene with river flowing by lush banks with people swimming, relaxing, and walking towards multistory buildings"></p>
<!-- Photo by Juan Pablo Ventoso -->
<p>I remember how we needed to deal with different image formats and sizes years ago: From using the WordPress-style approach of automatically saving different resolutions on the server when uploading a picture, to using a PHP script to resize or crop images on the fly and return the result as a response to the frontend. Of course, many of those approaches were expensive, and not fully optimized for different browsers or device sizes.</p>
<p>With those experiences in mind, it was a nice surprise for me to discover <a href="https://cloudinary.com/">Cloudinary</a> when working on a new project a couple of months ago. It’s basically a cloud service that saves and delivers media content with a lot of transformations and management options for us to use. <a href="https://cloudinary.com/pricing">There is a free version</a> with a usage limit: Up to 25K transformations or 25 GB of storage/bandwidth, which should be enough for most non-enterprise websites. The cheapest paid service is $99 per month.</p>
<p>Here’s a list of the image features we used on that project. I know they offer many other things that can be used as well, but I think this is a good start for anyone who hasn’t used this service yet:</p>
<h3 id="resizing-and-cropping">Resizing and cropping</h3>
<p>When you make a request for an image, you can instruct the Cloudinary API to <a href="https://cloudinary.com/documentation/resizing_and_cropping">retrieve it with a given size</a>, which will trigger a transformation on their end before delivering the content. You can also use a cropping method: fill, fill with padding, scale down, etc.</p>
<h3 id="gravity-position">Gravity position</h3>
<p>When we specify a <a href="https://cloudinary.com/documentation/resizing_and_cropping#control_gravity">gravity position</a> to crop an image, the service will keep the area of the image we decide to use as the focal point. We can choose a corner (for example, top left), but also—and this is probably one of the most interesting capabilities on this service—we can specify <a href="https://cloudinary.com/documentation/transformation_reference#g_special_position">“special positions”</a>: By using machine learning, we can instruct Cloudinary to use face detection, or even focus on other objects, like an animal or a flower in the picture.</p>
<h3 id="automatic-format">Automatic format</h3>
<p>Another cool feature is the <a href="https://cloudinary.com/documentation/transformation_reference#f_auto">automatic format</a>, which will use your request headers to find the most efficient picture format for your browser type and version. For example, if the browser supports it, Cloudinary will return the image in WebP format, which is generally more efficient than standard JPEG, as End Point CTO Jon Jensen demonstrates on his recent <a href="https://www.endpointdev.com/blog/2022/02/webp-heif-avif-jpegxl/">blog post</a>.</p>
<p><img src="/blog/2022/03/optimizing-image-delivery-with-cloudinary/image-response.jpg" alt="Screenshot of Chrome browser dev tools showing network response for a WebP image"><br>
Automatic format in action: Returning a WebP image in Chrome</p>
<h3 id="other-features">Other features</h3>
<p>There are many other options for us to choose when querying their API, like setting up a default placeholder when we don’t have an image, applying color transformations, removing red eyes, among other things. The <a href="https://cloudinary.com/documentation/transformation_reference">Transformation reference page</a> on their documentation section is a great resource.</p>
<h3 id="nuxtjs-integration">NuxtJS integration</h3>
<p>The project I mentioned above was a <a href="https://nuxtjs.org/">NuxtJS</a> application with a <a href="https://nodejs.org/">Node.js</a> backend. And since there’s a <a href="https://cloudinary.nuxtjs.org/">NuxtJS module for Cloudinary</a>, it made sense to use it instead of building the queries to the API from scratch.</p>
<p>The component works great, except for one bug that we found that didn’t allow us to fully use their image component with server-side rendering enabled. Between that drawback and some issues trying to use the lazy loading setting, we ended up creating a Vue component ourselves that used a standard image tag instead. But we still used their component to generate most of the API calls and render the results.</p>
<p>Below is an example of using the Cloudinary Image component on a Vue template:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html"><<span style="color:#b06;font-weight:bold">template</span>>
<<span style="color:#b06;font-weight:bold">div</span>>
<<span style="color:#b06;font-weight:bold">cld-image</span>
<span style="color:#369">:public-id</span>=<span style="color:#d20;background-color:#fff0f0">"publicId"</span>
<span style="color:#369">width</span>=<span style="color:#d20;background-color:#fff0f0">"200"</span>
<span style="color:#369">height</span>=<span style="color:#d20;background-color:#fff0f0">"200"</span>
<span style="color:#369">crop</span>=<span style="color:#d20;background-color:#fff0f0">"fill"</span>
<span style="color:#369">gravity</span>=<span style="color:#d20;background-color:#fff0f0">"auto:subject"</span>
<span style="color:#369">radius</span>=<span style="color:#d20;background-color:#fff0f0">"max"</span>
<span style="color:#369">fetchFormat</span>=<span style="color:#d20;background-color:#fff0f0">"auto"</span>
<span style="color:#369">quality</span>=<span style="color:#d20;background-color:#fff0f0">"auto"</span>
<span style="color:#369">alt</span>=<span style="color:#d20;background-color:#fff0f0">"An image example with Cloudinary"</span>
/>
</<span style="color:#b06;font-weight:bold">div</span>>
</<span style="color:#b06;font-weight:bold">template</span>>
</code></pre></div><h3 id="alternatives">Alternatives</h3>
<p>Of course, Cloudinary is not the only image processing and CDN company out there: There are other companies offering similar services, like <a href="https://www.cloudflare.com/products/cloudflare-images/">Cloudflare images</a>, <a href="https://www.cloudimage.io/">Cloudimage</a>, or <a href="https://imagekit.io/">imagekit.io</a>.</p>
<p>Do you know any other good alternatives, or have you used any other Cloudinary feature that is not listed here? Feel free to add a comment below!</p>
Choosing Between SaaS and a Custom Websitehttps://www.endpointdev.com/blog/2021/05/choosing-between-saas-and-custom-website/2021-05-18T00:00:00+00:00Greg Hanson
<p><img src="/blog/2021/05/choosing-between-saas-and-custom-website/drafting.jpg" alt="">
<a href="https://unsplash.com/photos/-FPFq_trr2Y">Photo</a> by <a href="https://unsplash.com/@d_mccullough">Daniel McCullough</a></p>
<p>So you need a website, but you’re not sure whether you want to pay for a website provided as software as a service (SaaS), or build a custom website and host it.</p>
<p>The options are plentiful, as are the reasons for building a website in the first place. The purpose of this article is not to put forward specific packages or providers for consideration, rather I want to discuss how you might make that decision more objectively. Also, this discussion is for a commercial website, not a personal website or blog.</p>
<p>Here at End Point, we receive many inquiries asking for new websites. We are well equipped to help you work through this process, and are happy to do so. But for those of you who want to “go it alone”, or if you just want to be better prepared before giving us a call, read on for some things to consider as you make a pros & cons list for SaaS vs. custom websites.</p>
<p>While deciding between a SaaS offering and a custom build carries unlimited considerations, here are a few main points to help you narrow down the field.</p>
<h3 id="experience">Experience</h3>
<p>The foremost factor that you should consider for your pros & cons list is your experience. This may come as a little bit of a shock, as you might think that budget would be the top consideration. Budget is very important, but it is largely determined by your experience with your chosen technology. Don’t think for a minute that either SaaS or custom development cannot consume almost any budget, especially when you are working with an unfamiliar technology.</p>
<p>So before budget, comes experience. Experience can be futher divided into experience with your business and experience with websites in general. Here are a few questions to start off with.</p>
<p>In your industry, are you a:</p>
<ol>
<li>Rookie</li>
<li>Veteran</li>
</ol>
<p>How long have you owned this business?</p>
<ol>
<li>1–3 years</li>
<li>3+ years</li>
</ol>
<p>Does this business have an existing website?</p>
<ol>
<li>No</li>
<li>Yes</li>
</ol>
<p>If yes, is it currently SaaS or custom-developed?</p>
<ol>
<li>SaaS</li>
<li>Custom-developed</li>
</ol>
<p>If you answered “1” to more than half of the above questions, it’s more likely that a SaaS system would be a better fit for you. If you mostly answered “2”, you may want to lean towards custom. These questions are not definitive, but are meant to help you decide where to focus your research.</p>
<h3 id="budget">Budget</h3>
<p>In general, if your budget is under $10,000 then SaaS is most likely the choice for you. Some exceptions here:</p>
<ul>
<li>You are a talented web programmer.</li>
<li>Your brother, sister, friend, or cousin is a talented web programmer.</li>
<li>You or your developer friend have enough time to devote to this endeavor. You will need a lot.</li>
</ul>
<p>Custom websites are no longer appropriate for the average business owner with less than a $10k minimum start up cost, as well as a $1–3k monthly budget for ongoing improvements and maintenance. Currently, droves of talented programmers are working for SaaS companies, building tools for you to use to build your own website. In fact, SaaS offerings are so much cheaper and more widely supported that building a custom site for the average small business usually makes little sense.</p>
<p>If your budget is $10k or more, you are probably capable of funding a custom website. However, this alone should not rule out a SaaS website. SaaS offerings come in many shapes and sizes, and many are fully capable of running enterprise-level websites!</p>
<h3 id="how-does-your-business-make-money">How does your business make money?</h3>
<p>One good case for using a custom website is if your company offers a niche product. Most SaaS offerings are based on popular business or product templates, so they might not fit well if you need to break from the mold.</p>
<p>For example, do you sell clothing, movies, or tools? There are great SaaS offerings out there that can have your website up and running in less than a day. Do you provide a service that uses multiple providers, working in different capacities and for different rates depending on the level of service provided? You may need a custom application! The further from commonplace your products or services are, the more likely it is that you will need a custom application.</p>
<p>Again, all of this advice is general, and there are exceptions to every rule. SaaS choices still require customizing to fit your business model. None of them will fit perfectly, and you will usually need to configure and add plugins to make your site conform to your business practices. SaaS offerings typically have a wide range of plugins and customizations to accommodate this. Those extras usually cost extra too.</p>
<p>While SaaS sites do provide a great starting point with a plethora of potential plugins, in many cases plugins are supplied by 3rd parties. That means that if you have problems with the plugin, you will need to deal with that provider separate from the main service provider.</p>
<p>A lot of time and money can be spent trying to make diverse systems work together. SaaS can be more “turn-key” in the beginning, but especially for more complex websites, it can end up costing more than if you created a custom site in the beginning.</p>
<h3 id="what-vendors-does-your-company-work-with">What vendors does your company work with?</h3>
<p>Vendors are sometimes overlooked when trying to decide on what type of website will be needed. Here are some questions which might complicate your website:</p>
<ul>
<li>Do you use a 3rd party to ship or fulfill your products?</li>
<li>Do you sell your products on Amazon, Google Shopping, or other providers?</li>
<li>Do you use a vendor to provide your products to you?</li>
<li>Do you assemble the product after receiving parts from different vendors?</li>
<li>Does your company use any software for customer management, accounting, or shipping?</li>
</ul>
<p>If your answer is yes to any of these questions, you need to know what platform each of those vendors or platforms use, and if it is compatible with the website you are planning to build. Almost all business done today involves the exchange of information between you, your customer, and your vendors.</p>
<p>That exchange of information usually takes place through an Application Programming Interface (API). If you aren’t familiar with APIs, here’s a <a href="https://www.freecodecamp.org/news/what-is-an-api-in-english-please-b880a3214a82/">great explanation</a>. Understanding how websites communicate with your vendors is very important.</p>
<p>The point is that if you plan on doing any volume of business, at some point you will need to exchange information with some vendor or other. Verifying that your new website is capable of exchanging information with existing vendors is a big consideration for you to make <em>before</em> you build. Building a website without the required APIs would be like building a house without any provision for water, plumbing, or electricity. This is important stuff, and it can get very expensive to retrofit!</p>
<h3 id="is-that-all">Is that all?</h3>
<p>Absolutely not. There are endless considerations that can play into your decision. But hopefully this post has given you some good ideas of where to start and will help you avoid <a href="https://en.wikipedia.org/wiki/Analysis_paralysis">analysis paralysis</a>. Use this information to get a good idea of your needs and document them, so that you can investigate the right things. Compare how well different solutions fit your needs.</p>
<p>Who knows, you may start with a SaaS solution for a few years, and then when things are rolling and you have a better handle on your site layout, migrate to a custom-built site. There are no set rules.</p>
<p>Don’t read an ad for a website service offering to find out you what you need in a website. Determine what you need in your website and look for a product which meets your needs!</p>
Shopify Admin API: Importing Products in Bulkhttps://www.endpointdev.com/blog/2020/05/shopify-product-creation/2020-05-04T00:00:00+00:00Patrick Lewis
<p><img src="/blog/2020/05/shopify-product-creation/banner.jpg" alt="Cash Register">
<a href="https://www.flickr.com/photos/mrvjtod/279845948/">Photo</a> by <a href="https://www.flickr.com/photos/mrvjtod/">Chris Young</a>, used under <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC BY-SA 2.0</a>, cropped from original.</p>
<p>I recently worked on an interesting project for a store owner who was facing a daunting task: he had an inventory of hundreds of thousands of <a href="https://en.wikipedia.org/wiki/Magic%3A_The_Gathering">Magic: The Gathering</a> (MTG) cards that he wanted to sell online through his Shopify store. The logistics of tracking down artwork and current market pricing for each card made it impossible to do manually.</p>
<p>My solution was to create a custom Rails application that retrieves inventory data from a combination of APIs and then automatically creates products for each card in Shopify. The resulting project turned what would have been a months- or years-long task into a bulk upload that only took a few hours to complete and allowed the store owner to immediately start selling his inventory online. The online store launch turned out to be even more important than initially expected due to current closures of physical stores.</p>
<h3 id="application-requirements">Application Requirements</h3>
<p>The main requirements for the Rails application were:</p>
<ul>
<li>Retrieving product data for MTG cards by merging results from a combination of sources/APIs</li>
<li>Mapping card attributes and metadata into the format expected by the Shopify Admin API for creating Product records</li>
<li>Performing a bulk push of products to Shopify</li>
</ul>
<p>There were some additional considerations like staying within rate limits for both the inventory data and Shopify APIs, but I will address those further in a follow-up post.</p>
<h3 id="retrieving-card-artwork-and-pricing">Retrieving Card Artwork and Pricing</h3>
<p>I ended up using a combination of two APIs to retrieve MTG card data: <a href="https://mtgjson.com/">MTGJSON</a> for card details like the name of the card and the set it belonged to, and <a href="https://scryfall.com/">Scryfall</a> for retrieving card images and current market pricing. It was relatively easy to combine the two because MTGJSON provided Scryfall IDs for all of its records, allowing me to merge results from the two APIs together.</p>
<h3 id="working-with-the-shopify-admin-api-in-ruby">Working With the Shopify Admin API in Ruby</h3>
<p>The <a href="https://shopify.dev/docs/admin-api">Shopify Admin API</a> deals in terms of generic <a href="https://shopify.dev/docs/admin-api/rest/reference/products/product">Product</a> records with predefined attributes like <code>title</code> and <code>product_type</code>. The official <a href="https://github.com/Shopify/shopify_api">shopify_api</a> Ruby gem made it very easy to connect to my client’s Shopify store and create new products by creating <code>Shopify::Product</code> objects with a hash of attributes like so:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"> attrs = {
<span style="color:#a60;background-color:#fff0f0">images</span>: [{ <span style="color:#a60;background-color:#fff0f0">src</span>: scryfall_card.image_uris.large }],
<span style="color:#a60;background-color:#fff0f0">options</span>: [
{
<span style="color:#038">name</span>: <span style="color:#d20;background-color:#fff0f0">'Card Type'</span>
},
{
<span style="color:#038">name</span>: <span style="color:#d20;background-color:#fff0f0">'Condition'</span>
}
],
<span style="color:#a60;background-color:#fff0f0">product_type</span>: <span style="color:#d20;background-color:#fff0f0">'MTG Singles'</span>,
<span style="color:#a60;background-color:#fff0f0">tags</span>: card.setCode,
<span style="color:#a60;background-color:#fff0f0">title</span>: card.name,
<span style="color:#a60;background-color:#fff0f0">variants</span>: [
{
<span style="color:#a60;background-color:#fff0f0">inventory_management</span>: <span style="color:#d20;background-color:#fff0f0">'shopify'</span>,
<span style="color:#a60;background-color:#fff0f0">inventory_quantity</span>: <span style="color:#00d;font-weight:bold">1</span>,
<span style="color:#a60;background-color:#fff0f0">option1</span>: <span style="color:#d20;background-color:#fff0f0">'Foil'</span>,
<span style="color:#a60;background-color:#fff0f0">option2</span>: <span style="color:#d20;background-color:#fff0f0">'Like New'</span>,
<span style="color:#a60;background-color:#fff0f0">price</span>: scryfall_card.prices.usd_foil
}
]
}
<span style="color:#036;font-weight:bold">Shopify</span>::<span style="color:#036;font-weight:bold">Product</span>.new(attrs).save
</code></pre></div><p>The actual production code is a bit more complicated to account for outliers like cards with multiple “faces” and cards that come in both regular and foil variants, but the example above shows the basic shape of the attributes expected by the Shopify API.</p>
<h3 id="pushing-50000-products-to-shopify">Pushing 50,000 Products to Shopify</h3>
<p>After I completed testing with individual products and confirmed the ability to take a specific card and turn it into a Shopify product with artwork and pricing pre-populated it was time to perform the full upload of all 50,000+ cards in the MTGJSON database. I decided to use <a href="https://sidekiq.org/">Sidekiq</a> and create jobs for each card upload so that I could rate limit the workers to stay within rate limits for both the Scryfall and Shopify APIs, and also have persistence that would allow me to pause/resume the queue or retry individual failed jobs.</p>
<p>The Sidekiq approach to queueing up all of the card uploads worked great; I was able to use the Sidekiq dashboard to monitor the queue of 50,000 jobs as it worked its way through each card, and was able to see the Shopify products being created on the store in real time. Once the inventory was in place in Shopify the store owner was able to start updating his inventory levels and make cards available for sale via the Shopify Admin.</p>
<h3 id="conclusion">Conclusion</h3>
<p>A custom Ruby application using the Shopify API is a powerful solution for online storefronts that need to retrieve a large number of inventory data from external sources. I was pleased with how this project turned out; it was rewarding to create a custom application that leveraged several APIs and automated a task that would have been extremely repetitive, and probably impossibly time-consuming, to do manually. It was encouraging to do my first upload of a card and see it show up on the Shopify store with artwork, pricing, and card details pre-populated.</p>
<p>The development model used for this project could be applied to stores in a wide variety of markets. This project used external APIs to retrieve product information but that data source could easily be replaced with a spreadsheet, CSV file, or some other export file containing bulk information on products to be sold.</p>
Ecommerce sales tax primerhttps://www.endpointdev.com/blog/2020/01/ecommerce-sales-tax-primer/2020-01-13T00:00:00+00:00Elizabeth Garrett Christensen
<p>Co-authored by <a href="/team/greg-hanson/">Greg Hanson</a></p>
<p><img src="/blog/2020/01/ecommerce-sales-tax-primer/image-0.jpg" alt="Roman tax burning">
<a href="https://www.flickr.com/photos/internetarchivebookimages/14591980537">Source image</a></p>
<p>Tax collection is one of the topics <em>du jour</em> for those of us in the ecommerce industry. Since state and local authorities are now able to levy taxes on ecommerce goods, taxation for online stores has become quite complicated. The purpose of this post is to give you some next steps and ideas on implementation if you’re new to the topic and need to know how to get started on tax collection for your ecommerce business.</p>
<p>Current ecommerce sales tax policy stems from the 2018 U.S. Supreme Court decision South Dakota v. Wayfair, Inc. Since that decision, favoring South Dakota, 30 states have enacted legislation to require ecommerce stores to pay sales tax if they fit the definition of having an ‘economic nexus’, that is, they do enough business in the state to be worth taxing.</p>
<h3 id="talk-to-your-tax-accountant">Talk to your Tax Accountant</h3>
<p>So the first and most important note is to get your own legal counsel in regards to your taxes. There are many rules and things are changing every month with local and state authorities, so you’ll need reliable counsel on the topic.</p>
<p>If you’re looking for someone to help, make sure this person has:</p>
<ol>
<li>Knowledge about product variants. For example, clothing may not be taxed in some areas.</li>
<li>Familiarity with tax policy in the entire country, and not just one local retail area.</li>
<li>The ability to help you determine in which states you have a tax ‘nexus’ and need to pay sales tax. For many small businesses, you might only do enough business to pay sales tax in your home state and a few large ones like California or New York.</li>
</ol>
<h3 id="research-software">Research Software</h3>
<p>Luckily for anyone starting to collect sales tax, there are some very good SaaS (software as a service) systems out there to make tax collection, reporting, and compliance easy. These software systems typically integrate with your ecommerce store by providing the store with the correct tax amount for the sale and collecting information for you on your reports and filing information to get the taxes paid to the correct authorities. Some systems might even file things for you.</p>
<p>After you’ve worked with your tax accountant on what you need, start looking at the available software. The two main companies End Point has worked with are <a href="https://www.taxjar.com/">TaxJar</a> and <a href="https://www.avalara.com/us/en/index.html">Avalara</a>, though there are a number of other vendors in the market.</p>
<p><img src="/blog/2020/01/ecommerce-sales-tax-primer/image-1.svg" alt="TaxJar" width="48%" style="padding-right: 2%" />
<img src="/blog/2020/01/ecommerce-sales-tax-primer/image-2.svg" alt="Avalara" width="48%" style="padding-left: 2%" /></p>
<h4 id="why-use-an-automated-tax-solution">Why use an automated tax solution?</h4>
<ul>
<li>They automatically update tax rates as they change with local and state regulation.</li>
<li>They can integrate into your checkout processes via API or plugin to automatically calculate the correct tax for the right location and product.</li>
<li>They can have product-specific taxes, for things that might not be taxed like food and clothing in certain states.</li>
<li>They give you end-of-year reports and help with your payments.</li>
<li>You can customize settings, in case there are some states where you have a ‘nexus’ (are subject to sales tax) and other places where sales tax payments are not required.</li>
</ul>
<h4 id="what-to-look-for-in-automated-tax-software">What to look for in automated tax software:</h4>
<ul>
<li>Choose a reputable company with large brand presence. You don’t want to do anything experimental and unreliable here.</li>
<li>Pick something with documentation you can understand. You don’t want working with your tax software to be a pain, and you might need to refer to their documentation when configuring it or changing things in the future. Make sure that company speaks your language and you can easily get answers to your questions.</li>
<li>This company should be able to guide you through all aspects of tax collections, filing and payment. You will legally be liable for taxes on all sales in states where you have nexus, <em>whether you collect the taxes or not</em>! So make sure the company you select can work with you not only to set up the system, but on an ongoing basis providing support in filing reports and making payments.</li>
<li>Integration with your platform is a key component of what you choose. Both Avalara and TaxJar have existing plugins for sites running on WordPress, Shopify, BigCommerce, Magento, and others. Keep in mind though that the integration might be different depending on your platform. If you’re on a custom platform, talk to your development team about integrations; they can read the docs and give you an estimate and recommendation for ease of implementation (that’s where we come in for many clients). For Interchange stores, we have integration code for both TaxJar and Avilara to leverage.</li>
<li>Consider how your inventory or ERP system might be affected. Many of our ecommerce clients sell in-house or over the phone. Consider how your other systems might need to tie into this new tax system.</li>
</ul>
<h3 id="implementation">Implementation</h3>
<p>So you’ve done the hard part, right? You sorted out what states you need to be compliant with and picked a software solution. Now all you need to do is get it working. This is really where your software consultant, such as us at End Point, would come in and get you to the finish line. The steps to implementation are:</p>
<ol>
<li>Set up your account and pay for your tax solution software.</li>
<li>Work with the tax solution provider to set up any required bank accounts or payment channels.</li>
<li>Configure your settings.</li>
<li>Share the API key and information with your developer.</li>
<li>Test the implementation. I recommend you do this with several orders in different scenarios: products that do and don’t have sales tax, locations that do and don’t have tax, locations that tax shipping, etc. Test all the variants you know about.</li>
<li>Go live with your tax solution on your site.</li>
<li>Make sure to check back for your reports and filings for later in the year.</li>
</ol>
<p>Need help picking a system or looking at implementation? <a href="/contact/">Call us today</a> and we can help.</p>
<h3 id="other-resources">Other resources</h3>
<ul>
<li><a href="https://www.salestaxinstitute.com/sales_tax_faqs/wayfair-economic-nexus">https://www.salestaxinstitute.com/sales_tax_faqs/wayfair-economic-nexus</a></li>
<li><a href="https://www.thebalancesmb.com/how-to-collect-report-and-pay-state-sales-taxes-399043">https://www.thebalancesmb.com/how-to-collect-report-and-pay-state-sales-taxes-399043</a></li>
<li><a href="https://www.bigcommerce.com/blog/ecommerce-sales-tax/">https://www.bigcommerce.com/blog/ecommerce-sales-tax/</a></li>
<li><a href="https://www.taxjar.com/guides/intro-to-sales-tax/">https://www.taxjar.com/guides/intro-to-sales-tax/</a></li>
</ul>
Currency exchange rates with exchangeratesapi.iohttps://www.endpointdev.com/blog/2018/07/currency-rates-exchangeratesapi-io/2018-07-14T00:00:00+00:00Jon Jensen
<p><img src="/blog/2018/07/currency-rates-exchangeratesapi-io/38037392525_3501fee918_o-sm.jpg" alt="city street with currency exchange signs" /></p>
<p>Several of our clients run ecommerce sites, built on custom software, that allow customers to pay in their choice of a few different currencies.</p>
<p>Some have set up separate merchant bank accounts for each currency and use separate payment gateway accounts to accept payments natively in each currency. But more commonly they use a payment gateway that allows them to accept payment in several currencies, but receive funds converted into their specified native currency in their merchant bank account.</p>
<p>In either case, it is common to store prices for products, shipping, etc. in one base currency (say, USD for companies based in the U.S.) and dynamically convert prices for customers. Non-native prices may need to be marked up to cover the cost of conversion into the native currency, depending on the terms of the agreement with the payment gateway or bank.</p>
<p>Because currency exchange rates change often, and because payment gateways generally do not offer a way to retrieve the exchange rates in advance, we need our own source for ongoing retrieval and storage of our exchange rates (also known as forex rates).</p>
<p>For a while we were very pleased with <a href="https://fixer.io/">Fixer.io</a>, which was a free service that collected exchange rates from the European Central Bank (ECB) and provided current or historical rates via a simple JSON API. We were sad to find that in March 2018 they deprecated that API and in June 2018 they discontinued it entirely, as <a href="https://github.com/fixerAPI/fixer#readme">described to their users</a>. Fixer.io has transitioned to a paid service and they appear to have improved their operation to retrieve exchange rate data from at least a dozen more sources than the ECB, and to store far more frequent rate updates. Those are nice features, but not something our clients need.</p>
<p>Fixer.io still offers a free plan that allows 1000 API calls per month but in that plan the exchange rates are all based on the Euro. You need to sign up for at least the $10/month plan to retrieve exchange rates from the other currencies as base. As our customers needed exchange rates based on USD and CAD, the free plan wouldn’t work for us. They offer a limited-time Legacy Plan which would work, but that would just be “kicking the can down the road” until that plan too is discontinued. Their lowest paid plan is inexpensive, but with one of our clients retrieving exchange rates just once per week for only 4 currencies, it felt like overkill to track another paid service and API key, deal with renewals and updated credit card payment details, etc.</p>
<p>We quickly found another service called <a href="https://exchangeratesapi.io/">Exchange Rates API</a>, run by <a href="https://github.com/madisvain">Madis Väin</a>, which is free to use without any account setup or API key needed. It is also based on the published ECB exchange rates, and uses the same API that Fixer.io did. The <a href="https://github.com/madisvain/exchangeratesapi">server side is open source</a> written in Python using the <a href="https://github.com/channelcat/sanic">Sanic</a> web server library (similar to Flask, but focused on speed and async request handlers).</p>
<p>The ExchangeRatesAPI.io service runs on <a href="https://www.heroku.com/">Heroku</a> and the open source code is easy to deploy to your own Heroku instance if you want to run your own private service.</p>
<p>Thanks to Madis Väin for providing it, and to Fixer.io for the good service in the past!</p>
Ecommerce Shakeups: Magento Acquisition and Etsy Rate Increaseshttps://www.endpointdev.com/blog/2018/06/ecommerce-shakeups/2018-06-19T00:00:00+00:00Steph Skardal
<p><img src="/blog/2018/06/ecommerce-shakeups/ecommerce-shakeups.jpg" alt="Magento, Etsy" /></p>
<p>If you’ve been paying any attention to much in the ecommerce world, there have been a couple shakeups and transitions that could affect how you look at your ecommerce options these days.</p>
<h3 id="adobe-to-acquire-magento">Adobe to Acquire Magento</h3>
<p>A few weeks ago, <a href="http://news.adobe.com/press-release/corporate/adobe-acquire-magento-commerce">it was announced</a> Adobe would acquire Magento in a large acquisition. We’ve seen Magento clients come and go. It used to be the case that the Magento Community version was free and open source, but lacking in features, and the Magento Enterprise version was not free and came with many more features but was closed source.</p>
<p>But, times change, and admittedly I haven’t looked into the current Magento offerings until writing this post. The two current options for Magento are Magento Commerce Starter and Magento Commerce Pro, more details <a href="https://web.archive.org/web/20180610090249/https://magento.com/trial/plans-comparison">here</a>. These plans are not for small potatoes, starting at $2k/mo. I can see how the cost of this is worth it in lieu of paying a full time developer, but this is not a good fit for small businesses just getting started.</p>
<p>There at not many public details on the acquisition, other than bringing Magento to Adobe’s range of “physical and digital goods across a range of industries, including consumer packaged goods, retail, wholesale, manufacturing, and the public sector”. Only time will tell.</p>
<h3 id="etsy-hikes-rates">Etsy Hikes Rates</h3>
<p>I am personally connected to the craft industry by way of my own hobby, so I’ve heard rumblings of the changes going on within Etsy with a new CEO throughout the last year. They will be <a href="https://craftindustryalliance.org/etsy-shuts-down-etsy-wholesale/">shutting down Etsy wholesale</a> as of July 31st, 2018, <a href="https://craftindustryalliance.org/etsy-close-etsy-studio-etsy-manufacturing-focus-sales-growth-continues/">closing Etsy Studio & Manufacturing</a> later this year, and last week, they announced increasing transaction fees from 3.5% to 5% which will now also apply to shipping charges. With that money, they will be offering improved tools and marketing efforts. You can read the official announcement <a href="https://www.etsy.com/seller-news/2018-june-update">here</a> and more Q&A from Etsy <a href="https://www.etsy.com/teams/7722/discussions/discuss/18737155/">here</a>.</p>
<p>There are so many overwhelming options when it comes to determining what the best ecommerce solution is for any size of ecommerce business, and whether or not now is the right time to move away from Etsy. There is no one size fits all approach, and the best solution is very dependent on the company size and sales, in-house personnel and their skillset, structural organization, and so much more.</p>
<p>There are many competing SaaS options like <a href="https://www.shopify.com/">Shopify</a>, <a href="https://www.bigcommerce.com/">Big Commerce</a>, <a href="https://www.bigcartel.com/">Big Cartel</a>, <a href="https://www.squarespace.com/">Squarespace</a>. We’ve helped set up these software as a solution environments for many clients and they can be a great fit for business owners interested in offloading support and maintenance. In addition to SaaS options, <a href="https://woocommerce.com/">WooCommerce</a> in WordPress is the most popular open-source [free] solution, although many plugins and themes for it are not free. There are plenty of other open source ecommerce options out there, running on a web framework/language (Ruby on Rails, Django, MVC in PHP, etc.) of your choosing.</p>
<h3 id="conclusion">Conclusion</h3>
<p>Like I mentioned above, finding the right solution is very circumstantial. I tend to suggest starting with a low-investment starting point for ecommerce, in whatever shape or form that takes for you, and then incrementally moving up if that’s what you need.</p>
<p>While Etsy might offer a nice low-investment starting point, more exposure and marketing tools, you ultimately aren’t building your own brand on your own domain. I have seen a handful of people in the craft industry keep their Etsy shop open for a specific audience but grow things on their own domain running on another SaaS platform.</p>
<p>On the flip side, many of End Point clients have businesses that are further along and the more enterprisey versions or custom software development solutions make great sense for them, with or without in-house development staff.</p>
<p>If you’re interested in finding out more about setting up a SaaS shop, moving away from Etsy, or understanding your options with Magento, <a href="/contact/">contact us</a> to find out how we can support your business goals.</p>
Expert Help with Your SaaS Systemhttps://www.endpointdev.com/blog/2018/04/expert-help-with-saas/2018-04-23T00:00:00+00:00Elizabeth Garrett Christensen
<p><img src="/blog/2018/04/expert-help-with-saas/123go.jpg" width="770" height="485" alt="1, 2, 3 … Let’s Go!" /></p>
<p>Are you thinking about starting a new website and using BigCommerce, Shopify, or WooCommerce? The software-as-a-service offerings on the market today can help you get a great-looking, low-cost ecommerce website up and running quickly, but you may need more help than you first expect.</p>
<p>In order to get the most out of your site, ecommerce consultants like us at End Point can guide you through setup, customize your site to fit your brand, manage all of your technical requirements, and help drive traffic to your site. This post is an overview of services we offer to clients looking for a SaaS solution.</p>
<h3 id="select-the-right-vendor">Select the Right Vendor</h3>
<p>Working with an expert consultant can help you make the right choices from the start. Sometimes knowing the level of customization that your project requires can be a real challenge. End Point has experience with everything from out-of-the-box SaaS platforms to large-scale, custom software developments—we take time to understand your requirements and guide you to the perfect solution for your business.</p>
<h3 id="custom-design">Custom Design</h3>
<p>Most SaaS offerings include ready-to-use, beautiful design templates, but you’ll often find that they require some tweaking. We can customize your design so that it fits perfectly with the look and feel of your brand, without the time and expense of going through the design process from scratch.</p>
<h3 id="user-experience-and-navigation">User Experience and Navigation</h3>
<p>Working with an ecommerce consultant that has experience with user behavior, site navigation, and business workflows can help you develop the best way to organize your pages and products. With improved navigation, we can ensure that your users are finding what they’re looking for and getting where they’re going quickly and seamlessly.</p>
<h3 id="customizing-your-store">Customizing Your Store</h3>
<p>Customizing your store to work with your specific needs, like shipping integrations, 3rd party apps, and APIs can be a challenge. End Point can help you research the solutions already in place, or build custom solutions for your site.</p>
<h3 id="email-setup">Email Setup</h3>
<p>End Point can help you set up your email on your desktop or in the cloud, and can help you configure and maintain all of your in-house email needs.</p>
<h3 id="dns-and-domain-names">DNS and Domain Names</h3>
<p>End Point has DevOps experts who can make sure everything with your domain name and DNS changes is handled quickly and correctly during the setup or migration of your site from one provider to another.</p>
<h3 id="search-engine-optimization-seo">Search Engine Optimization (SEO)</h3>
<p>A solid search engine optimization strategy is critical to the success of your website, and therefore critical to the success of your business. A high Google ranking means more page views—and more conversions. At End Point, we design and build with SEO in mind from the start to help you get the most value from your online presence.</p>
<h3 id="payments-and-merchants">Payments and Merchants</h3>
<p>End Point has experience with many major merchant vendors. We can help you find the right merchant, be it PayPal, Stripe, Authorize.net, Braintree, etc. We can make sure that payments are set up, tested, and integrated into your business cash flow. We also have experience with PCI compliance and can help you step through an evaluation or mitigation process and get your system in tip-top shape.</p>
<h3 id="project-management">Project Management</h3>
<p>Are you trying to wrangle a team of people? Your old vendor and your new one? Do you need help in managing the project? Our project managers are here to help you meet your business goals and get to the finish line on time and within budget.</p>
<h3 id="system-migrations">System Migrations</h3>
<p>Working with an expert consultant can really help when you are moving from one system to another. We have customizable data export and import scripts and many automated tools to move your content to your new platform and can save you hours of moving products and pages by hand.</p>
<h3 id="summary">Summary</h3>
<p>Working with a consultant agency can really give your SaaS project the professional edge you’ll need to compete in today’s ecommerce market. We offer consulting packages to fit your budget and the depth of services that you need. Talk to us today about how we could help get your project off the ground.</p>
<hr>
<p>(<a href="/blog/authors/jon-allen/">Jon Allen</a> co-authored this article.)</p>
Integrate Twilio in Djangohttps://www.endpointdev.com/blog/2014/11/integrate-twilio-in-django/2014-11-24T00:00:00+00:00Kulbir Singh
<h3 id="twilio">Twilio</h3>
<p><a href="https://www.twilio.com/">Twilio</a> is a powerful HTTP API that allows you to build powerful voice and SMS apps. The goal of this blog post is to help make building the SMS applications as simple as possible in django.</p>
<p>There is a already Twilio Python help library available. The open source <a href="https://github.com/twilio/twilio-python">twilio-python</a> library lets us to write Python code to make HTTP requests to the Twilio API.</p>
<h3 id="installation">Installation</h3>
<p>The easiest way to install twilio-python library is using <a href="http://pip.readthedocs.org/en/latest/quickstart.html">pip</a>. Pip is a package manager for Python.</p>
<p>Simply run following command in terminal.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">$ pip install twilio
</code></pre></div><h3 id="twilio-api-credentails">Twilio API Credentails</h3>
<p>To Integrate twilio API in django application, we need <strong>TWILIO_ACCOUNT_SID</strong> and <strong>TWILIO_AUTH_TOKEN</strong> variables. These variables can be found by logging into your Twilio account dashboard. These variables are used to communicate with the Twilio API.</p>
<p>You’ll need to add them to your <strong>settings.py</strong> file:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">TWILIO_ACCOUNT_SID = <span style="color:#d20;background-color:#fff0f0">'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'</span>
TWILIO_AUTH_TOKEN = <span style="color:#d20;background-color:#fff0f0">'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'</span>
</code></pre></div><h3 id="create-a-new-app">Create a New App</h3>
<p>We are going to interact with people using SMS, so I prefer to create an app named <strong>communication</strong>. I am assuming you’ve already installed Django.</p>
<p>Run following command in terminal.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">$ django-admin.py startapp communcation
</code></pre></div><p>We will need to register the new app in our django project.</p>
<p>Add it to your INSTALLED_APPS tuple in your settings.py file:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">INSTALLED_APPS = (
<span style="color:#d20;background-color:#fff0f0">'django.contrib.auth'</span>,
<span style="color:#d20;background-color:#fff0f0">'django.contrib.contenttypes'</span>,
<span style="color:#d20;background-color:#fff0f0">'django.contrib.sessions'</span>,
<span style="color:#d20;background-color:#fff0f0">'django.contrib.sites'</span>,
<span style="color:#d20;background-color:#fff0f0">'django.contrib.messages'</span>,
<span style="color:#d20;background-color:#fff0f0">'django.contrib.staticfiles'</span>,
<span style="color:#a61717;background-color:#e3d2d2">‘</span>communication<span style="color:#a61717;background-color:#e3d2d2">’</span>,
...
)
</code></pre></div><h3 id="create-the-model">Create the Model</h3>
<p>Now we’ll open up <strong>communication/models.py</strong> to start creating models for our app.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#080;font-weight:bold">class</span> <span style="color:#b06;font-weight:bold">SendSMS</span>(models.Model):
to_number = models.CharField(max_length=<span style="color:#00d;font-weight:bold">30</span>)
from_number = models.CharField(max_length=<span style="color:#00d;font-weight:bold">30</span>)
sms_sid = models.CharField(max_length=<span style="color:#00d;font-weight:bold">34</span>, default=<span style="color:#d20;background-color:#fff0f0">""</span>, blank=<span style="color:#080;font-weight:bold">True</span>)
account_sid = models.CharField(max_length=<span style="color:#00d;font-weight:bold">34</span>, default=<span style="color:#d20;background-color:#fff0f0">""</span>, blank=<span style="color:#080;font-weight:bold">True</span>)
created_at = models.DateTimeField(auto_now_add=<span style="color:#080;font-weight:bold">True</span>)
sent_at = models.DateTimeField(null=<span style="color:#080;font-weight:bold">True</span>, blank=<span style="color:#080;font-weight:bold">True</span>)
delivered_at = models.DateTimeField(null=<span style="color:#080;font-weight:bold">True</span>, blank=<span style="color:#080;font-weight:bold">True</span>)
status = models.CharField(max_length=<span style="color:#00d;font-weight:bold">20</span>, default=<span style="color:#d20;background-color:#fff0f0">""</span>, blank=<span style="color:#080;font-weight:bold">True</span>)
</code></pre></div><p>and run the <strong>syncdb</strong> command after defining the model:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">$ python manage.py syncdb
</code></pre></div><p>It will create the necessary database tables for our app.</p>
<h3 id="create-utilspy-file">Create utils.py file</h3>
<p>Create a new file named utils.py and save in <strong>communication/utils.py</strong>.</p>
<p>Put the following code in <strong>communication/utils.py</strong>:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#080;font-weight:bold">from</span> <span style="color:#b06;font-weight:bold">django.conf</span> <span style="color:#080;font-weight:bold">import</span> settings
<span style="color:#080;font-weight:bold">import</span> <span style="color:#b06;font-weight:bold">twilio</span>
<span style="color:#080;font-weight:bold">import</span> <span style="color:#b06;font-weight:bold">twilio.rest</span>
<span style="color:#080;font-weight:bold">def</span> <span style="color:#06b;font-weight:bold">send_twilio_message</span>(to_number, body):
client = twilio.rest.TwilioRestClient(
settings.TWILIO_ACCOUNT_SID, settings.TWILIO_AUTH_TOKEN)
<span style="color:#080;font-weight:bold">return</span> client.messages.create(
body=body,
to=to_number,
from_=settings.TWILIO_PHONE_NUMBER
)
</code></pre></div><h3 id="testing-send_twilio_message">Testing send_twilio_message</h3>
<p>Open the <strong>shell</strong> and run following commands.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">>>> <span style="color:#080;font-weight:bold">from</span> <span style="color:#b06;font-weight:bold">communication.utils</span> <span style="color:#080;font-weight:bold">import</span> send_twilio_message
>>> sms = send_twilio_message(<span style="color:#d20;background-color:#fff0f0">'+15005550006'</span>, <span style="color:#d20;background-color:#fff0f0">'Hello Endpointer,'</span>)
>>> <span style="color:#038">print</span> sms.sid
SM97f8ac9321114af1b7fd4463ff8bd038
</code></pre></div><p>Having the sid means that everything in the backend is working fine. And we can proceed to work on the front end.</p>
<h3 id="create-form">Create Form</h3>
<p>Lets create a form to gather the data. Now open/create up <strong>communication/forms.py</strong> to start creating forms for our app. And paste the following code into it:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#080;font-weight:bold">class</span> <span style="color:#b06;font-weight:bold">SendSMSForm</span>(forms.ModelForm):
<span style="color:#080;font-weight:bold">class</span> <span style="color:#b06;font-weight:bold">Meta</span>:
model = SendSMS
fields = (<span style="color:#d20;background-color:#fff0f0">'to_number'</span>, <span style="color:#d20;background-color:#fff0f0">'body'</span>)
</code></pre></div><h3 id="the-view-createview">The View CreateView</h3>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#080;font-weight:bold">class</span> <span style="color:#b06;font-weight:bold">SendSmsCreateView</span>(CreateView):
model = SendSMS
form_class = SendSMSForm
template_name = <span style="color:#d20;background-color:#fff0f0">'communication/sendsms_form.html'</span>
success_url = reverse_lazy(<span style="color:#d20;background-color:#fff0f0">'send_sms'</span>)
<span style="color:#080;font-weight:bold">def</span> <span style="color:#06b;font-weight:bold">form_valid</span>(self, form):
number = self.cleaned_data[<span style="color:#d20;background-color:#fff0f0">'to_number'</span>]
body = self.cleaned_data[<span style="color:#d20;background-color:#fff0f0">'body'</span>]
<span style="color:#888"># call twilio</span>
sent = send_twilio_message(number, body)
<span style="color:#888"># save form</span>
send_sms = form.save(commit=<span style="color:#080;font-weight:bold">False</span>)
send_sms.from_number = settings.TWILIO_PHONE_NUMBER
send_sms.sms_sid = sent.sid
send_sms.account_sid = sent.account_sid
send_sms.status = sent.status
send_sms.sent_at = now()
<span style="color:#080;font-weight:bold">if</span> sent.price:
send_sms.price = Decimal(force_text(sent.price))
send_sms.price_unit = sent.price_unit
send_sms.save()
<span style="color:#080;font-weight:bold">return</span> <span style="color:#038">super</span>(SendSmsCreateView, self).form_valid(form)
</code></pre></div><h3 id="defining-urls">Defining URLS</h3>
<p>The URL configuration tells Django how to match a request’s path to your Python code. Django looks for the URL configuration, defined as urlpatterns, in the <strong>urls.py</strong> file in your project:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#080;font-weight:bold">from</span> <span style="color:#b06;font-weight:bold">django.conf.urls</span> <span style="color:#080;font-weight:bold">import</span> patterns, url
<span style="color:#080;font-weight:bold">from</span> <span style="color:#b06;font-weight:bold">.views</span> <span style="color:#080;font-weight:bold">import</span> SendSmsCreateView
urlpatterns = patterns(<span style="color:#d20;background-color:#fff0f0">''</span>,
url(
regex=<span style="color:#d20;background-color:#fff0f0">r</span><span style="color:#d20;background-color:#fff0f0">'^communication/send/sms/$'</span>,
view=SendSmsCreateView.as_view(),
name=<span style="color:#d20;background-color:#fff0f0">'send_sms'</span>
),
)
</code></pre></div><h3 id="creating-the-template">Creating the Template</h3>
<p>Now that we’ve defined a URL for our list view, we can try it out. Django includes a server suitable for development purposes that you can use to easily test your project:</p>
<p>If you visit the <strong>http://127.0.0.1:8000/communication/send/sms/</strong> in your browser, though, you’ll see an error: <strong>TemplateDoesNotExist</strong>.</p>
<p>This is because we have not defined the template file yet. So now create <strong>sendsms_form.html</strong> file in <strong>templates/communication/</strong> and put the following code in it:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html"><<span style="color:#b06;font-weight:bold">form</span> <span style="color:#369">action</span>=<span style="color:#d20;background-color:#fff0f0">"."</span> <span style="color:#369">class</span>=<span style="color:#d20;background-color:#fff0f0">"form-horizontal"</span> <span style="color:#369">method</span>=<span style="color:#d20;background-color:#fff0f0">"post"</span> <span style="color:#369">role</span>=<span style="color:#d20;background-color:#fff0f0">"form"</span>>{% csrf_token %}
{% for field in form %}
<<span style="color:#b06;font-weight:bold">div</span> <span style="color:#369">class</span>=<span style="color:#d20;background-color:#fff0f0">"form-group"</span>> <<span style="color:#b06;font-weight:bold">label</span> <span style="color:#369">class</span>=<span style="color:#d20;background-color:#fff0f0">"col-sm-2 control-label"</span> <span style="color:#369">for</span>=<span style="color:#d20;background-color:#fff0f0">"inputEmail3"</span>>{{ field.label_tag }}</<span style="color:#b06;font-weight:bold">label</span>>
<<span style="color:#b06;font-weight:bold">div</span> <span style="color:#369">class</span>=<span style="color:#d20;background-color:#fff0f0">"col-sm-10"</span>> {{ field }}
{{ field.errors }}
</<span style="color:#b06;font-weight:bold">div</span>> </<span style="color:#b06;font-weight:bold">div</span>> {% endfor %}
<<span style="color:#b06;font-weight:bold">div</span> <span style="color:#369">class</span>=<span style="color:#d20;background-color:#fff0f0">"form-group"</span>> <<span style="color:#b06;font-weight:bold">div</span> <span style="color:#369">class</span>=<span style="color:#d20;background-color:#fff0f0">"col-sm-offset-2 col-sm-10"</span>> <<span style="color:#b06;font-weight:bold">button</span> <span style="color:#369">class</span>=<span style="color:#d20;background-color:#fff0f0">"btn btn-default"</span> <span style="color:#369">type</span>=<span style="color:#d20;background-color:#fff0f0">"submit"</span>>Submit</<span style="color:#b06;font-weight:bold">button</span>>
</<span style="color:#b06;font-weight:bold">div</span>> </<span style="color:#b06;font-weight:bold">div</span>></<span style="color:#b06;font-weight:bold">form</span>>
</code></pre></div><p>Now reload the <strong>http://127.0.0.1:8000/communication/send/sms/</strong> in your browser. Assuming everything is okay, you should then see the following form:</p>
<div class="separator" style="clear: both; text-align: center;"><a href="/blog/2014/11/integrate-twilio-in-django/image-0-big.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="/blog/2014/11/integrate-twilio-in-django/image-0.png"/></a></div>
<p>Fill out the form, and hit the submit button to send your SMS.</p>
<h3 id="conclusion">CONCLUSION</h3>
<p>Congratulations, your SMS is successfully sent. Good luck!</p>