October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PCOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
VGSources
Blog

How to Create a Custom REST API Endpoint in WordPress

Learn how to build a custom WordPress REST API endpoint from registration through permissions, validation, JSON requests, structured errors, testing, and controller architecture.
WorldWordPress Length11 min Posted Quest giverVGSources Team
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Register a custom WordPress REST endpoint on the rest_api_init hook with register_rest_route(). Give it a unique versioned namespace, an HTTP method, a callback, a permission_callback, and argument rules for validation and sanitization. The endpoint will then be available below /wp-json/, for example /wp-json/myplugin/v1/books/42.

What a custom REST endpoint is

A REST route is the URL pattern that identifies a resource. An endpoint is the behavior attached to that route for a particular HTTP method. The same route can therefore have different endpoint definitions for reading, creating, updating, or deleting a resource.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For example, /books/42 is a route pattern. A GET endpoint on that route could return book 42, while a DELETE endpoint on the same route could remove it. WordPress exposes the resulting API below your site’s /wp-json/ base path, so a complete read request might be https://example.com/wp-json/myplugin/v1/books/42.

Keep the namespace unique to your plugin or project and include a version such as myplugin/v1. A future breaking contract can then be introduced as myplugin/v2 without silently changing what existing clients receive.

#1 Best Overall
Sale
Gaoye Blue Light Blocking Glasses
  • BLUE LIGHT BLOCKING GLASSES: Our blue light glasses for women boast UV400 protection, blocking harmful blue rays from computer screens. With these bluelight glasses women, you can enjoy gaming, reading, or watching TV with no worries of eye strain.
  • EYE RELIEF: Our blue light glasses are engineered to reduce blurry vision or strain caused by prolonged screen time. These womens blue light glasses aid in better sleep by preventing blue light from disrupting your natural sleep cycle, helping you fall asleep faster and enjoy a more restful night's sleep, making them the perfect christmas present.
  • COMFORTABLE: Crafted from durable material, our trendy blue light glasses for woman or blue light glasses men ensure long-lasting comfort. The high-transmittance lenses accessories, gamer gifts for men, help keep your eyes relaxed. Perfect stocking stuffers, gifts for gamers men, christmas gifts for men, halloween costumes.
  • LIGHTWEIGHT: These clear blue light glasses feature a lightweight frame, meaning they’ll stay comfy for long-term wear. Perfect as blue blockers glasses for women or mens blue light glasses, these non-prescription fake glasses for men can be worn throughout the day. The blue light blocking glasses women feature polycarbonate HD lenses, which are anti-reflective and restore true color.
  • WORRY-FREE PURCHASE: If you experience any issues, our support team is ready to assist you quickly. These are the perfect costume glasses for cosplay dressing up.

The smallest useful endpoint

This example registers a read-only book endpoint. It demonstrates the lifecycle hook, a versioned namespace, a numeric path parameter, permission checking, argument rules, a callback, and a structured 404 response.

<?php
add_action( 'rest_api_init', function () {
    register_rest_route( 'myplugin/v1', '/books/(?P<id>d+)', array(
        'methods'             => WP_REST_Server::READABLE,
        'callback'            => 'myplugin_get_book',
        'permission_callback' => function () {
            return current_user_can( 'read' );
        },
        'args'                => array(
            'id' => array(
                'required'          => true,
                'sanitize_callback' => 'absint',
                'validate_callback' => function ( $value ) {
                    return is_numeric( $value ) && (int) $value > 0;
                },
            ),
        ),
    ) );
} );

function myplugin_get_book( WP_REST_Request $request ) {
    $id   = (int) $request['id'];
    $book = get_post( $id );

    if ( ! $book ) {
        return new WP_Error(
            'book_not_found',
            'Book not found.',
            array( 'status' => 404 )
        );
    }

    return array(
        'id'    => $book->ID,
        'title' => get_the_title( $book ),
    );
}

Replace the illustrative capability, data source, response fields, and error policy with choices appropriate for your resource. The callback can return an array, a WP_REST_Response, or a WP_Error; WordPress converts those return values into the HTTP response.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Where and when to register the route

Put the registration code in a plugin, a project-specific must-use plugin, or another deliberately loaded PHP component. Avoid putting a route definition in a template file that may not load for every request. WordPress documents that register_rest_route() should run on rest_api_init, which is why the example wraps it in add_action().

Use a namespaced function or a controller method for the callback. A prefixed name such as myplugin_get_book prevents collisions in PHP’s global function namespace.

