DomainPunch Logo

 A Service of Softnik Technologies

WMD SED - Custom Tools Developer Guide

System reference for building tools with AI assistance
Watch My Domains SED v6 Developer Reference AI-Assisted Development

This guide documents the WMD SED system - its architecture, deployment models, authentication, user and admin rights, and the full API - so that an AI assistant has the context needed to build a new custom tool. Tools can be built in any language or stack (PHP, Python, plain HTML and JavaScript, Node.js, and so on). This guide describes what the system does and how it works, not what files to include or which helper functions to call. UI and implementation decisions are entirely left to the tool builder.

What is Watch My Domains SED?

Watch My Domains Server Edition (WMD SED) is a self-hosted domain portfolio management platform. It provides organizations with a centralized system for tracking, monitoring, and governing their domain name assets across their full lifecycle.

Core capabilities include:

  • Domain inventory - a centralized, searchable database of all domains, with support for custom data columns, categories, and bulk operations
  • Expiry and renewal tracking - automated monitoring of registration and SSL certificate expiry dates, with configurable alerts
  • WHOIS and RDAP lookups - scheduled and on-demand retrieval of registry and registrar data, with historical change tracking
  • DNS monitoring - continuous visibility into DNS configuration, nameserver delegation, and record changes
  • SSL and HTTP checks - certificate validity, website availability, and HTTP response monitoring
  • Registrar integration - direct API connections to registrars for portfolio import and synchronization
  • Multi-user access control - role-based permissions with category-level and column-level access rights
  • Authentication - native username/password login with optional two-factor authentication (2FA) and SAML/SSO integration for enterprise identity providers
  • Web page monitoring - periodic HTTP checks that capture screenshots, detect changes in page content, and analyze cookies set by monitored domains
  • Reporting and alerts - scheduled CSV reports and email notifications for expiry events and data changes

WMD SED is designed to support DNRAM practices - treating domain names as managed resources that require the same visibility and governance as other critical infrastructure. More information on DNRAM is available at softnik.com/dnram.

WMD SED runs as a PHP web application on your own server and exposes a comprehensive API that gives programmatic access to all of its functionality. This guide covers how to build custom tools against that API.


What the API Can Do

The WMD SED API gives programmatic access to virtually everything the application can do. This includes:

  • Domain data - read, write, import and delete domain records; bulk edit columns across multiple domains
  • Lookups - queue and trigger domain WHOIS, DNS, SSL, HTTP, IP WHOIS, ping and subdomain lookups; monitor queue status
  • Categories and queries - create, edit and delete categories and auto-queries; manage domain membership
  • Custom columns - add, configure and delete custom data columns; set column-level access rights
  • Users - create, edit and delete users; configure access rights per user and per column
  • Reports - create and schedule CSV reports; trigger and configure email reports
  • DNS monitoring - enable and configure DNS change monitoring and alerts
  • Subdomains - retrieve subdomain and DNS record data
  • Web screenshots - take and retrieve web page screenshots (if the feature is enabled on the server)
  • WHOIS and RDAP - configure WHOIS and RDAP settings per TLD
  • Email - configure email settings and templates
  • Authentication and security - configure SAML/SSO, two-factor authentication (2FA) and session timeout settings
  • Branding - change the application logo and branding
  • Logs - access audit logs and system logs

The full API reference is at learn.domainpunch.com/wmdsed/api/. This guide covers the subset needed to build tools - authentication, session handling, deployment models, and the core domain data endpoints.


Architecture

Watch My Domains SED is a PHP web application that exposes all its functionality through a single API endpoint - api.php. Custom tools are clients of this API. They can be built in any language or stack - PHP, Python, plain HTML and JavaScript, Node.js, or anything else that can make HTTP requests and parse JSON. They can be embedded pages living inside the WMD installation folder, separate applications on the same server, or entirely external tools running on a different domain.

The API is stateful and session-based. All responses are JSON. A successful response always contains "status": "ok". Every call must be authenticated - either via a shared browser session or via an explicit login step.

Full official API reference: learn.domainpunch.com/wmdsed/api/


