1. How to install the plugin?

Step 1. Extract all files.
Step 2. Upload to your Magento root so the module lives at magento_root/app/code/FM/Feemaker.
Step 3. From the Magento root over SSH:
            php bin/magento setup:upgrade
            php bin/magento setup:di:compile
            php bin/magento setup:static-content:deploy -f
Step 4. The bundled signing client requires the PHP `gmp` and `curl` extensions. Confirm both are loaded in CLI and FPM (`php -m | grep -E 'gmp|curl'`).

2. How to set up the plugin?

Step 1. Log in to Magento Admin and go to Stores -> Configuration -> Sales -> Payment Methods.
Step 2. Open Feemaker (Invoice API) and fill:
            - Owner Address: your merchant EVM address.
            - Session Private Key: 32-byte hex private key registered against
              Owner Address via POST /auth/register-pubkey. Stored encrypted; used
              to sign API calls (POST /invoice, POST /poll/events).
            - Default Chain ID: 1 Ethereum, 11155111 Sepolia, 728126428 TRON, 56 BSC, ...
            - Accepted Tokens: one "{chainId}:{tokenAddress}" per line. Use
              0x0000000000000000000000000000000000000000 for the native coin.
            - Invoice Deadline (seconds): default 86400.
Step 3. Save. Feemaker will appear as a checkout option. On order placement the
        plugin calls POST /invoice and redirects the customer to the returned
        paymentUrl on app.feemaker.io.

3. Receiving status updates

Polling (recommended):
    Configure a system cron entry to POST `{"action":"poll"}` to
        /rest/V1/feemaker/ipn
    every minute. The IpnManagement endpoint will drain /poll/events and apply
    each invoice to the matching Magento order.

Webhook:
    Register the same URL via POST /auth/register-callback. Feemaker will then
    POST a JSON-encoded Invoice record (including `guid` and `status`) on every
    state change. The endpoint also accepts those payloads directly.

In both modes orders flip to the "Paid order status" on `paid`, stay on the
"Placed order status" with a comment on `init`/`partialPaid`, and are cancelled
on `expired`.