Build an endpoint step by step

  1. Choose a namespace and version. Use a distinctive vendor or plugin prefix followed by a version, for example myplugin/v1. Do not reuse another plugin’s namespace.
  2. Define the route pattern. A static route might be /books. A resource route can capture an identifier with a named regular-expression group such as /books/(?P<id>d+).
  3. Select the method. Use the WordPress constants that describe the intended operation, such as WP_REST_Server::READABLE for a read endpoint. A route can have separate definitions for different methods.
  4. Write one focused callback. Accept WP_REST_Request $request, read the path, query, or body values you need, perform one resource operation, and return the representation or an error.
  5. Add a permission callback. Every endpoint needs an explicit authorization decision. For a protected operation, check the capability that represents the action with current_user_can(). For a deliberately public endpoint, WordPress documents __return_true.
  6. Describe the arguments. Mark required values, set defaults where appropriate, declare types, and add sanitization and validation callbacks. This metadata also makes the contract easier for clients to understand.
  7. Handle failures with REST errors. Return a WP_Error containing a stable error code, a human-readable message, and an HTTP status when the operation cannot be completed.
  8. Document the contract. State the URL, accepted methods, parameters, authentication expectations, response fields, and possible error shapes for client developers.

Routes, methods, and callbacks

The route pattern identifies the URL; the method-and-callback pair defines what happens there. Keep callbacks aligned with the method so that reads retrieve existing data, while writes validate input, authorize the action, and return the created or changed representation.

Operation Typical method Callback responsibility Important checks
Read one or many resources GET / WP_REST_Server::READABLE Fetch and shape existing data Validate identifiers and filters; apply visibility rules
Create a resource POST Validate submitted fields, create the record, and return it Capability for creation, required fields, uniqueness and business rules
Update a resource POST or the method your contract defines Validate the identifier and changed fields, then return the updated record Capability for editing this resource and ownership or status rules
Delete a resource DELETE Authorize and remove or archive the record Capability, existence, and an explicit response for the deletion result

Choose the method deliberately and keep each callback limited to its corresponding resource operation. A callback that mixes unrelated reads and writes is harder to secure and document.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Path, query, and JSON body parameters

Path parameters

A named capture in the route, such as (?P<id>d+), becomes available through the request object. In the example, $request['id'] is converted to an integer before the database lookup. The route pattern prevents non-numeric values from matching, while the argument validation still provides a clear contract and a second line of defense.

Rank #2
Windex Gaming Cleaning Wipes, Pre-Moistened Wipes to Instantly Clean all Gaming Gear and Electronics, Resealable Packaging for a Freshness Lock, 25 count (Pack of 1)
  • WINDEX GAMING WIPES: effortlessly clean all your gaming gear and gaming electronics in one easy step with our new Windex Gaming Wipes
  • AMMONIA FREE: our ammonia-free formula is safe to use on all of your favorite gaming equipment like consoles, headsets, controllers, screens, keyboards, and more
  • PRE-MOISTENED WIPES: each wipe instantly removes dust, dirt, and stubborn smudges and fingerprints leaving a streak-free shine
  • ANTI-STATIC: great for cleaning and wiping down your gaming gear and electronics leaving behind no visible residue
  • COMPACT RESEALABLE PACKAGE: store your pack of Windex Gaming Wipes anywhere in your home for whenever a quick and easy wipedown is needed

Query parameters

Collection routes commonly accept filters, pagination values, or sort choices in the query string. Declare each accepted argument in args, set a type or default when appropriate, and reject values outside the supported range or enum. Do not pass raw query values directly into a query or a write operation.

JSON request bodies

For a JSON body, send the request with a JSON content type and read the parsed associative array:

$params = $request->get_json_params();
$title  = isset( $params['title'] ) ? $params['title'] : '';

Define body fields in the endpoint’s argument metadata as well. Validate required fields and allowed values before changing data, and sanitize values when normalization is intended.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Validation and sanitization are different

Validation answers whether a value is acceptable. Sanitization transforms a value into a normalized form before you process it. Use both where they serve different purposes; sanitization is not a substitute for rejecting an invalid value.

Concern What it does Example from the endpoint When to use it
required Requires the client to supply a value 'required' => true Identifiers or fields with no meaningful default
sanitize_callback Normalizes input before your callback uses it absint converts an identifier to a non-negative integer When a predictable normalized representation is wanted
validate_callback Accepts or rejects the value Check that the value is numeric and greater than zero When malformed, out-of-range, or disallowed input must produce an error
type and enums Describe the expected data shape and allowed choices A string field restricted to a known set of values When clients and tooling need a machine-readable contract
default Supplies a value when the client omits an optional argument A default sort direction or page size Only when the default is safe and documented

