/ โ† HTTP Error Fixes / API 404 and 403 Errors
In this guide
  1. What 404 and 403 mean in an API
  2. The common causes, layer by layer
  3. How to reproduce the error with curl and Postman
  4. WordPress REST API 404 and 403 errors
  5. Firewall, server and framework causes
  6. A worked example
  7. The fix, step by step
  8. Edge cases worth knowing
  9. Keeping the API reliable
  10. Questions and answers

What 404 and 403 mean in an API

In a REST API the status code is the first thing a client reads, so it pays to know exactly what each one claims:

CodeWhat the server is sayingTypical API meaning
404 Not FoundNothing exists at this addressUnknown route, wrong prefix or version, missing record, or a route that exists only for another method
403 ForbiddenI know who you are, or I do not care, and the answer is noValid route, but the caller lacks permission, or a firewall or server rule blocked the request
401I do not know who you areMissing, expired or malformed credentials
405 Method Not AllowedThe route exists but not for this methodPOST sent to a GET-only route; many frameworks send 404 instead

The important question is who sent the response. A 404 or 403 can come from your application code, from the web server before the application ever runs, from a CDN or firewall in front of the server, or from a security plugin inside the application. Each layer leaves different fingerprints in the body and headers, and each needs a different fix. A generic HTML error page from nginx and a JSON error object from your API framework both carry a 404, but they point to completely different problems.

Some APIs deliberately answer 404 instead of 403 when a caller is not allowed to see a record, so as not to reveal that it exists. If your own API does that, a 404 for an existing record may really be a permission problem.

The common causes, layer by layer

LayerCauses of 404Causes of 403
Client requestWrong base address, typo in the path, missing version such as /v1/, wrong method, trailing slash mismatchMissing or wrong credentials, wrong auth type, expired token, API key in the wrong header
CDN or firewallRare; a rule returning a block page that looks like a 404WAF rule matching the body, user agent or country; bot protection challenge; rate limiting set to 403
Web serverRewrite rules not passing the path to the application; location block not matchingdeny rules, directory permissions, ModSecurity, blocked file types
ApplicationRoute not registered, router prefix differs, record ID not foundPermission checks fail, missing nonce, role lacks the capability, security plugin blocks the API

Work from the outside in. If the request never reaches your application, no amount of changing application code will help, and the same goes in reverse. The 403 errors guide and the 404 errors guide cover these codes for normal web pages, which share many of the server-level causes.

How to reproduce the error with curl and Postman

Start with curl, because it sends exactly what you type and shows every header in the response:

curl -i -X GET https://www.example.com/wp-json/wp/v2/posts?per_page=1

The -i flag prints the status line and headers above the body. Read three things:

To send credentials with curl, use -u for a username and password, or --oauth2-bearer for a bearer token:

curl -i -u "editor:abcd efgh ijkl mnop qrst uvwx" \
  -X POST https://www.example.com/wp-json/wp/v2/posts \
  -H "Content-Type: application/json" \
  -d '{"title":"Test","status":"draft"}'

curl -i --oauth2-bearer "$API_TOKEN" https://api.example.com/v1/orders/1042

404 error in Postman

When Postman shows a 404, check the request it really sent, not the one you think it sent. Open the Postman Console from the bottom bar and look at the full address. Common faults are an environment variable such as {{baseUrl}} that is empty or points at staging, a missing /wp-json or /api/v1 prefix, a double slash where two variables join, and the wrong method in the dropdown.

403 Forbidden error in Postman

For a 403, check the request's auth settings tab. A request set to inherit from its collection sends nothing if the collection has no auth set. Check the type matches what the API expects, and that the token has not expired. If curl succeeds with the same credentials and Postman fails, compare headers in the console. Some firewalls block the default Postman user agent string.

๐Ÿ’ก If the request works in curl and Postman but fails in the browser, look at the Console tab in DevTools. A CORS error is a browser rule, not a server status. Postman and curl ignore CORS, which is why they succeed.

WordPress REST API 404 and 403 errors

The WordPress REST API lives under /wp-json/. A request to https://www.example.com/wp-json/ should return a JSON index of the available routes. If it returns an HTML 404 page, WordPress never saw the request.

wp-json returns 404

location / {
    try_files $uri $uri/ /index.php?$args;
}

A quick test that bypasses pretty permalinks is the query form of the route. If this works while /wp-json/ fails, the problem is rewriting, not the API:

curl -i "https://www.example.com/?rest_route=/wp/v2/posts&per_page=1"

