Visser Labs – WooCommerce Plugins

  1. Home
  2. Knowledge Base
  3. Checkout Guard
  4. Checkout Guard REST API reference

Checkout Guard REST API reference

Sometimes you want to block a customer without opening the WordPress admin. Maybe a fraud-scoring service flags an order, or a helpdesk tool marks someone as abusive. Checkout Guard ships a REST API so your own scripts and tools can read and manage your blocked entries, and check whether a customer would be blocked.

All routes live under one namespace, cgfw/v1. This article lists every route for blocked entries and settings, what it accepts, what it returns, and the errors you can hit. The namespace also has two license routes that the plugin’s own Settings screen uses. This article does not cover them.

This is a developer reference. It assumes you’re comfortable making HTTP requests with a tool like curl. If you just want to add or remove a blocked entry by hand, go to WooCommerce → Checkout Guard in your admin. For common blocking problems, see the Checkout Guard troubleshooting guide.

Prerequisites

RequirementDetails
PluginCheckout Guard 1.0.2 or later. The /check and /entries/batch routes, and wildcard matching, are part of 1.0.2.
WordPress5.6 or later to use Application Passwords. Checkout Guard itself supports WordPress 5.2 and up, but sites on 5.2 to 5.5 can’t use the authentication method below.
User roleA user with the manage_woocommerce capability, such as an Administrator or Shop Manager.
ConnectionHTTPS. WordPress only enables Application Passwords on HTTPS sites, or on sites where WP_ENVIRONMENT_TYPE is set to local.

Base URL and request format

Every route starts with your site’s REST base URL followed by the namespace:

https://your-store.example.com/wp-json/cgfw/v1

In every example below, replace your-store.example.com with your own domain.

If your site uses plain permalinks, /wp-json/ won’t work. Use the rest_route form instead:

https://your-store.example.com/?rest_route=/cgfw/v1/entries

Send request bodies as JSON and set the Content-Type: application/json header. Responses are JSON too. If a URL returns a 404, check your site’s REST base first.

Authentication

Every route needs the manage_woocommerce capability, so only Administrators and Shop Managers can call the API. For scripts and other automated callers, use a WordPress Application Password. It signs each request in as a specific user with HTTP Basic authentication. You don’t need a cookie or a nonce.

To create an Application Password:

  1. Log in as an Administrator or Shop Manager and go to Users → Profile.
  2. Scroll down to the Application Passwords section.
  3. Enter a name, such as Checkout Guard automation, in the New Application Password Name field.
  4. Click Add Application Password.
  5. Copy the password now, because WordPress shows it only once. It looks like xxxx xxxx xxxx xxxx xxxx xxxx. You can send it with or without the spaces.

Use that user’s login name as the username and the Application Password as the password:

curl https://your-store.example.com/wp-json/cgfw/v1/entries \
  --user "shopmanager:xxxx xxxx xxxx xxxx xxxx xxxx"

The API answers authentication problems in two ways:

  • No credentials: you get 401 Unauthorized.
  • Valid credentials, but the user lacks manage_woocommerce: you get 403 Forbidden. An Application Password for a Customer or Editor account signs in fine but is still refused.

The Checkout Guard admin screen uses these same routes. It authenticates with your logged-in session cookie plus an X-WP-Nonce header. You only need that approach if your own code runs inside the WordPress admin.

Route overview

Paths are relative to /wp-json/cgfw/v1.

MethodRoutePurpose
GET/entriesList blocked entries, optionally filtered.
POST/entriesCreate an entry. Safe to repeat.
POST/entries/batchCreate and delete many entries in one request.
PUT/entries/{id}Update an entry.
DELETE/entries/{id}Delete an entry.
POST/checkFind out whether a customer would be blocked.
GET/settingsRead the plugin settings.
POST/settingsUpdate the plugin settings.

How a blocked entry works

Each blocked entry has these fields:

FieldTypeDetails
idstringA UUID that Checkout Guard assigns when you create the entry.
first_namestringOptional. Supports a * wildcard, such as jo*.
last_namestringOptional. Supports a * wildcard, such as sm*th.
emailstringOptional. Supports a * wildcard, such as *@example.com.
ip_addressstringOptional. A single IPv4 or IPv6 address, or an IPv4 wildcard such as 192.168.1.*.
notesstringOptional. Cut to 140 bytes, which is 140 characters for plain Latin text and fewer for other scripts.
created_by_user_idintegerThe user who created the entry.
sourcestringapi when the entry was created with an Application Password, otherwise admin.

You must send at least one of first_name, last_name, email or ip_address. A name only blocks when the entry has both a first and a last name.

An entry blocks a customer when any one of these is true:

  • Both its first and last name match the customer’s name.
  • Its email matches the customer’s email.
  • Its IP address matches the customer’s IP address at checkout.

Name and email matching ignores upper and lower case. IP address matching is exact.

Checkout Guard reads the customer’s IP address the way WooCommerce does, so it follows common proxy headers.

Wildcard rules

