<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Delver Blog</title><description>All your cards in one place</description><link>https://delver.app/</link><language>en</language><item><title>Customizing Themes in Delver X</title><link>https://delver.app/posts/delverx/themes/</link><guid isPermaLink="true">https://delver.app/posts/delverx/themes/</guid><description>Create extensions to customize the color theme of Delver X using the setTheme API.</description><pubDate>Sun, 29 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Overview&lt;/h2&gt;
&lt;p&gt;Delver X extensions allow you to personalize your experience, and one of the simplest yet most impactful ways is by creating custom themes.
You can change the entire color scheme of the application to suit your preferences.&lt;/p&gt;
&lt;p&gt;Theme extensions are small Javascript files that use the &lt;code&gt;delver.setTheme()&lt;/code&gt; API function to apply new colors.
Like all extensions, they run in a sandboxed environment and activate as soon as the app loads.&lt;/p&gt;
&lt;h2&gt;The &lt;code&gt;setTheme&lt;/code&gt; API&lt;/h2&gt;
&lt;p&gt;The core of any theme extension is the &lt;code&gt;delver.setTheme()&lt;/code&gt; function. This function takes a single object that specifies the colors you want to override. You don&apos;t need to define every color; any color key you omit will keep its default value.&lt;/p&gt;
&lt;p&gt;Here are the color keys you can customize:&lt;/p&gt;
&lt;h4&gt;Primary Theme Colors&lt;/h4&gt;
&lt;p&gt;These define the main branding colors of the application.
Delver for Magic the Gathering is &lt;code&gt;blue/dark blue&lt;/code&gt; while Pokemon is &lt;code&gt;blue/green&lt;/code&gt;, for instance.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;primary&lt;/code&gt;: The main primary color.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;primary-dark&lt;/code&gt;: A darker shade of the primary color.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;primary-light&lt;/code&gt;: A lighter shade of the primary color.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;secondary&lt;/code&gt;: The secondary color.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Text Colors&lt;/h4&gt;
&lt;p&gt;Color of text in both light and dark modes.
Numbers go from darker (100) to lighter (300), for both light and dark values.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;text-color-100&lt;/code&gt;: Main text color for light mode.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text-color-200&lt;/code&gt;: Secondary text color for light mode.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text-color-300&lt;/code&gt;: Tertiary/disabled text color for light mode.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dark-text-color-100&lt;/code&gt;: Main text color for dark mode.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dark-text-color-200&lt;/code&gt;: Secondary text color for dark mode.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dark-text-color-300&lt;/code&gt;: Tertiary/disabled text color for dark mode.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Background Colors&lt;/h4&gt;
&lt;p&gt;Background surfaces for both light and dark modes.
Numbers go from darker (100) to lighter (300), for both light and dark values.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;background-color-100&lt;/code&gt;: Base background for light mode.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;background-color-200&lt;/code&gt;: Primary surface color for light mode.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;background-color-300&lt;/code&gt;: Secondary surface color for light mode.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dark-background-color-100&lt;/code&gt;: Base background for dark mode.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dark-background-color-200&lt;/code&gt;: Primary surface color for dark mode.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dark-background-color-300&lt;/code&gt;: Secondary surface color for dark mode.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Demo: A &quot;True Dark&quot; Theme&lt;/h2&gt;
&lt;p&gt;Let&apos;s create a simple extension that makes the default dark theme even darker.
Feel free to experiment with different color values to create your perfect theme.&lt;/p&gt;
&lt;h3&gt;How to Use&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Create a new file on your computer and name it &lt;code&gt;true-dark.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Copy the code below and paste it into your new file.&lt;/li&gt;
&lt;li&gt;In Delver X, navigate to the &lt;strong&gt;Extensions&lt;/strong&gt; page, tap &lt;strong&gt;Create&lt;/strong&gt; then &lt;strong&gt;Install&lt;/strong&gt;. Select the &lt;code&gt;true-dark.js&lt;/code&gt; file you just created.&lt;/li&gt;
&lt;li&gt;The new, darker theme will be applied immediately.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Full Extension Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;/*
 * @id true-dark
 * @name True Dark
 * @version 100
 * @short_description Make the dark-theme even darker
 * @description_start
 * This extension uses the setTheme API to apply a theme that is darker than the default dark theme.
 * @description_end
 * @icon_start
 * &amp;lt;svg xmlns=&quot;[http://www.w3.org/2000/svg](http://www.w3.org/2000/svg)&quot; viewBox=&quot;0 0 24 24&quot;&amp;gt;
 * &amp;lt;path fill=&quot;white&quot; d=&quot;M17.75,4.09L15.22,6.03L16.13,9.09L13.5,7.28L10.87,9.09L11.78,6.03L9.25,4.09L12.44,4L13.5,1L14.56,4L17.75,4.09M21.25,11L19.61,12.25L20.2,14.23L18.5,13.06L16.8,14.23L17.39,12.25L15.75,11L17.81,10.95L18.5,9L19.19,10.95L21.25,11M18.97,15.95C19.8,15.87 20.69,17.05 20.16,17.8C19.84,18.25 19.5,18.67 19.08,19.07C15.17,23 8.84,23 4.94,19.07C1.03,15.17 1.03,8.83 4.94,4.93C5.34,4.53 5.76,4.17 6.21,3.85C6.96,3.32 8.14,4.21 8.06,5.04C7.79,7.9 8.75,10.87 10.95,13.06C13.14,15.26 16.1,16.22 18.97,15.95M17.33,17.97C14.5,17.81 11.7,16.64 9.53,14.5C7.36,12.31 6.2,9.5 6.04,6.68C3.23,9.82 3.34,14.64 6.35,17.66C9.37,20.67 14.19,20.78 17.33,17.97Z&quot; /&amp;gt;
 * &amp;lt;/svg&amp;gt;
 * @icon_end
 * @developer Delver Lab
 * @developer_url [https://delverlab.com](https://delverlab.com)
 */