Validate identifiers even when the route includes a regular expression. Validate ownership, status, and business rules in the callback because those checks depend on the resource being loaded and the current user.

Authorization and public access

permission_callback is authorization, not merely a test that someone is logged in. Match the capability to the operation and, when necessary, to the specific resource. A user who can read one type of content should not automatically be able to edit or delete every resource.

The example uses current_user_can( 'read' ) only as an illustration. Use the capability that represents your actual operation, and add object-level checks in the permission callback or callback when access depends on ownership, status, or another property.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #3
Sale
LISEN Cell Phone Stand Phone Holder for Desk, Office Decor Gadgets for Men
  • Ergonomic & Adjustable Design: Fight "text neck" and improve your posture. Designed for comfort, it offers an adjustable height (7.1in-8.5in) (1.4in adjustable range) and angle (5°-85°) Please note: cell phone stand is only 9 inches tall—the length of a standard pencil
  • Without blocking subtitles Perfect for office desk Tiktok Face Time Zoom video—this is the ultimate kitchen desk essential for phones! Perfect viewing experience while reducing neck back strain, A must-have for gamers streamers desk, and anyone who values both style and support!
  • Sleek & Stable Design fits Otterbox Case: Say goodbye to bent cables, tangles, and tip-overs! LISEN’s stylish adjustable desk phone holder features a built-in charging hole and smart cable management, keeping your phone secure and your workspace clutter-free cool gadgets for men
  • ANTI-SLIP DESIGN free hands: The under 10.00 items easy gadgets back and the bottom of this kitchen essentials for women are fully covered by anti-skid silicone, which LISEN stand up desk decor can provide maximum protection device from any scratches and slides
  • Your Perfect Viewing Companion:If your product arrives damaged or breaks within 365 days, reach out to LISEN for a quick and hassle-free solution. Struggling with assembly, like tightening the screw? We’ve got your back! Your experience matters to us. (Product including: phone Holder stand*1, screw*1, hexagon screwdriver*1, specification*1)

A public route is an explicit product decision. WordPress documents __return_true for a deliberately public endpoint; it grants access to anyone who can reach the route. Public does not mean unvalidated: continue to validate parameters, limit the data returned, and avoid exposing private fields or state-changing actions without a separate authorization design.

Returning data and errors

Return only the fields clients need. A stable response shape is easier to consume than a raw database object whose internal fields may change. For successful operations, an array is sufficient for many small endpoints; use WP_REST_Response when you need explicit status or headers.

When an operation fails, return a structured WP_Error:

return new WP_Error(
    'book_not_found',
    'Book not found.',
    array( 'status' => 404 )
);

The error code should be stable enough for client logic, the message should help a human understand the problem, and the status should reflect the HTTP outcome. Use a not-found status for a missing resource, an authorization failure for a denied operation, and a client-error status for malformed or unacceptable input.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When to use a controller class

A few lines of registration and one callback are appropriate for a small, read-only endpoint. As an API grows, a WP_REST_Controller keeps route registration, permission methods, CRUD behavior, and schema together. WordPress’s controller pattern is useful when several methods share permissions, when the resource has multiple routes, or when clients need a discoverable schema.

A controller typically provides methods such as register_routes(), get_item(), get_items(), permission checks, and get_item_schema(). A minimal shape looks like this:

class MyPlugin_Books_Controller extends WP_REST_Controller {
    public function __construct() {
        $this->namespace = 'myplugin/v1';
        $this->rest_base = 'books';
    }

    public function register_routes() {
        register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>d+)', array(
            'methods'             => WP_REST_Server::READABLE,
            'callback'            => array( $this, 'get_item' ),
            'permission_callback' => array( $this, 'get_item_permissions_check' ),
            'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::READABLE ),
        ) );
    }

    public function get_item_permissions_check( $request ) {
        return current_user_can( 'read' );
    }

    public function get_item( $request ) {
        // Load the resource, shape the response, or return WP_Error.
    }

    public function get_item_schema() {
        return array(
            '$schema' => 'http://json-schema.org/draft-04/schema#',
            'title'   => 'book',
            'type'    => 'object',
            'properties' => array(
                'id' => array(
                    'description' => 'Unique book identifier.',
                    'type'        => 'integer',
                    'readonly'    => true,
                ),
                'title' => array(
                    'description' => 'Book title.',
                    'type'        => 'string',
                ),
            ),
        );
    }
}

