=== Qint Payments for WooCommerce ===
Contributors: qint
Tags: woocommerce, payments, crypto, bitcoin, checkout
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.0.5
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Accept crypto payments in CHF, EUR, USD or GBP through the Qint hosted checkout.

== Description ==

Qint Payments adds a "Pay with crypto" method to WooCommerce. At checkout the
customer is redirected to Qint's secure hosted checkout page; the order is
updated automatically via cryptographically signed webhooks, with a
server-side polling fallback on the order-received page in case a webhook is
missed.

* Supports store currencies CHF, EUR, USD and GBP — whichever are currently
  enabled on Qint (read from the Qint API and cached for 10 minutes).
* Signed webhooks (HMAC-SHA256, constant-time verification, replay dedupe,
  out-of-order delivery guards).
* Underpaid payments put the order on hold for a manual decision; a payment
  reversed after settlement puts the order on hold and never counts as paid.
* Hidden at checkout when the cart is below Qint's minimum per payment
  (CHF 10 or the equivalent), with Qint's limits message shown instead.
* WooCommerce 8.0 – 11.x, HPOS (custom order tables) and block checkout
  compatible.
* No external assets, no tracking.

Download the latest package from https://qint.ch/downloads/qint-payments.zip
and follow the guide at https://docs.qint.ch/guides/woocommerce. You need a
Qint merchant account (https://dashboard.qint.ch) with an API key and a
webhook endpoint.

== Installation ==

1. Download https://qint.ch/downloads/qint-payments.zip, then WP Admin →
   Plugins → Add New → Upload Plugin → choose the zip → Activate
   (WooCommerce must be active).
2. WooCommerce → Settings → Payments → "Qint — Pay with crypto".
3. Paste your qk_live_… API key (Read + Write scopes) and save — the
   connection is tested automatically.
4. Copy the webhook URL shown at the top of the gateway settings page (it is
   computed for your site: `https://YOURSITE/wp-json/qint/v1/webhook` with
   pretty permalinks, `https://YOURSITE/index.php?rest_route=/qint/v1/webhook`
   with "Plain" permalinks). In the Qint dashboard, create a webhook endpoint with
   exactly that URL and paste its signing secret into the gateway settings.

== Frequently Asked Questions ==

= Which currencies are supported? =

CHF, EUR, USD and GBP. Qint can switch a currency off temporarily; the
plugin reads the current list from the Qint API (cached for 10 minutes,
refreshed when you save the settings) and hides the payment method while the
store currency is off or unsupported. The gateway settings page lists the
enabled currencies and warns when your store currency is not one of them. If
the Qint API cannot be reached, the four currencies are assumed enabled and
Qint still refuses a disabled one at checkout, with a clear message to the
customer.

= Is there a minimum order amount? =

Yes. Every Qint payment must be between CHF 10 and CHF 100'000 (or the
equivalent in EUR, USD or GBP). In a CHF store the payment method is hidden
for carts under CHF 10 and the checkout shows "Pay with crypto is not
available for this order. Payments must be between CHF 10 and CHF 100'000
(or the equivalent). This amount is CHF 5.00." In EUR/USD/GBP stores the
plugin learns Qint's rate the first time Qint refuses a small amount and
hides the method for small carts from then on; until then the method stays
visible and Qint's message is shown if the customer tries to pay.

= My webhook deliveries show as successful but orders do not update =

Your site most likely uses "Plain" permalinks and the endpoint in the Qint
dashboard points at `/wp-json/qint/v1/webhook`. On Plain permalinks that path
serves your homepage with HTTP 200, so Qint counts the delivery as successful
although the plugin never received it. Copy the exact webhook URL from the top
of the gateway settings page (the `?rest_route=` form), or switch to any other
permalink structure.

= What happens if a customer underpays? =

The order is set to "on hold" with a note so you can decide how to proceed
from the Qint dashboard's review queue.

= What happens if a settled payment is reversed? =

