WordPress Development

The WordPress REST API: A Practical Guide for Developers

The WordPress REST API: A Practical Guide for Developers

For most of its life, WordPress was a system that produced web pages. You requested a URL, PHP built the HTML and sent it back. That’s still how most sites work. But since the REST API arrived in core, WordPress can also behave like a data service. It can hand out content as JSON to a mobile app, receive orders from another system, or feed a JavaScript front end that doesn’t use WordPress themes at all.

I use the REST API constantly. Custom dashboards, automated posting scripts, syncing products with outside systems and small interactive features all rely on it. It’s one of the most useful tools a WordPress developer has, and also one of the easiest ways to accidentally expose data if you’re careless.

This guide covers the practical side: how the API is organised, how to read and write data, how to authenticate properly and how to build your own endpoints safely.

What the REST API is

REST is a style of building web APIs around URLs and standard HTTP methods. Each type of data has a URL, called an endpoint, and you use methods like GET to read, POST to create, and PUT, PATCH or DELETE to change things.

In WordPress, every API URL starts at /wp-json/. Try it on any WordPress site:

You’ll get a large JSON document describing every available route. The core content lives under the wp/v2 namespace:

Custom post types appear here too, as long as they were registered with show_in_rest set to true.

Reading data

Public content can be read without authentication. You can filter, search and paginate with query parameters:

The _fields parameter is worth knowing. By default, responses include a lot of data you may not need. Asking only for specific fields makes responses smaller and faster, which matters on mobile or when you’re fetching hundreds of items.

Pagination information is sent in response headers. X-WP-Total gives the total number of items and X-WP-TotalPages tells you how many pages there are. Many developers miss this and assume they’ve received everything after the first request.

Here’s a simple fetch from JavaScript:

Authentication: choosing the right method

Anything that creates, edits or deletes content requires authentication. WordPress supports a few approaches, and choosing the right one depends on where the request comes from.

Cookie authentication with nonces

If your JavaScript runs inside WordPress itself, for example in a plugin’s admin page or on the front end for logged-in users, use the normal login cookie together with a nonce. The nonce proves the request came from your site and not from a malicious page somewhere else.

Then send the nonce with each request:

Application passwords

For external scripts, servers and apps, application passwords are the built-in solution. Each user can create them from their profile screen. They’re separate from the real login password, can be revoked individually and only work for API and XML-RPC requests, not for logging into the dashboard.

You send them with basic authentication over HTTPS:

I use this approach for automated posting tools. A few tips from experience:

  • Create a dedicated user for each integration, with the lowest role that does the job. A script that only creates drafts doesn’t need an administrator account.
  • Name each application password after the system that uses it, so you know which one to revoke.
  • Never send application passwords over plain HTTP.

OAuth and JWT

Third-party plugins add OAuth or JSON Web Token authentication. These make sense for public apps where many different users log in through your API. For server-to-server automation, application passwords are simpler and perfectly adequate.

Writing data

Creating and updating content follows the same pattern. Send JSON to the endpoint with the right method. You can set the title, content, status, categories, featured image and registered custom fields:

Uploading media is slightly different. You send the raw file to the media endpoint with a Content-Disposition header naming the file, then use the returned ID as the featured image on a post.

Building custom endpoints

The core endpoints cover standard content. For anything specific to your site, you’ll want your own routes. This is where most security mistakes happen, so let’s look at a correct example.

The important parts:

Use your own namespace. Something like mysite/v1 avoids clashes with other plugins and lets you version the API later.

Always write a real permission_callback. WordPress requires one, and shows a notice if it’s missing. If an endpoint should be public, use __return_true deliberately. If it reads private data or changes anything, check a capability. I regularly find plugins where the callback returns true on endpoints that update settings. That’s how site takeovers happen.

Validate and sanitize arguments. The args array lets WordPress check input before your callback runs. Use enums for fixed sets of values, validate numbers, and sanitize strings.

Return proper responses and errors. Use rest_ensure_response for success, and return a WP_Error with a status code when something fails:

Should you restrict the REST API?

Some security plugins offer to disable the REST API entirely. Don’t. The block editor, many plugins and WordPress itself depend on it. Turning it off breaks things in confusing ways.

A more measured approach is to restrict specific endpoints. The users endpoint is the usual concern, since it reveals usernames. If your site doesn’t need it to be public, you can limit it to logged-in users:

Performance tips

API requests run through WordPress just like page loads, so a slow site means a slow API. A few habits help:

  • Request only the fields you need with _fields.
  • Avoid the _embed parameter unless you really need embedded data, as it triggers extra queries.
  • Cache responses on the client or at a CDN for public data that doesn’t change often.
  • For heavy custom endpoints, cache results with transients or the object cache.

Headless WordPress: worth it?

Headless WordPress means using WordPress only as a content back end, with a separate front end built in a JavaScript framework that fetches content through the API. It’s fashionable, and it can be the right choice.

It makes sense when the same content feeds a website, an app and other channels, or when a team of front-end developers wants full control with modern tools. It often doesn’t make sense for a typical business site. You lose theme features, many plugins that output front-end code stop working, previews get complicated, and you now maintain two systems instead of one. For most of my clients, a well-built traditional theme is faster to develop, cheaper to run and easier to edit.

Debugging and testing API requests

When an API request doesn’t behave as expected, a few habits make troubleshooting much quicker.

Start by testing outside your code. A tool like curl, or an API client with a graphical interface, lets you send the exact request and see the full response, including headers and status codes. If the request works there but not in your application, the problem is in your code rather than WordPress.

Read the error response carefully. WordPress returns structured errors with a code, a message and usually a status. A rest_forbidden code points to permissions, rest_invalid_param tells you which argument failed validation, and rest_no_route means the URL or method is wrong. These messages are more helpful than many developers expect.

Check the method as well as the URL. Sending a GET request to an endpoint that only accepts POST returns a “no route” error, which can be confusing if you’re sure the route exists.

Watch for caching. Some hosts and CDNs cache API responses, which can make it look as though your updates aren’t saving. If a GET request keeps returning stale data after a successful update, check your caching rules and exclude /wp-json/ paths where needed.

Finally, keep the Query Monitor plugin in mind. It can display information about REST requests for logged-in users, including queries and errors triggered during the request, which is invaluable when a custom endpoint is slow.

Frequently asked questions

Is the REST API a security risk?

Not by itself. Core endpoints respect user permissions, so private content isn’t exposed to anonymous visitors. Problems come from custom endpoints with weak permission checks, and from overly powerful credentials given to integrations.

How do I see what’s available on my site?

Visit /wp-json/ in your browser. Every registered route is listed, including those added by plugins. It’s a good way to audit what your plugins expose.

Can I use the REST API with custom fields?

Yes. Register the meta with show_in_rest set to true and it appears in responses and can be updated. Field plugins usually have their own options for REST support.

Why do I get a 401 error?

Your request isn’t authenticated correctly. Check the credentials, make sure you’re using HTTPS, and confirm the user has permission to perform the action. Some hosts strip the Authorization header, which can be fixed in the server configuration.

Final thoughts

The REST API turns WordPress into a platform that can connect with almost anything. Learn the core endpoints, choose the right authentication for each job and treat every custom endpoint as a door into your site that needs a proper lock. Do that, and you’ll find a huge range of projects becoming simpler.