Technical Architecture
Understanding the code structure and class organization of Signifyd for WooCommerce.
Plugin Structure
signifyd-for-woocommerce/
├── signifyd-for-woocommerce.php # Main plugin file (bootstrap)
├── composer.json # Composer dependencies
├── README.md # Plugin changelog
├── inc/ # Core classes
│ ├── class-plugin.php # Main plugin orchestration
│ ├── class-admin.php # Admin UI and meta boxes
│ ├── class-orders.php # Order processing and submission
│ ├── class-payload.php # API payload construction
│ ├── class-settings.php # Settings page and options
│ ├── class-webhook-routes.php # REST API webhook endpoints
│ ├── class-session-finger-print.php # Device fingerprinting
│ └── class-log.php # Logging functionality
├── lib/ # Third-party libraries
│ └── signifyd-php/ # Signifyd PHP SDK (if used)
└── vendor/ # Composer dependencies
Class Diagram
Plugin (Main Orchestrator)
├── Admin (UI & Meta Boxes)
├── Orders (Order Processing)
│ └── Payload (Payload Builder)
├── Settings (Configuration)
├── Webhook_Routes (REST API)
├── Session_Finger_Print (Device ID)
└── Log (Logging System)
Core Classes
Plugin Class
File: inc/class-plugin.php
Namespace: \Suma\Signifyd\Plugin
Main orchestrator responsible for initialization and dependency loading.
Key Methods:
activate()— Runs on plugin activationdeactivate()— Runs on plugin deactivationloadDependencies()— Loads all plugin classesrun()— Hooks into WordPress
Initialization Flow:
1. WordPress loads signifyd-for-woocommerce.php
2. Plugin constants defined (SSROOT, SSINC, VERSION)
3. Plugin class instantiated
4. Activation/deactivation hooks registered
5. run() method hooks into 'plugins_loaded'
6. loadDependencies() creates class instances
Code Example:
<?php
namespace Suma\Signifyd;
class Plugin {
public function run() {
add_action('plugins_loaded', [$this, 'loadDependencies']);
}
public function loadDependencies() {
if (class_exists('WooCommerce')) {
require_once(SSINC . 'class-log.php');
require_once(SSINC . 'class-admin.php');
// ... load other classes
new Admin();
new Orders();
new Settings();
// ... instantiate classes
}
}
}
Orders Class
File: inc/class-orders.php
Namespace: \Suma\Signifyd\Orders
Handles order data collection and submission to Signifyd API.
Responsibilities:
- Listen for WooCommerce order status changes
- Collect order data (billing, shipping, items, customer)
- Build API payload
- Submit orders to Signifyd
- Process API responses
- Update order meta with Signifyd data
Key Hooks:
add_action('woocommerce_payment_complete', [$this, 'submit_order']);
add_action('woocommerce_order_status_processing', [$this, 'submit_order']);
Workflow:
1. WooCommerce order reaches "processing" status
2. Orders class hooked to status change
3. Check if plugin enabled and order qualifies
4. Collect order data via helper methods
5. Build payload using Payload class
6. Submit to Signifyd API via cURL
7. Parse response and save to order meta
8. Log request/response
9. Fire action hooks for third-party integrations
Key Methods:
submit_order($order_id)— Main submission handlerget_order_data($order)— Extracts order informationget_customer_data($order)— Extracts customer dataget_line_items($order)— Formats product line itemssend_to_signifyd($payload)— Makes API callhandle_response($response, $order)— Processes API response
Payload Class
File: inc/class-payload.php
Namespace: \Suma\Signifyd\Payload
Constructs the JSON payload sent to Signifyd API.
Payload Structure:
[
'purchase' => [
'orderSessionId' => '',
'browserIpAddress' => '',
'orderId' => '',
'createdAt' => '',
'totalPrice' => '',
'currency' => '',
'products' => []
],
'recipient' => [
'fullName' => '',
'confirmationEmail' => '',
'deliveryAddress' => []
],
'card' => [
'bin' => '', // First 6 digits
'last4' => '' // Last 4 digits
],
'userAccount' => [
'email' => '',
'username' => '',
'accountNumber' => '',
'createdDate' => ''
]
]
Methods:
build_payload($order)— Main payload builderget_purchase_data($order)— Purchase sectionget_recipient_data($order)— Shipping recipient sectionget_card_data($order)— Payment card sectionget_user_account_data($order)— Customer account sectionsanitize_data($data)— Cleans data for API submission
Webhook_Routes Class
File: inc/class-webhook-routes.php
Namespace: \Suma\Signifyd\Webhook_Routes
Registers REST API endpoints for receiving Signifyd webhooks.
Endpoint:
POST /wp-json/suma-signifyd/v1/webhook
Request Flow:
1. Signifyd sends webhook POST request
2. WordPress REST API routes to endpoint
3. HMAC signature validation (security)
4. Parse webhook payload
5. Extract order ID and decision
6. Update order status based on decision
7. Fire WordPress actions
8. Log webhook data
9. Return JSON response with status
Key Methods:
register_routes()— Registers REST API endpointshandle_webhook($request)— Main webhook handlervalidate_signature($request)— HMAC validationprocess_decision($order_id, $decision)— Updates orderlog_webhook($data)— Webhook-specific logging
HMAC Validation:
$signature = hash_hmac(
'sha256',
$request->get_body(),
$webhook_secret,
false
);
if (!hash_equals($signature, $request_signature)) {
return new WP_Error('invalid_signature', 'Invalid HMAC signature', ['status' => 401]);
}
Decision Actions:
switch ($decision) {
case 'ACCEPT':
case 'APPROVED':
// Update order to processing
do_action('signifyd_order_approved', $order_id);
break;
case 'REJECT':
case 'DECLINED':
// Update order to failed
do_action('signifyd_order_rejected', $order_id);
break;
case 'HOLD':
case 'REVIEW':
// Update order to on-hold
do_action('signifyd_order_held', $order_id);
break;
}
Admin Class
File: inc/class-admin.php
Namespace: \Suma\Signifyd\Admin
Handles admin interface additions and order meta boxes.
Features:
- Adds Signifyd meta box to order edit screen
- Displays fraud score and decision
- Shows submission timestamp
- Provides link to Signifyd case dashboard
- Manual order submission button
Meta Box Display:
add_action('add_meta_boxes', [$this, 'add_signifyd_meta_box']);
Displayed Data:
- Signifyd Case ID
- Fraud Score (0-1000)
- Decision (APPROVED, REJECTED, HOLD)
- Submission Date/Time
- Link to Signifyd Dashboard
Settings Class
File: inc/class-settings.php
Namespace: \Suma\Signifyd\Settings
Manages plugin settings interface and option storage.
Hooks:
add_action('admin_menu', [$this, 'add_settings_page']);
add_action('admin_init', [$this, 'register_settings']);
Settings Sections:
- API Settings — Enable, keys, mode
- Fulfillment — Origin address, enable fulfillment
- Advanced — Email notifications, starting post ID
- WIP — Work in progress features
Field Registration:
register_setting('suma_signifyd_plugin_options', 'suma_signifyd_plugin_options');
add_settings_field('suma_signifyd_setting_api_key', 'Production API Key', [...]);
Session_Finger_Print Class
File: inc/class-session-finger-print.php
Namespace: \Suma\Signifyd\Session_Finger_Print
Generates device fingerprints for fraud detection.
Purpose:
- Track unique browser sessions
- Detect account takeover attempts
- Identify suspicious patterns across orders
Methods:
get_fingerprint()— Generates browser fingerprintstore_fingerprint($order)— Saves to order meta
Log Class
File: inc/class-log.php
Namespace: \Suma\Signifyd\Log
Centralized logging functionality using WooCommerce logging system.
Log Files:
signifyd-for-woocommerce-{date}.log— API requests/responsessignifyd-for-woocommerce-webhooks-{date}.log— Webhook events
Methods:
log($message, $level)— Write log entrylog_api_request($request, $response)— API logginglog_webhook($data)— Webhook logging
Usage:
Log::log('Order submitted to Signifyd', 'info');
Log::log_api_request($payload, $response);
Data Flow
Order Submission Flow
┌─────────────────────┐
│ Customer Places │
│ Order │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Payment Gateway │
│ Processes Payment │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ WooCommerce │
│ Status: Processing │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Orders Class │
│ submit_order() │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Payload Class │
│ build_payload() │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ cURL API Request │
│ POST to Signifyd │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Signifyd API │
│ Analyzes Order │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ API Response │
│ {case_id, score} │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Save Order Meta │
│ Fire Action Hooks │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Log Request/Response│
└─────────────────────┘
Webhook Processing Flow
┌─────────────────────┐
│ Signifyd Decision │
│ Update │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Webhook POST │
│ to WP REST API │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Webhook_Routes │
│ handle_webhook() │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Validate HMAC │
│ Signature │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Parse Decision │
│ Extract Order ID │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Update Order Status │
│ Based on Decision │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Fire WordPress │
│ Action Hooks │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Log Webhook Data │
│ Return HTTP 200 │
└─────────────────────┘
Database Schema
Order Meta Keys
The plugin stores Signifyd data as order meta:
| Meta Key | Description | Example Value |
|---|---|---|
signifyd_case_id | Signifyd case identifier | 12345678 |
signifyd_score | Fraud score (0-1000) | 850 |
signifyd_decision | Fraud decision | APPROVED |
signifyd_submitted_at | Submission timestamp | 2026-04-20 14:30:00 |
signifyd_fingerprint | Browser fingerprint | abc123... |
signifyd_fulfillment_sent | Fulfillment submitted | 1 |
Access in Code:
$case_id = get_post_meta($order_id, 'signifyd_case_id', true);
Constants
Defined in main plugin file:
| Constant | Description | Value |
|---|---|---|
SSROOT | Plugin root directory | plugin_dir_path(__FILE__) |
SSINC | Include directory | SSROOT . 'inc/' |
SUMA_SIGNIFYD_VERSION | Plugin version | 1.1.5 |
SUMA_SIGNIFYD_SETTINGS | Plugin settings array | get_option(...) |
API Integration
Signifyd API Endpoints
Base URL: https://api.signifyd.com/v2/
Endpoints Used:
POST /cases— Submit new caseGET /cases/{caseId}— Get case detailsPOST /cases/{caseId}/fulfillments— Submit fulfillment
Authentication:
$headers = [
'Authorization: Basic ' . base64_encode($api_key . ':'),
'Content-Type: application/json'
];
cURL Request Example
$ch = curl_init('https://api.signifyd.com/v2/cases');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
Security Considerations
HMAC Signature Validation
Webhooks use HMAC-SHA256 signatures:
$expected = hash_hmac('sha256', $body, $secret, false);
$received = $_SERVER['HTTP_X_SIGNIFYD_SEC_HMAC_SHA256'];
if (!hash_equals($expected, $received)) {
die('Invalid signature');
}
Nonce Verification
Settings form uses WordPress nonces:
wp_nonce_field('suma_signifyd_settings', 'suma_signifyd_nonce');
// Verify:
if (!wp_verify_nonce($_POST['suma_signifyd_nonce'], 'suma_signifyd_settings')) {
wp_die('Security check failed');
}
Capability Checks
Settings require admin capabilities:
if (!current_user_can('manage_options')) {
wp_die('Unauthorized');
}
Performance Considerations
- Async Recommended: Consider using
wp_schedule_single_event()for API submissions to avoid blocking checkout - Caching: Response data cached in order meta to avoid repeated API calls
- Logging: Log files can grow large; consider rotation strategy
- Webhook Processing: Fast response required (< 5 seconds)
Next Steps
- Hooks & Filters — Available customization hooks
- Configuration — Settings reference
- Installation — Setup guide