Register the controller’s routes from the rest_api_init hook, just as you would register a function-based route. The exact methods you implement depend on whether the controller supports collection reads, single-item reads, creation, updates, or deletion.

Rank #4
Ledagic IC+RGBW USB Powered Led Light Bar with App & Remote Control, 2 Pack
  • Easy Installation: Our gaming lights have been designed to enhance your entertainment experience. Simply position the led light bar next to your TV or game console to create a game room environment with ease. They come with USB power and a 60 inch cord for direct mounting and mobility
  • Audio Syncing & Extensive Mode: The built-in high-sensitivity music sensor allows you to sync the TV led lights to your favorite music. Lights react and move to the beat of music, film and game audio, creating an incredible immersive sound and light experience – and all without the need for an additional hub. You can choose from 64+ patterns, including strobe, illusion, jump, energy, gradient, running, chasing, fluttering mode etc. Each mode can be applied to different scenes
  • 64+ Chasing IC+RGB & W Effect: The independent control design of IC+RGB and white all-in-one multifunctional rgbw led bar lights monitor backlight allows you to easily switch the led lights for desk between IC+RGB and white to enjoy a variety of lighting effects, you can choose white lighting mode with high brightness for better illumination when working, etc. Choose IC+RGB lighting mode when you need to create an entertaining atmosphere for the light show, 16 million colours of Color changing rgb light bar let you dance to the beat and create a dynamic party atmosphere
  • Dynamic and Dimmable Lights: 1%-full brightness free brightness adjustment gives you the flexibility to adjust dimmable led light bar for room decorations or a variety of occasions
  • USB Powered: USB light bars for room can be powered by powernank, usb charger, TV, Monitor, laptop PC mainframe, making behind TV led lighting bar easy to install in any location.TV led lights are powered by the TV usb interface / PC mainframe, can be turned on/off synchronously with TV / PC

JSON Schema and reusable contracts

Schema describes the fields, types, and constraints of a representation. WordPress notes that schema helps structure data so applications can reason about interactions with the REST API more easily. It is especially valuable when several endpoints expose the same resource or when clients and generated tooling depend on a consistent machine-readable contract.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For a tiny endpoint with a few parameters, inline argument validation may be clearer and faster to maintain. For a growing resource API, derive endpoint arguments from the controller schema so validation and documentation do not drift apart. Keep the schema aligned with the actual response: if a property can be absent, nullable, or read-only, describe that explicitly in the contract you publish.

Choosing an architecture

Decision Use this when Trade-off
Small function route One simple endpoint, often read-only Fast to implement, but shared behavior can become scattered as routes multiply
WP_REST_Controller Several methods, shared permissions, or a growing resource API More structure up front, with better reuse and discoverability
Inline callback validation A few parameters and a narrow contract Easy to read, but repeated rules can diverge across endpoints
JSON Schema Several endpoints, multiple clients, or generated tooling Requires maintaining a formal schema, but creates a consistent contract
Public access The data or action is intentionally available to anyone who can reach the site Simpler clients, but greater exposure and no user-specific authorization
Protected access The endpoint returns private data or changes site state Requires an authentication mechanism and capability checks
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Testing a custom route

After the plugin code loads, request the route directly and check both the success and failure paths. The following read request uses the standard WordPress REST URL shape:

curl -i 'https://example.com/wp-json/myplugin/v1/books/42'

Test an identifier that does not exist and confirm that the response contains your stable error code and a 404 status. Test a malformed identifier, omitted required argument, and a user who lacks the required capability. For a JSON write, send the declared content type and a body matching the documented fields:

curl -i -X POST 
  -H 'Content-Type: application/json' 
  -d '{"title":"Example book"}' 
  'https://example.com/wp-json/myplugin/v1/books'

Use the authentication mechanism configured for your WordPress installation when testing protected operations. A request that reaches the callback without the right capability must still be rejected by the permission check.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Common failure modes and fixes

The route returns a 404

  • Confirm that the registration runs on rest_api_init.
  • Check the namespace, route spelling, and version in the requested URL.
  • Confirm that the HTTP method matches the endpoint definition.
  • Make sure the plugin or PHP file containing the registration is actually loaded.

WordPress reports a missing permission callback

Add permission_callback to every endpoint definition. Protected endpoints should perform a capability check; a deliberately public endpoint can use __return_true. Do not omit the key simply because the callback only reads data.

Valid-looking input is rejected

Inspect the argument’s validate_callback, type, enum, and required settings. Remember that request values may arrive as strings. Convert them only after validation and make sure sanitization does not silently turn an invalid value into a different valid one.