Qint re-sends the payment event with `reversed: true` when the execution
partner reverses a payment after settlement. The plugin puts the order on
hold with an explicit "REVERSED" note (and flags it in the order's Qint box);
the order never counts as paid again for that intent.

= Which WooCommerce versions are supported? =

WooCommerce 8.0 up to 11.x on WordPress 6.0+ (tested up to WordPress 7.1
and WooCommerce 11.2) and PHP 7.4+, with both the
classic shortcode checkout and the block checkout, with or without HPOS.

= Does it work on a site without HTTPS? =

Payments work, but webhooks require a public HTTPS URL, so orders would only
update through the polling fallback. Use HTTPS.

== Changelog ==

= 1.0.5 =
* Follows the Qint API change of 20 October 2026: your Qint balance is held
  in fiat, in your Account Currency. The "payment settled" order note now
  shows the amount credited to your Qint balance in that currency, for
  example "Qint settlement: fee 0.50 EUR, net 99.50 EUR, credited 93.42 CHF."
  (it used to show the stablecoin credited, USDT/USDC, which the API no
  longer reports). The webhook path shows the credit as well. No settings
  change; orders, statuses and checkout behave as before.

= 1.0.4 =
* The gateway settings page now shows the exact webhook URL for your store,
  ready to copy into the Qint dashboard, and warns when your permalinks are
  set to "Plain". On Plain permalinks the webhook URL is the
  `?rest_route=/qint/v1/webhook` form: the `/wp-json/qint/v1/webhook` path
  serves the homepage there, so deliveries looked successful in the Qint
  dashboard while orders never updated.
* The Qint payment method is hidden when the cart total is below Qint's
  minimum per payment (CHF 10 or the equivalent), and the checkout explains
  why with Qint's own limits message. If the minimum cannot be determined
  the method stays visible, and a payment Qint refuses for its amount now
  shows Qint's message instead of a generic error.
* Fix: on current WooCommerce versions the payment method did not appear on
  the block-based checkout (the default checkout page) because it registered
  with the block checkout too late. It now appears there as well, and is
  hidden live when the cart drops below the minimum.
* Tested up to WordPress 7.1 and WooCommerce 11.2.

= 1.0.3 =
* Respect Qint's currency switches: read the enabled currencies from
  `GET /api/v1/public/currencies` (cached 10 minutes, 1 minute after a failed
  fetch, falling back to CHF/EUR/USD/GBP) and hide the payment method while
  the store currency is switched off.
* Gateway settings page lists the currencies enabled on Qint and warns when
  the store currency is disabled or unsupported.
* A checkout that races a currency switch-off now shows "Crypto payments are
  not available for orders in GBP at the moment…" instead of the raw API
  error, and refreshes the cached list.
* The "payment settled" order note adds Qint's fee, the net amount and the
  settlement asset credited (USDT/USDC) when the API reports them.

= 1.0.2 =
* Add GBP as a supported store currency.

= 1.0.1 =
* Handle payments reversed after settlement (`reversed` / `reversedAt`): the
  order goes on hold with a note and is never completed for that intent.
* Status polling no longer clears the underpaid flag (the GET intent response
  does not carry it).
* Ignore stale webhook deliveries: a live status after a terminal one, or an
  `occurredAt` older than the last applied event.
* Mark a webhook event as processed only after it was applied, so a failure
  mid-way is retried by Qint instead of being swallowed as a duplicate.
* Reuse an existing intent only when its amount and currency still match the
  order; mint a fresh one after an idempotent replay returned a terminal
  intent.
* Respect API limits: title capped at 200 characters, returnUrl only when
  https and at most 500 characters.
* Reconcile when the hosted checkout sends the buyer back with
  `?qint_intent=` (works even if the theme's thank-you hooks do not fire).
* Log the dashboard "Send test event" ping so the setup can be verified from
  WooCommerce → Status → Logs.
* Declare `Requires Plugins: woocommerce`; add a dependency-free unit test
  suite (`php tests/run.php`).

= 1.0.0 =
* Initial release: hosted-checkout redirect gateway, signed webhook receiver,
  order-received polling fallback, admin order box, block checkout support.
