=== OrderGuard ===
Contributors: orderguard
Tags: woocommerce, cash on delivery, fraud prevention, returns, shipping
Requires at least: 6.5
Tested up to: 7.1
Requires PHP: 8.2
Stable tag: 0.3.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Stop risky uncollected orders and serial returners before you ship.

== Description ==

**Stop risky uncollected orders and serial returners before you ship.**

OrderGuard relies on an external cloud service (api.orderguard.net) to work — the risk scores come from a network shared between merchants. Full details of what is sent and when are in the **External services** section below.

Powered by a shared merchant network, OrderGuard shows collection and return risk before you ship. Built-in automations save time and protect your margins — without slowing down reliable customers.

Cash on delivery loses money two ways: parcels that are never collected, and orders that come straight back as returns. OrderGuard scores both — so you can spot the no-shows *and* the serial returners before a parcel goes out.

When an order arrives, OrderGuard shows two numbers right inside the WooCommerce order: a **collection risk** and a **return risk**. Every order with a usable phone number or email is checked, not only cash-on-delivery ones — except for customers on your exclusion list, who are never checked and never sent — the scores matter most for COD, but a serial returner is worth knowing about whatever they paid with. You decide what to do — ship as normal, confirm by phone, or offer prepayment instead. OrderGuard never cancels or holds an order by itself.

= Privacy-first by design =

Phone numbers and email addresses are converted into SHA-256 hashes **inside your own website**, before anything is transmitted — these contact fields leave your site only as hashes, and the raw values never reach OrderGuard's servers. The service also receives the order facts listed below, such as status, outcome, billing country and references; those facts may be sent even when no usable contact hash can be produced. Names, customer IP addresses, street addresses, cities or regions, postal codes, order amounts and payment-card or payment-credential details are never transmitted.

Two things we would rather state plainly than gloss over. Those hashes are **pseudonymous** data, not anonymous data. And if you flag or block a customer, their name, email and phone are stored **locally, on your own site**, so that your blocked-clients list is readable by you — that data stays on your server and is not sent to OrderGuard.

= What you get =

* **Collection risk and return risk** on every COD order, from a shared merchant network.
* **Serial-returner detection** — a first-time buyer with a poor return record shows up before you ship.
* **Report or block a customer** at three levels: report (a private record on your own site — and a signal to the network too, but only if you switch Merchant Signals on, which is off by default), block cash on delivery only (they can still order, but prepaid), or block entirely.
* **Automatic COD hiding** (optional, off by default) — hide cash on delivery at checkout when a customer crosses the limits. On the free plan the limits are fixed defaults (5 not-collected parcels or 12 returns); setting your own limits is a Pro feature. Works on both the classic and the block-based checkout.
* **Courier delivery sync** — reads tracking data made available by courier integrations. Courier adapters are included for Econt, Speedy, BOX NOW and Pigeon Express. Live-store verification has covered Econt through mreja.net's WooCommerce Econt plugin, Speedy through Extensa's woocommerce-speedy plugin, and BOX NOW. Econt's official plugin, Econt and Speedy through Bulgarisation, and Pigeon Express have not yet been verified on a live store. API-based adapters query the courier directly; the mreja.net WooCommerce Econt adapter reads that plugin's local tracking tables. When the available data gives an unambiguous final result, OrderGuard records the shipment as kept, returned or not collected instead of inferring the outcome from order statuses alone. Anything unclear is left open and re-checked later.
* **Order history import** — checks your last 24 months of orders in the background, so the scoring is useful from day one.
* **Insights** — local activity counts showing what the plugin checked, flagged or blocked.

== External services ==

This plugin connects to the OrderGuard API at **https://api.orderguard.net**, operated by Fregata Group Ltd (Bulgaria, EU). This is required for the plugin to function: the reliability scores come from a shared network that no single store could build alone.

**When data is sent:**