Deployment Models

There are three ways to build and deploy a tool against the WMD API. The right choice depends on where the tool is hosted and how it handles authentication.

1. Embedded tool (simplest)

The tool is a .php or .html file placed inside the WMD installation folder. The recommended location is a user-tools/ folder in the installation root:

wmdsed/user-tools/my-tool.php
wmdsed/user-tools/expiring-domains.php
wmdsed/user-tools/ai-built/my-tool.php

Placing user tools in user-tools/ keeps them clearly separate from the app's own tools/ folder, which contains pre-built tools distributed with WMD along with their associated JS and CSS files. Putting user files directly inside tools/ risks filename clashes and files being overwritten during app updates.

Because the tool is served from the same origin as WMD, it automatically inherits the active session cookie. No login step is needed - if the user is already logged in to WMD, the tool is authenticated. All API calls use credentials: 'same-origin' and the API URL is resolved from window.location at runtime (see Startup Context).

This is the lowest-friction option and the recommended starting point for most tools.

Resolving the API URL from any subfolder
Because a tool can live at any depth inside the installation, it cannot hardcode a relative path like ../api.php. Instead, walk up window.location.pathname one segment at a time, probing each candidate with api.php?sw=0. The first path that returns validate === 0 is the WMD root. This probe also serves as session validation - no separate check is needed.
async function findApiUrl() {
  const parts = window.location.pathname.split('/').filter(Boolean);
  for (let i = parts.length; i >= 0; i--) {
    const candidate = window.location.origin
      + (i > 0 ? '/' + parts.slice(0, i).join('/') : '')
      + '/api.php';
    try {
      const r = await fetch(candidate + '?sw=0', { credentials: 'same-origin' });
      const d = await r.json();
      if (d && d.validate === 0) return candidate;
    } catch (_) {}
  }
  return null; // not found or session expired
}

2. Same-origin standalone tool

The tool is a separate application on the same server and domain as WMD, but outside the WMD installation folder - for example at https://example.com/my-app/ while WMD lives at https://example.com/wmdsed/.

Whether the WMD session cookie is accessible depends on how WMD sets its cookie path. If the cookie is scoped to /wmdsed/, it will not be visible to pages at /my-app/. If WMD sets it at the root path /, it will be shared. This is determined by WMD's server configuration, not by the tool.

If the cookie is available, the tool can call api.php at its known absolute URL using credentials: 'same-origin', with no login step. If the cookie is not available, the tool must implement the full login flow described in model 3. The API URL is known and fixed in this model - no path-walking probe is needed.

3. Cross-origin / external tool

The tool runs on a different domain or server entirely. It has no access to the WMD session cookie and must authenticate explicitly using c=auth, then manage the session ID for all subsequent requests.

The login flow is:

  1. Call api.php?c=auth&user=username&pass=password
  2. Capture the session ID from the response - see the official session ID guide
  3. Include the session ID in every subsequent API request
  4. Call api.php?c=auth&logout=1 to end the session when done

Because credentials and session IDs are handled in application code, this pattern is best suited to server-side tools (PHP, Python, Node, etc.) rather than browser JavaScript, where credentials would be exposed in client-side code.

CORS

WMD does not set any CORS headers itself - it is a same-origin application by design and has no built-in CORS configuration. Browser-based JavaScript running on a different origin will have its requests blocked by the browser before they reach the API.

If you need cross-origin browser access to the WMD API, CORS headers must be added at the web server level, outside of WMD. The two most common setups:

Nginx

Add the following inside the location block that serves your WMD installation, or scope it specifically to api.php:

location /wmdsed/api.php {
    add_header Access-Control-Allow-Origin  "https://your-tool-domain.com";
    add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
    add_header Access-Control-Allow-Headers "Content-Type";
    add_header Access-Control-Allow-Credentials "true";

    if ($request_method = OPTIONS) {
        return 204;
    }
}

Apache

Add the following to your .htaccess in the WMD installation folder, or to the relevant <Directory> block in your virtual host config:

Header set Access-Control-Allow-Origin  "https://your-tool-domain.com"
Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"
Header set Access-Control-Allow-Headers "Content-Type"
Header set Access-Control-Allow-Credentials "true"

RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^ - [R=204,L]
Use a specific origin, not a wildcard
Do not use Access-Control-Allow-Origin: * - browsers block credentialed requests (cookies) when the origin is a wildcard. You must specify the exact origin of your tool. Also note that CORS headers only control browser behaviour - they do not add any server-side authentication or access control. The WMD session still needs to be valid for every request.

For most external tool scenarios, a server-side proxy is simpler and safer than configuring CORS - the proxy authenticates with WMD using the session ID pattern, and the browser only ever talks to the proxy on the same origin as the tool.


Startup Context

When a tool page loads, the following information must be available to the tool's JavaScript before any API calls are made. How this is obtained is an implementation detail - what matters is that the tool has these values:

ValueTypeDescription
Base URLstringAbsolute base URL of the WMD installation, e.g. https://example.com/wmdsed/. Resolved at runtime - see Tool Placement above.
API URLstringFull URL to the API endpoint, always <base_url>api.php. Resolved at runtime - see Tool Placement above.
Is AdminboolWhether the currently logged-in user has administrator rights.
Current UsernamestringThe logged-in user's name.

Session & Authentication

WMD uses PHP session-based authentication. How a tool authenticates depends on its deployment model - see Deployment Models above. For embedded and same-origin tools that have access to the session cookie, no explicit login step is needed. For external tools, authentication must be handled explicitly via c=auth.

Session cookie must be sent on every API request
For cookie-based tools, every fetch() call must include a credentials option. Use credentials: 'same-origin' for embedded and same-origin tools. Use credentials: 'include' only for genuine cross-origin requests where CORS headers are configured on the server. Without the correct setting the browser will not send the session cookie and the API will return a session error.

The validate field

Every API response includes a validate field. Your tool should check this on every response - not just at startup. The possible values are:

ValueConstantMeaning
0VALIDSession is valid - continue normally
1TIMEDOUTSession timed out - redirect to login
-1INVALIDSession is invalid - redirect to login
-2UNKNOWNSession state unknown - redirect to login
-3LIMITEDAccess limited - user has no access to this endpoint, or an endpoint-specific timeout has been reached. Handle gracefully rather than redirecting to login.

Because validate is present on every response, session monitoring comes for free from your normal API calls. There is no need for a separate polling mechanism - just check validate whenever you process a response and redirect if it is non-zero.

function handleResponse(data) {
  if (!data) return;
  if (data.validate !== 0) {
    // session timed out or logged out - redirect to login
    window.location.href = '../index.php';
    return;
  }
  // process data.rows, data.status etc. normally
}

Startup probe with ?sw=0

Before rendering any UI, you need to confirm the session is active. If your tool has no other API call to make at startup, use api.php?sw=0 - it is a minimal no-op call whose only purpose is to return a response containing validate.

const res  = await fetch(API_URL + '?sw=0', { credentials: 'same-origin' });
const data = await res.json();
if (!data || data.validate !== 0) {
    // session not valid - redirect to login
    return;
}

If your tool makes a real API call at startup (e.g. loading initial data), you can skip ?sw=0 entirely and just check validate on that first response instead. For embedded tools, the API URL discovery probe described in Deployment Models already serves as the startup session check.

Users & Rights

WMD has two user types: admin and regular user. The distinction affects both what the tool should show and what the API will permit.

CapabilityAdminRegular User
Read domain dataAll columnsOnly permitted columns - enforced automatically by the API
Write domain dataYesYes, within permitted columns
Write config values (c=admin)YesNo - API returns a permission error
Delete categories / auto-queriesYesNo
Add or edit categories / auto-queriesYesNo
Access all categoriesYesOnly categories explicitly assigned to their account

The API enforces column-level and category-level access automatically. A regular user requesting a restricted column via c=grid will simply not receive that column in the response - no error is raised. The tool does not need to filter the response; it can trust the API output.

Checking admin status