delver.setTheme({
    colors: {
        primary: &apos;#020617&apos;,
        &apos;primary-dark&apos;: &apos;#000000&apos;,
        &apos;primary-light&apos;: &apos;#0f172a&apos;,
        secondary: &apos;#000000&apos;,

        // Override dark mode background colors
        &apos;dark-background-color-100&apos;: &apos;#000000&apos;,
        &apos;dark-background-color-200&apos;: &apos;#020617&apos;,
        &apos;dark-background-color-300&apos;: &apos;#0f172a&apos;
    }
});
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Extensions for Delver X</title><link>https://delver.app/posts/delverx/extensions/</link><guid isPermaLink="true">https://delver.app/posts/delverx/extensions/</guid><description>Creating and using extensions to expand the functionality of Delver X, using a Dropbox Sync extension as an example.</description><pubDate>Sat, 28 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Overview&lt;/h2&gt;
&lt;p&gt;Delver X extensions allow you to build integrations and new features directly within the application.
This guide will walk you through the process of writing and using your own extensions.&lt;/p&gt;
&lt;p&gt;Extensions in Delver X operate within a sandboxed &lt;code&gt;iframe&lt;/code&gt; and activate as soon as the page loads.
They communicate with the main application through a message-passing system.
A global &lt;code&gt;delver&lt;/code&gt; object is available within the extension&apos;s scope.&lt;/p&gt;
&lt;p&gt;The extension API is designed to be minimal and evolve based on developer needs.
If you find the current API lacking for your project, we encourage you to reach out to us at &lt;a href=&quot;mailto:contact@delverlab.com&quot;&gt;contact@delverlab.com&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Quick Start&lt;/h2&gt;
&lt;p&gt;Let&apos;s create a very simple extension to get a feel for the process.
This &quot;True Dark&quot; extension uses the &lt;code&gt;delver.setTheme()&lt;/code&gt; API function to make the default dark theme even darker.
The entire extension is contained in a single Javascript file.&lt;/p&gt;
&lt;h3&gt;How to Use&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Create a new file on your computer and name it &lt;code&gt;true-dark.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Copy the code below and paste it into your new file.&lt;/li&gt;
&lt;li&gt;In Delver X, navigate to the &lt;code&gt;Extensions&lt;/code&gt; page, tap &lt;code&gt;create&lt;/code&gt; then &lt;code&gt;install&lt;/code&gt;. Point to the &lt;code&gt;true-dark.js&lt;/code&gt; file you created.&lt;/li&gt;
&lt;li&gt;The new theme will be applied immediately.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Extensions are synchronized with your Delver account.
This means that once you install an extension on one device, it will automatically be installed on any other device you&apos;re signed into.&lt;/p&gt;
&lt;h3&gt;Full Extension Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;/*
 * @id true-dark
 * @name True Dark
 * @version 100
 * @short_description Make the dark-theme even darker
 * @description_start
 *  This extension sets a dark theme that&apos;s darker than the one available in the app.
 *  This is also a good example of how to use the setTheme API.
 * @description_end
 * @icon_start
 * &amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 24 24&quot;&amp;gt;
 * &amp;lt;path d=&quot;M17.75,4.09L15.22,6.03L16.13,9.09L13.5,7.28L10.87,9.09L11.78,6.03L9.25,4.09L12.44,4L13.5,1L14.56,4L17.75,4.09M21.25,11L19.61,12.25L20.2,14.23L18.5,13.06L16.8,14.23L17.39,12.25L15.75,11L17.81,10.95L18.5,9L19.19,10.95L21.25,11M18.97,15.95C19.8,15.87 20.69,17.05 20.16,17.8C19.84,18.25 19.5,18.67 19.08,19.07C15.17,23 8.84,23 4.94,19.07C1.03,15.17 1.03,8.83 4.94,4.93C5.34,4.53 5.76,4.17 6.21,3.85C6.96,3.32 8.14,4.21 8.06,5.04C7.79,7.9 8.75,10.87 10.95,13.06C13.14,15.26 16.1,16.22 18.97,15.95M17.33,17.97C14.5,17.81 11.7,16.64 9.53,14.5C7.36,12.31 6.2,9.5 6.04,6.68C3.23,9.82 3.34,14.64 6.35,17.66C9.37,20.67 14.19,20.78 17.33,17.97Z&quot; /&amp;gt;
 * &amp;lt;/svg&amp;gt;
 * @icon_end
 * @developer Delver Lab
 * @developer_url https://delverlab.com
 */

