=== Ulasend Payments for WooCommerce ===
Contributors: ulasend
Tags: woocommerce, payments, checkout, usdc
Requires at least: 6.6
Requires PHP: 8.1
Stable tag: 0.1.0
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

One-time USD orders through Ulasend hosted checkout, with verified payment updates for classic checkout and Checkout Blocks.

== Description ==

Ulasend creates an invoice from the server-side WooCommerce order total, redirects the customer to hosted checkout, and updates the order after checking the signed payment notification and the current invoice. Processing fees passed to the customer are included in the Ulasend quote and checked before fulfillment. The WooCommerce order total remains the original store total.

Version 0.1.0 supports one-time orders in USD using USDC on Base. Eligible card-funded crypto is offered by the hosted checkout when available. It does not offer subscriptions, saved payment methods, automatic refunds, bank transfer checkout, or other settlement currencies. A card-funded crypto checkout is not a direct card acquiring integration.

This is a first-party package, not a claim of WooCommerce Marketplace certification. Test it with your theme, checkout and fulfillment extensions on a staging store before enabling live payments.

== Installation ==

1. Back up your staging store and install WooCommerce 9.0 or newer on WordPress 6.6 or newer with PHP 8.1 or newer. Production requires HTTPS and MySQL/MariaDB with named lock support. SQLite development environments require a test lock adapter and are not supported for production payment processing.
2. Upload the ZIP using Plugins > Add New > Upload Plugin, then activate it.
3. Open WooCommerce > Settings > Payments > Ulasend.
4. Copy your merchant UUID from Ulasend Dashboard > Integrations. Your Ulasend business must be approved for processing and have USDC on Base enabled.
5. In Ulasend Dashboard > Developers, create a test API key with invoices:write. This scope also permits invoice reads. Save it in the plugin's Test API key field.
6. Create a TEST webhook endpoint in Ulasend using the Test webhook URL displayed by this plugin. Select invoice.paid, invoice.overpaid, invoice.partially_paid, invoice.manual_review and invoice.expired individually from the offered events. Selecting all events is also supported. Cancellation status is checked during reconciliation; there is no separate invoice.cancelled webhook event.
7. Copy the signing secret into the plugin's Test webhook signing secret field and save. Return to Ulasend and verify the endpoint. The plugin returns the signed ownership challenge automatically.
8. Enable the gateway in Test mode. Only signed-in users with the manage_woocommerce capability see test checkout. Create a test order and use Ulasend's simulation. A verified test payment leaves the order On hold, adds a test note, and never calls WooCommerce payment_complete or releases fulfillment.
9. Test notification retries, a missing notification, changed totals, expired checkouts and the Recheck Ulasend payment order action.
10. For live use, create a separate live API key and webhook endpoint. Live key and endpoint management requires the authorized Ulasend owner/admin dashboard flow and two-factor authentication. Save and verify the separate live signing secret, then select Live and test a controlled real order. No live endpoint is installed silently by this plugin.

Webhook URLs:
/wp-json/ulasend/v1/webhook/test
/wp-json/ulasend/v1/webhook/live

Both endpoints need public HTTPS access. A localhost-only development store cannot receive Ulasend notifications; use local mocked tests or a secure staging site for external testing.

== Payment behavior and recovery ==

The order amount, mode, API creation request, and checkout reference are frozen before invoice creation. Retrying after a timeout uses the same idempotency key and exact request. The plugin does not create a replacement invoice for an existing order, even after expiry. If the total or mode changes, or creation cannot be recovered within 23 hours, contact support and reconcile the original invoice before creating a new order. Do not discard an invoice that could still receive funds.

Signed notifications are checked against the endpoint mode and merchant UUID. The plugin fetches the invoice using the same mode's API key and checks its identity, order reference, USD total, settlement asset/network, unchanged full quoted amount, received amount, and remaining allocation. It requires full quote coverage even if your Ulasend account tolerates a crypto shortfall. The browser return URL never marks an order paid.

Partial, reviewing, expired and cancelled invoices do not release an order. A fully paid order already cancelled, failed or refunded in WooCommerce, or an invoice previously observed expired/cancelled, is flagged for manual review. To accept a verified late payment, first resolve inventory/customer issues and restore the order to On hold. Use Recheck Ulasend payment to see the review result, then explicitly select Accept verified late Ulasend payment. The plugin still requires all payment checks to pass. Automatic refunds are unavailable; contact Ulasend support to discuss the payment before making promises to the customer.

WordPress cron rechecks up to 25 unresolved invoices every five minutes for 30 days after creation. Configure a real cron runner when WP-Cron is disabled or the store has little traffic. The order action Recheck Ulasend payment is available for older orders. Ulasend also retries failed webhook deliveries. Deactivation stops the recovery schedule; reconnecting after uninstall requires restoring credentials and verifying webhook setup.

Payment records are serialized by a MySQL connection lock. Already completed orders and durable event records prevent duplicate order completion. Temporary API or lock failures return an error so webhook delivery can retry. Event deduplication records are retained for 90 days; order/payment evidence remains for reconciliation.

== Credentials and privacy ==

API keys and webhook secrets stay on the WordPress server and are never included in checkout JavaScript or saved-secret HTML values. They are stored in WordPress options; restrict database access, protect backups and use your hosting provider's encryption at rest. Leave secret fields blank to keep saved values, or select Disconnect to clear all credentials and disable the gateway. Disconnect also pauses reconciliation of existing orders until credentials are restored. Uninstall removes the connection settings but keeps payment evidence and WooCommerce order data.

The plugin sends order amount, order reference, return URL and optional billing email to https://ulasend.com/api/v1/invoices. It retrieves invoice status from the same service. External calls are necessary to create and verify payments. Review https://ulasend.com/privacy and https://ulasend.com/terms. It does not send the customer's card details, billing address or product list to Ulasend.

No request/response bodies, API keys or webhook secrets are written to plugin logs. Test and live credentials and webhook endpoints are separate. Disable automatic fulfillment by unrelated plugins for any On hold or review-required order.

== Changelog ==

= 0.1.0 =
Initial one-time hosted checkout integration, Checkout Blocks registration, HPOS order APIs, signed webhook reconciliation and scheduled recovery.