A JSON response with the code rest_no_route means WordPress received the request but no route matches the path and method. Check the namespace and version in the path, the HTTP method, and that the plugin registering a custom route is active.

WordPress REST API returns 403 or 401

See the WordPress HTTP errors guide for other status codes from the same site.

Firewall, server and framework causes

Web application firewalls

A WAF inspects each request and can block API calls whose JSON body contains strings that look like SQL or script injection, or whose user agent looks automated. The block usually comes back as a 403 HTML page. On Cloudflare, open Security, then Events, and search by the cf-ray value from the response to see which rule fired. On Plesk with ModSecurity, check the web application firewall log and the domain error log for the rule ID. Then write a narrow exception for that rule on your API path, rather than switching the firewall off. The Plesk HTTP errors guide shows where those settings live.

Web server rules

Check the access and error logs for the exact request:

sudo grep ' /api/v1/orders' /var/log/nginx/access.log | tail -5
sudo tail -20 /var/log/nginx/error.log

An entry in the access log with 403 and an error log line mentioning access forbidden by rule means an nginx deny rule matched. A 404 in the access log with no matching application log means the location block did not hand the request to the application.

Application frameworks

In Node.js with Express, a route that exists only for GET answers a POST with a 404 and a body such as Cannot POST /api/v1/orders. The same body appears when a router is mounted at a different prefix from the one the client uses. List your registered routes and compare them with the request. The Node.js HTTP errors guide covers error handling in more depth.

A worked example

Example Bakery's order form posted to /wp-json/bakery/v1/orders. It worked in Postman, but the live form failed. The browser's Network panel showed a 403 with an HTML body and a Server: cloudflare header, so the application was never reached.

Searching Cloudflare Security Events by the cf-ray ID showed a managed WAF rule matching the order notes field, which contained an apostrophe followed by the word or. The fix was a WAF exception that skipped that one rule for that one path. The next request returned a 401 instead, this time as JSON from WordPress, because the form's JavaScript was not sending the X-WP-Nonce header. Adding the nonce brought a 201 Created.

Two layers, two different fixes. Reading the body and headers first saved hours of changing code in the wrong place.

The fix, step by step

Step 1

Reproduce the failing request with curl

Copy the exact address, method, headers and body of the failing call and send it with curl -i. Include credentials with -u or --oauth2-bearer if the call needs them. Note the status line, the Server header, any request ID header such as cf-ray, and whether the body is JSON or HTML. If curl succeeds where your app fails, the difference lies in what the app sends, so compare the two requests line by line.

Step 2

Identify which layer answered

Use the response to decide who sent it. A JSON error with a code field came from your application. An HTML block page with a CDN server header came from the CDN or firewall. A plain nginx or Apache error page came from the web server. Check the access log with sudo grep for the request path. If the request appears there but not in the application log, the web server stopped it.

Step 3

Fix the route for a 404

Compare the requested path and method with the routes your application registers. Check the base address, version prefix, trailing slash and method. For WordPress, request /wp-json/ to see the route index, and try ?rest_route= to bypass rewriting. If the query form works, resave permalinks or fix the nginx try_files rule. Confirm the corrected request returns 200 and a JSON body from the application.

Step 4

Fix the credentials for a 401 or 403

Confirm the API expects the auth type you are sending, that the token or password is current and that the user has the permission the route needs. For WordPress Application Passwords on Apache with CGI or FastCGI, add CGIPassAuth On so the credentials reach PHP. For browser calls using the login cookie, send the REST nonce in X-WP-Nonce. Retry with curl and confirm the error changes or clears.

Step 5

Check the firewall and security plugins

If the 403 is an HTML block page, find the event in your CDN or firewall log using the request ID, and note the rule that fired. Add a narrow exception for that rule on that API path rather than switching protection off. In WordPress, check security plugins for settings that restrict the REST API to logged-in users. Re-run the request and confirm the response now comes from the application.

Step 6

Test in Postman and the browser

Build the corrected request in Postman, using an environment variable for the base address. Open the Postman Console and confirm the full address, method and headers it actually sends. Then trigger the call from your site and watch the DevTools Network panel. If the browser alone fails, check the Console for a CORS error and make sure OPTIONS preflight requests return a success status with the right access control headers.

Step 7

Purge caches and retest

If a CDN sits in front of the API, purge the cached responses for the affected path, because an old 404 or 403 can be served after the fix. Add Cache-Control: no-store to API responses that change per user. Run the curl request again, then the Postman request, then the browser call, and confirm all three return the expected success status and JSON body.