* When you connect your store to the service on the OrderGuard screen (this is separate from activating the plugin in WordPress, which sends nothing), to verify that you control the store domain: your store domain and the fact that you accepted the Terms, Privacy Policy and DPA. Nothing about any customer is sent before this is complete. If your key is ever reissued, the same domain-control verification runs again (only your store domain is sent then — the acceptance was already recorded when you connected).
* When a non-excluded order is created, except for a checkout attempt that OrderGuard itself rejects. This is not limited to cash-on-delivery orders. If a usable phone number or email exists, its hash is sent; even without a usable contact hash, the order's billing country, order reference and item references may still be sent.
* At checkout, if you have switched on automatic COD protection: the plugin asks the server whether to offer cash on delivery. This happens before an order exists.
* Whenever an order's WooCommerce status changes — including statuses such as `processing`, `on-hold`, `completed`, `cancelled` or `failed` — when a refund is recorded, and when the plugin records a kept, returned or not-collected result from your courier.
* When you open an order in the admin: with the Pro add-on and live scoring switched on, to refresh the score; on any plan, if Merchant Signals is enabled, to count how many other stores have flagged that customer; and on any plan, if automatic COD protection is on, to show whether cash on delivery is currently hidden for that customer — the same decision request the checkout makes.
* During the automatic history import — each imported order is sent with its original creation date, so past orders are weighed by their real age — and during the hourly reconciliation sweep that retries anything the server has not acknowledged.
* When you flag or block a customer from one of their orders, if you have switched Merchant Signals on. A blocked-client record you type in by hand stays on your site and sends nothing. Removing a flag withdraws the signal your store sent earlier — and that withdrawal is sent even if you have since switched Merchant Signals off, so a signal you retract does not linger on the network.
* When you exclude someone by phone or email: their hashes are sent so the matching records your store contributed can be erased from the server. An exclusion by name only stays on your site — names are never transmitted, so there are no name records on the server to erase; to erase past signals, exclude their phone or email too.
* When you look up or erase a customer's data from the Legal tab.
* When you erase a customer's personal data with WordPress's Tools → Erase Personal Data and OrderGuard's owned-storage erasure engine is active on your site: an erasure request, so that the records your store contributed can be erased on the server. It contains the SHA-256 hash of the requester's email address, the internal references of the orders in scope with a SHA-256 hash of each order's key, the time cutoff, random installation and namespace identifiers, the WordPress request ID, an operation identifier, and a digest of the local evidence. The customer's phone number and other order contact details are not sent in this request. The plugin also checks that the service is ready, sending a random challenge and the store's API key. Receipt acknowledgements resend the full erasure request described above together with the receipt digest. Restart-approval requests resend that full request together with the proposed new operation identifier. A proof request made from Tools → OrderGuard erasure proofs sends the full request and a fresh random challenge. All these calls carry the store's API key. Pending acknowledgements and restart-approval requests are checked by scheduled hourly jobs; those jobs send nothing when no eligible local request is pending.
* When the plugin checks which plan your store is on or shows your subscription details on the Plan tab; when you request the Pro add-on download (your browser is then sent to a personal download link on api.orderguard.net that stays valid for a few minutes; WordPress itself does not download or install anything); when you open the billing portal, switch your billing interval or open an invoice; and, if the Pro add-on is installed, when it checks for updates. Each of these sends your store's API key and nothing about any customer.
* When you start an upgrade to Pro from the Plan tab: the plugin asks the service to create a checkout for the billing interval you chose (monthly or annual), then asks it to confirm that the checkout belongs to your account, and then sends your browser to the checkout page on orderguard.net, where payment is handled by Paddle. These two requests send your store's API key, the chosen interval and the checkout's transaction identifier — nothing about any customer.
* When you press Contact Support on the Support tab (Pro): the plugin asks the service for a support pass, sending your store's API key, and then opens the OrderGuard support page on orderguard.net in your browser with that pass, so the page knows which store you are. The pass-generation call sends no order data, customer data or diagnostic report. Opening the support website and submitting the form are separate website interactions, covered by the website privacy policy.
* If you join the waiting list from inside the plugin, your own email address is sent.

