Tutorial
This tutorial provides a step-by-step walkthrough of WP Engine’s Hosting Platform API. You’ll learn how to authenticate, query resources, handle pagination, and respond to errors.
0. Prerequisites
Section titled “0. Prerequisites”- The cURL pagination loop later uses
jqfor JSON parsing. Install via Homebrew:brew install jq. - JavaScript examples rely on top-level
await(Node 18+ or any modern runtime supporting ESM). - Python examples require the
requestslibrary. Install withpip install requests.
1. Authenticate
Section titled “1. Authenticate”The API uses Basic Auth with your User ID and Password from the API Access page of the WP Engine User Portal.
Store your credentials in environment variables (we’ll use WPE_API_USER_ID and WPE_API_PASSWORD consistently across all language examples):
# Exact method for storing env vars may vary by OS/shell/developer preference/etcWPE_API_USER_ID="YOUR_API_USER_ID"WPE_API_PASSWORD="YOUR_API_PASSWORD"Then construct the Authorization header:
curl -u "$WPE_API_USER_ID:$WPE_API_PASSWORD" \ "https://api.wpengineapi.com/v1/installs?limit=3"package main
import ( "fmt" "io" "net/http" "os")
func main() { user := os.Getenv("WPE_API_USER_ID") pass := os.Getenv("WPE_API_PASSWORD") req, _ := http.NewRequest("GET", "https://api.wpengineapi.com/v1/installs?limit=3", nil) req.SetBasicAuth(user, pass) resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))}const user = process.env.WPE_API_USER_ID;const pass = process.env.WPE_API_PASSWORD;const auth = "Basic " + Buffer.from(`${user}:${pass}`).toString("base64");
// Top-level await requires Node 18+ (ESM) or a modern runtime.try { const res = await fetch("https://api.wpengineapi.com/v1/installs?limit=3", { headers: { Authorization: auth } }); if (!res.ok) throw new Error(`Request failed: ${res.status}`); console.log(await res.json());} catch (err) { console.error(err);}import os, requests
user = os.getenv("WPE_API_USER_ID")password = os.getenv("WPE_API_PASSWORD")
resp = requests.get( "https://api.wpengineapi.com/v1/installs?limit=3", auth=(user, password), timeout=10,)print(resp.json())2. List Installs
Section titled “2. List Installs”The /installs endpoint returns all WordPress installs accessible to your account.
Example request:
curl -u "$WPE_API_USER_ID:$WPE_API_PASSWORD" \ "https://api.wpengineapi.com/v1/installs?limit=3"package main
import ( "fmt" "io" "net/http" "os")
func main() { user := os.Getenv("WPE_API_USER_ID") pass := os.Getenv("WPE_API_PASSWORD") url := "https://api.wpengineapi.com/v1/installs?limit=3" req, _ := http.NewRequest("GET", url, nil) req.SetBasicAuth(user, pass) resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))}const user = process.env.WPE_API_USER_ID;const pass = process.env.WPE_API_PASSWORD;const auth = "Basic " + Buffer.from(`${user}:${pass}`).toString("base64");
try { const res = await fetch("https://api.wpengineapi.com/v1/installs?limit=3", { headers: { Authorization: auth } }); if (!res.ok) throw new Error(`Request failed: ${res.status}`); const data = await res.json(); data.results?.forEach(i => console.log(i.name));} catch (e) { console.error(e); }import os, requests
user = os.getenv("WPE_API_USER_ID")password = os.getenv("WPE_API_PASSWORD")
url = "https://api.wpengineapi.com/v1/installs?limit=3"resp = requests.get(url, auth=(user, password), timeout=10)for install in resp.json().get("results", []): print(install["name"])Example response:
{ "count": 232, "results": [ { "id": 12345, "name": "marketing-site", "account_id": 67890, "created_at": "2024-01-01T12:00:00Z" }, { "id": 12346, "name": "blog-site", "account_id": 67890, "created_at": "2024-01-02T15:00:00Z" } ], "next": "https://api.wpengineapi.com/v1/installs?limit=3&offset=3"}3. Handle Pagination
Section titled “3. Handle Pagination”Many list endpoints return large result sets. The API uses offset-based pagination.
- limit: number of results per page (max 100).
- offset: number of results to skip.
Example:
curl -u "$WPE_API_USER_ID:$WPE_API_PASSWORD" \ "https://api.wpengineapi.com/v1/installs?limit=5&offset=5"package main
import ( "fmt" "io" "net/http" "os")
func main() { user := os.Getenv("WPE_API_USER_ID") pass := os.Getenv("WPE_API_PASSWORD") url := "https://api.wpengineapi.com/v1/installs?limit=5&offset=5" req, _ := http.NewRequest("GET", url, nil) req.SetBasicAuth(user, pass) resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))}const user = process.env.WPE_API_USER_ID;const pass = process.env.WPE_API_PASSWORD;const auth = "Basic " + Buffer.from(`${user}:${pass}`).toString("base64");
try { const res = await fetch("https://api.wpengineapi.com/v1/installs?limit=5&offset=5", { headers: { Authorization: auth } }); if (!res.ok) throw new Error(`Request failed: ${res.status}`); const data = await res.json(); console.log("Page count:", data.results?.length); console.log("Next:", data.next);} catch (e) { console.error(e); }import os, requests
user = os.getenv("WPE_API_USER_ID")password = os.getenv("WPE_API_PASSWORD")
url = "https://api.wpengineapi.com/v1/installs?limit=5&offset=5"resp = requests.get(url, auth=(user, password), timeout=10)data = resp.json()print("Page count:", len(data.get("results", [])))print("Next:", data.get("next"))The response will include next and previous URLs for easy navigation:
{ "previous": "https://api.wpengineapi.com/v1/installs?limit=5&offset=0", "next": "https://api.wpengineapi.com/v1/installs?limit=5&offset=10", "count": 232, "results": [...]}When no previous or next page exists, the value of next/previous will be null.
4. Fetch a Single Resource
Section titled “4. Fetch a Single Resource”You can fetch a single install by ID:
# Placeholder ID 12345 used for illustration; replace with a real install ID.# A 404 response means the placeholder doesn't exist in your account.curl -u "$WPE_API_USER_ID:$WPE_API_PASSWORD" \ "https://api.wpengineapi.com/v1/installs/12345"package main
import ( "fmt" "io" "net/http" "os")
func main() { user := os.Getenv("WPE_API_USER_ID") pass := os.Getenv("WPE_API_PASSWORD") installID := "12345" // placeholder; replace with a real install ID to avoid 404 url := "https://api.wpengineapi.com/v1/installs/" + installID req, _ := http.NewRequest("GET", url, nil) req.SetBasicAuth(user, pass) resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))}const user = process.env.WPE_API_USER_ID;const pass = process.env.WPE_API_PASSWORD;const auth = "Basic " + Buffer.from(`${user}:${pass}`).toString("base64");const installId = 12345; // placeholder; replace with a real ID from a list response
try { const res = await fetch(`https://api.wpengineapi.com/v1/installs/${installId}`, { headers: { Authorization: auth } }); if (!res.ok) throw new Error(`Request failed: ${res.status}`); // 404 likely if placeholder not present console.log(await res.json());} catch (e) { console.error(e); }import os, requests
user = os.getenv("WPE_API_USER_ID")password = os.getenv("WPE_API_PASSWORD")
install_id = 12345 # placeholder; replace with a real install ID to avoid 404url = f"https://api.wpengineapi.com/v1/installs/{install_id}"resp = requests.get(url, auth=(user, password), timeout=10)print(resp.json()) # May be an error body if placeholder isn't validResponse:
{ "id": 12345, "name": "marketing-site", "account_id": 67890, "created_at": "2024-01-01T12:00:00Z", "domains": [{ "hostname": "marketing.example.com", "primary": true }]}5. Handle Errors
Section titled “5. Handle Errors”The API uses standard HTTP status codes.
-
2xx — success.
-
4xx — validation or request error.
-
5xx — server error.
Example of a 400 Bad Request:
curl -u "$WPE_API_USER_ID:$WPE_API_PASSWORD" \ "https://api.wpengineapi.com/v1/installs?limit=5000"package main
import ( "fmt" "io" "net/http" "os")
func main() { user := os.Getenv("WPE_API_USER_ID") pass := os.Getenv("WPE_API_PASSWORD") url := "https://api.wpengineapi.com/v1/installs?limit=5000" req, _ := http.NewRequest("GET", url, nil) req.SetBasicAuth(user, pass) resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() fmt.Println("Status:", resp.StatusCode) body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))}const user = process.env.WPE_API_USER_ID;const pass = process.env.WPE_API_PASSWORD;const auth = "Basic " + Buffer.from(`${user}:${pass}`).toString("base64");
try { const res = await fetch("https://api.wpengineapi.com/v1/installs?limit=5000", { headers: { Authorization: auth } }); const body = await res.json(); console.log("Status:", res.status); console.log(body);} catch (e) { console.error(e); }import os, requests
user = os.getenv("WPE_API_USER_ID")password = os.getenv("WPE_API_PASSWORD")
url = "https://api.wpengineapi.com/v1/installs?limit=5000" # invalid, over 100resp = requests.get(url, auth=(user, password), timeout=10)print("Status:", resp.status_code)print(resp.json())Response:
{ "type": "invalid_value", "code": "too_large", "message": "Limit cannot exceed 100."}Always check the response body for structured error details.
6. Automate Workflows
Section titled “6. Automate Workflows”With the basics in place, you can script automation:
-
Sync site data into dashboards.
-
Trigger cache purges or deploys from CI/CD pipelines.
-
Run scheduled tasks against installs or domains.
Below are examples that iterate through every page of installs until no further next link is provided.
These loops may output many lines if you have numerous installs.
# Requires: WPE_API_USER_ID / WPE_API_PASSWORD env vars# Iterate through all pages using the 'next' link. Requires jq.NEXT="https://api.wpengineapi.com/v1/installs?limit=100"AUTH="${WPE_API_USER_ID}:${WPE_API_PASSWORD}"while [ -n "$NEXT" ] && [ "$NEXT" != "null" ]; do RESP=$(curl -u "$AUTH" "$NEXT") echo "$RESP" | jq -r '.results[]?.name' NEXT=$(echo "$RESP" | jq -r '.next')donepackage main
import ( "encoding/json" "fmt" "io" "net/http" "os")
type install struct { Name string `json:"name"` }type page struct { Results []install `json:"results"` Next *string `json:"next"`}
func main() { user := os.Getenv("WPE_API_USER_ID") pass := os.Getenv("WPE_API_PASSWORD") next := "https://api.wpengineapi.com/v1/installs?limit=100" client := http.DefaultClient for next != "" && next != "null" { req, _ := http.NewRequest("GET", next, nil) req.SetBasicAuth(user, pass) resp, err := client.Do(req) if err != nil { panic(err) } body, _ := io.ReadAll(resp.Body) _ = resp.Body.Close()
var p page if err := json.Unmarshal(body, &p); err != nil { panic(err) } for _, inst := range p.Results { fmt.Println(inst.Name) } if p.Next == nil { break } next = *p.Next }}const user = process.env.WPE_API_USER_ID;const pass = process.env.WPE_API_PASSWORD;const auth = "Basic " + Buffer.from(`${user}:${pass}`).toString("base64");
let url = "https://api.wpengineapi.com/v1/installs?limit=100";const seen = new Set();while (url && url !== 'null') { if (seen.has(url)) { console.warn('Cycle detected, aborting.'); break; } seen.add(url); const res = await fetch(url, { headers: { Authorization: auth } }); if (!res.ok) throw new Error(`Request failed: ${res.status}`); const data = await res.json(); data.results?.forEach(inst => console.log(inst.name)); url = data.next; // continue if more pages}import os, requests
user = os.getenv("WPE_API_USER_ID")password = os.getenv("WPE_API_PASSWORD")
url = "https://api.wpengineapi.com/v1/installs?limit=100"while url and url != 'null': resp = requests.get(url, auth=(user, password), timeout=15) data = resp.json() for inst in data.get("results", []): print(inst.get("name")) url = data.get("next")Next Steps
Section titled “Next Steps”Now that you’ve seen authentication, pagination, and error handling, you can:
- Explore more endpoints in the API Reference.