Zi COD Confirm – WhatsApp Order Confirmation for WooCommerce
Stop shipping fake COD orders: customers confirm on WhatsApp before you ship.
COD Confirm dashboard: confirmation rate, shipments saved, 14-day chart and setup checklist
Your license key appears in your account (My license keys) as soon as the payment is confirmed, and is emailed to you.
Overview
Cash on delivery is how most shoppers pay in Egypt, Saudi Arabia, the UAE, Kuwait and Morocco – and it is where stores quietly lose money. Fake orders, wrong numbers and customers who changed their mind all end the same way: a parcel that comes back and a shipping fee you pay twice.
Zi COD Confirm adds one simple step between checkout and shipping. Every new COD order waits in a new Awaiting confirmation status while the customer is asked, on WhatsApp, to confirm or cancel. Confirmed orders move to Processing and your normal e-mails go out. Orders nobody confirms are cancelled automatically and their stock goes back on sale.
Works with or without an API
- WhatsApp Cloud API: an approved template with Confirm / Cancel quick-reply buttons. One tap updates the order; every webhook is verified with your App Secret.
- UltraMsg, Twilio or any HTTP provider: customers can also reply 1 / 2, yes / no or نعم / لا.
- No API at all: one click on the order opens WhatsApp with the customer's number and the whole message typed, including secure Confirm / Cancel links.
Built for MENA stores
- Phone numbers converted to international format for Egypt, Saudi Arabia, UAE, Kuwait, Qatar, Bahrain, Oman, Morocco and Jordan – Arabic digits and local formats included – with optional blocking of invalid numbers at checkout.
- Messages and the customer confirmation page in Arabic (RTL) and English, with an optional one-time code.
- A Refused on delivery status that remembers customers who refuse parcels.
Know who you are shipping to
Every order shows the customer's history by phone number – confirmed, cancelled, no reply, refused, delivered – plus a risk score with clear reasons. Blacklist phones, e-mails or IPs, limit COD orders per phone per day, and refuse cash on delivery for repeat offenders while they can still pay another way.
The dashboard shows your confirmation rate and how many shipments you did not have to send. Compatible with WooCommerce HPOS and the block checkout.
Features
Awaiting confirmation status
New COD orders are held in their own status instead of going straight to Processing, so nothing ships before the customer says yes.
WhatsApp Cloud API with buttons
Approved template with Confirm / Cancel quick-reply buttons carrying a signed payload per order; webhooks verified with X-Hub-Signature-256 and a verify token.
UltraMsg, Twilio and any HTTP API
Ready presets for UltraMsg and Twilio WhatsApp (including Content templates) and a generic URL / headers / body template for any other provider. Replies like 1 / 2 or نعم / لا are understood.
Zero-API manual mode
One click opens WhatsApp with the customer's number and the full message, including signed Confirm / Cancel links. Works on any store, licensed or not.
Mobile confirmation page
A fast page on your own domain in Arabic or English with the order summary, big buttons and an optional OTP by WhatsApp or e-mail. Link previews can never confirm by accident.
Reminders and auto-cancel
Up to three reminders, then automatic cancellation with restock after your deadline – only for orders that were actually asked.
Phone normalisation for 9 markets
E.164 for EG, SA, AE, KW, QA, BH, OM, MA and JO: Arabic digits, 00 / + prefixes, leading zeros. Optionally block checkout when the mobile number is invalid.
Risk score and blacklists
Block or flag by phone, e-mail, domain or IP (wildcards and CIDR), cap COD orders per phone per day, and see the reasons behind every score.
Refused-delivery history
Mark returned parcels as Refused on delivery: stock comes back and the phone's history follows the customer to every future order.
Order list column, filter and order box
See the confirmation state, risk and refusals in the order list, filter by state, and confirm, cancel, resend or blacklist from the order screen.
Dashboard
Confirmation rate, confirmed, cancelled, no reply, refused, blocked and shipments saved, a 14-day chart and recent activity.
HPOS, blocks and Arabic ready
Compatible with High-Performance Order Storage and the Cart & Checkout blocks; full Arabic translation and RTL-safe admin.
Installation
- 1In WordPress go to Plugins → Add New → Upload Plugin, choose the zip and click Install, then Activate (WooCommerce must be active).
- 2Open WooCommerce → COD Confirm → Settings: choose which COD orders need confirmation, the reminder and auto-cancel hours, and your store WhatsApp number.
- 3Open the WhatsApp channel tab: keep Manual to start without an API, or enter your WhatsApp Cloud API, UltraMsg, Twilio or HTTP provider details.
- 4For the Cloud API, copy the webhook URL and verify token into your Meta app, subscribe to messages and enter your approved template name.
- 5Review the English and Arabic messages on the Messages tab and send yourself a test message.
- 6Paste your license key on the License tab to switch on automatic sending, reminders and auto-cancel.
Documentation
Show the full documentationHide the documentation+
WooCommerce plugin by Zaki International (engzaki.pro).
Slug zi-cod-whatsapp-confirm · prefix zicw_ / ZICW_ · text domain zi-cod-whatsapp-confirm · PHP 7.4–8.3 · WordPress 6.0+ (tested 6.8) · WooCommerce 7.1+ (HPOS and Cart & Checkout blocks compatible).
Product page: https://engzaki.pro/en/products/whatsapp-cod-order-confirmation-woocommerce
1. Overview
Fake and unreachable cash-on-delivery (COD) orders cost stores in Egypt, Saudi Arabia, the UAE, Kuwait and Morocco a shipping fee every time a parcel is refused. Zi COD Confirm:
- puts each new COD order into Awaiting confirmation (
wc-zicw-awaiting) instead of Processing; - asks the customer on WhatsApp to confirm or cancel – automatically through an API, or with one click through a pre-filled WhatsApp link;
- moves confirmed orders to Processing (or the status you choose) and sends the usual WooCommerce e-mails then;
- reminds customers who have not answered and auto-cancels + restocks orders after your deadline;
- normalises phone numbers, keeps a history per phone (confirmed / cancelled / no reply / refused / delivered), scores risk, and can refuse COD for blacklisted or abusive customers.
2. Requirements
| WordPress | 6.0 or newer (tested up to 6.8) |
| PHP | 7.4 – 8.3 |
| WooCommerce | 7.1 or newer (tested up to 10.2), core "Cash on delivery" gateway |
| WP-Cron | must run (real cron recommended: */5 * * * * wget -q -O - https://example.com/wp-cron.php?doing_wp_cron) |
| Optional | WhatsApp Cloud API account (Meta), UltraMsg instance, Twilio WhatsApp sender, or any HTTP WhatsApp provider |
| License | from engzaki.pro, for automatic sending, reminders, auto-cancel and WhatsApp OTP |
3. Installation
- WordPress → Plugins → Add New → Upload Plugin → choose
zi-cod-whatsapp-confirm-1.0.0.zip→ Install → Activate. - On activation the plugin creates two tables (
{prefix}zicw_events,{prefix}zicw_phones), a random signing secret, a webhook verify token and an inbound secret, and schedules two cron events (zicw_cronevery 15 min,zicw_dailytwice a day). - Open WooCommerce → COD Confirm.
4. Configuration, screen by screen
4.1 Dashboard
- KPIs for the last 7 / 30 / 90 / 365 days: awaiting now (links to the filtered order list), COD orders held, confirmation rate (= confirmed ÷ (confirmed + cancelled + no reply)), confirmed, cancelled by customer, no reply – auto-cancelled, COD blocked at checkout, refused on delivery, shipments saved (= cancelled + auto-cancelled + blocked) and, if you enter your average shipping cost, an estimate of the fees saved.
- 14-day bar chart (confirmed vs cancelled / no reply), setup checklist and the latest 25 events.
4.2 Settings
| Setting | Meaning |
|---|---|
| Enable | Master switch. |
| Rules | All COD orders, or any of: total ≥ amount, first-time customers, risk score ≥ N. |
| Trusted customers | Skip confirmation for phones with N+ delivered (completed) orders and no refusals (unless flagged). |
| After confirmation | Target status (default Processing). |
| Reminders | 0–3 reminders, every X hours without a reply (licensed, API channel). |
| Auto-cancel | Cancel + restock after X hours (licensed). Only orders whose request was really sent (or with an invalid number after 3 failed attempts) are cancelled. |
| Stock | Reduce stock while waiting (restored when cancelled); restock on "Refused on delivery". |
| WooCommerce e-mails | Admin "New order" e-mail on placement or after confirmation; send the usual customer e-mails ("Processing order") at confirmation. |
| Follow-up messages | WhatsApp thank-you after confirming / notice after cancelling (API channels; free-form texts are only delivered by Meta inside the 24-hour window). |
| Message language | Checkout language (WPML / Polylang / site locale) · Arabic for Arab billing countries · always Arabic · always English. |
| Store WhatsApp number | For the thank-you page button "Confirm now on WhatsApp". |
| Thank-you page | Show the confirmation box; button to your store number; optional link to the confirmation page. |
| OTP | Require a 6-digit code (WhatsApp or e-mail) on the confirmation page before confirming. |
| Average shipping cost | Only for the dashboard estimate. |
| Uninstall | Delete settings and tables when the plugin is deleted (order notes / meta always stay). |
| Update server | Defaults to https://engzaki.pro/api/plugins/zi-cod-whatsapp-confirm/update. |
4.3 WhatsApp channel
Manual – no API. Order screen → Send on WhatsApp opens https://api.whatsapp.com/send?phone=…&text=… (this form keeps emoji intact) with the rendered request message. Clicking it is logged and counts as "sent" for the auto-cancel timer.
WhatsApp Cloud API (Meta)
- Meta Business → create a System User, give it the WhatsApp app and
whatsapp_business_messaging, generate a permanent token → Access token. - WhatsApp → API Setup → Phone number ID.
- App → Settings → Basic → App secret (required: every webhook POST is rejected unless
X-Hub-Signature-256 == "sha256=" . HMAC-SHA256(app_secret, raw_body)). - WhatsApp → Configuration → Webhook: callback URL = the one shown (
/wp-json/zicw/v1/meta), verify token = the one shown; subscribe to messages. - WhatsApp Manager → create a Utility template (suggested EN / AR text is in the plugin) with body variables and two quick-reply buttons (1st Confirm, 2nd Cancel). After approval enter its name and language codes (e.g.
en,ar). - Body variables = values for
{{1}},{{2}}… separated by|(default{first_name}|{order_number}|{order_total}|{order_items}). Each quick-reply button gets the payloadzicw|c|<order>|<hmac>/zicw|x|<order>|<hmac>; a tap confirms / cancels that exact order. Delivery statuses (delivered / read / failed) are logged; failures are added to the order notes. Optional: reminder template, Authentication template for OTP (body{{1}}= code + copy-code button).
UltraMsg – instance ID + token. Messages: POST https://api.ultramsg.com/{instance}/messages/chat (token, to, body). For replies set the instance webhook to the Replies webhook URL (/wp-json/zicw/v1/inbound?secret=…) and enable "on message received". Note: UltraMsg links a normal WhatsApp number via QR (unofficial).
Twilio WhatsApp – Account SID, Auth token, From (+1415… or a Messaging Service MG…). Messages: POST https://api.twilio.com/2010-04-01/Accounts/{SID}/Messages.json with From/To = whatsapp:+… and Body, or ContentSid + ContentVariables (from Body variables) for an approved Content template – required to start a conversation outside the 24-hour window. Give its quick-reply buttons the IDs confirm / cancel. Incoming webhook: /wp-json/zicw/v1/twilio (verified with X-Twilio-Signature).
Generic HTTP API – URL, method (POST / GET / PUT), JSON or form body, headers (one per line), optional success text. Placeholders: {phone} (digits), {phone_plus}, {message}, {message_json} (JSON-escaped, use inside quotes), {message_url}. Replies: POST phone + text (or payload) as JSON or form to the Replies webhook URL.
Test send – builds the chosen message (request / reminder / confirmed / cancelled) from an existing order and sends it to any number with the saved settings. Without a license or in Manual mode it returns the WhatsApp link instead.
4.4 Messages
English and Arabic templates for: request, reminder, after confirmation, after cancellation, OTP. Arabic is saved without diacritics. Placeholders:
{first_name} {customer_name} {order_number} {order_total} {order_items} {order_date} {shipping_address} {phone} {store_name} {store_url} {confirm_url} {cancel_url} {page_url} {hours} {otp}
Empty a box and save to restore the default. With the Cloud API, the request and reminder use your approved Meta template instead.
4.5 Phones & risk
- Normalisation (E.164) for EG +20, SA +966, AE +971, KW +965, QA +974, BH +973, OM +968, MA +212, JO +962 – Arabic-Indic / Persian digits, spaces, dashes,
00/+, national leading zeros, numbers typed with the country code but no+, and+20 010…style trunk zeros. Other countries are accepted with their calling code (8–15 digits). Filterzicw_phone_rulesto add countries. - Validation: mobile patterns per country; optionally block checkout for COD (or every method).
- Blacklist: phones (any format), e-mails (
@domain.comfor a domain), IPs (exact,41.33.*,41.33.0.0/16). Action: refuse COD at checkout, or allow and flag. - COD orders per phone per day (from midnight, site time zone): flag or refuse.
- Refused parcels: refuse COD after N refusals.
- Risk score (0–100): blacklisted +100 · invalid number +40 · each refusal +30 (max 60) · each never-confirmed order +10 (max 30) · daily limit +50 · high value +15 · first order +10 · each delivered order −10 (max −30). Orders at/above Flag orders from score are flagged (column badge + filter + order note).
Blocking applies only to Cash on delivery – the customer can still choose another method.
4.6 License
Paste the key → Activate. Shows status, domain, expiry and last check; Check now, Deactivate on this site (frees the activation on engzaki.pro). The verdict is cached 12 h; if engzaki.pro is unreachable a previously valid license keeps working for 7 days. localhost, *.local and *.test validate without using an activation (server side).
| No license | Licensed | |
|---|---|---|
| Hold COD orders, statuses, phone validation, risk, blacklists | ✓ | ✓ |
| Manual WhatsApp button, signed links, confirmation page, e-mail OTP | ✓ | ✓ |
| Automatic sending (Cloud API, UltraMsg, Twilio, HTTP), WhatsApp OTP, follow-ups | — | ✓ |
| Reminders and auto-cancel with restock | — | ✓ |
| Updates | — | ✓ |
Developers can force the licensed behaviour on their own sites: add_filter( 'zicw_is_licensed', '__return_true' );
5. How it works
Checkout (classic or blocks)
└─ phone / blacklist / daily-limit checks → may refuse COD (WC notice / Store API error)
WC_Gateway_COD::process_payment
└─ filter woocommerce_cod_process_payment_order_status → "zicw-awaiting" when a rule matches
meta: _zicw_state=pending, _zicw_phone (E.164), _zicw_lang, _zicw_risk(+reasons), _zicw_flag
Status → zicw-awaiting
├─ log "placed", phone history +1, stock reduced (optional), admin e-mail (optional)
└─ licensed + API channel → Action Scheduler job zicw_send_request (3 attempts, 10/20 min apart)
Customer
├─ taps a quick-reply button (Meta) → /wp-json/zicw/v1/meta (signature checked) → payload HMAC checked
├─ replies 1/2, yes/no, نعم/لا … → newest awaiting order of that phone
├─ opens {confirm_url}/{cancel_url} → ?zicw=<token> page → POST Confirm / Cancel (+ OTP)
└─ messages your store number → you click "Mark confirmed"
Confirmed → target status + WooCommerce e-mails + optional thank-you message
Cancelled → "Cancelled" (WooCommerce restocks) + optional message
zicw_cron (15 min, licensed) → reminders, auto-cancel ("No reply")
"Refused on delivery" status → history +1, optional restock
"Completed" → history "delivered" +1
- Page tokens:
{order_id}-{expiry}-{HMAC-SHA256(secret, "page|id|exp|order_key")[0..24]}, valid for the auto-cancel time + 72 h. The secret is a random 64-character string in a non-autoloaded option. - Opening a link never changes an order – WhatsApp, Telegram and mail scanners fetch links for previews. The action is a POST from the page, protected by an HMAC form signature, a honeypot and a per-IP rate limit (30 / 10 min). OTP: 6 digits, hashed, valid 10 minutes, 5 tries, 60 s between sends.
- Everything is logged to
{prefix}zicw_events(pruned after 400 days, filterzicw_log_days) and to the order notes.
Hooks
| Hook | Type | Use |
|---|---|---|
zicw_should_hold( bool $hold, WC_Order $order, array $risk ) |
filter | Decide per order. |
zicw_risk( array $result, array $customer ) |
filter | Change score / reasons / block. |
zicw_phone_rules( array $rules ) |
filter | Add or change countries. |
zicw_template_values( array $values, WC_Order $order ) |
filter | Add placeholders. |
zicw_reply_yes_words / zicw_reply_no_words |
filter | Extra reply words. |
zicw_pre_send( null, $channel, $digits, $text, $order, $type ) |
filter | Return ['ok'=>bool,'id'=>'','error'=>''] to send through your own code. |
zicw_block_message( string ) |
filter | Text shown when COD is refused. |
zicw_is_licensed, zicw_capability |
filter | Licensing / capability (manage_woocommerce). |
zicw_order_held, zicw_order_confirmed, zicw_order_cancelled, zicw_order_expired, zicw_order_refused, zicw_message_sent |
action | React to events. |
6. Troubleshooting
| Symptom | Check |
|---|---|
| Orders go straight to Processing | Only the core Cash on delivery gateway is held. Check Enable and the Rules; trusted customers are skipped. Another plugin may override woocommerce_cod_process_payment_order_status later – try it alone. |
| "Automatic sending is off" note on orders | No license, channel is Manual, or credentials are missing (dashboard checklist). |
| Meta error 131047 / "Re-engagement message" | You sent free text outside the 24-hour window – set an approved request template. |
| Meta error 132000 / 132012 | Template parameters don't match the template – adjust Body variables to the exact number of {{n}} in the template. |
| Meta webhook "could not be verified" | Verify token must match; the site must be reachable over HTTPS; security plugins must not block /wp-json/zicw/v1/meta. |
| Button taps do nothing | App Secret missing/wrong (401 in the Meta webhook logs), or the app is not subscribed to messages. |
| Twilio replies rejected (401) | The webhook URL in Twilio must be exactly the URL shown (same scheme, no extra query). Proxies that rewrite the host break the signature. |
| Reminders / auto-cancel never run | WP-Cron disabled or the site has no traffic – add a real cron job. Both need a license. |
| Confirmation page shows an old state | Exclude URLs containing ?zicw= from your page cache / CDN. |
| Customer says the link is "not valid" | The order key changed, or the link was truncated by the provider – resend from the order screen. |
| Wrong language | Message language setting; for "auto" the language is taken from the checkout request. |
Activity per order: order screen → COD confirmation (WhatsApp) box → Activity. Global: Dashboard → Recent activity. API errors are stored without tokens or secrets.
7. FAQ
Does it change orders paid by card? No. Only the core Cash on delivery gateway is held. Phone validation can optionally apply to all methods.
What happens if the customer cancels in My Account? "Awaiting confirmation" orders can be cancelled there; the plugin records it as cancelled by the customer.
Can I confirm manually? Yes – Mark confirmed in the order box, or simply change the status; the plugin records it as confirmed by the shop manager and sends the usual e-mails.
Is UltraMsg allowed by WhatsApp? UltraMsg is an unofficial gateway based on WhatsApp Web. Use the official Cloud API (or Twilio) if you need a policy-compliant setup; the plugin cannot guarantee a number will not be restricted.
Does the plugin make my store compliant with WhatsApp or privacy rules? No plugin can. You must have your customers' consent to be contacted on WhatsApp, use approved templates, and update your privacy policy (a suggested paragraph is added to Settings → Privacy → Policy guide).
Multisite? Activate per site; each site has its own settings, tables and license activation.
Uninstall – removes cron events always; settings, the two tables and the secrets only if Delete all plugin settings and tables is ticked. Order meta and notes stay with your orders.
8. Files
zi-cod-whatsapp-confirm.php bootstrap, constants, HPOS / blocks declarations
includes/class-zicw-plugin.php boot, cron, activation
includes/class-zicw-settings.php options + default templates
includes/class-zicw-license.php engzaki.pro license client (12 h cache, 7-day grace)
includes/class-zicw-updater.php self-updater (update transient + plugins_api)
includes/class-zicw-orders.php statuses, holding, confirm / cancel / expire, cron, thank-you box
includes/class-zicw-channels.php Meta / UltraMsg / Twilio / generic / manual links
includes/class-zicw-webhooks.php REST webhooks + reply parsing
includes/class-zicw-confirm-page.php customer page + OTP
includes/class-zicw-checkout.php classic + Store API checks
includes/class-zicw-risk.php blacklists, limits, score
includes/class-zicw-phone.php E.164 normalisation
includes/class-zicw-token.php HMAC tokens
includes/class-zicw-templates.php placeholders, language
includes/class-zicw-log.php events + phone history tables
includes/class-zicw-admin.php admin pages, order column / filter / box, AJAX
assets/ admin.css/js, confirm.css, public.css, icons
languages/ .pot, Arabic .po/.mo
Dev only (not in the zip): tools/i18n.py (pot / po / mo), tools/build.py (zip), tests/smoke.php (phone / reply / blacklist / signature checks).
9. Changelog
1.0.0 – first release.
Changelog
= 1.0.0 = * First release: "Awaiting confirmation" and "Refused on delivery" statuses, WhatsApp Cloud API (signed quick-reply buttons, verified webhook), UltraMsg, Twilio, generic HTTP API and manual click-to-chat channels, confirmation page with optional OTP, reminders, auto-cancel with restock, phone normalisation for EG / SA / AE / KW / QA / BH / OM / MA / JO, blacklists, daily COD limit, refused-delivery history, risk score, dashboard, order list column and filter, Arabic translation, HPOS and checkout blocks compatibility.
FAQ
+Do I need the WhatsApp Business API?
No. Manual mode needs no API: one click opens WhatsApp with the message ready. The Cloud API, UltraMsg, Twilio or another HTTP provider make it fully automatic.
+Which payment methods are affected?
Only WooCommerce's built-in Cash on delivery. Card and other payments are never held. Phone validation can optionally apply to all methods.
+What does Meta require for the first message?
A business-initiated WhatsApp message must use an approved template. The plugin shows a suggested English and Arabic Utility template with two quick-reply buttons that you submit in WhatsApp Manager.
+Can a link preview confirm an order by mistake?
No. Links only open the confirmation page; the order changes only when the customer presses Confirm or Cancel.
+What happens to stock while an order waits?
By default stock is reserved while the order waits and restored automatically if it is cancelled by the customer, by you or by the auto-cancel.
+Will orders be cancelled if my API is down?
No. Auto-cancel only applies to orders whose confirmation request was actually sent, or whose number is invalid. Others stay waiting for you.
+Does it work with HPOS and the block checkout?
Yes. It declares compatibility with High-Performance Order Storage and the Cart & Checkout blocks, and works with the classic checkout too.
+What works without a license?
Holding COD orders, phone validation, risk checks, blacklists, the manual WhatsApp button and the confirmation page. Automatic sending, reminders, auto-cancel and WhatsApp OTP need a license.
+Does the plugin make me compliant with WhatsApp policies?
No plugin can. You still need your customers' consent to message them, approved templates for the Cloud API, and an updated privacy policy. A suggested privacy paragraph is included.
Support
Every purchase includes support from the developer. If something does not work as described, send us your license key and site address and we will help you get it running.