The admin flag is a boolean available at startup (see Startup Context). Use it to conditionally show admin-only UI and to guard any calls to admin-only endpoints. The API will reject admin-only calls from regular users regardless, but checking client-side avoids unnecessary failed requests.

User rights bitmask

A user's rights are available as a bitmask from c=get&t=users&oper=info (see API: Get). One important bit controls whether the user can see all domains regardless of category assignment. If a user does not have this right and is not an admin, query results should be filtered to only the category IDs assigned to that user - obtainable from the same endpoint's cids array.

Never rely solely on client-side access checks
The API enforces all access rules server-side. Client-side checks are for UX only - hiding UI elements that would result in permission errors. Always assume the API is the source of truth.

API Overview

All requests go to api.php. Requests should be sent over HTTPS. The standard URL structure is:

api.php?c=command&t=target&oper=operation

Every response is JSON. A successful call always returns "status": "ok". A failed call returns "status": "notok" with a description in the error field. Authenticated responses also include a validate field which is always 0 for a valid session.

Command (c=)AccessPurpose
authBothAuthenticate or log out
gridBothPaginated data tables - read, delete, edit rows
getBothFetch a single record, column metadata, config values, lookup queue
setBothUpdate domain data, queue lookups, manage category membership
listBothColumn metadata lists, category lists, domain history
addBothImport domains via CSV
adminAdminWrite config values and other admin operations

API: Authentication

All API commands require prior authentication. For embedded and same-origin tools the browser session handles this automatically. For external scripts, authenticate explicitly using the auth command. Once authenticated the session remains valid until the user logs out or the session times out.

Login

GETapi.php?c=auth&user=username&pass=password

Authenticates and creates a session.

ParameterNotes
cAlways auth
userThe user's login name
passThe user's password

On failure:

{ "status": "notok", "user": "", "group": "", "error": "Invalid name or password (1/6)" }

On success:

{
  "status": "ok",
  "user":   "myuser",
  "group":  "setupadmin",
  "error":  "",
  "userid": 0,
  "admin":  1,
  "url":    "https://example.com/wmdsed/"
}

The admin field is 1 if the user has administrator rights. The url field contains the absolute base URL of the WMD installation, which can be used to construct the full API URL for subsequent calls.

Logout

GETapi.php?c=auth&logout=1
Logs out and destroys the current session. The user and pass parameters are ignored when logout=1 is present.

Session ID pattern for PHP scripts

The standard stateful API works well for browser-based tools, but is awkward for server-side PHP scripts that need to authenticate and make API calls without a browser. The recommended approach is to create a custom copy of api.php that accepts a session ID as a URL parameter, allowing the script to manage its own session explicitly.

  1. Copy api.php to a new file - for example myapi.php - in the same installation folder. Do not modify the original api.php.
  2. At the top of myapi.php, before the require 'lib/php/loader.php' line, add:
    if (isset($_REQUEST['seid'])) {
        $seid = $_REQUEST['seid'];
        // validate $seid contains only safe characters before using it
        session_id($seid);
    }
  3. In your PHP script, generate a session ID, pass it to myapi.php as the seid parameter, then authenticate and make API calls using that same ID:
    $seid = session_create_id('myprefix-');
    $apiUrl = "https://example.com/wmdsed/myapi.php?seid=$seid";
    // First call: authenticate
    // Subsequent calls: use the same $apiUrl - session is now active
Security considerations
Passing a session ID as a URL parameter has security implications - URLs can appear in server logs and browser history. Restrict access to myapi.php to trusted IP addresses (check $_SERVER['REMOTE_ADDR']) and use it only within a trusted network or intranet. Always use HTTPS.

Sample myapi.php

Place this file in the WMD installation root alongside the original api.php. It adds session ID injection and optional IP allowlisting, then hands off to the standard loader unchanged.

<?php
/**
 * myapi.php - WMD SED custom API entry point for server-side scripts.
 *
 * Place in the WMD installation root (same folder as api.php).
 * Do NOT modify the original api.php.
 *
 * Usage: call this file instead of api.php, passing a session ID
 * as the 'seid' parameter, e.g.:
 *   https://example.com/wmdsed/myapi.php?seid=abc123&c=auth&user=user&pass=xxx
 */