**What is sent:**

* SHA-256 hashes of the customer's phone number and email address — computed on your server, before transmission. The raw values are never sent.
* The order outcome (kept, returned, not collected), an internal order/item reference, and the order's billing country — the country is used to format the phone number correctly before hashing, and it is also transmitted and stored with the order's record on the server.
* The order's WooCommerce status as it changes, in WooCommerce's own words (for example `processing`, `completed`, `cancelled`), whether the order was cash on delivery, and — for a refund — what proportion of the order was refunded.
* When a courier reports an outcome: which courier it was and that the outcome came from a courier rather than from you.
* Your store domain and API key, so the request can be authenticated.
* When automatic COD protection is on: the not-collected and returned limits in effect on your site. On the free plan these are the fixed defaults; custom limits require the Pro add-on, and the server — which knows your plan — honours custom values only for Pro accounts.
* Where you use them: a flag or block signal type, and a plan check so the plugin knows whether this store is on Free or Pro.
* If you join the waiting list: your own email address, your store domain and your country.
* If you open a Pro invoice from the Plan tab: the identifier of that payment transaction, so the invoice can be fetched.
* If you start an upgrade to Pro: the billing interval you chose and the checkout's transaction identifier.
* For an erasure through WordPress's privacy tools: the hashed requester email, hashed order keys with internal order references, and the identifiers, challenges and digests described above.

