Developer guidesThe REST API

The REST API

How the Easy SVG Pro REST routes work: namespace, authentication, licence and feature gates, and curl examples for sets, packs, the audit and features.

Every screen of Easy SVG Pro talks to WordPress through REST routes under one namespace. You can call the same routes from a script, a deploy pipeline or another site. This page explains how they are protected, which families exist, and shows working curl calls for the ones you are most likely to need.

These routes are internal. They exist for the plugin's own screens, none of them is documented in the readme, and any of them may change shape between versions. For anything your project depends on, prefer the WP-CLI commands, the abilities or the documented hooks. Pin the plugin version when you script against REST.

The basics

Base urlhttps://example.com/wp-json/easy-svg-pro/v1/
FormatJSON in, JSON out, except pack exports (ZIP bytes) and uploads (multipart)
WhoA logged-in WordPress user with manage_options for almost every route
ErrorsWordPress errors: code, message and data.status

An error always looks like this:

{
  "code": "easy_svg_pro_no_set",
  "message": "Set not found.",
  "data": { "status": 404 }
}

Branch on code, not on the message: messages are translated into the user's language.

Authentication

Create an application password under Users → Profile → Application Passwords for an administrator, then send it with HTTP Basic auth. WordPress offers application passwords only over HTTPS, or on a site whose environment type is local.

export WP_URL="https://example.com"
export WP_AUTH="admin:abcd efgh ijkl mnop qrst uvwx"

curl -s -u "$WP_AUTH" "$WP_URL/wp-json/easy-svg-pro/v1/features"

Use a dedicated user for automation, so you can revoke its password without touching anyone else.

Who may call what

Each route has one of these permission checks. A failed check answers 401 (not logged in) or 403 (logged in, not allowed).

