Title: Paymos for Easy Digital Downloads
Author: Paymos
Published: <strong>November 6, 2026</strong>
Last modified: November 6, 2026

---

Search plugins

![](https://ps.w.org/paymos-easy-digital-downloads/assets/icon-256x256.png?rev=3787430)

# Paymos for Easy Digital Downloads

 By [Paymos](https://profiles.wordpress.org/paymos/)

[Download](https://downloads.wordpress.org/plugin/paymos-easy-digital-downloads.1.6.2.zip)

 * [Details](https://wordpress.org/plugins/paymos-easy-digital-downloads/#description)
 * [Reviews](https://wordpress.org/plugins/paymos-easy-digital-downloads/#reviews)
 *  [Installation](https://wordpress.org/plugins/paymos-easy-digital-downloads/#installation)
 * [Development](https://wordpress.org/plugins/paymos-easy-digital-downloads/#developers)

 [Support](https://wordpress.org/support/plugin/paymos-easy-digital-downloads/)

## Description

The official package contains no merchant credentials. Open Downloads -> Settings-
> Payments -> Paymos and click Connect Paymos. Approve the current project in Paymos;
the plugin receives Sandbox and Live credentials once, stores them in an AES-256-
GCM encrypted WordPress option, and discards the short-lived OAuth token.

Runtime Merchant API requests remain HMAC signed. Signed webhooks update invoices
without a local invoice reconciliation job: a delivery that fails is retried by 
Paymos across roughly 16 hours, and anything that outlives the ladder is replayed
from the Paymos dashboard. Pending refunds are reconciled locally by a 1-minute 
WP-Cron job (`paymos_edd_refunds_reconcile`).

### External services

Paymos handles payment requests for this Easy Digital Downloads gateway. To connect,
click **Connect Paymos** in your WordPress admin and approve the connection in Paymos.
Device authorization starts at `https://app.paymos.io/connect/cms/device`; the plugin
polls `https://app.paymos.io/connect/token` for approval. The browser approval URL
carries the plugin identifier, store origin, admin return URL, and `user_code`. 
The plugin sends the secret `device_code` to the token endpoint. It stores the returned
Sandbox and Live credentials in AES-256-GCM-encrypted WordPress options and discards
the short-lived OAuth token.

For payments, the plugin creates invoices at `https://api.paymos.io/v1/invoices`,
checks them with `GET /v1/invoices/{invoice_id}`, and cancels them with `POST /v1/
invoices/{invoice_id}/cancel`. Each signed request sends a key ID, timestamp, and
HMAC signature. The API secret stays with the plugin for signing. Invoice fields
include `project_id`, `amount`, `currency`, `external_order_id`, and, when available,
the native customer ID as `client_id`. New orders use a random opaque reference.
Existing references remain in use and can contain an EDD purchase key.

For refunds, the plugin sends `POST /v1/refunds` requests to `https://api.paymos.
io/v1/refunds` with only `invoice_id`, `mode` (`full` or `overpayment`), and `external_order_id`;
Paymos returns funds strictly to the verified `first_sender` address recorded on
the invoice. The plugin checks individual refund status with `GET /v1/refunds/{refund_id}`,
polls cursor-paginated refund pages with `GET /v1/refunds` (`cursor`, `limit`, `
invoice_id`, and `status`), and in Sandbox mode simulates terminal outcomes with`
POST /v1/sandbox/refunds/{refund_id}/simulate` sending `status` (`completed`, `failed`,
or `cancelled`). Pending refunds are polled by a 1-minute WP-Cron job (`paymos_edd_refunds_reconcile`).

Buyers pay over HTTPS at `https://checkout.paymos.io`. Signed invoice and payment
webhooks return to the store to update orders. Service terms and data handling appear
in the [Terms](https://paymos.io/terms) and [Privacy Policy](https://paymos.io/privacy).

## Installation

 1. Install and activate the official release.
 2. Open the intended project in Paymos; that current project is used automatically.
 3. Open Downloads -> Settings -> Payments -> Paymos.
 4. Click Connect Paymos and approve the displayed store URL and current project.
 5. Test in Sandbox, then switch to Live.

## FAQ

### Does the ZIP contain secrets?

No. Every merchant downloads the same public package.

### Where are credentials stored?

In a non-autoloaded WordPress option encrypted with AES-256-GCM using installation
security salts.

## Reviews

There are no reviews for this plugin.

## Contributors & Developers

“Paymos for Easy Digital Downloads” is open source software. The following people
have contributed to this plugin.

Contributors

 *   [ Paymos ](https://profiles.wordpress.org/paymos/)

[Translate “Paymos for Easy Digital Downloads” into your language.](https://translate.wordpress.org/projects/wp-plugins/paymos-easy-digital-downloads)

### Interested in development?

[Browse the code](https://plugins.trac.wordpress.org/browser/paymos-easy-digital-downloads/),
check out the [SVN repository](https://plugins.svn.wordpress.org/paymos-easy-digital-downloads/),
or subscribe to the [development log](https://plugins.trac.wordpress.org/log/paymos-easy-digital-downloads/)
by [RSS](https://plugins.trac.wordpress.org/log/paymos-easy-digital-downloads/?limit=100&mode=stop_on_copy&format=rss).

## Changelog

#### 1.6.2

 * fix(cms): align marketplace manifests, refund copy, store links, and release 
   guards
 * chore: bundle Paymos PHP SDK v1.9.1
 * chore: rebuild canonical CMS package

#### 1.6.1

 * fix(plugins): use wp_add_inline_script, sanitize nonces before wp_verify_nonce,
   and guard curl_close on PHP 8+
 * chore: bundle Paymos PHP SDK v1.9.1
 * Moved optional Paymos diagnostics from PHP error_log to the EDD debug log, with
   masking for supported key patterns. Logging remains off by default.
 * Compare amounts as exact decimals and require complete invoice snapshots plus
   API confirmation before changing payment state.
 * Serialize order updates and recover when native payment completion returns `false`
   from save or status updates.
 * Check ownership when updating event reservations, and purge at most 100 expired
   records per reservation.

Fixed:
 * Entries that were present, non-empty and still English — `Connect Paymos`
in German and Spanish, the plugin name in Turkish and Chinese, `Webhook URL` in 
Chinese — and one string missing from every catalogue (`in the invoice currency`,
the fallback in the underpayment notice). * A late non-final webhook could reopen
a finished order. Webhooks are delivered at least once and in no particular order,
and only paid orders were guarded: an `invoice.underpaid_waiting` or `invoice.confirming`
arriving after the invoice had already ended underpaid, expired or cancelled moved
the order back into an open state. Nothing leaves a final status on the server, 
so once one is recorded for an invoice every later event for it is ignored and the
final status stays recorded. * A new invoice now resets the Paymos status recorded
on the payment, so an event for it is never taken for a stale one after an earlier
final status. * A webhook retry that arrived while the first delivery was still 
being processed was answered 200 “duplicate”. Paymos gives a delivery 10 seconds
and retries, while a slow reverse-verification call can take longer; the retry was
acknowledged as delivered, and if the first attempt then failed the event was lost.
An event that is only locked, not yet committed, is now answered 409 so Paymos tries
again, and the lock the first delivery holds is left alone.

#### 1.6.0

 * feat(refunds): finalize clean merchant refunds spec, SDKs, CMS plugins, and targeted
   test scripts
 * wip: snapshot shared working tree before merging main
 * wip(refunds): merchant refund plugin work (CMS adapters, PHP SDK, tests) – unverified
   WIP snapshot
 * chore: bundle Paymos PHP SDK v1.9.0
 * chore: rebuild canonical CMS package
 * Moved optional Paymos diagnostics from PHP error_log to the EDD debug log, with
   masking for supported key patterns. Logging remains off by default.
 * Compare amounts as exact decimals and require complete invoice snapshots plus
   API confirmation before changing payment state.
 * Serialize order updates and recover when native payment completion returns `false`
   from save or status updates.
 * Check ownership when updating event reservations, and purge at most 100 expired
   records per reservation.

Fixed:
 * Entries that were present, non-empty and still English — `Connect Paymos`
in German and Spanish, the plugin name in Turkish and Chinese, `Webhook URL` in 
Chinese — and one string missing from every catalogue (`in the invoice currency`,
the fallback in the underpayment notice). * A late non-final webhook could reopen
a finished order. Webhooks are delivered at least once and in no particular order,
and only paid orders were guarded: an `invoice.underpaid_waiting` or `invoice.confirming`
arriving after the invoice had already ended underpaid, expired or cancelled moved
the order back into an open state. Nothing leaves a final status on the server, 
so once one is recorded for an invoice every later event for it is ignored and the
final status stays recorded. * A new invoice now resets the Paymos status recorded
on the payment, so an event for it is never taken for a stale one after an earlier
final status. * A webhook retry that arrived while the first delivery was still 
being processed was answered 200 “duplicate”. Paymos gives a delivery 10 seconds
and retries, while a slow reverse-verification call can take longer; the retry was
acknowledged as delivered, and if the first attempt then failed the event was lost.
An event that is only locked, not yet committed, is now answered 409 so Paymos tries
again, and the lock the first delivery holds is left alone.

#### 1.5.4

 * chore: bundle Paymos PHP SDK v1.8.1
 * Moved optional Paymos diagnostics from PHP error_log to the EDD debug log, with
   masking for supported key patterns. Logging remains off by default.
 * Compare amounts as exact decimals and require complete invoice snapshots plus
   API confirmation before changing payment state.
 * Serialize order updates and recover when native payment completion returns `false`
   from save or status updates.
 * Check ownership when updating event reservations, and purge at most 100 expired
   records per reservation.

Fixed:
 * Entries that were present, non-empty and still English — `Connect Paymos`
in German and Spanish, the plugin name in Turkish and Chinese, `Webhook URL` in 
Chinese — and one string missing from every catalogue (`in the invoice currency`,
the fallback in the underpayment notice). * A late non-final webhook could reopen
a finished order. Webhooks are delivered at least once and in no particular order,
and only paid orders were guarded: an `invoice.underpaid_waiting` or `invoice.confirming`
arriving after the invoice had already ended underpaid, expired or cancelled moved
the order back into an open state. Nothing leaves a final status on the server, 
so once one is recorded for an invoice every later event for it is ignored and the
final status stays recorded. * A new invoice now resets the Paymos status recorded
on the payment, so an event for it is never taken for a stale one after an earlier
final status. * A webhook retry that arrived while the first delivery was still 
being processed was answered 200 “duplicate”. Paymos gives a delivery 10 seconds
and retries, while a slow reverse-verification call can take longer; the retry was
acknowledged as delivered, and if the first attempt then failed the event was lost.
An event that is only locked, not yet committed, is now answered 409 so Paymos tries
again, and the lock the first delivery holds is left alone.

#### 1.5.3

 * chore: rebuild canonical CMS package
 * Moved optional Paymos diagnostics from PHP error_log to the EDD debug log, with
   masking for supported key patterns. Logging remains off by default.
 * Compare amounts as exact decimals and require complete invoice snapshots plus
   API confirmation before changing payment state.
 * Serialize order updates and recover when native payment completion returns `false`
   from save or status updates.
 * Check ownership when updating event reservations, and purge at most 100 expired
   records per reservation.

Fixed:
 * Entries that were present, non-empty and still English — `Connect Paymos`
in German and Spanish, the plugin name in Turkish and Chinese, `Webhook URL` in 
Chinese — and one string missing from every catalogue (`in the invoice currency`,
the fallback in the underpayment notice). * A late non-final webhook could reopen
a finished order. Webhooks are delivered at least once and in no particular order,
and only paid orders were guarded: an `invoice.underpaid_waiting` or `invoice.confirming`
arriving after the invoice had already ended underpaid, expired or cancelled moved
the order back into an open state. Nothing leaves a final status on the server, 
so once one is recorded for an invoice every later event for it is ignored and the
final status stays recorded. * A new invoice now resets the Paymos status recorded
on the payment, so an event for it is never taken for a stale one after an earlier
final status. * A webhook retry that arrived while the first delivery was still 
being processed was answered 200 “duplicate”. Paymos gives a delivery 10 seconds
and retries, while a slow reverse-verification call can take longer; the retry was
acknowledged as delivered, and if the first attempt then failed the event was lost.
An event that is only locked, not yet committed, is now answered 409 so Paymos tries
again, and the lock the first delivery holds is left alone.

#### 1.5.2

 * fix(edd): validate refund controls and prepare directory database queries
 * Moved optional Paymos diagnostics from PHP error_log to the EDD debug log, with
   masking for supported key patterns. Logging remains off by default.
 * Compare amounts as exact decimals and require complete invoice snapshots plus
   API confirmation before changing payment state.
 * Serialize order updates and recover when native payment completion returns `false`
   from save or status updates.
 * Check ownership when updating event reservations, and purge at most 100 expired
   records per reservation.

Fixed:
 * Entries that were present, non-empty and still English — `Connect Paymos`
in German and Spanish, the plugin name in Turkish and Chinese, `Webhook URL` in 
Chinese — and one string missing from every catalogue (`in the invoice currency`,
the fallback in the underpayment notice). * A late non-final webhook could reopen
a finished order. Webhooks are delivered at least once and in no particular order,
and only paid orders were guarded: an `invoice.underpaid_waiting` or `invoice.confirming`
arriving after the invoice had already ended underpaid, expired or cancelled moved
the order back into an open state. Nothing leaves a final status on the server, 
so once one is recorded for an invoice every later event for it is ignored and the
final status stays recorded. * A new invoice now resets the Paymos status recorded
on the payment, so an event for it is never taken for a stale one after an earlier
final status. * A webhook retry that arrived while the first delivery was still 
being processed was answered 200 “duplicate”. Paymos gives a delivery 10 seconds
and retries, while a slow reverse-verification call can take longer; the retry was
acknowledged as delivered, and if the first attempt then failed the event was lost.
An event that is only locked, not yet committed, is now answered 409 so Paymos tries
again, and the lock the first delivery holds is left alone.

#### 1.5.1

 * fix(plugins): require helper-complete PHP SDK for refunds
 * Moved optional Paymos diagnostics from PHP error_log to the EDD debug log, with
   masking for supported key patterns. Logging remains off by default.
 * Compare amounts as exact decimals and require complete invoice snapshots plus
   API confirmation before changing payment state.
 * Serialize order updates and recover when native payment completion returns `false`
   from save or status updates.
 * Check ownership when updating event reservations, and purge at most 100 expired
   records per reservation.

Fixed:
 * Entries that were present, non-empty and still English — `Connect Paymos`
in German and Spanish, the plugin name in Turkish and Chinese, `Webhook URL` in 
Chinese — and one string missing from every catalogue (`in the invoice currency`,
the fallback in the underpayment notice). * A late non-final webhook could reopen
a finished order. Webhooks are delivered at least once and in no particular order,
and only paid orders were guarded: an `invoice.underpaid_waiting` or `invoice.confirming`
arriving after the invoice had already ended underpaid, expired or cancelled moved
the order back into an open state. Nothing leaves a final status on the server, 
so once one is recorded for an invoice every later event for it is ignored and the
final status stays recorded. * A new invoice now resets the Paymos status recorded
on the payment, so an event for it is never taken for a stale one after an earlier
final status. * A webhook retry that arrived while the first delivery was still 
being processed was answered 200 “duplicate”. Paymos gives a delivery 10 seconds
and retries, while a slow reverse-verification call can take longer; the retry was
acknowledged as delivered, and if the first attempt then failed the event was lost.
An event that is only locked, not yet committed, is now answered 409 so Paymos tries
again, and the lock the first delivery holds is left alone.

#### 1.5.0

 * fix(ton): return friendly addresses with existing webhook schema
 * feat(edd): native refund adapter for full and overpayment refunds
 * fix(edd): refuse native refunds that bypass the Paymos gateway
 * fix(edd): prepare clean WordPress.org distribution
 * chore: bundle Paymos PHP SDK v1.8.0
 * chore: rebuild canonical CMS package
 * Moved optional Paymos diagnostics from PHP error_log to the EDD debug log, with
   masking for supported key patterns. Logging remains off by default.
 * Compare amounts as exact decimals and require complete invoice snapshots plus
   API confirmation before changing payment state.
 * Serialize order updates and recover when native payment completion returns `false`
   from save or status updates.
 * Check ownership when updating event reservations, and purge at most 100 expired
   records per reservation.

Fixed:
 * Entries that were present, non-empty and still English — `Connect Paymos`
in German and Spanish, the plugin name in Turkish and Chinese, `Webhook URL` in 
Chinese — and one string missing from every catalogue (`in the invoice currency`,
the fallback in the underpayment notice). * A late non-final webhook could reopen
a finished order. Webhooks are delivered at least once and in no particular order,
and only paid orders were guarded: an `invoice.underpaid_waiting` or `invoice.confirming`
arriving after the invoice had already ended underpaid, expired or cancelled moved
the order back into an open state. Nothing leaves a final status on the server, 
so once one is recorded for an invoice every later event for it is ignored and the
final status stays recorded. * A new invoice now resets the Paymos status recorded
on the payment, so an event for it is never taken for a stale one after an earlier
final status. * A webhook retry that arrived while the first delivery was still 
being processed was answered 200 “duplicate”. Paymos gives a delivery 10 seconds
and retries, while a slow reverse-verification call can take longer; the retry was
acknowledged as delivered, and if the first attempt then failed the event was lost.
An event that is only locked, not yet committed, is now answered 409 so Paymos tries
again, and the lock the first delivery holds is left alone.

#### 1.4.10

 * chore: rebuild canonical CMS package
 * Compare amounts as exact decimals and require complete invoice snapshots plus
   API confirmation before changing payment state.
 * Serialize order updates and recover when native payment completion returns `false`
   from save or status updates.
 * Check ownership when updating event reservations, and purge at most 100 expired
   records per reservation.

Fixed:
 * Entries that were present, non-empty and still English — `Connect Paymos`
in German and Spanish, the plugin name in Turkish and Chinese, `Webhook URL` in 
Chinese — and one string missing from every catalogue (`in the invoice currency`,
the fallback in the underpayment notice). * A late non-final webhook could reopen
a finished order. Webhooks are delivered at least once and in no particular order,
and only paid orders were guarded: an `invoice.underpaid_waiting` or `invoice.confirming`
arriving after the invoice had already ended underpaid, expired or cancelled moved
the order back into an open state. Nothing leaves a final status on the server, 
so once one is recorded for an invoice every later event for it is ignored and the
final status stays recorded. * A new invoice now resets the Paymos status recorded
on the payment, so an event for it is never taken for a stale one after an earlier
final status. * A webhook retry that arrived while the first delivery was still 
being processed was answered 200 “duplicate”. Paymos gives a delivery 10 seconds
and retries, while a slow reverse-verification call can take longer; the retry was
acknowledged as delivered, and if the first attempt then failed the event was lost.
An event that is only locked, not yet committed, is now answered 409 so Paymos tries
again, and the lock the first delivery holds is left alone.

#### 1.4.9

 * chore: rebuild canonical CMS package
 * Compare amounts as exact decimals and require complete invoice snapshots plus
   API confirmation before changing payment state.
 * Serialize order updates and recover when native payment completion returns `false`
   from save or status updates.
 * Check ownership when updating event reservations, and purge at most 100 expired
   records per reservation.

Fixed:
 * Entries that were present, non-empty and still English — `Connect Paymos`
in German and Spanish, the plugin name in Turkish and Chinese, `Webhook URL` in 
Chinese — and one string missing from every catalogue (`in the invoice currency`,
the fallback in the underpayment notice). * A late non-final webhook could reopen
a finished order. Webhooks are delivered at least once and in no particular order,
and only paid orders were guarded: an `invoice.underpaid_waiting` or `invoice.confirming`
arriving after the invoice had already ended underpaid, expired or cancelled moved
the order back into an open state. Nothing leaves a final status on the server, 
so once one is recorded for an invoice every later event for it is ignored and the
final status stays recorded. * A new invoice now resets the Paymos status recorded
on the payment, so an event for it is never taken for a stale one after an earlier
final status. * A webhook retry that arrived while the first delivery was still 
being processed was answered 200 “duplicate”. Paymos gives a delivery 10 seconds
and retries, while a slow reverse-verification call can take longer; the retry was
acknowledged as delivered, and if the first attempt then failed the event was lost.
An event that is only locked, not yet committed, is now answered 409 so Paymos tries
again, and the lock the first delivery holds is left alone.

## Meta

 *  Version **1.6.2**
 *  Last updated **9 hours ago**
 *  Active installations **Fewer than 10**
 *  WordPress version ** 6.5 or higher **
 *  Tested up to **7.1.4**
 *  PHP version ** 7.4 or higher **
 * Tags
 * [easy digital downloads](https://wordpress.org/plugins/tags/easy-digital-downloads/)
   [payments](https://wordpress.org/plugins/tags/payments/)[stablecoin](https://wordpress.org/plugins/tags/stablecoin/)
   [usdc](https://wordpress.org/plugins/tags/usdc/)[USDT](https://wordpress.org/plugins/tags/usdt/)
 *  [Advanced View](https://wordpress.org/plugins/paymos-easy-digital-downloads/advanced/)

## Ratings

No reviews have been submitted yet.

[Your review](https://wordpress.org/support/plugin/paymos-easy-digital-downloads/reviews/#new-post)

[See all reviews](https://wordpress.org/support/plugin/paymos-easy-digital-downloads/reviews/)

## Contributors

 *   [ Paymos ](https://profiles.wordpress.org/paymos/)

## Support

Got something to say? Need help?

 [View support forum](https://wordpress.org/support/plugin/paymos-easy-digital-downloads/)