Skip to main content

Duda Sites Service

๐Ÿ“– Overviewโ€‹

Service Path: external/Integrations/Duda/services/sites.service.js

The Duda Sites service provides comprehensive site management for the Duda website builder platform. Core responsibilities include:

  • Site Management: Create, read, update, and delete Duda websites
  • Publishing: Publish and unpublish sites
  • Analytics: Retrieve site analytics data
  • Form Data: Access form submissions from Duda sites
  • Templates: Get template information
  • Plan Management: Set site subscription plans

๐Ÿ—„๏ธ Collections Usedโ€‹

  • Stores Duda API username and password for authentication

๐Ÿ”„ Data Flowโ€‹

Site Creation Flowโ€‹

sequenceDiagram
participant Client
participant SitesService
participant ConfigDB
participant DudaAPI

Client->>SitesService: createSite(dudaHeader, body, account_id)

SitesService->>ConfigDB: Find API credentials
ConfigDB-->>SitesService: Duda credentials

alt Credentials Not Found
SitesService-->>Client: 404 - Api token not found
else Credentials Found
SitesService->>SitesService: Generate Basic Auth token
SitesService->>SitesService: Add external_uid to site_data

SitesService->>DudaAPI: POST /sites/multiscreen/create
Note over SitesService,DudaAPI: Authorization: Basic {token}

DudaAPI-->>SitesService: Site created response
SitesService-->>Client: Site data
end

style SitesService fill:#e3f2fd
style DudaAPI fill:#fff4e6

Site Publishing Flowโ€‹

flowchart TD
A[Publish Request] --> B[Fetch Duda credentials]
B --> C{Credentials exist?}

C -->|No| D[Throw 404 error]
C -->|Yes| E[Generate Basic Auth token]

E --> F[POST to Duda API /publish/:id]
F --> G{Publish successful?}

G -->|Yes| H[Return true]
G -->|No| I[Throw error]

D --> J[End]
H --> J
I --> J

style F fill:#e8f5e9
style H fill:#c8e6c9

๐Ÿ”ง Business Logic & Functionsโ€‹

getSites(dudaHeader, account_id)โ€‹

Purpose: Retrieve all Duda sites for a specific account by external ID

Parameters:

  • dudaHeader (ObjectId) - Config ID containing Duda API credentials
  • account_id (ObjectId) - DashClicks account ID (used as external_uid in Duda)

Returns:

// Array of site objects
[
{
site_name: String,
site_domain: String,
site_business_info: Object,
site_seo: Object,
site_data: {
external_uid: String, // DashClicks account_id
},
// ... other Duda site fields
},
];

Business Logic Flow:

  1. Fetch API Credentials

    let query = await Config.findById(dudaHeader);

    if (!query) {
    throw notFound('Api token not found');
    }
  2. Generate Authentication Token

    const access_token = utils.base64(query);
    // Encodes username:password to Base64
  3. Call Duda API

    let options = {
    method: 'GET',
    url: `${DUDA_SITES_DOMAIN}/byexternalid/${account_id}`,
    headers: {
    'Content-Type': 'application/json',
    authorization: `Basic ${access_token}`,
    },
    };
    const response = await axios(options);

    return response.data;

API Endpoint: GET https://api.duda.co/api/sites/multiscreen/byexternalid/:account_id

Key Business Rules:

  • External UID: Uses DashClicks account_id as Duda's external_uid for tracking
  • Basic Auth: Requires Base64-encoded username:password from Config
  • Account Isolation: Returns only sites belonging to specified account

getSite(dudaHeader, id)โ€‹

Purpose: Retrieve a single Duda site by site ID

Parameters:

  • dudaHeader (ObjectId) - Config ID for Duda credentials
  • id (String) - Duda site ID

Returns:

{
site_name: String,
site_domain: String,
site_default_domain: String,
site_business_info: {
business_name: String,
address: Object,
phone: String,
email: String
},
site_seo: {
og_image: String,
title: String,
description: String
},
site_data: {
external_uid: String
},
creation_date: String,
last_published_date: String,
last_reset_by: String,
account_name: String,
// ... more Duda fields
}