Name and email values can use * to match zero or more characters. Matching is anchored to the whole value, so john* matches johnny but not ajohn. Every other character, including ., matches literally.

IP addresses accept wildcards only in IPv4 form. Use exactly four segments, where each segment is either all digits or exactly *, and at least one segment is a digit.

Each digit segment must be 0 to 255 with no leading zeros, so 192.168.01.* and 256.1.1.* are rejected with 400.

ValueResult
192.168.1.*, 192.168.*.1, 192.*.*.1Accepted
*.*.*.*Rejected with 400. No digit segment.
19*.168.1.1Rejected with 400. Mixed segment.
1.2.3.*.5Rejected with 400. Five segments.
2001:db8::*Rejected with 400. IPv6 wildcards aren’t supported.

A few more limits apply to every field:

  • No bare wildcards. A value that matches everything, such as *, **, *@* or *.*, is rejected with 400. *@example.com is fine because it has literal text left over.
  • At most 5 wildcards. A value with 6 or more * characters is rejected with 400.
  • Batch creates skip bad values. In a batch request, a rejected item isn’t saved. It’s counted in the skipped total, and the request itself still returns 200.
  • Lookups stay literal. When you filter GET /entries or send a repeat create, * is treated as a plain character. A wildcard rule and a literal value with the same characters are always separate entries.

Endpoints

List entries

GET /entries returns an array of entries. Add any of email, first_name, last_name or ip_address as query parameters to filter the list. Name and email filters are exact, case-insensitive matches. The ip_address filter is an exact match. Several filters combine with AND. An invalid email or ip_address returns 400.

Each entry in the list also includes created_by_display_name, and created_by_edit_url when the creating user still exists.

curl https://your-store.example.com/wp-json/cgfw/v1/entries \
  --user "shopmanager:xxxx xxxx xxxx xxxx xxxx xxxx"

# Look up one email
curl "https://your-store.example.com/wp-json/cgfw/v1/[email protected]" \
  --user "shopmanager:xxxx xxxx xxxx xxxx xxxx xxxx"

Response:

[
  {
    "id": "11112222-3333-4444-5555-666677778888",
    "first_name": "",
    "last_name": "",
    "email": "[email protected]",
    "ip_address": "",
    "notes": "chargeback fraud",
    "created_by_user_id": 2,
    "source": "api",
    "created_by_display_name": "Shop Manager",
    "created_by_edit_url": "https://your-store.example.com/wp-admin/user-edit.php?user_id=2"
  }
]

Create an entry

POST /entries creates an entry and returns it. Repeating the same request doesn’t create a duplicate. If an entry already exists with the same email, Checkout Guard updates it with any non-empty fields you send and returns it. When you send no email, it matches on the same first and last name. When you send neither, it matches on the same ip_address.

curl -X POST https://your-store.example.com/wp-json/cgfw/v1/entries \
  --user "shopmanager:xxxx xxxx xxxx xxxx xxxx xxxx" \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","notes":"chargeback fraud"}'

Response:

{
  "id": "11112222-3333-4444-5555-666677778888",
  "first_name": "",
  "last_name": "",
  "email": "[email protected]",
  "ip_address": "",
  "notes": "chargeback fraud",
  "created_by_user_id": 2,
  "source": "api"
}

To block by IP address only, send {"ip_address":"203.0.113.42","notes":"repeat spammer"}. A non-empty ip_address that isn’t valid returns 400.

Create and delete in bulk

POST /entries/batch lets you sync a whole list in one request. Send a create array, a delete array of entry IDs, or both. Checkout Guard processes the creates first, each one through the same repeat-safe path as a single create. Then it processes the deletes. At least one of the two arrays must have something in it, or you get 400.

curl -X POST https://your-store.example.com/wp-json/cgfw/v1/entries/batch \
  --user "shopmanager:xxxx xxxx xxxx xxxx xxxx xxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "create": [
      { "email": "[email protected]", "notes": "ring leader" },
      { "first_name": "Jane", "last_name": "Doe" }
    ],
    "delete": [ "99998888-7777-6666-5555-444433332222" ]
  }'

Response:

{
  "created": [
    {
      "id": "aaaa1111-2222-3333-4444-555566667777",
      "first_name": "",
      "last_name": "",
      "email": "[email protected]",
      "ip_address": "",
      "notes": "ring leader",
      "created_by_user_id": 2,
      "source": "api"
    }
  ],
  "deleted": [ "99998888-7777-6666-5555-444433332222" ],
  "not_found": [],
  "skipped": 0
}
Response fieldMeaning
createdThe entries that were created or updated.
deletedThe IDs that were removed.
not_foundDelete IDs that didn’t match any entry.
skippedHow many create items were ignored. An item is skipped when it has no name, email or IP address, or when it has an invalid IP address or wildcard.

Update or delete one entry

PUT /entries/{id} changes an entry. Send only the fields you want to change. The response is the full updated entry. You can’t clear every identifying field. The entry must keep at least one of the name, email or IP fields, or you get 400.

DELETE /entries/{id} removes an entry and returns { "success": true }. If the ID doesn’t match an entry, both routes return 404.

