Docs Advanced Webhook Configuration

Webhook Configuration

Configure inbound webhooks from AdminLocks Cloud for remote approvals, snapshot triggers, and policy deployment across your connected sites.

Advanced guide 6 min read

Overview

AdminLocks Cloud communicates with your WordPress sites through inbound webhooks. When an operator takes an action in the Cloud dashboard — such as approving a client request, triggering a snapshot, or deploying a policy — Cloud sends a signed HTTP POST request to your site's webhook endpoint.

This architecture means your WordPress site does not need to poll the Cloud for updates. Actions initiated in the Cloud dashboard are delivered to your site in near real-time, typically within one to two seconds.

The webhook system supports three action types:

Endpoint URL

The webhook endpoint is registered automatically when AdminLocks is activated. The full URL is:

POST https://yoursite.com/wp-json/adminlocks/v1/cloud-webhook

This endpoint is publicly accessible (it does not require WordPress authentication) because it uses its own HMAC-based authentication scheme. Your site must be reachable from the internet for Cloud webhooks to work — sites behind HTTP basic auth, IP restrictions, or maintenance mode may need exceptions for requests from cloud.adminlocks.com.

If your site uses a non-standard REST API prefix (changed via the rest_url_prefix filter), adjust the endpoint URL accordingly. AdminLocks uses the standard WordPress REST API registration, so the endpoint follows whatever prefix your site is configured to use.

Authentication

Every webhook request includes an X-AdminLocks-Signature header containing an HMAC-SHA256 signature of the request body. The signature is computed using your site's Cloud API key as the secret.

The verification process on your WordPress site works as follows:

  1. AdminLocks reads the raw request body
  2. It retrieves the stored Cloud API key from the adminlocks_cloud_api_key option
  3. It computes hash_hmac('sha256', $request_body, $api_key)
  4. It compares the computed hash to the value in the X-AdminLocks-Signature header using a timing-safe comparison
  5. If the signatures do not match, the request is rejected with a 403 Forbidden response
// How AdminLocks verifies the signature (simplified)
$body      = file_get_contents('php://input');
$api_key   = get_option('adminlocks_cloud_api_key');
$expected  = hash_hmac('sha256', $body, $api_key);
$signature = $_SERVER['HTTP_X_ADMINLOCKS_SIGNATURE'] ?? '';

if (!hash_equals($expected, $signature)) {
    return new WP_Error('forbidden', 'Invalid signature', ['status' => 403]);
}

If you rotate your Cloud API key, webhooks will fail until the new key is saved on both the WordPress site and in the Cloud dashboard. Always update both sides simultaneously to avoid downtime.

Supported Actions

Every webhook payload follows the same envelope structure:

{
  "action": "action_name",
  "data": {
    // Action-specific fields
  }
}

The action field determines how the data object is processed. Unrecognized actions are ignored and return a 200 OK response to prevent retry loops.

approval_reviewed

Sent when an operator approves or denies a client request from the Cloud dashboard. This syncs the decision back to the WordPress site so the local approval record is updated.

FieldTypeDescription
approval_idintegerThe local WordPress approval ID
statusstringNew status: approved or denied
notestringOptional reviewer note explaining the decision
{
  "action": "approval_reviewed",
  "data": {
    "approval_id": 42,
    "status": "approved",
    "note": "Safe to proceed — plugin is on our approved list"
  }
}

When processed, AdminLocks updates the local approval record's status and note, then logs an audit event recording that the approval was reviewed via Cloud.

create_snapshot

Triggers a new site snapshot on the WordPress site. This is commonly used before deploying changes or as part of a scheduled maintenance workflow from Cloud.

FieldTypeDescription
labelstringHuman-readable label for the snapshot
{
  "action": "create_snapshot",
  "data": {
    "label": "Pre-deployment snapshot — March 2026"
  }
}

The snapshot is created synchronously. The webhook response includes the snapshot ID and file path on success, or an error message if snapshot creation fails (e.g., insufficient disk space).

update_policy

Deploys a new policy or updates an existing one on the WordPress site. Policies are matched by slug — if a policy with the given slug already exists, it is updated (upsert behavior). If no matching slug is found, a new policy is created.

FieldTypeDescription
slugstringUnique policy identifier used for matching
namestringDisplay name for the policy
descriptionstringHuman-readable description
rulesobjectPolicy rules (deny_menus, deny_pages, deny_capabilities)
rolesstringComma-separated target roles
is_activebooleanWhether the policy should be active immediately
priorityintegerEvaluation priority (lower numbers run first)
{
  "action": "update_policy",
  "data": {
    "slug": "agency-standard-v2",
    "name": "Agency Standard v2",
    "description": "Updated agency lockdown policy deployed from Cloud",
    "rules": {
      "deny_menus": ["plugins.php", "themes.php", "users.php", "tools.php"],
      "deny_pages": ["plugin-install.php", "theme-install.php"],
      "deny_capabilities": [
        "install_plugins", "activate_plugins", "delete_plugins",
        "install_themes", "switch_themes", "delete_themes",
        "create_users", "delete_users", "promote_users"
      ]
    },
    "roles": "editor,author",
    "is_active": true,
    "priority": 10
  }
}

The upsert-by-slug behavior makes it safe to send the same policy to multiple sites. Each site will create the policy on first receipt and update it on subsequent deliveries, ensuring all sites stay in sync with the Cloud-defined policy.

Testing

You can test the webhook endpoint locally using curl. First, compute the HMAC signature, then send the request with the signature header.

Step 1: Compute the Signature

# Set your API key and payload
API_KEY="your_cloud_api_key_here"
PAYLOAD='{"action":"create_snapshot","data":{"label":"Test snapshot"}}'

# Compute HMAC-SHA256
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$API_KEY" | awk '{print $2}')

echo "Signature: $SIGNATURE"

Step 2: Send the Webhook

curl -X POST "https://yoursite.com/wp-json/adminlocks/v1/cloud-webhook" \
  -H "Content-Type: application/json" \
  -H "X-AdminLocks-Signature: $SIGNATURE" \
  -d "$PAYLOAD"

Expected Responses

StatusMeaning
200 OKAction processed successfully
200 OKUnknown action (ignored gracefully)
403 ForbiddenInvalid or missing HMAC signature
400 Bad RequestMalformed JSON or missing required fields
500 Internal Server ErrorProcessing failed (check debug.log)

Testing approval_reviewed

PAYLOAD='{"action":"approval_reviewed","data":{"approval_id":1,"status":"approved","note":"Test approval from CLI"}}'
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$API_KEY" | awk '{print $2}')

curl -X POST "https://yoursite.com/wp-json/adminlocks/v1/cloud-webhook" \
  -H "Content-Type: application/json" \
  -H "X-AdminLocks-Signature: $SIGNATURE" \
  -d "$PAYLOAD"

Testing update_policy

PAYLOAD='{"action":"update_policy","data":{"slug":"test-policy","name":"Test Policy","description":"Deployed via webhook test","rules":{"deny_menus":["plugins.php"]},"roles":"editor","is_active":false,"priority":99}}'
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$API_KEY" | awk '{print $2}')

curl -X POST "https://yoursite.com/wp-json/adminlocks/v1/cloud-webhook" \
  -H "Content-Type: application/json" \
  -H "X-AdminLocks-Signature: $SIGNATURE" \
  -d "$PAYLOAD"

When testing update_policy, set is_active to false to avoid accidentally enforcing restrictions. You can activate the policy through the WordPress admin once you have verified it was created correctly.