App Manifest

Manifest overview

The Application Manifest is a JSON structure that provides the configuration options of your app within the Duda platform. The manifest includes:

Integration info

  • Endpoints to which Duda sends install, upgrade, and uninstall callbacks.
  • The scopes of APIs your app requires.
  • Webhooks your app is registered to and the webhook endpoint.
  • SSO base path to which Duda uses to SSO users into your app's iframe.
  • The Public RSA key Duda includes with SSO requests to your app's iframe.
  • The feature plans you offer and their properties.

Display info

  • The public profile of your application.
  • What languages your app supports.
  • Description of the feature plans you offer (branded and white-labeled).

See the following example:

{
    "uuid": "2257f749-03a7-45c2-9e8a-ae5f5e6e072c",
    "webhooks": {
        "endpoint": "https://temporary.com/endpoint",
        "events": [
            "CONTENT_LIB_CHANGED",
            "CONTENT_LIB_PUBLISHED",
            "PUBLISH"
        ]
    },
    "scopes": [
        "GET_WEBSITE",
        "UPDATE_PAGES",
        "SITE_WIDE_HTML",
        "GET_PAGES"
    ],
    "public_key": "MIIBI...",
    "installation_endpoint": "https://temporary.com/endpoint",
    "uninstallation_endpoint": "https://temporary.com/endpoint",
    "updowngrade_installation_endpoint": "https://temporary.com/endpoint",
    "base_sso_url": "https://temporary.com/sso",
    "supported_locales": [
        "en"
    ],
    "app_profile": {
        "en": {
            "app_name": "Display name",
            "app_logo": "https://temporary.com/imageLogo.png",
            "app_short_description": "A short description goes here.",
            "app_long_description": "This app can do this a that",
            "public_page": "https://temporary.com/ourproduct",
            "terms_of_service_page": "https://temporary.com/terms_en",
            "privacy_note_page": "https://temporary.com/privacy_en",
            "app_screenshots": [
                {
                    "image_url": "https://temporary.com/image.jpg",
                    "alt_text": "Description of image above"
                },
                {
                    "image_url": "https://temporary.com/image2.jpg",
                    "alt_text": "Description of image above"
                }
            ]
        }
    },
    "wl_app_profile": {
        "en": {
            "app_name": "White Labeled display name",
            "app_logo": "https://temporary.com/imageLogo.png",
            "app_short_description": "A short description goes here.",
            "app_long_description": "This app can do this a that",
            "app_screenshots": [
                {
                    "image_url": "https://temporary.com/image.jpg",
                    "alt_text": "Description of image above"
                },
                {
                    "image_url": "https://temporary.com/image2.jpg",
                    "alt_text": "Description of image above"
                }
            ]
        }
    },
    "app_plans": [
        {
            "plan_uuid": "332653a3-df51-45ce-a873-fbb0b1ccb49f",
            "plan_type": "free",
            "is_hidden": false,
            "plan_grade": 0,
            "plan_profiles": {
                "en": {
                    "plan_name": "First",
                    "plan_subtitle": "Start...",
                    "plan_features": [
                        "My first feature",
                        "<strong>My best feature</strong>",
                        "another feature"
                    ]
                }
            }
        },
        {
            "plan_uuid": "bd50e369-e7d4-4246-83d4-e190038e7f07",
            "plan_type": "paid",
            "is_hidden": false,
            "plan_grade": 1,
            "plan_profiles": {
                "en": {
                    "plan_name": "Second",
                    "plan_subtitle": "...Finish",
                    "plan_features": [
                        "My first feature",
                        "<strong>My best feature</strong>",
                        "another feature"
                    ]
                }
            }
        }
    ],
  "default_plan_uuid": "332653a3-df51-45ce-a873-fbb0b1ccb49f",
  "required_fields": ["EMAIL", "LOCATION"]
}

Updating the manifest

❗️

Sending a complete manifest

When updating the manifest, it's important that you send the entire manifest object to Duda. We do not currently support partial updates.

We recommend fetching the entire App Manifest from the /integrationhub/application/{{site_name}} endpoint, and then merging the response with any updates you'd like to apply. Lodash's merge is a great third-party method to support this workflow.

You can update your app's manifest using a REST API call:

curl -X POST https://api-sandbox.duda.co/api/integrationhub/application/{{appUuid}} \
-u 'AppAccountUser:AppAccountPass' \
-H 'Content-Type: application/json' \
-d '{{YOUR UPDATED MANIFEST JSON}}'
const fetch = require('node-fetch');

const app_uuid = A-UUID;
const token = Buffer.from('<api_user>:<api_pass>').to('base64');