Business Logic Flow:

  1. Fetch credentials from Config
  2. Generate Basic Auth token
  3. Call Duda API: GET /sites/multiscreen/:id
  4. Return site details

API Endpoint: GET https://api.duda.co/api/sites/multiscreen/:id

Key Business Rules:

  • Direct Access: No account filtering, requires exact site ID
  • Detailed Data: Returns complete site configuration including SEO and business info

createSite(dudaHeader, body, account_id)โ€‹

Purpose: Create a new Duda website

Parameters:

  • dudaHeader (ObjectId) - Config ID for credentials
  • body (Object) - Site creation data
  • account_id (ObjectId) - DashClicks account ID

Request Body Structure:

{
template_id: String, // Optional: Duda template to use
site_data: {
site_domain: String, // Custom domain
site_business_info: Object, // Business information
site_seo: Object, // SEO settings
// ... other site configuration
},
default_domain_prefix: String // Subdomain for default Duda domain
}

Returns:

{
site_name: String, // Generated site ID
site_domain: String,
site_default_domain: String,
// ... complete site data
}

Business Logic Flow:

  1. Validate Request Body

    if (Object.keys(body).length <= 0) {
    throw badRequest('Invalid request body.');
    }
  2. Inject External UID

    body.site_data = {
    ...(body.site_data ?? {}),
    external_uid: account_id, // Track ownership
    };
  3. Create Site via Duda API

    const options = {
    method: 'POST',
    url: `${DUDA_SITES_DOMAIN}/create`,
    headers: {
    'content-type': 'application/json',
    authorization: `Basic ${access_token}`,
    },
    data: body,
    };
    const response = await axios(options);

    return response.data;

API Endpoint: POST https://api.duda.co/api/sites/multiscreen/create

Key Business Rules:

  • External UID Injection: Automatically adds DashClicks account_id to site_data
  • Template Support: Can create from template or blank site
  • Default Domain: Duda generates default subdomain (e.g., sitename.multiscreensite.com)

deleteSites(dudaHeader, id)โ€‹

Purpose: Delete a Duda site permanently

Parameters:

  • dudaHeader (ObjectId) - Config ID
  • id (String) - Duda site ID to delete

Returns: true on success

Business Logic Flow:

  1. Fetch credentials
  2. Generate auth token
  3. Call DELETE endpoint
  4. Return success boolean

API Endpoint: DELETE https://api.duda.co/api/sites/multiscreen/:id

Key Business Rules:

  • Permanent Deletion: Cannot be undone
  • No Validation: Doesn't check if site belongs to account (relies on Duda API permissions)

updateSites(dudaHeader, id, requestBody)โ€‹

Purpose: Update an existing Duda site configuration

Parameters:

  • dudaHeader (ObjectId) - Config ID
  • id (String) - Site ID to update
  • requestBody (Object) - Updated site data

Request Body Example:

{
site_data: {
site_domain: 'newdomain.com',
site_business_info: {
business_name: 'Updated Business Name',
phone: '555-0100'
}
}
}

Returns: true on success

Business Logic Flow:

  1. Validate Request Body

    if (Object.keys(requestBody).length <= 0) {
    throw badRequest('Request body required.');
    }
  2. Update via Duda API

    var options = {
    method: 'POST',
    url: `${DUDA_SITES_DOMAIN}/update/${id}`,
    headers: {
    'Content-Type': 'application/json',
    authorization: `Basic ${access_token}`,
    },
    data: requestBody,
    };
    await axios(options);

    return true;

API Endpoint: POST https://api.duda.co/api/sites/multiscreen/update/:id

Key Business Rules:

  • Partial Updates: Only provided fields are updated
  • POST Method: Uses POST instead of PUT/PATCH

publishSites(dudaHeader, id)โ€‹

Purpose: Publish a Duda site to make it live

