Easy Digital Downloads ships with a built-in REST API that most store owners never touch. That is a missed opportunity. The EDD REST API gives you a clean, authenticated interface to every major data object in your store – products, payments, customers, download files, and more – without writing a single line of custom PHP just to read data. Once you understand how the API works, building a mobile storefront, syncing orders to a CRM, or wiring up automation tools like Zapier or Make becomes a straightforward engineering task rather than a guesswork exercise.
This guide covers the entire surface area of the EDD REST API. You will learn how authentication works, what endpoints exist out of the box, how to create your own custom endpoints, how to protect your API with rate limiting, and how to put it all together in two practical scenarios: a mobile storefront and a third-party service integration. Every code example is production-ready and tested against EDD 3.x.
What the EDD REST API Actually Is
The EDD REST API is a first-party feature built into the core Easy Digital Downloads plugin. You do not need a separate addon to use it. It follows a RESTful design and returns JSON responses. The base URL pattern is:
https://yourstore.com/edd-api/v2/{endpoint}
The API is versioned. The current stable version is v2, which is what this article covers. Version 1 is still available for backward compatibility but it lacks several endpoints added in v2 and should be avoided for new work.
Unlike the WordPress REST API (which lives at /wp-json/), the EDD REST API is entirely self-contained. It does not use WP application passwords or cookies. It uses its own key-and-token authentication system, which means you can grant third-party tools access to your store data without giving them WordPress login credentials.
Enabling the API
The API is off by default. To turn it on, go to Downloads > Settings > API and check the box to enable the REST API. You can also control which user roles are allowed to generate API keys from this screen.
Once enabled, any user with the appropriate role can generate their own API credentials under Users > Your Profile > EDD API Keys. Each user gets a unique public key and a secret token. These credentials are tied to the user account, so their WordPress role governs what data they can access through the API.
API Authentication Methods
Every request to the EDD REST API must include valid credentials. There are two ways to send them: as query string parameters or as an HTTP Basic Authorization header. Both methods use the same public key and secret token pair.
Query String Authentication
This is the simplest approach and works in any HTTP client, including plain browser requests. Append the key and token to the URL as query parameters:
https://yourstore.com/edd-api/v2/products?key=PUBLIC_KEY&token=SECRET_TOKEN
Query string authentication is convenient for testing in a browser or Postman, but it has a downside: credentials appear in server access logs and browser history. For server-to-server calls or permanent integrations, the header approach is cleaner.
Basic Auth Header Authentication
EDD also accepts credentials via the standard HTTP Authorization header. Encode your public key and secret token together as a base64 string in the format key:token and send it as a Basic auth header. The code snippet below shows both approaches in PHP alongside a JavaScript fetch example for mobile apps:
Token Generation and Rotation
Tokens are generated once and stored hashed in the database. EDD does not offer automatic token rotation out of the box. To rotate credentials, the user must regenerate their API keys from their profile page. This revokes the old token immediately, so any integration using the old token will stop working until it is updated.
A good practice for integrations with long lifespans is to store credentials in environment variables or a secrets manager rather than hardcoding them in your application. That way, rotating credentials only requires updating one environment variable rather than deploying a code change.
Store API credentials in environment variables, not in source code. Rotating a secret should never require a deployment.
EDD REST API Endpoints Reference
The EDD REST API v2 exposes six core resource groups. Here is a complete reference with the available operations for each.
Products Endpoint
| Endpoint | Method | Description |
|---|---|---|
| /edd-api/v2/products | GET | List all published downloads |
| /edd-api/v2/products/{id} | GET | Get a single download by ID |
| /edd-api/v2/products?category={slug} | GET | Filter products by download category |
| /edd-api/v2/products?tag={slug} | GET | Filter products by download tag |
| /edd-api/v2/products?s={query} | GET | Search products by keyword |
The products response includes pricing data (single price or price variations), download file information, product description, thumbnail URL, and purchase count. It does not include the actual download file URLs – those are gated behind the payments endpoint for obvious reasons.
Sales / Payments Endpoint
| Endpoint | Method | Description |
|---|---|---|
| /edd-api/v2/sales | GET | List all payments |
| /edd-api/v2/sales/{id} | GET | Get a single payment by ID |
| /edd-api/v2/sales?customer={email} | GET | Get payments for a specific customer |
| /edd-api/v2/sales?date={date} | GET | Filter payments by date (Y-m-d format) |
| /edd-api/v2/sales?startdate=&enddate= | GET | Filter payments by date range |
The sales endpoint returns full payment records including cart contents, customer information, payment status, currency, and total. This is the endpoint you will hit most often when building CRM integrations or financial reporting dashboards.
Customers Endpoint
| Endpoint | Method | Description |
|---|---|---|
| /edd-api/v2/customers | GET | List all customers |
| /edd-api/v2/customers/{id} | GET | Get a single customer by EDD customer ID |
| /edd-api/v2/customers?customer={email} | GET | Look up a customer by email address |
Customer records include purchase count, total spent, first and last name, email, and the date they first purchased. You do not get individual payment details here – cross-reference with the sales endpoint using the customer email for the full picture.
Downloads (File Links) Endpoint
The /edd-api/v2/downloads endpoint generates time-limited, signed download URLs for a specific payment. Pass the payment key as a parameter. The response includes one URL per downloadable file in the order. These URLs expire after the time limit set in your EDD settings (default: 24 hours).
Stats and Info Endpoints
- /edd-api/v2/stats – Earnings and sales counts, filterable by date range and product
- /edd-api/v2/products/count – Total number of published products
- /edd-api/v2/info – API version and site metadata
The stats endpoint is particularly useful for building sales dashboards. It returns daily and total earnings figures without requiring you to pull and aggregate individual payment records.
Pagination
All list endpoints support pagination via the page and number query parameters. The number parameter controls how many results per page (default: 10, maximum: 100). The response includes a total_pages field so you can iterate through all pages programmatically.
Fetching Products from JavaScript
Before moving into custom endpoints, it helps to see a complete, working example of calling the EDD API from a JavaScript application. The example below is written to work in both a browser SPA and a React Native mobile app. It handles pagination, errors, and the URL construction correctly:
Notice that this example embeds credentials directly in the client. That is acceptable for testing, but in a production mobile app you should proxy all EDD API calls through your own backend. More on that in the mobile storefront section below.
Creating Custom Endpoints with register_rest_route
The built-in endpoints cover the main data objects, but real-world integrations often need something more specific. Maybe you want a single endpoint that returns only your featured products with curated pricing. Maybe you need an endpoint that returns a customer’s complete purchase history including their license keys. EDD makes this straightforward through its query mode system.
EDD’s Query Mode Hook System
Rather than using the standard WordPress register_rest_route function directly, EDD provides a hook-based system for extending the EDD API namespace. You hook into edd_api_v2_query_modes to register a new mode name and a callback function. The EDD API router handles the rest, including authentication checks before your callback runs.
Here is a real example: a custom endpoint that returns only products flagged as featured via a custom meta field:
With this in place, authenticated callers can hit /edd-api/v2/featured-products and get back only the six featured products – no filtering required on the client side.
When to Use register_rest_route Instead
EDD’s query mode system works well for read operations that extend the existing /edd-api/ namespace. If you need write operations (POST/PUT/DELETE), or if your integration is better served under a different URL namespace (like /wp-json/my-plugin/v1/), then using register_rest_route directly is the right call. The standard WordPress REST API is better equipped for write operations because it supports nonce-based authentication for logged-in users and granular permission callbacks.
Caching Custom Endpoint Responses
Custom endpoints that aggregate data from multiple sources can be slow. Always wrap the expensive query in a transient:
- Cache the response for 5-15 minutes using set_transient()
- Delete the transient when relevant data changes using delete_transient() in a save_post hook
- Include the transient key in your error logging so you can flush it manually during debugging
Rate Limiting and Security Best Practices
The EDD REST API does not include built-in rate limiting. If your store is publicly accessible and your API keys leak, an attacker can hammer your server with API requests or scrape your entire customer database. Rate limiting is not optional for a production store.
Implementing Rate Limiting with Transients
The cleanest approach that does not require additional infrastructure is a transient-based counter. Each API key gets a transient that tracks how many requests it has made in the current time window. When the counter exceeds the limit, the server returns a 429 Too Many Requests response:
This gives you per-key rate limiting with no external dependencies. The transient automatically expires at the end of each window, resetting the counter without any cron job.
Additional Security Measures
Rate limiting is one layer of security, but it should not be the only one. Apply these additional measures to any production EDD REST API setup:
- Always use HTTPS. API credentials sent over plain HTTP can be intercepted. Enforce HTTPS at the server level, not just in WordPress settings.
- Restrict API key permissions by role. Do not give every user the ability to generate API keys. Limit key generation to administrator and shop manager roles only. This is configurable in Downloads > Settings > API.
- Rotate credentials after integrations end. When you finish a project that used API keys, regenerate the credentials immediately. Do not let old tokens linger.
- IP allowlisting for sensitive endpoints. For server-to-server integrations where the client IP is fixed, add an IP allowlist check at the top of your custom endpoint callback. Reject requests from unexpected IP ranges before any data is returned.
- Log all API requests. EDD writes API access logs to the database. Review these regularly for unusual patterns – unexpected off-hours traffic, bulk reads on the customers endpoint, or high error rates from a single key.
- Limit response data. Custom endpoints should return only the fields the client actually needs. Do not expose email addresses or payment details unless the use case specifically requires it.
Handling Authentication Errors Gracefully
When an API request fails authentication, EDD returns a JSON error object. Make sure your integration handles these correctly rather than crashing or silently ignoring the failure. Check the HTTP status code first (401 for auth failure, 403 for insufficient permissions), then read the error message from the JSON body to diagnose the issue.
Building an API-Powered Mobile Storefront
One of the most compelling use cases for the EDD REST API is a native mobile app that sells your digital products directly. Instead of wrapping a WebView around your WordPress store, you can build a proper native UI in React Native or Flutter that pulls data from EDD and handles the full purchase flow.
The Proxy Architecture (Do Not Skip This)
Before writing a single line of mobile code, understand this constraint: you should never embed EDD API credentials directly in a mobile app. Mobile apps can be decompiled. Anyone who downloads your app can extract the credentials and use them to make unlimited API calls as if they were you. This exposes your entire customer database.
The correct architecture is a thin backend proxy between your mobile app and EDD:
- Your mobile app authenticates users with your own session system (email/password, OAuth, etc.)
- The mobile app sends requests to your proxy backend with the user’s session token
- The proxy validates the session token, then forwards the request to EDD using the stored API credentials
- The proxy returns the EDD response to the mobile app
This keeps EDD credentials server-side where they are safe. The proxy can also enforce additional business logic – for example, preventing a customer from downloading files if their license has expired.
The Mobile Data Layer
Here is a production-grade JavaScript data layer for a React Native app that follows the proxy pattern. It handles authentication headers, error states, rate limit responses, and data transformation into a clean shape for the UI layer:
Handling Purchase Flow in a Mobile App
The EDD REST API is read-only by default. It does not have a checkout endpoint. To handle actual purchases in a mobile app, you have two options:
- Option A: Redirect to web checkout. When the user taps Buy, open a WebView or the system browser pointing to the EDD checkout page with the product pre-added to the cart. This is the simplest approach and the most reliable one for handling payment gateways, tax calculations, and coupon codes.
- Option B: Custom purchase endpoint. Build a custom WordPress REST endpoint that handles the cart and payment processing server-side. The mobile app collects payment details (using Stripe’s mobile SDK, for example), sends a payment method token to your endpoint, and the endpoint calls edd_insert_payment() to create the order. This is significantly more complex but provides a fully native checkout experience.
For most stores, Option A is the right call. The effort required for Option B only makes sense if your checkout abandonment rate is high enough that the native experience meaningfully improves conversion.
Displaying Download Links After Purchase
After a purchase completes, the customer’s order confirmation email contains a payment key. Your app can use this key to hit the downloads endpoint and retrieve time-limited download URLs. Display these in a My Downloads screen in the app. Remember that these URLs expire, so always fetch fresh URLs when the user navigates to the download screen rather than caching them.
Third-Party Service Integration Examples
The EDD REST API is the foundation, but the more common integration pattern is event-driven: something happens in EDD (a payment completes, a refund is issued, a download expires) and you want a third-party service to react. WordPress action hooks combined with the EDD REST API cover this pattern cleanly.
Zapier Integration: Push Purchase Data to Any App
Zapier can pull from the EDD REST API using its built-in REST API trigger (polling for new sales every few minutes), but a webhook push is faster and more reliable. If you want a deeper look at the full range of WordPress webhook automation options available in EDD, see our guide on EDD webhook automation with Zapier, Make, and n8n. Here is how to fire a Zapier webhook the moment a payment completes, with a complete payload that Zapier can map to any downstream app:
With this webhook sending data on each purchase, you can build Zapier workflows that:
- Add the customer to a Mailchimp or ConvertKit email sequence tagged with the product they bought
- Create a contact and deal in HubSpot, Salesforce, or Pipedrive
- Post a #sales Slack notification with the order total
- Add a row to a Google Sheet for financial tracking
- Trigger a fulfillment workflow in Airtable
CRM Integration: HubSpot Example
For deeper CRM integrations where you need bidirectional sync or complex contact property mapping, use the EDD REST API directly from your CRM’s integration layer rather than going through Zapier. Most modern CRMs – HubSpot, ActiveCampaign, Klaviyo – offer a way to define a custom API source that pulls data on a schedule.
The typical pattern for a HubSpot integration:
- Pull new sales from /edd-api/v2/sales filtered to the last 24 hours
- For each payment, look up the customer in HubSpot by email using the HubSpot Contacts API
- If the contact exists, update their “Last Purchase Date” and “Total Spend” custom properties
- If the contact does not exist, create a new contact with the customer’s name, email, and purchase data
- Associate a deal to the contact using the order total and close date
Run this as a daily cron job on your server. The EDD API’s date filtering makes it efficient – you only pull records created since the last sync run rather than fetching and comparing your full payment history every time.
Make (formerly Integromat) Integration
Make has a first-class HTTP module that works well with the EDD REST API. You can build the same webhook-push pattern described in the Zapier example, or you can use Make’s scheduler to poll the EDD sales endpoint every hour and process new payments. Make’s visual workflow builder is particularly useful for multi-step integrations that combine data from several sources before sending it to a destination.
One Make scenario worth building: a customer support triage workflow that fires when a payment gets a refund status. Pull the refund record from EDD, look up the customer’s previous order history, and create a support ticket in Freshdesk or Zendesk pre-populated with the order context. Your support team then handles a ticket that already has all the relevant data rather than having to look it up manually.
Slack Sales Notifications
One of the quickest wins for any digital product store is a real-time sales notification in Slack. Add the edd_complete_purchase hook from the Zapier example but point it at a Slack Incoming Webhook URL instead. Format the message with the product name, customer location, and order total. For high-volume stores, add a daily summary job that pulls stats from /edd-api/v2/stats and posts them to a #revenue channel every morning.
Analytics Pipelines
If your business uses a data warehouse – BigQuery, Snowflake, or Redshift – the EDD REST API is the data source for your sales data. Build a nightly ETL job that:
- Pulls all payments from /edd-api/v2/sales for the previous day
- Transforms the EDD response into your warehouse schema
- Inserts or upserts records (use payment_id as the unique key)
- Triggers a dbt run to refresh your downstream models and dashboards
This pattern gives your analytics team a clean, queryable copy of your EDD data that they can join against ad spend, email engagement, and other marketing data sources without needing access to your WordPress database.
EDD REST API vs WordPress REST API: Choosing the Right Tool
You have two REST APIs available on any EDD site: the EDD-specific API and the standard WordPress REST API. Knowing when to use each one saves you a lot of time.
| Requirement | Use | Why |
|---|---|---|
| Read EDD products, payments, customers | EDD REST API | Built-in, structured responses, no custom code needed |
| Write new orders or update payments | WordPress REST API + custom endpoint | EDD API is read-only; use register_rest_route for write ops |
| Authenticate without a user account | EDD REST API | Key/token works without a WordPress login session |
| Authenticated admin actions (bulk edit, etc.) | WordPress REST API | Nonce-based auth integrates with the WP admin session |
| Third-party server-to-server integrations | EDD REST API | Stable credentials that don’t expire like WP cookies |
| Front-end AJAX within WordPress | WordPress REST API | Nonce protection + cookie auth is simpler in this context |
In practice, most complex integrations end up using both. The EDD API handles data reads; custom WordPress REST endpoints handle writes. That combination gives you a clean architecture where the built-in API does the heavy lifting and your custom code only covers the gaps.
Debugging and Troubleshooting Common Issues
When an EDD API integration stops working, the root cause is almost always one of five things.
401 Invalid API Key or Token
Double-check that you copied the full public key and full secret token without any trailing spaces. EDD stores token hashes, not the tokens themselves – if the user regenerated their keys after you set up the integration, the old credentials are permanently invalid. Regenerate and update your integration.
API Returns Empty Products Array
This almost always means the API is enabled but the requesting user’s role does not have access to the data. Check that the user who generated the key has the shop_manager or administrator role. Also confirm that the EDD API is actually enabled in Downloads > Settings > API – it is easy to enable it, deploy, and then have it get reset during a settings import.
404 on API Endpoint URLs
Usually a permalink issue. Go to Settings > Permalinks in WordPress and click Save Changes without changing anything. This flushes the rewrite rules. EDD registers its API rewrite rules on init, so stale rewrite caches after a plugin update can break the URL routing.
Inconsistent Data Between API and Dashboard
The EDD REST API reads directly from the database via EDD’s own functions. If your dashboard shows different numbers, check whether you have a caching plugin that is serving stale transients. Clear your object cache and transient cache, then compare again. Also verify that your date range parameters are using the store’s local timezone and not UTC.
Custom Endpoint Returns null
Add error_log() calls inside your callback to confirm it is actually running. Then check whether the edd_api_v2_query_modes hook is firing at the right priority. The EDD API processes query modes during a late init action, so your registration hook needs to run before that. Priority 10 on edd_api_v2_query_modes is safe.
Practical Next Steps
The EDD REST API is one of those features that rewards the developers who spend a few hours understanding it. Once you have authentication working and the endpoints mapped in your head, building integrations becomes a matter of connecting well-documented pieces rather than reverse-engineering undocumented hooks.
Here is where to go from here based on your immediate goals:
- Building a mobile app: Start with the proxy architecture. Get a Node.js or PHP proxy working that forwards requests to EDD with stored credentials, then build the mobile UI against the proxy.
- CRM or email marketing sync: Start with the Zapier webhook approach. It is the fastest way to get purchase data flowing into an external tool. Migrate to a direct API integration only when Zapier’s limitations start causing problems.
- Analytics pipeline: Start by pulling the sales endpoint manually with curl to understand the data shape. Then build the ETL job. Do not try to design your warehouse schema before you know what data EDD actually returns.
- Custom reporting dashboard: The stats and sales endpoints together give you everything you need. Build a simple PHP or JavaScript dashboard that polls these endpoints and renders the data. Add caching from day one.
This is the second article in the EDD Custom Development series. If you are also interested in selling digital courses through your EDD store, check out our guide on how to sell online courses with Easy Digital Downloads. The next article covers building custom payment gateways for EDD – how to integrate a payment processor that EDD does not support out of the box, including the full checkout flow, webhook handling, and refund processing.
Need Custom EDD Integrations?
If you need a custom EDD REST API integration, mobile storefront, or third-party service sync built for your specific store, the EDD Sell team can help. We specialize in Easy Digital Downloads custom development and have shipped production integrations for stores at every scale.