// ── Optional: restrict access to specific IP addresses ──────────────────────
// $allowed_ips = ['127.0.0.1', '192.168.1.10'];
// if (!in_array($_SERVER['REMOTE_ADDR'], $allowed_ips)) {
//     http_response_code(403);
//     exit(json_encode(['status' => 'notok', 'error' => 'Access denied']));
// }

// ── Session ID injection ─────────────────────────────────────────────────────
// Must happen before session_start(), which loader.php triggers internally.
if (isset($_REQUEST['seid'])) {
    $seid = $_REQUEST['seid'];
    // Allow only characters that are valid in a PHP session ID.
    if (preg_match('/^[a-zA-Z0-9,\-]+$/', $seid)) {
        session_id($seid);
    }
}

// ── Hand off to the standard WMD loader ─────────────────────────────────────
// Everything below this line is identical to api.php.
require 'lib/php/loader.php';

And a minimal PHP client script showing the full authenticate → query → logout cycle:

<?php
/**
 * Example: fetch domains expiring in the next 30 days via myapi.php.
 */

$base    = 'https://example.com/wmdsed/';
$api     = $base . 'myapi.php';
$seid    = session_create_id('ext-');   // generate a unique session ID

// Helper: GET request carrying the session ID
function wmd_get(string $api, string $seid, string $query): array {
    $url = $api . '?seid=' . urlencode($seid) . '&' . $query;
    $ch  = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
    ]);
    $body = curl_exec($ch);
    curl_close($ch);
    return json_decode($body, true) ?? [];
}

// 1. Authenticate
$auth = wmd_get($api, $seid, 'c=auth&user=myuser&pass=mypassword');
if (($auth['status'] ?? '') !== 'ok') {
    die('Login failed: ' . ($auth['error'] ?? 'unknown'));
}

// 2. Query domains expiring within 30 days
$today  = date('Y-m-d');
$future = date('Y-m-d', strtotime('+30 days'));
$filter = urlencode("registry_expiry>='$today' AND registry_expiry<='$future'");

$result = wmd_get($api, $seid,
    "c=grid&t=domain&columns=domain,registry_expiry&page=1&rows=500" .
    "&sidx=registry_expiry&sord=asc&query=$filter"
);

foreach ($result['rows'] ?? [] as $row) {
    echo $row['domain'] . ' expires ' . $row['registry_expiry'] . PHP_EOL;
}

// 3. Logout
wmd_get($api, $seid, 'c=auth&logout=1');

API: Grid

Paginated access to domain, category, DNS, SSL and auto-query data tables.

Read grid data

GETapi.php?c=grid&t=domain&columns=domain,registry_expiry&page=1&rows=100
Returns a page of rows. Column names may use d. prefix for the domain table and s. for the subdomain table.
ParameterNotes
tdomain, dns, ssl, category, query
columnsComma-separated column names. Use d. / s. prefixes where needed.
pagePage number, starting from 1
rowsRows per page
sidxSort column name
sordasc or desc
cidFilter by category ID (domain grid only)
aqidFilter by auto-query ID (domain grid only)
queryOptional additional SQL filter expression
{ "page": 1, "total": 5, "records": "487", "rows": [ { "id": "23", "domain": "example.com", ... } ] }
total vs records
total is the number of pages. records is the total row count as a string. Calculate total pages yourself: Math.ceil(parseInt(records) / rowsPerPage).
Success condition
A grid response is successful when x.total >= 0 || x.status === 'ok'. Do not rely on status: "ok" alone.
validate is not present on c=grid responses
c=grid is the only endpoint that does not include a validate field in its JSON response. All other endpoints (c=get, c=set, c=list, c=admin, etc.) do return validate. For grid requests, session errors are signalled via an HTTP-level failure (non-2xx status code). Check response.ok before parsing the JSON and treat an HTTP error as a session timeout.

Delete rows

POSTapi.php?c=grid&t=domain&oper=del&id=23,24,27
Permanently deletes rows. id is a comma-separated list of row IDs. Deleting categories or auto-queries requires admin rights.