Step 8

Add monitoring

Create a simple health route that returns 200, and check it from outside your network every few minutes with an uptime monitor. Save a Postman collection with one working request per route and method, and run it after every server, plugin or firewall change. Log request IDs in the application. Next time an API returns 404 or 403, you can match it to a log line and a layer within minutes.

Edge cases worth knowing

Keeping the API reliable

  1. Add a health route such as /api/v1/health that returns 200, and monitor it from outside your network so you hear about rewrite and firewall problems first.
  2. Return JSON errors with clear codes from the application, so any HTML error page is instantly recognisable as coming from another layer.
  3. Keep a saved Postman collection with one working request per route and method, and run it after server, plugin or firewall changes.
  4. Log request IDs in the application and pass them back in a response header, so you can match a failed call to a log line in seconds.
  5. Review firewall exceptions every few months and keep them as narrow as possible: one rule, one path.
Questions and answers

1. How do I fix a 404 error in a REST API?

You fix a REST API 404 by finding why the server has nothing at that path for that method. Send the request with curl to see who answered, then check the base address, version prefix, trailing slash and HTTP method against the routes your application registers. If the web server returns an HTML 404 before the application runs, fix the rewrite rules. For WordPress, resave permalinks or correct the nginx try_files rule so requests under wp-json reach WordPress.

2. Why do I get a 404 error in Postman?

You get a 404 in Postman when the address it actually sends does not match a route on the server. The usual causes are an empty or wrong environment variable for the base address, a missing prefix such as wp-json or api/v1, a double slash where variables join, a typo in the path or the wrong method in the dropdown. Open the Postman Console to see the exact request that was sent, then compare it with a request that works in curl.

3. How do I fix a 403 Forbidden error in Postman?

You fix a 403 in Postman by sending credentials the server accepts and ruling out a firewall block. Check the auth settings tab on the request and the parent collection, confirm the auth type and token are correct and current, and make sure the user has permission for that route. If the response is an HTML block page rather than JSON, a web application firewall stopped it, so find the event in its log and add a narrow exception.

4. What is the difference between a 401 and a 403 error in an API?

A 401 means the server does not know who you are, while a 403 means it knows or does not care, and still refuses. In practice, 401 points to missing, expired or malformed credentials, so fix the token or login. A 403 points to permissions or a block: the user lacks the role or capability, a security plugin restricts the route, or a firewall or server rule stopped the request. WordPress uses both in exactly this way for REST API calls.

5. Why does my WordPress REST API return 404?

Your WordPress REST API returns 404 when requests under wp-json never reach WordPress, or when no registered route matches the path and method. If you get an HTML 404 page, resave the permalink settings and check the Apache rewrite block or the nginx try_files rule. If you get a JSON error with the code rest_no_route, WordPress saw the request, so check the namespace, version, method and that the plugin registering the route is active.

6. Why does my API work in Postman but not in the browser?

An API that works in Postman but fails in the browser is usually blocked by CORS, which is a browser rule rather than a server error. The browser may send an OPTIONS preflight request first, and if the server or firewall answers it with 403 or 404, the real request is never sent. Check the DevTools Console for a CORS message, allow OPTIONS on the API routes and return the right access control headers for your site's origin.

7. Can a firewall cause a 403 error on my API?

Yes, a web application firewall is one of the most common causes of a 403 on an API. It may block requests whose JSON body looks like an injection attempt, whose user agent looks automated, or that arrive too quickly. The giveaway is an HTML block page instead of your API's usual JSON error. Use the request ID from the response headers to find the event in the firewall log, then add an exception for that rule on that path only.

Check your site and API endpoints for 4xx errors

The HTTP error audit requests your pages and endpoints, records each status code and the server that answered, and flags 404 and 403 responses so you can trace them to the right layer.

Open HTTP Error Fixes โ†’
๐Ÿ’ฌ Got a problem?
Related Guides: All HTTP Error Fixes  ·  Fixing 403 errors  ·  Fixing 404 errors  ·  WordPress HTTP errors  ·  Node.js HTTP errors  ·  Learning Hub

About aiwebpageseo

aiwebpageseo.com is a data-driven SEO and AEO (Answer Engine Optimisation) platform providing a free suite of technical SEO tools. Rather than relying on AI-theorised assumptions, the platform analyses live URL performance, delivering objective diagnostics, page speed metrics, CLS debugging, and site crawl data alongside actionable technical tutorials.