Best Value
Sale
HUANUO FlowLift™ Dual Monitor Stand, Fully Adjustable Gaming Monitor Desk Mount for 13–32″ Computer Screens, Full Motion VESA 75x75/100x100 with C-Clamp & Grommet Base, Each Arm Holds 4.4 to 19.8 lbs
  • Compatible with Wide Screens - To ensure compatibility with the dual monitor mount, your each monitor must meet three conditions at the same time: First, computer screens size range: 13 to 32 inches. Second, screen weight range: 4.4 to 19.8 lbs. Third, the back of the monitor screen must have VESA mounting holes with a pitch of 75x75mm or 100x100mm.
  • Regarding the compatibility with desks - Your desk must meet three conditions at the same time: First, desk material: Only wooden desks are recommended, plastic or glass desks cannot be used. Second, desk thickness range: 0.59" - 3.54". Third, the bottom of the desk should not have any cross beams or panels, as this will interfere with installation. We recommend carefully checking that your desk and monitors meets all above conditions before purchasing.
  • Dual C-Clamp Hold - Worried your dual monitors might wobble or slip? Our upgraded base uses a larger platform plus a dual C-clamp structure to lock the dual monitor arm firmly to your desk. Each arm safely keeps your screens steady while you type, click and game—no shaking, no sliding, just a clean and secure setup you can trust every day. It also provides Grommet Mounting installation choice, both options ensure stable and secure fixation for your 0.59" - 3.54" desk.
  • Full-Motion Adjustment For Comfortable View - Pull the screen closer when you’re deep in a spreadsheet, push it back to watch videos, or rotate to portrait for coding — moving everything smoothly with just one hand. The monitor stand offers +85°/-50° tilt, ±90° swivel and 360° rotation. Raise your monitor up to 15.75″ to support a healthy sitting posture. Whether you’re working from home, gaming through the night, or switching between video calls and documents, getting the screens to your natural line of sight helps relieve neck, shoulder and back strain so you can stay focused longer with less fatigue.
  • Keep Your Desk Organized: By lifting both screens off the desktop, this dual monitor stand opens up valuable space for your keyboard, notebook, docking station or a simple, clutter-free work area. Built-in cable management guides wires along the arms, keeping cords out of sight and out of the way. Enjoy a tidy, modern workstation that looks as good as it feels to use.

Private data is exposed

Review both the permission callback and the fields returned by the main callback. A broad capability check may allow access to a resource the current user should not see. Add resource-level authorization and omit private properties from the response.

The JSON body is empty

Send the request with a JSON content type and read it with $request->get_json_params(). Validate that the decoded value is present and that required fields exist before attempting a write.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Clients cannot rely on errors

Return WP_Error objects with stable codes, clear messages, and explicit HTTP statuses. Avoid returning ad hoc strings for one failure and a different shape for another.

Document and version the contract

Publish the exact namespace, route, methods, required and optional arguments, accepted types or enum values, authentication expectations, response fields, and error codes. Include a short request and response example for each operation. If a breaking response or parameter change is unavoidable, add a new namespace version rather than changing the existing contract in place.

Keep the callback, permission rules, argument metadata, and documentation synchronized. A route is a public interface: changing a field name, making an optional parameter required, or broadening access can break clients even when the PHP code still runs.

Production checklist

  • Registration is attached to rest_api_init.
  • The namespace is unique and versioned.
  • The route pattern and HTTP method match the intended resource operation.
  • Every endpoint has an explicit permission_callback.
  • Capabilities match the action, with resource-level checks where needed.
  • Path, query, and body values are validated; values are sanitized only when normalization is intended.
  • JSON bodies use the declared content type and get_json_params().
  • Callbacks return a stable representation or a structured WP_Error.
  • Public responses exclude private fields and state-changing actions are not accidentally exposed.
  • Tests cover successful requests, missing resources, malformed input, denied permissions, and JSON writes.
  • The route, schema, authentication expectations, and error shapes are documented for clients.

The Bottom Line

For a small endpoint, hook register_rest_route() to rest_api_init, use a versioned namespace, validate every argument, and enforce the operation’s capability in permission_callback. Move to a WP_REST_Controller with JSON Schema when the resource API grows.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More quests from Patch Notes

  1. How to Set Up a RedM (RDR2) Server in 2026: License Key, txAdmin and server.cfg, Step by StepBlog11min
  2. Best RedM (RDR2) Server Hosting in 2026: Comparing Four Hosts on Slots, Memory and PriceBlog10min
  3. How to Host a Mindustry Server in 2026: server-release.jar, Port 6567 and the Commands That MatterBlog7min
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.