Edit a row

POSTapi.php?c=grid&t=domain&oper=edit&id=23&ns1=ns1.example.com
Updates one or more column values for a single row. Pass column name/value pairs as additional parameters.
{ "status": "ok", "updated": 1 }

API: Get

Fetch a single domain record, specific columns, current user info, or lookup queue status.

Full domain record

GETapi.php?c=get&t=domain&id=211
Returns the complete record for a domain. The response includes:
  • data - all column values for the domain
  • info - metadata for each column (label, fieldtype, editable, gridview, width)
  • cids - array of category IDs the domain belongs to
  • luq - current lookup queue entries for the domain
  • subdomains - subdomain hostnames
Columns the user has no access to are suppressed automatically.

Specific columns only

GETapi.php?c=get&t=domain&id=211&oper=column&columns=domain,registry_expiry
Returns only the requested columns for the domain.
{ "status": "ok", "data": [ { "domain": "softnik.org", "registry_expiry": "2024-11-29" } ] }

Current user info

GETapi.php?c=get&t=users&oper=info
Returns information about the currently authenticated user. All fields are nested under a data object.
{
  "status": "ok", "validate": 0,
  "data": {
    "rights": 65535,
    "uid":    0,
    "cids":   [ { "cid": 2, "name": "Keyword Domains" }, ... ],
    "license": { ... }
  }
}

Note: this endpoint does not return the username. Store the username from the c=auth login response if you need it later (e.g. in sessionStorage). The rights field is a bitmask - a value of 65535 indicates full administrator rights. The cids array lists the categories the user can access.

Lookup queue status

GETapi.php?c=get&t=luq&id=173
Returns the lookup queue status for a domain. Key fields:
  • luqinfo - array of pending queue entries. Empty array means the lookup is complete.
  • queue_size - total pending lookups across all domains on the server
  • last_lookup_at - timestamp of the last completed lookup

API: Set

Update domain column values and manage the lookup queue.

Bulk edit one column across multiple domains

POSTapi.php?c=set&t=domain&oper=edit
POST body: id=186,187,188&columns=customer_name&data=ABC+Inc. Sets the same value for one column across all specified domains.
{ "status": "ok", "updated": 3 }

Set multiple columns for one domain

POSTapi.php?c=set&t=domain&oper=column
POST body: sid=186&customer_name=ABC+Inc&invoice_no=A5690. Pass any number of column name/value pairs. Note: uses sid as the identifier, not id.
{ "status": "ok", "count": 2 }

Queue a domain lookup

POSTapi.php?c=set&t=luq&oper=add
POST body: what=1&id=173,174&ri=300. Adds domains to the background lookup queue. what is a bitmask of lookup types: 1=domain WHOIS, 2=root DNS, 4=HTTP, 64=SSL, 128=IP WHOIS, 512=subdomains. Combine types with bitwise OR. ri is the minimum refresh interval in seconds.

API: List

Retrieve column metadata and category information.

All domain column metadata

GETapi.php?c=list&t=domain&oper=columns
Returns metadata for every column the current user can access. Restricted columns are excluded automatically.
{
  "columns": {
    "registry_expiry": {
      "label":     "Domain Expiry",
      "editable":  "1",
      "gridview":  "1",
      "custom":    "0",
      "fieldtype": "date",
      "width":     "123",
      "acslevel":  "0"
    }
  }
}
FieldMeaning
labelHuman-readable column name
editable"1" if the column can be written via the API
gridview"1" if the column is intended for table/grid display
custom"1" if this is a user-defined custom column
fieldtypestring, integer, float, boolean, date, datetime, text
widthLast saved display width in pixels

Add &group=type to receive columns grouped by fieldtype instead of a flat object.

Categories accessible to current user