**What is never sent about your customers:** names, customer IP addresses, street addresses, cities or regions, postal codes, order amounts, or payment-card data — nothing readable that identifies a shopper. The billing country is the only address field sent, as disclosed above. (Your own email address is sent if you choose to join the waiting list, and your store domain identifies your shop. Those are yours, not your customers'.)

Data is processed and stored within the EU. Your use of the service is subject to:

* Terms of Service: https://www.orderguard.net/terms/
* Privacy Policy: https://www.orderguard.net/privacy/
* Data Processing Agreement: https://www.orderguard.net/dpa/

No third-party payment or checkout script is embedded in your site, and no card data ever touches your WordPress admin: the Pro upgrade button asks the OrderGuard service to prepare a checkout, as described above, and then sends your browser to orderguard.net to pay. OrderGuard does run its own code during checkout when you switch on automatic COD protection — that call is described above; it sends the customer's identity hashes, your store's API key, and the applicable not-collected and returned limits.

= Courier delivery sync (optional) =

If you switch on courier sync, most adapters ask that courier directly what happened to your own shipments. They read the API credentials already saved by the courier's own WordPress plugin and use them to make that call on your behalf. Those credentials are never sent to OrderGuard's servers and are never stored by OrderGuard. Apart from those authentication fields, the only shipment-specific value sent to the courier is your shipment's tracking or order reference. The courier's reply may contain more than the delivery status; OrderGuard uses only the response fields needed to identify the matching shipment, handle the API result and derive its delivery outcome. It does not store or forward the full response.

The mreja.net **WooCommerce Econt** variant is different: OrderGuard does not use its credentials and does not contact Econt. It reads tracking already present in that plugin's local database tables. That courier plugin refreshes those tables only when an unsettled order is opened in the WordPress admin, so automatic coverage can remain incomplete if orders are not opened there.

Each courier is contacted only if you enable and configure it:

* **Econt** — the official Econt plugin uses https://delivery.econt.com (https://delivery-demo.econt.com in demo mode); the Bulgarisation integration uses https://ee.econt.com/services/ (https://demo.econt.com/ee/services/ in demo mode). With the mreja.net WooCommerce Econt plugin, OrderGuard makes no Econt request and reads only that plugin's local tracking tables, as described above.
  Terms: https://www.econt.com/econt-express/common-terms — Privacy: https://www.econt.com/econt-express/privacy-policy
* **Speedy** — https://api.speedy.bg
  Terms: https://www.speedy.bg/bg/terms-and-conditions — Privacy: https://www.speedy.bg/bg/gdpr
* **BOX NOW** — https://api-production.boxnow.bg
  Terms: https://boxnow.bg/terms-of-use-for-shipping-services — Privacy: https://boxnow.bg/personal-data-processing-notice
* **Pigeon Express** — https://api.pigeonexpress.com (https://api-demo.pigeonexpress.com in sandbox mode)
  Terms: https://pigeonexpress.com/terms — Privacy: https://pigeonexpress.com/privacy

Your use of each courier's API is governed by your own agreement with that courier.

== Installation ==

1. Install and activate the plugin (WooCommerce must be active).
2. Go to **OrderGuard** in the admin menu and complete activation for your store.
3. Your last 24 months of orders are imported automatically once activation completes, so scoring is useful straight away. Progress is shown in **OrderGuard → Settings → Account**. All payment methods are included, not only cash on delivery.
4. Review the settings in **OrderGuard → Features**. The privacy-sensitive options — automatic COD hiding and cross-store Merchant Signals — ship switched **off**; enable them only if you want them.

== Frequently Asked Questions ==

= Do my customers' phone numbers or emails leave my store? =

Not in readable form. They are converted into SHA-256 hashes on your own server first, and only those hashes are transmitted; the raw originals never leave your site. The hashes are still pseudonymous personal data, as explained below.

We do not claim those hashes are anonymous. A hash of a phone number is pseudonymous personal data — the range of possible mobile numbers is small enough that a plain hash could be guessed at. That is why OrderGuard's server applies HMAC-SHA256 with a secret key of its own before storing anything, so that someone holding only a copy of the database cannot test guesses against it without also holding that server-side key.

= Does OrderGuard block orders automatically? =

Not unless you switch it on. By default the scores are advisory — you decide. Automatic COD hiding is off by default, and even then it only hides the cash-on-delivery option; the customer can still buy using another payment method.

= Does it work with the new block-based checkout? =

Yes. COD hiding works on both the classic checkout and the block-based (Gutenberg) checkout.

= What do I have to tell my own customers? =

Because the plugin processes personal data on your behalf, you should mention it in your store's own privacy notice. OrderGuard provides ready-made disclosure text in the plugin's **Legal** tab that you can copy.

= What happens when a customer asks me to erase their data? =

OrderGuard automatically processes the records within the request's scope that meet its identity-matching checks. Manual flags that match the customer only through a phone number or an alternative email address are not proof that the flag belongs to that customer, so OrderGuard lists them for you to review. It records a review notice and does not report the erasure as complete. Very common phone numbers or email forms are counted rather than listed, and those counts still need investigating. The merchant guide explains what to do and how quickly to answer the customer: https://www.orderguard.net/merchant-guide/

When WordPress completes a customer erasure, OrderGuard deliberately keeps any matching entry in the store’s exclusion list. That minimal local suppression record is retained so the store continues to honour the person’s request and does not send their later data back to the network. An administrator may remove the exclusion separately after considering the store’s legal obligations.

= Which couriers does delivery sync cover? =

Courier adapters are included for Econt, Speedy, BOX NOW and Pigeon Express. Live-store verification has covered Econt through mreja.net's WooCommerce Econt plugin, Speedy through Extensa's woocommerce-speedy plugin, and BOX NOW. Econt's official plugin, Econt and Speedy through Bulgarisation, and Pigeon Express have not yet been verified on a live store. API-based adapters ask the courier directly, using credentials already saved by the courier's own WooCommerce plugin. The mreja.net WooCommerce Econt adapter instead reads that plugin's local tracking tables and does not contact Econt. Every adapter is designed to record an outcome only when the available data can be interpreted unambiguously. Without a working adapter the plugin still works — it relies on order statuses instead of courier-reported results.

= Is it really free? =

Yes. The core Free-plan features described above — including Merchant Signals and automatic COD hiding with fixed limits — are free. Custom limits and live order-screen re-scoring require the optional OrderGuard Pro add-on, distributed separately from orderguard.net.

= How does the network decide the scores? =

Only resolved order records feed the risk scores: kept, returned or not collected. Their age, the fraction refunded and the amount of resolved history affect the numerical result. A courier-reported result can settle what an order's outcome was, but it feeds that same order record — it is not a separate scoring input. Merchant reports never change the risk score at all: they are shown alongside it as a separate advisory count, and in the order panel, reports from other stores are shown only after at least **two independent stores** agree — so a single mistaken report can never follow a shopper elsewhere.

Cross-store sharing of flag/block marks ("Merchant Signals") is **free, off by default, and requires the merchant's deliberate opt-in**.

= What does Pro add? =

The Free plan includes the core features above, including automatic COD hiding with fixed limits. OrderGuard Pro is a separate add-on (installed from orderguard.net) that adds live re-scoring on the order screen and custom risk thresholds. The free plugin contains no locked code.

= Does OrderGuard work on multisite? =

Multisite network activation remains on OrderGuard’s established erasure engine in this release. The new owned-storage erasure engine and its supervised cutover are qualified only for individual WordPress sites.

== Screenshots ==

1. Collection and return risk inside a WooCommerce order, with the customer's history from the network.
2. The Features screen, showing Flag for review and Merchant Signals controls.
3. Order-card scoring (Pro) and courier delivery sync (free).
4. Flagging or blocking a customer from an order, with three levels of action.
5. The Insights report.

== Changelog ==

= 0.3.0 =
* Moves OrderGuard personal-data erasure onto the reviewed owned-storage engine. Existing stores require a supervised cutover after their workers are stopped; fresh stores activate the new engine during plugin activation.
* Exclusion checks now fail closed, signal changes use a durable outbox, and uninstall refuses while protected privacy work is unfinished or its authority records are damaged.
* New Support tab for contacting OrderGuard support in Bulgarian or English, Monday to Friday. No system data is sent automatically. Pro includes priority support.
* Start an upgrade to Pro from the Plan tab.
* Guided recovery for eligible interrupted customer erasures, with owner approval handled by OrderGuard and an attention page under Tools.
* Clearer erasure screens and messages, with Bulgarian translations.


= 0.2.23 =
* WordPress.org resubmission hardening: stored-data, scheduled-work and configuration identifiers now use the full OrderGuard namespace throughout the public plugin.
* The public package contains no private migration code. Existing private pilot stores use a separately controlled compatibility build to copy and verify their earlier rows before that schema is retired.
* Clarified that customer contact hashes leave the store in pseudonymous, non-readable form rather than implying that no customer-derived data is transmitted.

= 0.2.22 =
* Admin scripts and styles are now loaded through WordPress's enqueue APIs instead of being printed inline.
* Existing Free-plugin settings are carried forward automatically to the renamed storage keys during the update.
* Renamed scheduled tasks are repaired during the update. If an older history import was left running without a pending batch, OrderGuard may restart it after a safety delay of at least five minutes, using its saved position when one exists or starting from the beginning otherwise.
* Courier identifiers are now normalized consistently. Stores that previously recorded courier health or resume state under a non-standard identifier may rebuild those local counters once after updating; recorded order outcomes and customer data are unaffected.

= 0.2.21 =
* The order panel now shows what your own records say about a customer — imported order history included — alongside the network view. Your own evidence no longer hides behind withheld network counts.
* When your own records show enough not-collected or returned orders, that now surfaces where you already look: as a badge in the orders list, in the Review queue, and — on a new cash-on-delivery order — as a private order note. These are your own numbers, read from your own records — nothing new is sent anywhere.
* The "detailed counts stay locked" note now says what actually lifts the lock, instead of promising that a customer's first order will unlock the counts when your imported history already holds their completed orders.

= 0.2.20 =
* The order panel no longer says a customer is "new to the network" when OrderGuard has actually seen their orders but none of them reached a result it can score. It now tells you which of the two it is looking at.

= 0.2.19 =
* Bulgarian stores: the "no history yet" note in the order panel was showing in English. It is now translated like the rest of the panel.

= 0.2.18 =
* A customer OrderGuard has no history for no longer shows as a green 0. The score cards now show a dash, because a zero and "nothing to go on" are not the same thing. Customers with a real record are unaffected.
* If you have flagged or blocked a customer yourself, the order panel now says so at the top instead of only further down.

= 0.2.17 =
* The privacy disclosure you can copy from the Legal tab now includes a link to OrderGuard's own privacy policy, so your customers can read it directly.

= 0.2.16 =
* Order-history import now skips orders that ended without a usable outcome (failed, abandoned, or cancelled without a refund). Previously such orders created records that could never resolve and were re-checked every hour forever.

= 0.2.15 =
* Debug logging no longer records a full billing URL. No change to how the plugin behaves.

= 0.2.14 =
* Documentation corrections and clearer diagnostics. No change to how the plugin behaves.

= 0.2.13 =
* Hardening: the billing links on the Plan tab are now checked against an allowlist before your browser follows them.

= 0.2.12 =
* Upgrading to Pro now opens orderguard.net rather than a checkout inside your dashboard. No payment script loads in your admin.

= 0.2.11 =
* OrderGuard no longer writes diagnostic lines to your server's error log unless WP_DEBUG is switched on.

= 0.2.10 =
* Code quality pass for the WordPress.org review. No change to how the plugin behaves.

= 0.2.9 =
* Housekeeping only. No change to how the plugin behaves.

= 0.2.8 =
* If you subscribe to OrderGuard Pro, the Plan tab now has a Download button for the add-on, so you no longer have to ask us for the file.

= 0.2.7 =
* New Data removal card on the Account tab. Choose whether the data OrderGuard keeps on your site is kept or deleted if you ever delete the plugin. Off by default, so deleting the plugin keeps everything unless you deliberately switch it on. Deactivating never deletes anything.
* If you have subscribed to Pro but have not installed the add-on yet, OrderGuard now tells you and points you to the download.

= 0.2.6 =
* Cash-on-delivery hiding now works on the block-based (Gutenberg) checkout for manually blocked customers, with the same explanation the classic checkout shows.

= 0.2.5 =
* New Merchant Signals card: cross-store sharing of flag/block marks is free, off by default and opt-in.
* Flag retractions are no longer swallowed when cross-store sharing is switched off.
* Legal documents updated and language-aware links added.

= 0.2.4 =
* Fixed: a blocked customer could still see cash on delivery in a fresh browser session.
* Phone matching now recognises the same number written in different formats.

= 0.2.0 =
* Free / Pro split. The free plugin is complete on its own; Pro is a separate add-on.

== Upgrade Notice ==

= 0.3.0 =
Existing stores must follow the documented stop-the-workers and supervised takeover procedure. Do not force activation by editing lifecycle records.


= 0.2.23 =
Completes the full OrderGuard namespace required for directory review. Private pilot stores must complete the managed compatibility migration before installing the public package.

= 0.2.22 =
Carries existing settings forward and repairs renamed scheduled tasks. A previously stranded history import may restart after a safety delay of at least five minutes, from its saved position when available or from the beginning otherwise.

= 0.2.8 =
Pro subscribers can now download the add-on directly from the Plan tab.

= 0.2.7 =
Adds a Data removal setting on the Account tab. Nothing is deleted unless you deliberately switch it on.

= 0.2.6 =
Cash-on-delivery hiding now also works on the block-based checkout. Recommended for stores using the newer WooCommerce checkout blocks.