curl -X PUT https://your-store.example.com/wp-json/cgfw/v1/entries/11112222-3333-4444-5555-666677778888 \
  --user "shopmanager:xxxx xxxx xxxx xxxx xxxx xxxx" \
  -H "Content-Type: application/json" \
  -d '{"notes":"confirmed fraud"}'

curl -X DELETE https://your-store.example.com/wp-json/cgfw/v1/entries/11112222-3333-4444-5555-666677778888 \
  --user "shopmanager:xxxx xxxx xxxx xxxx xxxx xxxx"

Check a customer

POST /check tells you whether a customer would be blocked at checkout. It runs the same matching logic as the live checkout, so the answer matches what a real order would get. Send at least one of email, first_name, last_name or ip_address, or you get 400.

This route is strict about wildcards. The values you send are a real customer’s details, not a pattern. A * in any field returns 400.

curl -X POST https://your-store.example.com/wp-json/cgfw/v1/check \
  --user "shopmanager:xxxx xxxx xxxx xxxx xxxx xxxx" \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]"}'

Response:

{
  "blocked": true,
  "matched_entry": {
    "id": "11112222-3333-4444-5555-666677778888",
    "first_name": "",
    "last_name": "",
    "email": "[email protected]",
    "ip_address": "",
    "notes": "chargeback fraud",
    "created_by_user_id": 2,
    "source": "api"
  }
}

When no entry matches, blocked is false and matched_entry is null.

Read and update settings

GET /settings returns the plugin settings. The only setting is checkout_denial_message, which is the message a blocked customer sees at checkout. POST /settings changes it and returns the saved settings. The message can’t be empty, or you get 400.

curl https://your-store.example.com/wp-json/cgfw/v1/settings \
  --user "shopmanager:xxxx xxxx xxxx xxxx xxxx xxxx"

curl -X POST https://your-store.example.com/wp-json/cgfw/v1/settings \
  --user "shopmanager:xxxx xxxx xxxx xxxx xxxx xxxx" \
  -H "Content-Type: application/json" \
  -d '{"checkout_denial_message":"Sorry, you cannot place an order right now."}'

Response:

{ "checkout_denial_message": "Sorry, you cannot place an order right now." }

Error responses

Errors use the standard WordPress format, with a code, a message and an HTTP status.

StatusCodeWhen it happens
400invalid_entryA create or update has no name, email or IP address.
400invalid_checkA /check request has none of email, first_name, last_name or ip_address.
400invalid_batchA batch request has empty create and delete arrays.
400invalid_ip_addressAn IP address or IP wildcard isn’t valid.
400invalid_wildcard_valueA wildcard value is a bare wildcard or has more than 5 * characters.
400invalid_settingsThe settings message is empty.
400rest_invalid_paramA query or /check parameter isn’t valid, such as an email that isn’t valid or a * in a /check field.
401rest_forbiddenThe request has no credentials.
403rest_forbiddenThe user doesn’t have the manage_woocommerce capability.
404entry_not_foundNo entry matches the ID in the URL.

A 404 without a code means your site’s REST base URL is different from the one you used.

Privacy

Blocked entries are personal data. If you store customer emails, names or IP addresses, you’re responsible for handling them in line with your privacy obligations, such as GDPR.

Troubleshooting

I get a 403 even though my Application Password is correct
The password signed in, but the user it belongs to doesn’t have the manage_woocommerce capability. Create the Application Password under an Administrator or Shop Manager account instead.
The Application Passwords section is missing from my profile
Application Passwords need WordPress 5.6 or later and an HTTPS site, or a site where WP_ENVIRONMENT_TYPE is set to local. Check your WordPress version and that your store URL starts with https://. If your site is on 5.2 to 5.5, update WordPress first.
I get a 401 Unauthorized
The request reached the API without credentials, or WordPress didn’t accept them. Check that you’re sending the user’s username and the full Application Password. Also make sure your server passes the Authorization header through to WordPress.
The URL returns a 404
Your site probably uses plain permalinks or a custom REST base. Try the ?rest_route=/cgfw/v1/entries form, or ask your host what your REST base is.

Frequently asked questions

Can I use * in a /check request?
No. /check takes a real customer’s details, so a * in any field returns 400. Use wildcards only when you create or update entries.
Why does a repeat create return the same entry?
POST /entries is built to be safe to repeat. If an entry with the same email already exists, Checkout Guard updates it instead of adding a duplicate. That also applies to the same name or IP address when no email is sent.
What does skipped mean in a batch response?
It counts the create items that Checkout Guard ignored. An item is skipped when it has no name, email or IP address, or when it has an invalid IP address or a wildcard that isn’t allowed. The request itself still succeeds.
How can I tell which entries came from the API?
Check the source field. Entries created with an Application Password have source set to api. Entries added in the admin screen have admin.

Need help?

Checkout Guard is a licensed plugin. If you’re still stuck, open a support ticket and include the route, the request you sent and the response you got back. That helps our team check your setup directly.

Was this article helpful?

Related Articles

Resources & Help