fetch(`https://api-sandbox.duda.co/api/integrationhub/application/${app_uuid}`, {
  method: "POST",
  headers: {
    "Authorization": `Basic ${token}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ <updated manifest> })
})
.then(async (response) => {
  if (response.status >= 400) {
   console.log(await response.json());
  }
  // success
})
const fetch = require('node-fetch');
const _ = require('lodash');

const app_uuid = A-UUID;
const token = Buffer.from('<api_user>:<api_pass>').to('base64');
const url = `https://api-sandbox.duda.co/api/integrationhub/application/${app_uuid}`

// first we fetch the current manifest with a GET to the url
fetch(url).then((response) => response.json())
.then((manifest) => {
  // here's where we use Lodash's merge method to apply partial updates
  const newManifest = _.merge(manifest, { <updates> });
  // and a final POST request to apply those updates
  fetch(url, {
    method: "POST",
    headers: {
      "Authorization": `Basic ${token}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(newManifest);
  })
})

Unsupported actions

  • Add/delete plans
  • Change app or plan UUID
  • Set plan price
  • Change public key
  • Change scopes
  • Change plan type from free/trial to paid

URL Policies

  • All URLs must use the HTTPS protocol.
  • In order to comply with Duda’s White Label policy, paths should not include the string ‘duda’. You can use 'website_builder' instead.

🚧

Updating immutable properties

Sending a POST request to update immutable properties (such as UUID) will be ignored and return a successful 200 response code.

Publishing manifests to production

Making apps available in production is called releasing. In the releasing process, Duda takes the exact app manifest as it exists on sandbox and copies it to all Duda production environments. Duda will create the app in our production environment after you first publish the app.

Before publishing, Duda 'locks' the manifest to stabilize the version published to production. During the locking period, trying to update the manifest will return an error.

🚧

Webhook endpoints are not updated for old installations

For apps already in production and using webhooks, republishing the app does not update the webhooks endpoint of existing installations. Old installations will continue to send webhooks to the old endpoint.

Display

Item

Description

Comments/format

supported_locales

The locales the app supports. The list is displayed on the apps' more-info popup

Use the following ENUM: en, es, zh, pt, fr, de, tr, it, nl, fi, pl

app_profile

The information presented in the 'about' tab of the app's more-info popup.

app_profile["lang"]

Profile per language

App are not displayed if they don't have a valid profile.
Use the following enum: en, es_ar, zh, pt, fr, de, tr, it, nl, fi, pl

app_profile["lang"].app_name

The app name presented on the app's card, in the more-info popup and all other mentions of the app.

app_profile["lang"].app_logo

Branded logo

URL, png/jpg, minimum size 100x100px

app_profile["lang"]
.app_short_description

Presented on the app's card

The short description should be between 55-105 characters long.

app_profile["lang"]
.app_long_description

Presented in the more-info popup.

Supports HTML tags. A long description should be less than 500 characters long.

app_profile["lang"]
.public_page

A link to the app's public page

URL, HTTPS

app_profile["lang"]
.terms_of_service_page

A link to the app's terms of service

URL, HTTPS

app_profile["lang"]
.privacy_note_page

A link to the app's privacy note

URL, HTTPS

app_profile["lang"]
.app_screenshots

An array of screenshots with descriptions. Displayed in the more-info popup.

Object, URL + ALT tag, recommended size: 1,278 x 948 (4:3 aspect ratio)

wl_app_profile["lang"]

The profile presented to white-labeled users (not Duda aware).

Do no mention the app's branded name in the white-labeled profile.

wl_app_profile["lang"]
.app_logo

White labeled logo.

URL, png/jpg, minimum size 100x100px

wl_app_profile["lang"]
.app_short_description

Presented on the app's card.

Do no mention the app's branded name. The short description should be between 55-105 characters longs.

wl_app_profile["lang"]
.app_long_description

Presented in the more-info popup.

Supports HTML tags. Do no mention the app's branded name. The long description should be less than 500 characters longs.

wl_app_profile["lang"]
.app_screenshots

An array of screenshots with descriptions. Displayed in the more-info popup.

Object, URL + ALT tag, recommended size: 1,278 x 948 (4:3 aspect ratio). Do no mention the app's branded name.

visible_to_clients

Is the app visible to users of type 'client'

Boolean

default_plan_uuid

Use to define a plan which will be installed by default without asking the user to select a plan.

UUID of a free plan with grade 0.

required_fields

An array or mandatory fields that needs to be added to the site's content library before the application can in installed

Can be either "EMAIL" or "LOCATION"

Example Manifest in App Store

example app cardexample app card

example app card

example app panelexample app panel

example app panel


Did this page help you?