Parameters:

  • dudaHeader (ObjectId) - Config ID
  • id (String) - Site ID to publish

Returns: true on success

Business Logic Flow:

let options = {
method: 'POST',
url: `${DUDA_SITES_DOMAIN}/publish/${id}`,
headers: {
'Content-Type': 'application/json',
authorization: `Basic ${access_token}`,
},
};
await axios(options);

return true;

API Endpoint: POST https://api.duda.co/api/sites/multiscreen/publish/:id

Key Business Rules:

  • Live Deployment: Makes site publicly accessible
  • No Confirmation: Immediate publish without preview
  • Updates Last Published Date: Duda tracks publish timestamp

unpublishSites(dudaHeader, id)โ€‹

Purpose: Unpublish a Duda site to take it offline

Parameters:

  • dudaHeader (ObjectId) - Config ID
  • id (String) - Site ID to unpublish

Returns: true on success

API Endpoint: POST https://api.duda.co/api/sites/multiscreen/unpublish/:id

Key Business Rules:

  • Takes Site Offline: Site becomes inaccessible to public
  • Preserves Data: Content is not deleted, can be republished

getTemplate(dudaHeader, builderID)โ€‹

Purpose: Get Duda template information by template ID

Parameters:

  • dudaHeader (ObjectId) - Config ID
  • builderID (String) - Duda template ID

Returns:

{
template_id: String,
template_name: String,
preview_url: String,
thumbnail_url: String,
desktop_thumbnail_url: String,
tablet_thumbnail_url: String,
mobile_thumbnail_url: String
}

API Endpoint: GET https://api.duda.co/api/sites/multiscreen/templates/:builderID

Key Business Rules:

  • Template Info Only: Returns metadata, not template content
  • Used for Template Selection: Helps users choose templates before site creation

getAnalytics(dudaHeader, params, builder_id)โ€‹

Purpose: Retrieve site analytics data for a date range

Parameters:

  • dudaHeader (ObjectId) - Config ID
  • params (Object) - Query parameters
    • from (String) - Start date (YYYY-MM-DD)
    • to (String) - End date (YYYY-MM-DD)
    • dimension (String) - Analytics dimension (e.g., 'system', 'geo')
  • builder_id (String) - Duda site ID

Returns:

{
site_name: String,
date_range: {
from: String,
to: String
},
activities: [
{
dimension: String,
data: [
{
activity: String,
value: Number
}
]
}
]
}

Business Logic Flow:

let options = {
method: 'GET',
url: `https://api.duda.co/api/analytics/site/${builder_id}`,
headers: {
'Content-Type': 'application/json',
authorization: `Basic ${access_token}`,
},
params, // Includes from, to, dimension
};
const response = await axios(options);

return response.data;

API Endpoint: GET https://api.duda.co/api/analytics/site/:builder_id

Key Business Rules:

  • Date Range Required: Must specify from and to dates
  • Dimension Support: Can segment by system, geo, etc.
  • Activity Metrics: Returns pageviews, unique visits, etc.

getFormData(dudaHeader, params, id)โ€‹

Purpose: Retrieve form submissions from a Duda site

Parameters:

  • dudaHeader (ObjectId) - Config ID
  • params (Object) - Query parameters
    • from (String) - Start date
    • to (String) - End date
  • id (String) - Duda site ID

Returns:

[
{
form_title: String,
message: Object, // Form field values
date: String,
ip: String,
},
];

API Endpoint: GET https://api.duda.co/api/sites/multiscreen/get-forms/:id

Key Business Rules:

  • Date Filtering: Returns submissions within date range
  • All Forms: Includes all forms from the site
  • Field Data: message object contains all form fields

setSitesPlan(dudaHeader, id, plan)โ€‹

Purpose: Set or update the subscription plan for a Duda site

Parameters:

  • dudaHeader (ObjectId) - Config ID
  • id (String) - Duda site ID
  • plan (String) - Plan identifier (e.g., 'BASIC', 'PREMIUM')