delver.setTheme({
	colors: {
		primary: &apos;#020617&apos;,
		&apos;primary-dark&apos;: &apos;#000000&apos;,
		&apos;primary-light&apos;: &apos;#0f172a&apos;,
		secondary: &apos;#000000&apos;,

		// background colors
		&apos;dark-background-color-100&apos;: &apos;#000000&apos;,
		&apos;dark-background-color-200&apos;: &apos;#020617&apos;,
		&apos;dark-background-color-300&apos;: &apos;#0f172a&apos;
	}
})
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;More Complex Extension&lt;/h3&gt;
&lt;p&gt;The Dropbox Sync extension showcases advanced extension capabilities.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Download the Sample Project:&lt;/strong&gt; The Dropbox Sync extension code is available &lt;a href=&quot;https://delver-public.s3.us-west-1.amazonaws.com/extensions/dropbox-sync.js&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modify the Code:&lt;/strong&gt; Adapt the sample code to fit your needs. The sample demonstrates key concepts you may need, such as handling starting up, downloading additional libraries and handling user interaction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Upload and Install:&lt;/strong&gt; Once your extension is ready, you can upload and install it directly within Delver X in the &lt;code&gt;Extensions&lt;/code&gt; page.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;The Extension Manifest&lt;/h2&gt;
&lt;p&gt;You need to provide a manifest with several required fields within your extension&apos;s file.
Here is a breakdown of the manifest fields using the &quot;Dropbox Sync&quot; extension as an example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;@id&lt;/code&gt;&lt;/strong&gt;: A unique, machine-readable identifier for your extension.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;* @id dropbox-sync
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;@name&lt;/code&gt;&lt;/strong&gt;: The human-readable name of your extension that will be displayed in the UI.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;* @name Dropbox Sync
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;@version&lt;/code&gt;&lt;/strong&gt;: A numeric version for your extension. We recommend a number between 100 and 999 for your initial release. While the version is ignored when an extension is manually installed, it&apos;s used for the update process. Versions are displayed with dots inserted every two digits from the right. For instance, &lt;code&gt;100&lt;/code&gt; becomes &quot;1.00&quot;, and &lt;code&gt;10001&lt;/code&gt; is displayed as &quot;1.00.01&quot;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;* @version 100
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;@short_description&lt;/code&gt;&lt;/strong&gt;: A concise, one-line summary of what your extension does.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;* @short_description Sync with Delver Android using Dropbox Sync
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;@description_start&lt;/code&gt; / &lt;code&gt;@description_end&lt;/code&gt;&lt;/strong&gt;: The full description of your extension. This field supports Markdown for rich formatting. Everything between these two tags will be parsed.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;* @description_start
* Sync manually with Delver Android via Dropbox Sync.
*
* ## How Dropbox Sync works in Delver Android
*
* 1. Delver Android uploads two files to Dropbox: user and images.
* 2. You can manually restore these files in Delver Android.
* 3. You can force Delver Android to upload these files.
*
* ## What this extension does
*
* Adds a new &quot;Dropbox Sync&quot; item to the main screen&apos;s side menu.
* From there, you can:
*
* 1. Import the user and image files from Dropbox.
* 2. Export the local data to Dropbox where you can then restore it in Delver Android.
*
* This extension facilitates syncing between both apps.
* Note that synchronization is not automatic;
* manual import/export between apps is necessary.
*
* ## Limitations
*
* - List background image is not synced.
*
* @description_end
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;@icon_start&lt;/code&gt; / &lt;code&gt;@icon_end&lt;/code&gt;&lt;/strong&gt;: The icon for your extension. While SVGs are preferred, you can also use a base64 encoded image. Note that icons are displayed against a white background. All entries are sanitized, so scripts will not be executed.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;* @icon_start
* &amp;lt;svg xmlns=&quot;[http://www.w3.org/2000/svg](http://www.w3.org/2000/svg)&quot;
* viewBox=&quot;0 0 24 24&quot; fill=&quot;#1e40af&quot;&amp;gt;
* &amp;lt;path d=&quot;M3 6.2L8 9.39L13 6.2L8 3L3 6.2M13 6.2L18 9.39L23 6.2L18 3L13 6.2M3 12.55L8 15.74L13 12.55L8 9.35L3 12.55M18 9.35L13 12.55L18 15.74L23 12.55L18 9.35M8.03 16.8L13.04 20L18.04 16.8L13.04 13.61L8.03 16.8Z&quot; /&amp;gt;
* &amp;lt;/svg&amp;gt;
* @icon_end
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;@developer&lt;/code&gt;&lt;/strong&gt;: The name of the person or entity that developed the extension.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;* @developer Delver Lab
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;@developer_url&lt;/code&gt;&lt;/strong&gt;: A link to the developer&apos;s website or profile.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;* @developer_url [https://delverlab.com](https://delverlab.com)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The Delver X Extensiosn API&lt;/h2&gt;
&lt;p&gt;Your extension lives in a sandboxed &lt;code&gt;iframe&lt;/code&gt; and communicates with the Delver X application by passing messages back and forth.
A global &lt;code&gt;delver&lt;/code&gt; object is available to facilitate this interaction.&lt;/p&gt;
&lt;p&gt;The complete API, including the source code, is available for your reference &lt;a href=&quot;https://mtg.delver.app/delver_extensions_api.js&quot;&gt;here&lt;/a&gt;.
This file is the definitive source for understanding the available functionalities.&lt;/p&gt;
&lt;p&gt;Our philosophy is to add features to the API as they are requested by developers. If you have specific needs, please contact us at &lt;a href=&quot;mailto:contact@delverlab.com&quot;&gt;contact@delverlab.com&lt;/a&gt; to discuss them.&lt;/p&gt;
&lt;p&gt;Here&apos;s a non-exhaustive list of some functions that are available to you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;importScript&lt;/code&gt;: Loads an external script, like a third-party library.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;createMainMenuItem&lt;/code&gt;: Adds a clickable item to the main side menu.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;createTextSetting&lt;/code&gt;: Creates a text-based setting in the extension settings menu.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[set/get]Setting&lt;/code&gt;: Stores and retrieves the value of a setting.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;displayDialog&lt;/code&gt;: Shows a dialog box with a title, custom HTML content, and optional action buttons.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;displayProgressDialog&lt;/code&gt;: Displays a progress dialog for long-running operations.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;displayToast&lt;/code&gt;: Shows a temporary, non-intrusive notification message.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;oauthSignIn&lt;/code&gt;: Initiates a third-party OAuth sign-in flow.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;oauthGetToken&lt;/code&gt;: Retrieves a stored OAuth access token.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;oauthSignOut&lt;/code&gt;: Signs out by removing a stored OAuth token.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;exportV2&lt;/code&gt;: Exports the user&apos;s collection data and images as files for backup or transfer.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;importV2&lt;/code&gt;: Imports data from files generated by &lt;code&gt;exportV2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setTheme&lt;/code&gt;: Customizes the theme by applying custom colors.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Handling Authentication&lt;/h2&gt;
&lt;p&gt;If your extension requires users to sign in to a third-party service, the Dropbox Sync extension provides a clear example of how to manage the OAuth2 token exchange with the Dropbox API.&lt;/p&gt;
&lt;p&gt;Session tokens are stored in the user&apos;s &lt;code&gt;localStorage&lt;/code&gt;. Delver X ensures that only your extension can access the session tokens your extension creates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Always ensure that you do not expose a token with more permissions than is absolutely necessary for your extension to function.&lt;/p&gt;
&lt;h2&gt;The Future of Extensions&lt;/h2&gt;
&lt;p&gt;The Delver X extension system is being developed in phases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Phase 1: (Current)&lt;/strong&gt; Install and uninstall extensions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phase 2:&lt;/strong&gt; Publish extensions for other users to discover and install.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phase 3:&lt;/strong&gt; Enable monetization for published extensions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Publishing Your Extension&lt;/h2&gt;
&lt;p&gt;While direct publishing of extensions is not yet supported, we are actively looking for developers interested in sharing their creations with the Delver community. If you have an extension you&apos;d like to publish, please contact us with information about what you&apos;ve built.&lt;/p&gt;
&lt;p&gt;Here are some guidelines for publication to keep in mind:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Strive for perfection.&lt;/strong&gt; Your extensions should be useful, simple, and focused.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write clearly.&lt;/strong&gt; We value straightforward communication over marketing jargon.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Respect your user&apos;s intelligence.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Make something people want.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Sync Delver Lens and Delver X</title><link>https://delver.app/posts/misc/sync-dl-dx/</link><guid isPermaLink="true">https://delver.app/posts/misc/sync-dl-dx/</guid><description>How to sync between Delver Lens and Delver X.</description><pubDate>Sat, 08 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Overview&lt;/h2&gt;
&lt;p&gt;This guide explains how to sync your collection between Delver Lens (android app) and Delver X (web).&lt;/p&gt;
&lt;h3&gt;Delver Lens&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Tap the main screen side menu header to sign in/sign up.&lt;/li&gt;
&lt;li&gt;After signing in, tap the header again to access the sync options.&lt;/li&gt;
&lt;li&gt;Tap &lt;strong&gt;Backup Now&lt;/strong&gt; to send your collection to Delver Web.
&lt;blockquote&gt;
&lt;p&gt;A brief &quot;Backup complete&quot; message appears along the bottom to confirm the backup was created.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Restore&lt;/strong&gt; when importing from Delver Web.
&lt;blockquote&gt;
&lt;p&gt;Any cards in Delver Lens but not on Delver Web will be lost. Delver Lens will delete everything and copy over cards from Delver Web. Be careful using this option.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;lt;div class=&quot;flex justify-center&quot;&amp;gt;
&amp;lt;video class=&quot;w-64 h-full&quot; title=&quot;Delver Lens Sync&quot; frameborder=&quot;0&quot; autoplay controls loop&amp;gt;
&amp;lt;source src=&quot;/blog/videos/sync-dl-dx-delverlens.mp4&quot; type=&quot;video/mp4&quot;&amp;gt;
&amp;lt;source src=&quot;/blog/videos/sync-dl-dx-delverlens.webm&quot; type=&quot;video/webm&quot;&amp;gt;
&amp;lt;/video&amp;gt;
&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;h3&gt;Delver X&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Tap &quot;sign-in to save&quot; on the top-left to sign in/sign up.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After signing in, the top-left button again to open options.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under &lt;strong&gt;Delver Lens Android&lt;/strong&gt;, tap &lt;strong&gt;Import&lt;/strong&gt; to get your collection from Delver Lens.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When using Overwrite, any cards in Delver Web but not in Delver Lens will be lost. Delver Web will delete everything and copy over cards from Delver Lens. Be careful when using this option.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;strong&gt;Export&lt;/strong&gt; to send your collection from Delver Web to Delver Lens.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A confirmation message is displayed when your collection is exported and ready to be restored on Delver Lens.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;lt;div class=&quot;flex justify-center&quot;&amp;gt;
&amp;lt;video class=&quot;w-full h-full&quot; title=&quot;Delver X Sync&quot; frameborder=&quot;0&quot; autoplay controls loop&amp;gt;
&amp;lt;source src=&quot;/blog/videos/sync-dl-dx-delverx.mp4&quot; type=&quot;video/mp4&quot;&amp;gt;
&amp;lt;source src=&quot;/blog/videos/sync-dl-dx-delverx.webm&quot; type=&quot;video/webm&quot;&amp;gt;
&amp;lt;/video&amp;gt;
&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;h2&gt;Troubleshooting&lt;/h2&gt;
&lt;h3&gt;Sync Failed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Verify you&apos;re signed in with the same account on both apps&lt;/li&gt;
&lt;li&gt;Try signing out and back in&lt;/li&gt;
&lt;li&gt;Try clearing app cache and try again
&lt;blockquote&gt;
&lt;p&gt;Don&apos;t delete the app&apos;s data, just clear the cache.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;If problems persist, contact support&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Missing Cards After Sync&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Check if both Delver Lens and Delver X are updated&lt;/li&gt;
&lt;li&gt;Check if the card exists in both apps&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;The database on Delver Lens and Delver X may differ. The behavior of the apps is to not show the card if it doesn&apos;t exist in the internal database.&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>API Integration via Webhooks</title><link>https://delver.app/posts/delverx/webhooks/</link><guid isPermaLink="true">https://delver.app/posts/delverx/webhooks/</guid><description>How to integrate Delver X with your website or app via webhooks.</description><pubDate>Fri, 07 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Overview&lt;/h2&gt;
&lt;p&gt;Webhooks are a way for you to write custom code that runs when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;New cards are scanned&lt;/li&gt;
&lt;li&gt;The scanner is paused or resumed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This enables powerful automation possibilities. For example, you could:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build a machine that physically moves cards in and out of Delver as they&apos;re scanned&lt;/li&gt;
&lt;li&gt;Auto-populate a spreadsheet with scanned card data&lt;/li&gt;
&lt;li&gt;Trigger custom workflows when cards are added or modified&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Webhooks are a Pro feature.
You can enable and test the functionality for free, but
you&apos;ll need an active subscription to receive actual card data.
Visit &lt;a href=&quot;https://delver.app/#pricing&quot;&gt;delver.app/#pricing&lt;/a&gt; for subscription information.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Delver Webhook Server&lt;/h2&gt;
&lt;p&gt;The Delver Webhook Server receives webhook requests from Delver and holds the information until you retrieve it.
This allows you to use webhooks without worrying about HTTPS or CORS.&lt;/p&gt;
&lt;p&gt;&amp;lt;img
src=&quot;/blog/img/delver-webhook-server.svg&quot;
alt=&quot;Delver Webhook Server&quot;
class=&quot;w-48 bg-slate-100 mx-auto&quot;
/&amp;gt;&lt;/p&gt;
&lt;h3&gt;Enable Webhook Server&lt;/h3&gt;
&lt;p&gt;Navigate to &lt;strong&gt;Main Screen&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Side Menu&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Settings&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Advanced&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Delver Webhook Server&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Click the &lt;strong&gt;Generate&lt;/strong&gt; button to generate a new endpoint.&lt;/p&gt;
&lt;p&gt;That&apos;s it! You&apos;re all set.&lt;/p&gt;
&lt;h3&gt;Test Webhook Server&lt;/h3&gt;
&lt;p&gt;You can test it out directly by pasting the endpoint into a browser.
The first response the browser will show is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{ &quot;type&quot;: &quot;endpoint_created&quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you refresh the browser,
the server will wait up to 10 seconds and then timeout with response code 404 and the following json:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{ &quot;type&quot;: &quot;not_found&quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now scan a couple of cards with Delver and refresh the browser again.
You should see a json indicating the scanner started and cards that have been scanned.&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;flex justify-center&quot;&amp;gt;
&amp;lt;video class=&quot;w-full h-full&quot; title=&quot;Webhook&quot; frameborder=&quot;0&quot; autoplay controls loop&amp;gt;
&amp;lt;source src=&quot;/blog/videos/webhooks.mp4&quot; type=&quot;video/mp4&quot;&amp;gt;
&amp;lt;source src=&quot;/blog/videos/webhooks.webm&quot; type=&quot;video/webm&quot;&amp;gt;
&amp;lt;/video&amp;gt;
&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The endpoint is open and only secured by the endpoint URL. Ensure the URL remains secret.
Generate a new one if you suspect it has been compromised. Don&apos;t put on Github!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Enable Webhooks (Advanced)&lt;/h2&gt;
&lt;p&gt;Navigate to &lt;strong&gt;Main Screen&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Side Menu&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Settings&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Advanced&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Enable Webhooks&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Still under &lt;strong&gt;Settings&lt;/strong&gt;, set the &lt;strong&gt;Webhook Endpoint&lt;/strong&gt; to the URL of your server.&lt;/p&gt;
&lt;p&gt;Except for localhost, the endpoint must use HTTPS and must return CORS headers.&lt;/p&gt;
&lt;h3&gt;HTTPS&lt;/h3&gt;
&lt;p&gt;Enabling HTTPS requires advanced knowledge of IT infrastructure.
You can use this tutorial to deploy certificates in your local network &lt;a href=&quot;https://jamielinux.com/docs/openssl-certificate-authority/&quot;&gt;(link)&lt;/a&gt;.
You can also use proxy services like &lt;a href=&quot;https://ngrok.com/&quot;&gt;ngrok&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;CORS&lt;/h3&gt;
&lt;p&gt;Remember to set CORS headers in your response.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
	&quot;Access-Control-Allow-Origin&quot;: &quot;*&quot;,
	&quot;Access-Control-Allow-Methods&quot;: &quot;POST, OPTIONS&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Alternative to HTTPS and CORS&lt;/h3&gt;
&lt;p&gt;If you&apos;re not confident or don&apos;t have the time to setup HTTPS, use the Delver Webhook Server.
It was designed to be used in place of you developing your own server.&lt;/p&gt;
&lt;h2&gt;Types of Requests&lt;/h2&gt;
&lt;p&gt;Delver X sends webhook requests during active card recognition sessions.&lt;/p&gt;
&lt;h3&gt;Webhook Server Responses&lt;/h3&gt;
&lt;p&gt;When using the Delver Webhook Server, you may receive the following response types:&lt;/p&gt;
&lt;p&gt;The following response indicates that your endpoint was successfully created in the webhook server.
You&apos;ll see this only when first accessing a newly generated endpoint URL.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
	&quot;type&quot;: &quot;endpoint_created&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The following response (with HTTP status code 404) occurs when
polling the server but no new events are available within the 10-second timeout period.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
	&quot;type&quot;: &quot;not_found&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Scanner Status&lt;/h3&gt;
&lt;p&gt;When you open the recognition page and scanning becomes active:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;POST /&amp;lt;HTTP Post Endpoint&amp;gt;
{
	&quot;type&quot;: &quot;scanner_started&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When scanning is paused or you navigate away from the scanning page:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;POST /&amp;lt;HTTP Post Endpoint&amp;gt;
{
	&quot;type&quot;: &quot;scanner_paused&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Card Events&lt;/h3&gt;
&lt;p&gt;When a new card is scanned:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;POST /&amp;lt;HTTP Post Endpoint&amp;gt;
{
	&quot;type&quot;: &quot;card_scanned&quot;,
	&quot;cards&quot;: [{
		&quot;cardId&quot;: 6128,
		&quot;quantity&quot;: 1,
		&quot;name&quot;: &quot;Birds of Paradise&quot;,
		&quot;edition&quot;: &quot;Secret Lair Drop&quot;,
		&quot;number&quot;: &quot;92&quot;,
		&quot;priceUser&quot;: &quot;&quot;,
		&quot;fmtPriceUser&quot;: &quot;-&quot;,
		&quot;priceAcquired&quot;: 0.0,
		&quot;condition&quot;: &quot;&quot;,
		&quot;language&quot;: &quot;&quot;,
		&quot;listName&quot;: &quot;Temporary&quot;,
		&quot;listType&quot;: -1,
		&quot;board&quot;: 0,
		&quot;manaCost&quot;: &quot;&amp;lt;svg version=\&quot;1.1\&quot; viewBox=\&quot;0 0 600 600\&quot; xmlns=\&quot;http://www.w3.org/2000/svg\&quot;&amp;gt;&amp;lt;circle cx=\&quot;300\&quot; cy=\&quot;300\&quot; r=\&quot;300\&quot; fill=\&quot;#9bd3ae\&quot;/&amp;gt;&amp;lt;path d=\&quot;m562.6 337.4c0 10-3.9 19-11.6 27s-16.6 12-26.6 12c-16 0-27.7-7.5-35.2-22.5l-35.2-1.5c-7.5 0-22.3 3.3-44.2 9.8-23.5 6.5-37 11.7-40.5 15.7-5.5 6-10 20-13.5 42-3 18-4.5 31.2-4.5 39.7 0 13.5 2.1 23.4 6.4 29.6s13 11.5 26.2 15.7 21.4 6.6 24.4 7.1c2 0 5.2-0.2 9.8-0.7h9c6.5 0 13.2 1 20.2 3 10 3 14.3 7 12.8 12-7-1-19.2 0.5-36.7 4.5l21 10.5c0 6-8.5 9-25.5 9-4.5 0-10.6-1-18.4-3-7.7-2-12.9-3-15.4-3h-9.7c-0.5 5-2 12.5-4.5 22.5-8.5-0.5-18.5-5.5-30-15s-18.7-14.2-21.7-14.2-7.3 4.8-12.7 14.2c-5.5 9.5-8.2 16-8.2 19.5-6.5-3.5-12-10-16.5-19.5-2-6.5-4.2-13-6.7-19.5-5 0.5-14.2 11-27.7 31.5h-3.8c-1-1.5-4.8-12-11.2-31.5-15.5-5-30-7.5-43.5-7.5-6.5 0-16.5 1.5-30 4.5l-21-1.5c3-3 11.7-8.7 26.2-17.2 17-10 30-15 39-15 1.5 0 3.5 0.3 6 0.8s4.5 0.8 6 0.8c3.5 0 9.1-1.9 16.9-5.6 7.7-3.7 12.2-7.1 13.5-10.1s1.9-10.8 1.9-23.2c0-28.5-7.5-49.7-22.5-63.7-13-12.5-34.5-21.5-64.5-27-8 28.5-30.5 42.7-67.4 42.7-12 0-24-7.2-36-21.7-12.3-14.8-18.3-28-18.3-40 0-18.5 7.7-33.7 23.2-45.7-12.5-13-18.7-26.2-18.7-39.7 0-12.5 3.9-23.5 11.6-33s17.9-15 30.4-16.5c-1-16 4.2-27 15.7-33-5.5-5.5-8.2-15.2-8.2-29.2 0-16.5 5.5-30.2 16.5-41.2s24.7-16.5 41.2-16.5c18 0 32.7 6.3 44.2 18.8 14.5-49.5 45.7-74.2 93.7-74.2 25 0 47 10 66 30 7 7.5 10.5 11.5 10.5 12-6 0-3-1.1 9-3.4 12-2.2 20.7-3.4 26.2-3.4 19.5 0 36.7 7.2 51.7 21.7 13 13 22 29.5 27 49.5 3.5 0.5 9 2 16.5 4.5 11 5.5 16.5 15 16.5 28.5 0 2.5-2 7.3-6 14.2 32 18 48 43 48 75 0 9-3.5 21.5-10.5 37.5 13 7.5 19.5 18.5 19.5 33m-308.8 33v-9.7c0-11.5-5.6-22-16.9-31.5-11.2-9.5-22.6-14.2-34.1-14.2-14 0-27 3.2-39 9.7 26.5-1.5 56.5 13.8 89.9 45.7m-13.5-92.9c-7.5-8.5-14-17.2-19.5-26.2-21 5.5-31.5 11.7-31.5 18.7 6-0.5 14.7 0.6 26.2 3.4s19.7 4.1 24.8 4.1m45.7-23.2v-33c-12-2-19.3-3-21.7-3v11.2l21.7 24.7m97.4-21c-6-2.5-17.2-7.5-33.7-15v64.5c23.5-13.5 34.7-30 33.7-49.5m41.2 88.5-16.5-20.2c-10 7-20.1 14.1-30.4 21.4-10.3 7.2-19.1 15.4-26.6 24.4 22.5-12 47-20.5 73.4-25.5\&quot; fill=\&quot;#00160b\&quot;/&amp;gt;&amp;lt;/svg&amp;gt;&quot;,
		&quot;type&quot;: &quot;Creature — Bird&quot;,
		&quot;artist&quot;: &quot;Ovidio Cartagena&quot;,
		&quot;legal&quot;: &quot;mlvyhbc&quot;,
		&quot;restricted&quot;: &quot;&quot;,
		&quot;rules&quot;: &quot;Flying\n&amp;lt;svg width=\&quot;100\&quot; height=\&quot;100\&quot; enable-background=\&quot;new -945 -210.002 1045 730.002\&quot; version=\&quot;1.1\&quot; viewBox=\&quot;-945 -210 100 100\&quot; xml:space=\&quot;preserve\&quot; xmlns=\&quot;http://www.w3.org/2000/svg\&quot;&amp;gt;&amp;lt;g transform=\&quot;translate(0 -525)\&quot;&amp;gt;\t&amp;lt;circle cx=\&quot;-895\&quot; cy=\&quot;365\&quot; r=\&quot;50\&quot; fill=\&quot;#cac5c0\&quot;/&amp;gt;&amp;lt;path d=\&quot;m-859.67 373.92h-36.004l13.185-9.383c-4.898-3.887-10.566-5.828-16.984-5.828-3.211 0-5.414 0.613-6.59 1.836-1.184 1.227-1.777 3.445-1.777 6.654 0 8.873 4.563 18.34 13.691 28.396l-10.391 10.521c-12.09-14.705-18.129-27.844-18.129-39.424 0-6.928 2.086-12.447 6.27-16.545 4.18-4.098 9.746-6.148 16.668-6.148 8.453 0 17.664 3.215 27.641 9.635l7.728-13.182z\&quot; fill=\&quot;#0d0f0f\&quot;/&amp;gt;&amp;lt;/g&amp;gt;&amp;lt;/svg&amp;gt;: Add one mana of any color.&quot;,
		&quot;rulings&quot;: &quot;&quot;,
		&quot;reserved&quot;: &quot;0&quot;,
		&quot;altCardId&quot;: 0,
		&quot;imageId&quot;: -1,
		&quot;dataCardId&quot;: 53574,
		&quot;editionId&quot;: 586,
		&quot;rarity&quot;: &quot;R&quot;,
		&quot;editionCode&quot;: &quot;sld&quot;,
		&quot;finish&quot;: &quot;regular&quot;,
		&quot;deleted&quot;: 0,
		&quot;uuid&quot;: &quot;EF4A084815A24007A93A697EFB7B6E84&quot;,
		&quot;cardType&quot;: &quot;Creature — Bird&quot;,
		&quot;imageUuid&quot;: &quot;&quot;,
		&quot;nameId&quot;: 151,
		&quot;listUuid&quot;: &quot;51B2A9169E35442AA413EDCEA3E1B297&quot;,
		&quot;scryfallId&quot;: &quot;fdfeeb64-0f86-45e9-97e3-dcec72683164&quot;,
		&quot;price&quot;: 8.359999656677246,
		&quot;fmtPrice&quot;: &quot;$8.35&quot;,
		&quot;priceVariation&quot;: 0.0,
		&quot;fmtPriceVariation&quot;: &quot;↓ $0.00&quot;,
		&quot;tcgMid&quot;: 8.359999656677246,
		&quot;fmtTcgMid&quot;: &quot;$8.35&quot;,
		&quot;mkmTrend&quot;: 9.489999771118164,
		&quot;fmtMkmTrend&quot;: &quot;$9.49&quot;,
		&quot;ckRetail&quot;: 10.989999771118164,
		&quot;fmtCkRetail&quot;: &quot;$10.99&quot;,
		&quot;ckBuylist&quot;: 0.0,
		&quot;fmtCkBuylist&quot;: &quot;-&quot;,
		&quot;chRetail&quot;: 0.07999999821186066,
		&quot;fmtChRetail&quot;: &quot;0.08 TIX&quot;
	}]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you don&apos;t have Delver Pro, &quot;Birds of Paradise&quot; is returned.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Sample Code&lt;/h2&gt;
&lt;p&gt;Here&apos;s a simple example that polls the Delver Webhook Server endpoint continuously.
To install the dependencies, run &lt;code&gt;pip install requests&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import requests
import time

# Paste the endpoint URL here
webhook_url = &quot;https://api.delver.app/webhook/quick-brown-fox-jumps-over-the-lazy-dog&quot;

def poll_webhook_server(endpoint_url):
    while True:
        try:
            response = requests.get(endpoint_url)
            if response.status_code == 200:
                data = response.json()
                print(f&quot;Received event: {data}&quot;)
            elif response.status_code == 404:
                print(&quot;No new events&quot;)
            else:
                print(f&quot;Unexpected status code: {response.status_code}&quot;)
        except Exception as e:
            print(f&quot;Error polling webhook server: {e}&quot;)
        # Wait 1 second before next poll
        time.sleep(1)

if __name__ == &apos;__main__&apos;:
    poll_webhook_server(webhook_url)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Sample Self-Hosted Webhook Server&lt;/h2&gt;
&lt;p&gt;Here&apos;s a simple example to help you get started.
To install the dependencies, run &lt;code&gt;pip install flask&lt;/code&gt;.
Make sure to host this server over HTTPS or have a proxy service
like &lt;a href=&quot;https://ngrok.com/&quot;&gt;ngrok&lt;/a&gt; to provide a HTTPS endpoint for you.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from flask import Flask, request, jsonify

app = Flask(__name__)

# Function to add CORS headers
# This is necessary because requests come from a webview/browser on Delver X
# The browser may refuse to send the request after receiving a preflight
# that doesn&apos;t have the correct CORS headers
def add_cors_headers(response):
    response.headers[&apos;Access-Control-Allow-Origin&apos;] = &apos;*&apos;
    response.headers[&apos;Access-Control-Allow-Methods&apos;] = &apos;POST, OPTIONS&apos;
    response.headers[&apos;Access-Control-Allow-Headers&apos;] = &apos;Content-Type&apos;
    return response

@app.route(&apos;/&apos;, methods=[&apos;POST&apos;, &apos;OPTIONS&apos;])
def webhook():
    if request.method == &apos;OPTIONS&apos;:
        return add_cors_headers(jsonify({&apos;message&apos;: &apos;CORS preflight&apos;})), 200

    data = request.json
    print(data)

    if data[&apos;type&apos;] == &apos;card_scanned&apos;:
        print(f&quot;New card scanned: {data[&apos;card&apos;]}&quot;)
    elif data[&apos;type&apos;] == &apos;scanner_started&apos;:
        print(&quot;Scanner started&quot;)
    elif data[&apos;type&apos;] == &apos;scanner_paused&apos;:
        print(&quot;Scanner paused&quot;)

    return add_cors_headers(jsonify({&apos;message&apos;: &apos;OK&apos;})), 200

if __name__ == &apos;__main__&apos;:
    app.run(port=5000)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Troubleshooting&lt;/h2&gt;
&lt;p&gt;When using the Delver Webhook Server, make sure both Delver X and the device you using for sending the requests have access to the internet.&lt;/p&gt;
&lt;p&gt;You can try pinging &lt;code&gt;api.delver.app&lt;/code&gt; to see if the endpoint is reachable.&lt;/p&gt;
&lt;p&gt;If you&apos;re not using the Delver Webhook Server and is hosting your own server, here are a few things to check in case you don&apos;t receive webhook requests:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make sure the Webhook Endpoint is correct.&lt;/li&gt;
&lt;li&gt;Make sure the endpoint is reachable from the device running Delver X.&lt;/li&gt;
&lt;li&gt;Make sure the endpoint is HTTPS and CORS headers are returned.&lt;/li&gt;
&lt;li&gt;Inspect the developer console on Delver X and check for error messages of the type &lt;code&gt;failed to send request to &amp;lt;post URL&amp;gt; - code: &amp;lt;response code&amp;gt;&lt;/code&gt;. The code will be 0 if the endpoint is unreachable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Final Notes&lt;/h2&gt;
&lt;p&gt;If you find any issues, please let us know at &lt;a href=&quot;mailto:support@delverlab.com&quot;&gt;support@delverlab.com&lt;/a&gt;.
Suggestions and improvements are welcome!&lt;/p&gt;
</content:encoded></item></channel></rss>