CheckNeedsRoutes
Editormanage_options, active licence, Icon set editor featuresets/*, media/markup, library/move, library/usage
Licensedmanage_options, active licencesettings, features, packs/*, library/collections
Auditmanage_options, active licence, SVG cleaner featureaudit/*
Own flagmanage_options, active licence, that featurepresets/*, history/*, styles/*, bulk/*, replace/*, repair/* and the others

Activating the licence is not part of this API; do it under Icons → License.

Features: switch things on

Most routes need a feature flag, so this is usually the first call.

# Read the flags
curl -s -u "$WP_AUTH" "$WP_URL/wp-json/easy-svg-pro/v1/features"

# Switch on the set editor and the SVG cleaner. Flags you do not name keep their value.
curl -s -u "$WP_AUTH" -X POST "$WP_URL/wp-json/easy-svg-pro/v1/features" \
  -H "Content-Type: application/json" \
  -d '{"editor":true,"audit":true}'

The answer holds flags (key to boolean) and meta (label and description in the user's language). GET also returns groups and available, which says whether an integration's host plugin is installed. Unknown keys are dropped.

Icon sets

A set is a named collection of icons, stored as an easy_svg_set post. Every icon you send is sanitized and hardened before it is stored, and every write fires easy_svg_pro_set_icons_written.

List the sets

curl -s -u "$WP_AUTH" "$WP_URL/wp-json/easy-svg-pro/v1/sets/list?search=acme"
[
  { "id": 42, "title": "ACME", "slug": "acme", "status": "publish", "count": 12,
    "template_call": "easy_svg_icon( 'acme/icon-slug' )" }
]

Drafts and private sets are included. slug is the registered collection slug, the one templates use.

Create a set

curl -s -u "$WP_AUTH" -X POST "$WP_URL/wp-json/easy-svg-pro/v1/sets/create" \
  -H "Content-Type: application/json" \
  -d '{"label":"ACME"}'

The answer gives id, label and collection. The slug is made once from the label and never changes on a rename.

Add icons without touching the rest

curl -s -u "$WP_AUTH" -X POST "$WP_URL/wp-json/easy-svg-pro/v1/sets/42/icons/add" \
  -H "Content-Type: application/json" \
  -d '{
    "icons": {
      "phone": { "label": "Phone", "markup": "<svg viewBox="0 0 24 24"><path d="M2 2h20v20H2z"/></svg>" }
    }
  }'

At most 25 icons per call. An icon whose slug is already in the set is reported as exists and left alone. Send "replace": true to overwrite it, then the report says replaced. Icons the sanitizer refuses are dropped and do not appear in the report, so compare what you sent with what came back.

Remove icons by name

curl -s -u "$WP_AUTH" -X POST "$WP_URL/wp-json/easy-svg-pro/v1/sets/42/icons/remove" \
  -H "Content-Type: application/json" \
  -d '{"slugs":["phone","old-logo"]}'

A name the set does not hold is reported as not_found; the others are still removed.

GET /sets/42 returns the whole set. POST /sets/42 replaces it: every icon you leave out of the body is deleted. Use icons/add and icons/remove unless you really hold the full set.

# Read one set
curl -s -u "$WP_AUTH" "$WP_URL/wp-json/easy-svg-pro/v1/sets/42"

Packs

A pack is a collection as a ZIP: manifest.json plus one SVG per icon. These routes need a licence, but no feature flag.

# Every collection on the site, with origin, licence info and problems
curl -s -u "$WP_AUTH" "$WP_URL/wp-json/easy-svg-pro/v1/packs/collections"

# Export one collection. The answer is the ZIP itself, not JSON.
curl -s -u "$WP_AUTH" -o acme.zip \
  "$WP_URL/wp-json/easy-svg-pro/v1/packs/export?collection=acme"

Importing is a multipart upload in the field file. The pack becomes a new published icon set and never merges into an existing collection.

curl -s -u "$WP_AUTH" -X POST "$WP_URL/wp-json/easy-svg-pro/v1/packs/import" \
  -F "file=@acme.zip"

If the pack's slug is taken, nothing is stored yet. The answer has "collision": true, "imported": 0 and a free slug. Send that slug back to confirm:

curl -s -u "$WP_AUTH" -X POST "$WP_URL/wp-json/easy-svg-pro/v1/packs/import" \
  -F "file=@acme.zip" -F "slug=acme-2"

Errors you will meet: 422 easy_svg_pro_empty_pack (no icon survived the sanitizer), 409 easy_svg_pro_no_slug, 400 easy_svg_pro_no_file. The archive is read with the same caps as every import, see easy_svg_pro_import_max_entries.

SVG cleaner (audit)

The audit finds SVGs in the media library that the sanitizer would change, and cleans them one at a time. It needs the SVG cleaner feature.

# 1. Scan in chunks. Start at offset 0 and follow "next" until it is null.
next=0
while [ "$next" != "null" ]; do
  answer=$(curl -s -u "$WP_AUTH" -X POST "$WP_URL/wp-json/easy-svg-pro/v1/audit/scan" \
    -H "Content-Type: application/json" -d "{"offset":$next}")
  next=$(echo "$answer" | jq '.next')
done

# 2. Read the stored report without scanning again
curl -s -u "$WP_AUTH" "$WP_URL/wp-json/easy-svg-pro/v1/audit/report" | jq '.rows'

# 3. Clean one attachment. The original is stored first.
curl -s -u "$WP_AUTH" -X POST "$WP_URL/wp-json/easy-svg-pro/v1/audit/clean" \
  -H "Content-Type: application/json" -d '{"attachment":101}'

A scan call whose offset does not match the stored next answers 409 easy_svg_pro_stale_scan: someone started another scan meanwhile. Start again at 0. The clean route answers a state such as cleaned, already_clean or backup_failed; nothing is rewritten unless the original was stored and read back first.

Other families

FamilyWhat it doesFeature
settingsConfigurator: extra allowed tags and attributesnone
library/*The icon grid, moving icons, where an icon is usedLicensed or Icon set editor
presets, presets/installPreset catalog and installPreset icon sets
history/*Earlier drawings of an icon, restoreIcon history
styles/*Style templates and theme colorsStyles & theme colors
bulk/*Rename, copy, move many iconsBulk editing
replace/*Swap one icon for another everywhereReplace everywhere
repair/*Find and mend broken SVGsRepair broken SVGs
client/*Client mode swapClient mode
quick-insert/*Recents, favorites, insert from the editorQuick insert

Each route has its own page under the REST API reference.

Pitfalls

  • POST /sets/{id} deletes what you leave out. It is the editor's save, not an add.
  • 25 icons per call. icons/add and icons/remove refuse larger bodies. Send batches.
  • Refused icons are silent. An icon the sanitizer rejects is missing from the report rather than listed with a reason.
  • presets/install answers 200 on failure. Check state in the body, not the status code.
  • Without an active licence every route answers 403. Activate the site under Icons → License first.
  • Internal means internal. A route, a field or an error code can change in any release. Re-test your scripts after every update.