Returns: true on success

API Endpoint: POST https://api.duda.co/api/sites/multiscreen/:id/plan/:plan

Key Business Rules:

  • Plan Management: Controls site features based on plan
  • Billing Impact: May affect Duda billing

๐Ÿ”€ Integration Pointsโ€‹

Website Creation Workflowโ€‹

const sitesService = require('./services/sites.service');

// Step 1: Create site from template
const site = await sitesService.createSite(
dudaConfigId,
{
template_id: 'template_123',
default_domain_prefix: 'mybusiness',
site_data: {
site_business_info: {
business_name: 'My Business',
phone: '555-0100',
},
},
},
accountId,
);

// Step 2: Publish site
await sitesService.publishSites(dudaConfigId, site.site_name);

// Step 3: Set plan
await sitesService.setSitesPlan(dudaConfigId, site.site_name, 'PREMIUM');

Analytics Dashboardโ€‹

// Get analytics for last 30 days
const analytics = await sitesService.getAnalytics(
dudaConfigId,
{
from: '2025-09-09',
to: '2025-10-09',
dimension: 'system',
},
siteId,
);

console.log(
`Pageviews: ${analytics.activities[0].data.find(d => d.activity === 'pageviews').value}`,
);

Form Submission Integrationโ€‹

// Get form submissions
const forms = await sitesService.getFormData(
dudaConfigId,
{
from: '2025-10-01',
to: '2025-10-09',
},
siteId,
);

// Process form submissions
forms.forEach(form => {
console.log(`Form: ${form.form_title}`);
console.log(`Submitted: ${form.date}`);
console.log(`Data:`, form.message);
});

๐Ÿงช Edge Cases & Special Handlingโ€‹

Missing API Credentialsโ€‹

All Functions Check for Credentials:

let query = await Config.findById(dudaHeader);
if (!query) {
throw notFound('Api token not found');
}

Error: 404 - Api token not found

Empty Request Bodyโ€‹

createSite and updateSites Validation:

if (Object.keys(body).length <= 0) {
throw badRequest('Invalid request body.');
}

Error: 400 - Invalid request body

External UID Injectionโ€‹

Automatic Account Tracking:

body.site_data = {
...(body.site_data ?? {}),
external_uid: account_id, // Always injected
};

Duda API Errorsโ€‹

Axios Error Handling:

try {
const response = await axios(options);
return response.data;
} catch (error) {
// Axios automatically throws for 4xx/5xx responses
// Error includes response data from Duda
throw error;
}

โš ๏ธ Important Notesโ€‹

  1. Authentication: All functions require valid Duda API credentials stored in Config collection with Base64 encoding.

  2. External UID: DashClicks account_id automatically added to site_data.external_uid for ownership tracking.

  3. Error Handling: Uses custom error utilities (notFound, badRequest) for consistent error responses.

  4. Environment Variables: DUDA_SITES_DOMAIN must be set (typically https://api.duda.co/api/sites/multiscreen).

  5. Basic Auth: Duda API uses Basic Authentication with username:password Base64-encoded.

  6. No Async Validation: Functions don't validate site ownership before operations (relies on Duda API permissions).

  7. Permanent Operations: Delete and unpublish operations cannot be undone.

  8. Form Data Limitations: Form retrieval limited by Duda API date range restrictions.

  9. Analytics Dimensions: Supported dimensions depend on Duda API capabilities (system, geo, etc.).

  10. Plan Management: Plan changes may have billing implications on Duda side.

  11. Template Access: Template retrieval requires template ID, used primarily during site creation.

  12. Publishing: Sites must be published to be publicly accessible; updates to unpublished sites are not visible.

๐Ÿ’ฌ

Documentation Assistant

Ask me anything about the docs

Hi! I'm your documentation assistant. Ask me anything about the docs!

I can help you with:
- Code examples
- Configuration details
- Troubleshooting
- Best practices

Try asking: How do I configure the API?
09:30 AM