GETapi.php?c=list&t=category&oper=user
Returns the categories the current user can access. Results are in the ids array. Each entry includes id, name, caticon (icon filename), sortindex, and userids (array of user IDs that have access).
{
  "status": "ok",
  "validate": 0,
  "ids": [
    { "id": "2", "name": "Keyword Domains", "caticon": "folder-gray.png", "sortindex": "1", "userids": [1] },
    { "id": "3", "name": "Parked Domains",  "caticon": "folder-gray.png", "sortindex": "2", "userids": [1] }
  ]
}

Category ID 1 is the virtual "All Domains" category and is not included in this response. Alternatively, use c=grid&t=category&columns=name,sortindex,caticon&page=1&rows=50&sidx=sortindex&sord=asc to retrieve categories via the grid endpoint.

Category membership for specific domains

GETapi.php?c=list&t=category&oper=domain&id=40,41,42
Returns a map of domain ID → array of category objects the domain belongs to. Domains the user cannot access are suppressed.
{ "categories": { "41": [ { "cid": 6, "name": "Bookmarked Domains" }, ... ] } }

API: Add (Domain Import)

POSTapi.php?c=add&t=domain&oper=csv
Imports domains from a CSV file. The request must be a multipart form POST containing:
  • csv_file - the CSV file. Must have a header row with column names.
  • csv_sep - field separator, default ,
  • cid - optional category ID to assign imported domains to
Unknown columns in the CSV are silently ignored. Only columns where editable=1 can be set via import.
{ "status": "ok", "added": 15 }

API: Config Store

A simple server-side key-value store for saving tool settings. Config is global - shared across all users. There is no per-user config store in WMD. Writing requires admin rights; reading is available to all users.

POSTapi.php?c=get&t=config&oper=getBoth users
Reads a config value. POST body: configname=config_my_key. Returns the stored value (a raw string) in the data field. Parse it as JSON if the value was stored as JSON.
POSTapi.php?c=admin&t=config&oper=setAdmin only
Writes a config value. POST body: configname=config_my_key&configdata={"any":"json"}. configdata is stored as a raw string - JSON-encode it before sending.
Key naming rules
Config keys are stored with a config_ prefix - always include it in the configname parameter. Keys must use only letters, digits and underscores. Hyphens cause a validation error. Example: store as config_my_tool_settings.
No per-user config writes
Config writes require admin rights. For browser-specific user preferences that do not need to persist across devices, localStorage is acceptable - but make this clear to the user, as those settings will not roam to other browsers or devices.

API: Category Operations

Add or remove domains from categories. These operations work on the category membership table, not the domain data itself.

POSTapi.php?c=set&t=category&oper=addto
Adds one or more domains to one or more categories. POST body: cid=2,5&id=23,24,27. Both cid and id accept comma-separated lists.
{ "status": "ok", "added": 6 }
POSTapi.php?c=set&t=category&oper=delfrom
Removes one or more domains from one or more categories. POST body: cid=5&id=23,24.
{ "status": "ok" }
Category ID 1 is "All Domains"
Category ID 1 is a virtual category - every domain is implicitly a member. Do not attempt to add or remove domains from it. Filter it out of any category picker UI.

Column width persistence

POSTapi.php?c=admin&t=domain&oper=setAdmin only
Saves a user-resized column width server-side. POST body: name=registry_expiry&width=220. For virtual columns that have no server-side backing, save widths to localStorage instead.

Further Reading

This guide covers the bare minimum needed to build a working tool against the WMD API - authentication, session handling, deployment models, and the core data endpoints. The full API is considerably more extensive. Through the API you can also:

  • Add, edit and delete custom domain columns and set column-level access rights
  • Create, edit and delete users and configure their access rights
  • Create and schedule CSV reports and trigger email reports
  • Schedule and trigger domain, DNS, SSL and HTTP lookups
  • Retrieve subdomain and DNS record data
  • Configure WHOIS and RDAP settings per TLD
  • Enable and configure DNS change monitoring
  • Take and retrieve web page screenshots (if the feature is enabled)
  • Configure email settings and templates
  • Configure SAML/SSO and two-factor authentication (2FA)
  • Set the default session timeout (native mode)
  • Change branding and logo
  • Access audit logs and system logs

The full API reference is available at learn.domainpunch.com/wmdsed/api/.

↑ Back to top
Close